如何解决错误“在“生产”环境中缺少“ secret_key_base””(Rails 4.1)


169

我从头开始使用Rails 4.1创建了一个Rails应用程序,但遇到了一个我无法解决的奇怪问题。

每次尝试在Heroku上部署应用程序时,都会出现错误500:

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

secret.yml文件包含以下配置:

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

在Heroku上,我使用命令SECRET_KEY_BASE的结果配置了“ ”环境变量rake secret。如果启动heroku config,我可以看到具有正确名称和值的变量。

为什么我仍然收到此错误?


1
我遇到了完全相同的问题,也很想知道为什么会这样。如果我找出原因,我将回传我的解决方案。
danielricecodes 2014年

您的配置文件名为secret.yml还是secrets.yml
詹姆斯

2
我再次用rails生成的.gitignore文件进行了配置,现在一切正常
Paolo Laurenti 2014年

当我们升级到Rails 4时,我们也遇到了这个问题。在我们的例子中,这是因为我们有一个自定义的环境名称,而这并没有反映在secrets.yml中。我只需要在文件中添加非标准名称的行,提交并重新部署即可。
whognu

对于未来的读者:这个答案可能是最简单,最准确的:stackoverflow.com/a/26541742/4880924
BKSpurgeon

Answers:


208

我遇到了同样的问题,并通过创建每次登录生产服务器时都要加载的环境变量来解决了该问题,并制作了配置它的步骤的迷你指南

我在Unicorn v4.8.2上使用Rails 4.1,当我尝试部署我的应用程序时,它无法正常启动,并且在unicorn.log文件中我发现以下错误消息:

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

经过一番研究,我发现Rails 4.1改变了管理的方式secret_key,因此,如果您阅读secrets.yml位于的文件,exampleRailsProject/config/secrets.yml将会发现类似以下内容:

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

这意味着Rails建议您secret_key_base在生产服务器中使用环境变量。为了解决此错误,您应该按照以下步骤在生产服务器中为Linux(在我的情况下为Ubuntu)创建环境变量:

  1. 在生产服务器的终端中执行:

    $ RAILS_ENV=production rake secret

    这将返回包含字母和数字的大字符串。复制该代码,我们将其称为GENERATED_CODE

  2. 登录到您的服务器

    • 如果您以root用户身份登录,请找到此文件并进行编辑:

      $ vi /etc/profile

      在vi中使用Shift+ G(大写“ G”)转到文件底部。

      用编写您的环境变量GENERATED_CODE,按i插入vi。确保在文件末尾添加新行:

      $ export SECRET_KEY_BASE=GENERATED_CODE

      保存更改并使用Esc,然后使用“ :x” 关闭文件,然后Enter在vi中保存并退出。

    • 但是,如果您以普通用户身份登录,则example_user可以将此名称称为“ ”,您将需要找到以下其他文件之一:

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

      这些文件按重要性排序,这意味着,如果您拥有第一个文件,则无需编辑其他文件。如果您发现您的目录中这两个文件~/.bash_profile,并~/.profile只将在第一个写的~/.bash_profile,因为Linux只会读取这一个,其他的将被忽略。

      然后,我们去了文件的使用底部Shift+ G再次与我们写的环境变量GENERATED_CODE使用 i一次,并且一定要在文件的结尾添加新行:

      $ export SECRET_KEY_BASE=GENERATED_CODE

      已经写好的代码,保存更改并关闭使用该文件Esc再次和“ :x”,并Enter保存并退出。

  3. 您可以使用以下命令验证我们的环境变量是否在Linux中正确设置:

    $ printenv | grep SECRET_KEY_BASE

    或搭配:

    $ echo $SECRET_KEY_BASE

    当您执行此命令时,如果一切正常,它将显示GENERATED_CODE以前的内容。最后,在完成所有配置后,您应该能够毫无问题地使用Unicorn或其他工具部署Rails应用程序。

当您关闭外壳程序并再次登录生产服务器时,将设置此环境变量并准备使用它。

就是这样!希望本迷你指南可以帮助您解决此错误。

免责声明:我不是Linux或Rails专家,所以如果您发现任何错误或任何错误,我将很乐意解决。


11
看来,Rails没有看到环境变量SECRET_KEY_BASE。如果我检查ENV,printenv将显示它,rails c production也将显示它。但是,当我重新启动Unicorn时,我没有任何效果。现在有效的唯一方法是将其直接粘贴到
secrets.yml

1
这对我有用。感谢您的完整解释。我刚刚了解到,存在一些用于管理应用程序环境变量的工具。“ Dotenv”是heroku的“代言人”之一。在教育以这种方式手动修复错误时,也许使用其中的一颗宝石可以简化流程?
Nick Res

我很高兴我的回答对您有所帮助,感谢使用gem选项@ ninja08,它们使​​该过程更加轻松,主要是针对那些使用capistrano或其他增量工具来管理服务器的人:)
Demi Magus 2015年

按照Demi Magus的出色指导,我做了这样的事情:cd / var / www / rails; rvm使用ext-rbx-2.5.2@rails; SKB_FILE = / var / www / .secret_key_base; 回显“导出SECRET_KEY_BASE = $(RAILS_ENV =生产耙密钥)”> $ SKB_FILE; 。$ SKB_FILE; 回显“。$ SKB_FILE” | tee -a〜/ .bashrc〜/ .bash_profile; chmod o-rwx $ SKB_FILE;
David Winiecki 2015年

不错的答案!我不知道为什么会这样不就解决了我,我创建问题stackoverflow.com/questions/33117318/...
阿德里亚诺雷森迪

84

我将假设您没有secrets.yml签入源代码管理(即,它在.gitignore文件中)。即使这不是您的情况,这也是许多查看此问题的其他人所做的,因为他们的代码公开在Github上,并且不希望他们的秘密密钥在周围浮动。

如果不在源代码管理中,Heroku对此一无所知。因此,Rails正在寻找Rails.application.secrets.secret_key_base并且尚未设置它,因为Rails通过检查secrets.yml不存在的文件来设置它。简单的解决方法是进入config/environments/production.rb文件并添加以下行:

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

这告诉您的应用程序使用环境变量设置私钥,而不是在中查找私钥secrets.yml。这样可以节省很多时间来预先了解这一点。


15
这是最好的答案。Figaro并且heroku_secrets不要做任何事情,除非Rails知道SECRET_KEY_BASE生活在这里ENV。我一直在为这样的想法而苦苦挣扎:如果config var存在于Heroku上,Rails会仅仅依靠它的存在来选择它,但是现在看来,Rails显然需要知道在哪里看起来很盲目。我一直想知道如何在Github上编写代码而不必担心密钥基础问题;现在我明白了。
langler001 2015年

1
同意,我认为secrets.yml是多余的,例如Figaro这样的大宝石。

2
如果您在项目中使用github和heroku,则似乎是最佳选择。
flexus

1
用提交您的secrets.yml有什么问题production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>。也不意味着实际的秘密密钥不会被公开。如果仅是种子和测试数据,是否存在暴露已提交的secrets.yml中的开发和测试密钥的风险?
杰·基林

即使在不再有secrets.yml的Rails 6.0.2中,它也可以工作。
蔡坚

54

添加config/secrets.yml到版本控制并再次部署。您可能需要从中删除一行,.gitignore以便可以提交文件。

我遇到了完全相同的问题,结果发现.gitignoreGithub为我的Rails应用程序创建了样板config/secrets.yml


140
config / secrets.yml绝对不能在仓库中,您可以进行do.yml.sample并用假数据填充它,但是出于安全性考虑,切勿在仓库中进行.yml
user3379926 2014年

9
@ user3379926,在Heroku上的Rails应用程序的上下文中,您无法选择包含在版本控制中的文件,以及没有包含在版本控制中的文件。Rails 4.1期望秘密配置存在,否则应用程序将无法运行。如果您有办法解决以上问题中提出的问题,而又不必在Git中提交secrets.yml文件,请通过提供建议来帮助改进此线程。
danielricecodes 2014年

9
@danielricecodes可以在初始化程序中手动设置值。诸如此类的东西Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]可以工作并消除错误,而无需添加secrets.yml到源代码中。
joshhepworth 2014年

11
@ user3379926:当我使用生成新的Rails应用程序rails new(在这种情况下,生成的railsgem具有版本的Gemfile 4.2.4)时,将config/secrets.yml生成该文件。它包括用于开发和测试环境的预生成密钥,并从以下环境变量读取生产环境的密钥:secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>。在我看来,将这个secrets.yml文件保留在版本控制中是绝对安全的,而且确实有用,但前提是该文件从未真正在其中定义秘密密钥。
Teemu Leisti

2
@jasonleonhard为什么?无论如何,如果您正在从env vars读取密钥,那有什么大不了的?没有任何秘密被揭露。
horseyguy16年

13

这对我有用。

SSH进入生产服务器并cd进入当前目录,运行bundle exec rake secretrake secret,您将获得一个长字符串作为输出,复制该字符串。

现在运行sudo nano /etc/environment

粘贴在文件底部

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

rake secret您刚刚复制的字符串在哪里,将复制的字符串粘贴到的位置rake secret

重新启动服务器并通过运行进行测试echo $SECRET_KEY_BASE


3

虽然您可以像其他答案一样使用初始化程序,但传统的Rails 4.1+方法是使用config/secrets.yml。Rails团队引入此问题的原因超出了此答案的范围,但TL; DR的问题在于secret_token.rb将配置和代码混为一谈,并且存在安全风险,因为令牌已签入到源代码管理历史记录中,并且是唯一需要执行以下操作的系统:知道生产秘密令牌是生产基础结构。

您应该将此文件添加到.gitignore就像您也不会添加config/database.yml到源代码管理中一样。

引用Heroku的自己的代码用于设置config/database.ymlDATABASE_URL他们的Buildpack为Ruby,我结束了分叉的回购和修改它来创建config/secrets.ymlSECRETS_KEY_BASE环境变量。

由于该功能是在Rails 4.1中引入的,因此我认为编辑./lib/language_pack/rails41.rb和添加此功能是适当的。

以下是我在公司创建的经过修改的buildpack 的摘录

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

您当然可以扩展此代码,以添加要从您的环境变量中读取的其他机密信息(例如,第三方API密钥等):

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

这样,您可以以非常标准的方式访问此机密:

Rails.application.secrets.third_party_api_key

在重新部署应用程序之前,请确保首先设置环境变量: 在Heroku控制台中设置SECRET_KEY_BASE

然后将修改后的buildpack(或者不欢迎您链接到我的链接)添加到Heroku应用程序中(请参阅Heroku 文档)并重新部署您的应用程序。

config/secrets.yml每当您git push访问Heroku 时,作为dyno生成过程的一部分,buildpack都会自动从环境变量中创建您。

编辑:Heroku自己的文档建议创建config/secrets.yml从环境变量读取,但这意味着您应将此文件检入源代码管理。就我而言,这并不奏效,因为我已经硬编码了我宁愿不签到的开发和测试环境的秘密。


尽管.dotenv和.foreman gems是一个很好的解决方案,它解决了这个问题:“我为开发和测试环境提供了硬编码的机密”-因此,使用这些gems意味着您不需要buildpack,因为可以在开发人员和开发人员的机密文件中使用ENV_VAR也测试
rmcsharry18年

请注意,大多数基础结构都记录了环境变量,这意味着未加密的环境变量将在日志中以纯文本格式显示。我没有在我的Rails应用程序中使用Heroku,因此对此没有任何建议,但是使用AWS时,我们在构建期间从构建容器内部从Parameter Store中提取加密的值,并对它们进行解密以填充这些类型的安全资产。
丹尼尔·纳尔巴赫19/12/21

1

您可以将私钥导出到服务器上的~/.bashrc或作为环境变量~/.bash_profile

export SECRET_KEY_BASE = "YOUR_SECRET_KEY"

然后,您可以获取您的.bashrc.bash_profile

source ~/.bashrc 
source ~/.bash_profile

永远不要泄露您的secrets.yml


1

就我而言,问题是config/master.key版本控制中没有,我在另一台计算机上创建了该项目。

Rails创建的默认.gitignore排除了此文件。由于没有此文件就无法部署,因此必须处于版本控制中,以便能够从任何团队成员的计算机进行部署。

解决方案:config/master.key从中删除行.gitignore,从创建项目的计算机中提交文件,现在您可以git pull在另一台计算机上并从中进行部署。

人们说不要在不提供替代解决方案的情况下将其中一些文件提交给版本控制。只要您不从事开源项目,我就没有理由不提交运行该项目所需的所有信息,包括凭据。


切勿将主密钥文件提交给git。这是您的应用程序的巨大安全漏洞。对于开源来说,这很困难,但是使用首选的密码管理器创建密码库是一个更好的选择。
wsizoo

如果仓库是私有的,为什么会是安全漏洞?如果未经授权的人可以访问我的私人存储库,那么我将面临的不仅仅是API密钥泄漏问题。并非每个项目都是开源的。
安德鲁·科斯特

我觉得每个人都在重复这个步骤,因为他们在一个开源项目的教程中看到了它。
安德鲁·科斯特

整个事情更加令人困惑,因为关于旧secrets.yml文件的文档太多了,而在过去的多个Rails版本中已不推荐使用。这个Stack Overflow问题本身有很多答案,他们几乎都使用这个古老的API。
Andrew Koster

1

对于rails6,我面临着同样的问题,因为我缺少以下文件,一旦添加它们,问题就解决了:

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

确保您有此文件。


0

我的工作:在生产服务器上,我为Thin(我正在使用它)创建一个配置文件(confthin.yml)并添加以下信息:

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

然后,我使用

thin start -C /whereeveristhefieonprod/configthin.yml

像魅力一样工作,然后不需要版本控制上的密钥

希望它能有所帮助,但是我敢肯定,独角兽公司和其他公司也可以做同样的事情。


1
您能解释一下为什么/如何运作吗?问题是针对heroku的。薄的替代品还是与heroku兼容?
ahnbizcad 2014年

-1

我有一个在Rails 4.1应用程序中使用过的补丁,通过允许secret_key_base为空,可以让我继续使用旧式密钥生成器(并因此实现与Rails 3的向后会话兼容性)。

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

从那以后,我重新格式化了补丁,并将其作为请求请求提交给Rails。


-1

我已经创建了config/initializers/secret_key.rb文件,并且只编写了以下代码行:

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

但是我认为@Erik Trautman发布的解决方案更优雅;)

编辑:哦,最后我在Heroku上找到了这个建议:https : //devcenter.heroku.com/changelog-items/426 :)

请享用!





By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.