Rails ActiveStorage连接GCS遭遇OpenSSL::PKey::RSAError问题求助
问题场景
在Heroku部署的Rails应用中,配置ActiveStorage连接Google Cloud Storage(GCS),config/storage.yml按服务账号JSON密钥文件填写,服务账号拥有Owner权限,已验证环境变量和配置正确,手动执行OpenSSL::PKey::RSA.new(ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY'])可成功,但上传文件时触发以下错误:
2025-04-09T23:29:11.090818+00:00 app[web.1]: E, [2025-04-09T23:29:11.090754 #11] ERROR -- : [eeabb3d7-6d82-45ea-813a-716c33a5e1df] 2025-04-09T23:29:11.090819+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] OpenSSL::PKey::RSAError (Neither PUB key nor PRIV key): 2025-04-09T23:29:11.090819+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] 2025-04-09T23:29:11.090820+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] vendor/ruby-3.4.2/lib/ruby/3.4.0/openssl/pkey.rb:356:in 'OpenSSL::PKey::RSA#initialize' 2025-04-09T23:29:11.090820+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] vendor/ruby-3.4.2/lib/ruby/3.4.0/openssl/pkey.rb:356:in 'Class#new' 2025-04-09T23:29:11.090821+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] vendor/ruby-3.4.2/lib/ruby/3.4.0/openssl/pkey.rb:356:in 'OpenSSL::PKey::RSA.new' 2025-04-09T23:29:11.090821+00:00 app[web.1]: [eeabb3d7-6d82-45ea-813a-716c33a5e1df] googleauth (1.14.0) lib/googleauth/service_account.rb:79:in 'Google::Auth::ServiceAccountCredentials.make_creds' ...
当前使用的config/storage.yml配置:
google: service: GCS project: my-project bucket: my-project-<%= Rails.env %> credentials: type: service_account project_id: my-project private_key_id: "<%= ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY_ID'] %>" private_key: "<%= ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY'] %>" client_email: "my-project-service-account@my-project.iam.gserviceaccount.com" client_id: "<redacted>" auth_uri: "https://accounts.google.com/o/oauth2/auth" token_uri: "https://oauth2.googleapis.com/token" auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs" client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/my-project-service-account%40my-project.iam.gserviceaccount.com" universe_domain: "googleapis.com"
问题原因
问题出在storage.yml中对private_key的包裹方式:当用ERB读取环境变量并添加双引号时,会导致私钥中的换行符被转义或丢失,googleauth库解析时无法识别正确的RSA密钥格式。
虽然手动执行OpenSSL::PKey::RSA.new(ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY'])能成功,但ERB渲染后传递给googleauth的私钥已经被篡改(比如换行符变成了\n字符串而非实际换行)。
解决步骤
方案1:移除private_key的双引号
修改config/storage.yml中private_key的配置,去掉外层的双引号:
private_key: <%= ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY'] %>
这样ERB会直接输出环境变量中的原始私钥内容,保留正确的换行符格式。
方案2:使用完整JSON凭证(推荐)
避免在配置中拆分凭证字段,将服务账号JSON文件内容直接设置为Heroku环境变量GOOGLE_APPLICATION_CREDENTIALS_JSON,然后修改storage.yml:
google: service: GCS project: my-project bucket: my-project-<%= Rails.env %> credentials: <%= JSON.parse(ENV['GOOGLE_APPLICATION_CREDENTIALS_JSON']) %>
这种方式更简洁,也避免了单个字段的格式问题。
方案3:使用Heroku Google Cloud Buildpack
通过Heroku官方buildpack简化凭证配置:
- 添加buildpack:
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-google-cloud.git
- 设置环境变量(将服务账号JSON内容直接传入):
heroku config:set GOOGLE_APPLICATION_CREDENTIALS=path/to/your-keyfile.json
- 简化
storage.yml:
google: service: GCS project: my-project bucket: my-project-<%= Rails.env %>
此时ActiveStorage会自动通过默认凭证链加载权限。
验证方法
修改配置后重新部署,执行以下命令测试密钥解析:
heroku run rails c > OpenSSL::PKey::RSA.new(Rails.application.config.active_storage.service_configurations[:google][:credentials][:private_key])
如果能成功初始化RSA密钥,说明配置正确,再测试文件上传功能。
内容的提问来源于stack exchange,提问作者aec

