Jak rozwiązać błąd „Brak bazy danych klucza tajnego w środowisku produkcyjnym” (Rails 4.1)

169

Stworzyłem od podstaw aplikację Rails, używając Rails 4.1 i mam do czynienia z dziwnym problemem, którego nie jestem w stanie rozwiązać.

Za każdym razem, gdy próbuję wdrożyć moją aplikację w Heroku, pojawia się błąd 500:

Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml`

secret.ymlPlik zawiera następującą konfigurację:

secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

Na Heroku skonfigurowałem SECRET_KEY_BASEzmienną środowiskową " " z wynikiem rake secretpolecenia. Jeśli uruchamiam heroku config, widzę zmienną z poprawną nazwą i wartością.

Dlaczego nadal otrzymuję ten błąd?

Paolo Laurenti
źródło
1
Mam dokładnie ten sam problem i chciałbym wiedzieć, dlaczego tak się dzieje. Jeśli dowiem się, dlaczego, prześlę z powrotem moje rozwiązanie.
danielricecodes
Czy twój plik konfiguracyjny nazywa się secret.ymllub secrets.yml?
James
2
Skonfigurowałem ponownie plik .gitignore z tym wygenerowanym przez railsy i teraz wszystko działa dobrze
Paolo Laurenti
Mieliśmy również ten problem podczas aktualizacji do Rails 4. W naszym przypadku było to spowodowane tym, że mieliśmy niestandardową nazwę środowiska, a nie było to odzwierciedlone w pliku secrets.yml. Musiałem tylko dodać wiersz do pliku z niestandardową nazwą, zatwierdzeniem i ponownym wdrożeniem.
whognu
Dla przyszłych czytelników: ta odpowiedź jest prawdopodobnie najłatwiejsza i najdokładniejsza: stackoverflow.com/a/26541742/4880924
BKSpurgeon

Odpowiedzi:

208

Miałem ten sam problem i rozwiązałem go, tworząc zmienną środowiskową, która była ładowana za każdym razem, gdy logowałem się do serwera produkcyjnego, i zrobiłem mini przewodnik po krokach, aby ją skonfigurować:

Używałem Rails 4.1 z Unicorn v4.8.2 i kiedy próbowałem wdrożyć moją aplikację, nie uruchomiła się ona poprawnie, aw unicorn.logpliku znalazłem ten komunikat o błędzie:

app error: Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` (RuntimeError)

Po kilku poszukiwaniach dowiedziałem się, że Rails 4.1 zmienił sposób zarządzania secret_key, więc jeśli przeczytasz secrets.ymlplik znajdujący exampleRailsProject/config/secrets.ymlsię tam, znajdziesz coś takiego:

# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

Oznacza to, że Railsy zalecają użycie zmiennej środowiskowej dla secret_key_baseserwera produkcyjnego. Aby rozwiązać ten błąd, wykonaj następujące kroki, aby utworzyć zmienną środowiskową dla systemu Linux (w moim przypadku Ubuntu) na serwerze produkcyjnym:

  1. W terminalu twojego serwera produkcyjnego wykonaj:

    $ RAILS_ENV=production rake secret

    Zwraca duży ciąg z literami i cyframi. Skopiuj to, do którego będziemy odnosić się do tego kodu jako GENERATED_CODE.

  2. Zaloguj się do swojego serwera

    • Jeśli logujesz się jako użytkownik root, znajdź ten plik i edytuj go:

      $ vi /etc/profile

      Przejdź na dół pliku, używając Shift+ G(duże „G”) w vi.

      Napisz swoją zmienną środowiskową za pomocą GENERATED_CODE, naciskając, iaby wstawić do vi. Upewnij się, że na końcu pliku znajduje się nowy wiersz:

      $ export SECRET_KEY_BASE=GENERATED_CODE

      Zapisz zmiany i zamknij plik za pomocą, Esca następnie " :x" i Enterdo zapisania i wyjścia w vi.

    • Ale jeśli logujesz się jako zwykły użytkownik, nazwijmy to „ example_user” w tym celu, będziesz musiał znaleźć jeden z tych innych plików:

      $ vi ~/.bash_profile
      $ vi ~/.bash_login
      $ vi ~/.profile

      Te pliki są uporządkowane według ważności, co oznacza, że ​​jeśli masz pierwszy plik, nie musisz edytować pozostałych. Jeśli znalazłeś te dwa pliki w swoim katalogu ~/.bash_profilei ~/.profilebędziesz musiał pisać tylko w pierwszym ~/.bash_profile, ponieważ Linux odczyta tylko ten jeden, a drugi zostanie zignorowany.

      Następnie ponownie przechodzimy do końca pliku za pomocą Shift+ Gi ponownie zapisujemy zmienną środowiskową za GENERATED_CODEpomocą naszego użycia i, i pamiętaj, aby dodać nową linię na końcu pliku:

      $ export SECRET_KEY_BASE=GENERATED_CODE

      Po napisaniu kodu zapisz zmiany i zamknij plik używając Escponownie i " :x" oraz Enteraby zapisać i wyjść.

  3. Możesz sprawdzić, czy nasza zmienna środowiskowa jest poprawnie ustawiona w systemie Linux za pomocą tego polecenia:

    $ printenv | grep SECRET_KEY_BASE

    lub z:

    $ echo $SECRET_KEY_BASE

    Kiedy wykonasz to polecenie, jeśli wszystko poszło dobrze, pokaże ci to GENERATED_CODEz poprzedniego. Wreszcie, po wykonaniu całej konfiguracji, powinieneś być w stanie bez problemów wdrożyć aplikację Rails z Unicornem lub innym narzędziem.

Kiedy zamkniesz swoją powłokę i zalogujesz się ponownie do serwera produkcyjnego, będziesz mieć ustawioną zmienną środowiskową i gotową do użycia.

I to wszystko! Mam nadzieję, że ten mini poradnik pomoże ci rozwiązać ten błąd.

Uwaga: nie jestem guru Linuksa ani Railsów, więc jeśli znajdziesz coś nie tak lub jakikolwiek błąd, z przyjemnością to naprawię.

Demi Magus
źródło
11
Wygląda na to, że Railsy nie widzą zmiennej środowiskowej SECRET_KEY_BASE. printenv to pokazuje, rails c production również wyświetla to, jeśli sprawdzę ENV. Ale nie mam żadnego efektu, kiedy ponownie uruchamiam Unicorn. Jedynym sposobem, który teraz działa, jest wklejenie go bezpośrednio do
sekretów. Syml
1
To zadziałało dla mnie. Dziękuję za pełne wyjaśnienie. Właśnie dowiedziałem się, że istnieją klejnoty do zarządzania zmiennymi środowiskowymi aplikacji. „Dotenv” to jeden, a „brygadzista” dla heroku. Chociaż ręczne naprawienie błędu w ten sposób było edukacją, może użycie jednego z tych klejnotów usprawni ten proces?
Nick Res
Cieszę się, że moja odpowiedź była pomocna, dzięki za opcje klejnotów @ ninja08, zdecydowanie ułatwiają proces, głównie tym, którzy używają capistrano lub innego narzędzia przyrostowego do zarządzania serwerem :)
Demi Magus
Postępując zgodnie ze świetnymi instrukcjami Demi Magusa, zrobiłem coś takiego: cd / var / www / rails; rvm use ext-rbx-2.5.2@rails; SKB_FILE = / var / www / .secret_key_base; echo "export SECRET_KEY_BASE = $ (RAILS_ENV = sekret prowizji produkcji)"> $ SKB_FILE; . $ SKB_FILE; echo ". $ SKB_FILE" | tee -a ~ / .bashrc ~ / .bash_profile; chmod o-rwx $ SKB_FILE;
David Winiecki
Niezła odpowiedź!! Nie wiem, dlaczego to nie jest dla mnie rozwiązane, tworzę pytanie stackoverflow.com/questions/33117318/ ...
Adriano Resende
84

Zakładam, że nie masz secrets.ymlwpisanego do kontroli źródła (tj. Jest w .gitignorepliku). Nawet jeśli to nie jest twoja sytuacja, zrobiło to wiele innych osób przeglądających to pytanie, ponieważ mają ujawniony kod na Github i nie chcą, aby ich tajny klucz unosił się w pobliżu.

Jeśli nie podlega kontroli źródła, Heroku o tym nie wie. Tak więc Railsy poszukują Rails.application.secrets.secret_key_basei nie zostało to ustawione, ponieważ Railsy ustawiają to sprawdzając secrets.ymlplik, który nie istnieje. Prostym obejściem jest przejście do config/environments/production.rbpliku i dodanie następującego wiersza:

Rails.application.configure do
    ...
    config.secret_key_base = ENV["SECRET_KEY_BASE"]
    ...
end

Mówi to aplikacji, aby ustawiła tajny klucz przy użyciu zmiennej środowiskowej, zamiast szukać go w secrets.yml. Pozwoliłoby mi zaoszczędzić dużo czasu, gdybym wiedział o tym z góry.

Erik Trautman
źródło
15
To najlepsza odpowiedź. Figaroi heroku_secretsnie rób nic, chyba że Railsy wiedzą, że to SECRET_KEY_BASEżyje ENV. Zmagałem się z myślą, że gdyby zmienna konfiguracyjna istniała na Heroku, Railsy by ją odebrały tylko dlatego, że istnieje, ale teraz wydaje się oślepiająco oczywiste, że Railsy musiałyby wiedzieć, gdzie szukać. Zastanawiałem się, jak mogę mieć kod na Githubie bez martwienia się o tajną bazę klucza; teraz wiem.
flanger001
1
Zgoda, myślę, że tajemnice. Syml jest zbyteczny w przypadku wielkich klejnotów, takich jak Figaro.
Joe
2
Wydaje się, że jest to najlepsza opcja, jeśli używasz github i heroku do swojego projektu.
flexus
1
Co jest złego w przekazywaniu twoich sekretów production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>. Syml z . Czy nie oznacza to również, że rzeczywisty tajny klucz nie zostanie ujawniony. Czy istnieje ryzyko ujawnienia kluczy deweloperskich i testowych w zatwierdzonych sekretach .yml, jeśli są to tylko dane seed i testowe?
Jay Killeen,
Działa to nawet w Railsach 6.0.2, kiedy nie ma już pliku secrets.yml.
Ken Tsoi
54

Dodaj config/secrets.ymldo kontroli wersji i wdróż ponownie. Może być konieczne usunięcie linii z .gitignore, aby móc zatwierdzić plik.

Miałem dokładnie ten sam problem i okazało się, że .gitignorezawierał standardowy szablon Github stworzony dla mojej aplikacji Railsowej config/secrets.yml.

danielricecodes
źródło
140
config / secrets.yml NIGDY nie powinno znajdować się w repozytorium, które możesz zrobić.yml.sample i wypełnić go fałszywymi danymi, ale ze względów bezpieczeństwa nigdy nie rób .yml w
repozytoriach
9
@ user3379926, w kontekście aplikacji Rails na Heroku, nie możesz wybierać i wybierać, które pliki są objęte kontrolą wersji, a które nie. Rails 4.1 oczekuje, że tajna konfiguracja istnieje, w przeciwnym razie aplikacja nie będzie działać. Jeśli masz sposób na rozwiązanie problemu przedstawionego w powyższym pytaniu bez konieczności zapisywania pliku secrets.yml w Git, pomóż ulepszyć ten wątek, udzielając tej porady.
danielricecodes
9
@danielricecodes możesz ręcznie ustawić wartość w inicjatorze. Coś takiego Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]mogłoby zadziałać i usunąć błąd bez dodawania secrets.ymldo źródła.
joshhepworth,
11
@ user3379926: Kiedy generuję nową aplikację Railsów z rails new(w tym przypadku tworząc Gemfile, którego railsgem ma wersję 4.2.4), plik config/secrets.ymljest generowany. Obejmuje ona pregenerated tajnych kluczy dla środowisk programistycznych i testowych, a czyta tajny klucz do środowiska produkcyjnego od zmiennej środowiskowej: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>. Wydaje mi się, że utrzymywanie tego secrets.ymlpliku w kontroli wersji jest całkowicie bezpieczne, a nawet przydatne , pod warunkiem, że nigdy nie zdefiniowano tam tajnego klucza.
Teemu Leisti
2
@jasonleonhard why? jeśli mimo wszystko czytasz tajny klucz z vars env, o co chodzi? nie ma ujawnionych tajemnic.
horseyguy
13

To zadziałało dla mnie.

SSH na swój serwer produkcyjny i cddo bieżącego katalogu, uruchom bundle exec rake secretlub rake secret, jeśli otrzymasz długi ciąg jako wynik, skopiuj ten ciąg.

A teraz biegnij sudo nano /etc/environment.

Wklej na dole pliku

export SECRET_KEY_BASE=rake secret
ruby -e 'p ENV["SECRET_KEY_BASE"]'

Gdzie rake secretjest właśnie skopiowany ciąg, wklej ten skopiowany ciąg zamiast rake secret.

Uruchom ponownie serwer i przetestuj, uruchamiając echo $SECRET_KEY_BASE.

sumitsv21
źródło
3

Chociaż możesz używać inicjatorów, tak jak inne odpowiedzi, konwencjonalnym sposobem Rails 4.1+ jest użycie config/secrets.yml. Powód, dla którego zespół Railsów to wprowadził, wykracza poza zakres tej odpowiedzi, ale TL; DR jest to, że secret_token.rbłączy konfigurację i kod, a także stanowi zagrożenie bezpieczeństwa, ponieważ token jest sprawdzany w historii kontroli źródła i jest jedynym systemem, który musi wiedzieć, że tajny token produkcji to infrastruktura produkcyjna.

Powinieneś dodać ten plik .gitignoretak, jak nie byłbyś dodawany config/database.ymldo kontroli źródła.

Odwołując się do własnego kodu Heroku do konfiguracji config/database.ymlz DATABASE_URLich Buildpack for Ruby , skończyłem rozwidlając ich repozytorium i zmodyfikowałem je, aby utworzyć config/secrets.ymlze SECRETS_KEY_BASEzmiennej środowiskowej.

Odkąd ta funkcja została wprowadzona w Railsach 4.1, uznałem, że należy ją edytować ./lib/language_pack/rails41.rbi dodawać.

Poniżej znajduje się fragment zmodyfikowanego pakietu kompilacji, który utworzyłem w mojej firmie:

class LanguagePack::Rails41 < LanguagePack::Rails4

  # ...

  def compile
    instrument "rails41.compile" do
      super
      allow_git do
        create_secrets_yml
      end
    end
  end

  # ...

  # writes ERB based secrets.yml for Rails 4.1+
  def create_secrets_yml
    instrument 'ruby.create_secrets_yml' do
      log("create_secrets_yml") do
        return unless File.directory?("config")
        topic("Writing config/secrets.yml to read from SECRET_KEY_BASE")
        File.open("config/secrets.yml", "w") do |file|
          file.puts <<-SECRETS_YML
<%
raise "No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]
%>

<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
          SECRETS_YML
        end
      end
    end
  end

  # ...

end

Możesz oczywiście rozszerzyć ten kod, aby dodać inne wpisy tajne (np. Klucze API stron trzecich itp.), Które będą odczytywane ze zmiennej środowiskowej:

...
<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  third_party_api_key: <%= ENV["THIRD_PARTY_API"] %>

W ten sposób możesz uzyskać dostęp do tego sekretu w bardzo standardowy sposób:

Rails.application.secrets.third_party_api_key

Przed ponownym wdrożeniem aplikacji pamiętaj, aby najpierw ustawić zmienną środowiskową: Ustawianie SECRET_KEY_BASE w panelu Heroku

Następnie dodaj swój zmodyfikowany buildpack (lub możesz dodać link do mojego) do swojej aplikacji Heroku (zobacz dokumentację Heroku ) i ponownie wdróż aplikację.

Buildpack automatycznie utworzy twoją config/secrets.ymlzmienną środowiskową jako część procesu budowania hamowni za każdym razem, gdy będziesz git pushw Heroku.

EDYCJA: Własna dokumentacja Heroku sugeruje tworzenie config/secrets.ymldo odczytu ze zmiennej środowiskowej, ale oznacza to, że powinieneś sprawdzić ten plik w kontroli źródła. W moim przypadku nie działa to dobrze, ponieważ mam zakodowane na stałe sekrety środowisk programistycznych i testowych, których wolałbym nie sprawdzać.

stackunderflow
źródło
Chociaż wspaniałe rozwiązanie .dotenv i .foreman rozwiązują ten problem: „Mam zakodowane na stałe sekrety dla środowisk programistycznych i testowych” - więc używanie tych klejnotów oznacza, że ​​nie potrzebujesz pakietu kompilacji, ponieważ możesz użyć ENV_VAR w swoim pliku sekretów dla programistów i test również
rmcsharry
Zwróć uwagę, że zmienne środowiskowe są rejestrowane przez większość infrastruktury, co oznacza, że ​​niezaszyfrowane zmienne środowiskowe będą w dziennikach w postaci zwykłego tekstu. Nie używam Heroku do moich aplikacji Railsowych, więc nie mam dla niego rekomendacji, ale w przypadku AWS pobieramy zaszyfrowane wartości z magazynu parametrów podczas kompilacji z wnętrza kontenera kompilacji i odszyfrowujemy je, aby wypełnić tego rodzaju bezpieczne zasoby.
Daniel Nalbach,
1

Możesz wyeksportować tajne klucze jako zmienne środowiskowe na ~/.bashrclub ~/.bash_profilena serwerze:

export SECRET_KEY_BASE = "YOUR_SECRET_KEY"

Następnie możesz pozyskać swoje .bashrclub .bash_profile:

source ~/.bashrc 
source ~/.bash_profile

Nigdy nie ujawniaj swoich tajemnic. Syml

alessandrocb
źródło
1

W moim przypadku problem polegał na tym, że config/master.keynie było kontroli wersji, a projekt utworzyłem na innym komputerze.

Domyślny .gitignore, który tworzy Rails, wyklucza ten plik. Ponieważ nie można wdrożyć bez tego pliku, musi on podlegać kontroli wersji, aby można było wdrożyć z dowolnego komputera członka zespołu.

Rozwiązanie: usuń config/master.keylinię z .gitignore, zatwierdź plik z komputera, na którym projekt został utworzony, a teraz możesz git pullna innym komputerze i wdrożyć z niego.

Ludzie mówią, że nie wolno przekazywać niektórych z tych plików do kontroli wersji, nie oferując alternatywnego rozwiązania. Dopóki nie pracujesz nad projektem open source, nie widzę powodu, aby nie zatwierdzać wszystkiego, co jest wymagane do uruchomienia projektu, w tym poświadczeń.

Andrew Koster
źródło
Nigdy nie wysyłaj pliku klucza głównego do git. To olbrzymia luka w zabezpieczeniach Twojej aplikacji. W przypadku oprogramowania typu open source jest to trudne, ale lepszym rozwiązaniem jest utworzenie skarbca haseł za pomocą preferowanego menedżera haseł.
wsizoo
Dlaczego miałaby to być luka w zabezpieczeniach, skoro repozytorium jest prywatne? Jeśli do mojego prywatnego repozytorium ma dostęp osoba nieuprawniona, mam większe problemy niż tylko wyciek kluczy API. Nie każdy projekt jest open source.
Andrew Koster,
Wydaje mi się, że wszyscy to powtarzają, ponieważ widzieli to w samouczku dla projektu open source.
Andrew Koster,
Cała ta sprawa jest bardziej zagmatwana, ponieważ istnieje wiele przestarzałej dokumentacji dotyczącej starego secrets.ymlpliku, który był przestarzały w kilku poprzednich wersjach Railsów. Samo pytanie o przepełnienie stosu ma mnóstwo odpowiedzi i prawie wszyscy używają tego starożytnego interfejsu API.
Andrew Koster
1

W przypadku rails6 miałem ten sam problem, ponieważ brakowało mi następujących plików, po ich dodaniu problem ustąpił:

1. config/master.key
2. config/credentials.yml.enc

Upewnij się, że masz te pliki. !!!

Tushar H.
źródło
0

Co zrobiłem: na serwerze produkcyjnym tworzę plik konfiguracyjny (confthin.yml) dla Thin (używam go) i dodaję następujące informacje:

environment: production
user: www-data
group: www-data
SECRET_KEY_BASE: mysecretkeyproduction

Następnie uruchamiam aplikację za pomocą

thin start -C /whereeveristhefieonprod/configthin.yml

Działa jak urok i nie ma potrzeby posiadania tajnego klucza do kontroli wersji

Mam nadzieję, że to pomoże, ale jestem pewien, że to samo można zrobić z Jednorożcem i innymi.

Geraud Puechaldou
źródło
1
czy możesz wyjaśnić, dlaczego / jak to działa? Pytanie dotyczyło heroku. Czy cienka jest alternatywą, czy jest kompatybilna z heroku?
ahnbizcad
-1

Mam łatkę, której użyłem w aplikacji Rails 4.1, która pozwala mi dalej używać starszego generatora kluczy (a tym samym wstecznej kompatybilności sesji z Railsami 3), pozwalając na pozostawienie pustego pola secret_key_base.

Rails::Application.class_eval do
  # the key_generator will then use ActiveSupport::LegacyKeyGenerator.new(config.secret_token)
  fail "I'm sorry, Dave, there's no :validate_secret_key_config!" unless instance_method(:validate_secret_key_config!)
  def validate_secret_key_config! #:nodoc:
    config.secret_token = secrets.secret_token
    if config.secret_token.blank?
      raise "Missing `secret_token` for '#{Rails.env}' environment, set this value in `config/secrets.yml`"
    end 
  end 
end

Od tego czasu ponownie sformatowałem łatkę i wysłałem ją do Railsów jako żądanie ściągnięcia

BF4
źródło
-1

Utworzyłem config/initializers/secret_key.rbplik i napisałem tylko następującą linię kodu:

Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]

Ale wydaje mi się, że rozwiązanie opublikowane przez @Erik Trautman jest bardziej eleganckie;)

Edycja: Aha, iw końcu znalazłem tę radę na Heroku: https://devcenter.heroku.com/changelog-items/426 :)

Cieszyć się!

fadehelix
źródło
-1

to działa dobrze https://gist.github.com/pablosalgadom/4d75f30517edc6230a67 dla użytkownika root powinien edytować

$ /etc/profile

ale jeśli nie jesteś rootem, powinieneś umieścić kod generujący w następującym

$ ~/.bash_profile

$ ~/.bash_login

$ ~/.profile
bung_firman
źródło
-3

Miałem ten sam problem po użyciu pliku .gitignore z https://github.com/github/gitignore/blob/master/Rails.gitignore

Wszystko poszło dobrze po tym, jak skomentowałem następujące wiersze w pliku .gitignore.

config/initializers/secret_token.rb
config/secrets.yml

źródło
1
Jak to się wszędzie powtarza, wysyłanie plików secrets.yml lub secret_token.rb do git NIE jest zalecane.
cofiem