Capistrano任务执行时Rails credentials无法读取对应环境密钥如何解决?
Rails 6 Capistrano自定义任务读取环境对应credentials失败解决方案
问题根源
Rails应用启动时会预加载Rails.application.credentials配置,你在Capistrano任务的with块中动态设置的rails_env、rails_master_key变量,不会触发Rails重新加载credentials配置,因此始终读取初始化时加载的默认全局config/credentials.yml.enc和config/master.key。
解决方案
方案1:手动实例化对应环境的加密配置(推荐)
直接通过ActiveSupport::EncryptedConfiguration加载指定环境的credentials,不会影响全局Rails配置:
task :my_task do on roles(:app), in: :sequence, wait: 5 do run_locally do env = fetch(:rails_env).to_s # 手动指定对应环境的配置文件和密钥路径 creds = ActiveSupport::EncryptedConfiguration.new( config_path: Rails.root.join("config", "credentials", "#{env}.yml.enc"), key_path: Rails.root.join("config", "credentials", "#{env}.key"), env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true ) pp creds # 直接通过creds.xxx读取对应配置即可 end end end
方案2:强制重载全局credentials(不推荐,会修改全局配置)
如果必须使用Rails.application.credentials调用,可以手动清空已加载的配置实例触发重载:
task :my_task do on roles(:app), in: :sequence, wait: 5 do run_locally do env = fetch(:rails_env).to_s # 手动写入环境变量 ENV["RAILS_ENV"] = env ENV["RAILS_MASTER_KEY"] = File.read(Rails.root.join("config", "credentials", "#{env}.key")).strip # 清空已加载的credentials实例触发重载 Rails.application.instance_variable_set(:@credentials, nil) Rails.application.instance_variable_set(:@encrypted_configs, nil) pp Rails.application.credentials end end end
配套检查项
- 确认本地存在对应环境的credentials文件:
config/credentials/#{环境名}.yml.enc和config/credentials/#{环境名}.key,且key文件有可读权限 - 如果任务需要在服务器而非本地执行,移除
run_locally配置,同时确保服务器环境变量中配置了对应环境的master key,或已将对应环境的key文件上传到服务器对应路径
内容的提问来源于stack exchange,提问作者brcebn
相关产品推荐
相关产品推荐

