回答: Heroku では 2 つの環境変数が混同されていました。CERT は秘密鍵を指し、PRIVATE_KEY は証明書を指していました。それを修正しました。承認が機能するようになりました。
できる限り、この質問に回答済みのマークを付けます。
Rails 4 アプリケーションのサービス アカウントを使用して、Google Analytics Reporting API に接続しています。認証プロセスをセットアップし、開発で機能させました。デプロイ時に、.p12 キー ファイルの使用が問題であることに気付きました。リポジトリにコミットするか、それを回避する方法を見つける必要がありました。そこで、キー ファイルを 2 つの .PEM ファイルに分割し、それらのファイルの内容を環境変数として保存することで、これを回避する方法を見つけました。
開発でうまく機能します(dotenv-railsを使用して環境変数をそこに保存しています)。しかし、本番環境で認証方法を使用しようとすると、エラーが発生するため、Heroku の変数に何かが起こっているに違いありませんArgumentError: Could not parse PKey: no start line
。
ここで何が起こっているのかについて手がかりを探しました - バージョンの問題が原因で関連するエラーが発生する可能性があることを確認しました (誰かが Ruby 2.2 から 1.9.8 にダウングレードし、同様の問題を修正しました。 t はどこでも動作し、私の場合は開発中です)。私のRubyバージョンをダウングレードすることは、実際にはオプションではありません. :/
関連するコードは次のとおりです。
def authorize_with_services
begin
self.client = Google::APIClient.new(application_name: 'Playground', application_version: '1')
p12 = OpenSSL::PKCS12.create('notasecret', 'descriptor',
problem spot --> OpenSSL::PKey.read(ENV['PRIVATE_KEY']),
OpenSSL::X509::Certificate.new(ENV['CERT']))
p12_binary = p12.to_der
self.client.authorization = Signet::OAuth2::Client.new(
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
audience: 'https://accounts.google.com/o/oauth2/token',
scope: 'https://www.googleapis.com/auth/analytics.readonly',
issuer: GA_EMAIL,
signing_key: Google::APIClient::PKCS12.load_key(p12_binary, 'notasecret')
).tap { |auth| auth.fetch_access_token! }
rescue Signet::AuthorizationError
self.client = nil
end
self.client
end
次に、.env に格納されている ENV 変数:
PRIVATE_KEY: "Bag Attributes\n friendlyName: privatekey\n localKeyID: 54 69 6D 65 20 31 34 33 35 36 38 34 30 33 31 30 32 39\nKey Attributes: <No Attributes>\n-----BEGIN RSA PRIVATE KEY-----\nKEY\n-----END RSA PRIVATE KEY-----\n"
CERT: "Bag Attributes\nfriendlyName: privatekey\nlocalKeyID: 54 69 6D 65 20 31 34 33 35 36 38 34 30 33 31 30 32 39\nsubject=/CN=636085506886-096q9j1uotf9kp1tv4evhn2crip6dec8.apps.googleusercontent.com\nissuer=/CN=636085506886-096q9j1uotf9kp1tv4evhn2crip6dec8.apps.googleusercontent.com\n-----BEGIN CERTIFICATE-----\nCERT\n-----END CERTIFICATE-----\n"
そして、 と でそれらをまったく同じに設定しましheroku config:set PRIVATE_KEY
たheroku config:set CERT
。
編集
エラーにつながる Heroku コンソールのセッションは次のとおりです。
# 11:15:36 (ruby-2.1.5@yt-ga-playground) ~/projects/confreaks/yt-ga-playground (master)$ heroku run console
Running `console` attached to terminal... up, run.8357
Loading production environment (Rails 4.2.0)
irb(main):001:0> querier = AnalyticsQuerier.new
=> #<AnalyticsQuerier:0x007f81fc6f5358 @options={"ids"=>"ga:104082366", "start-date"=>"2015-01-01", "end-date"=>"2015-07-04", "metrics"=>"ga:totalEvents"}, @ids="ga:104082366", @start_date="2015-01-01", @end_date="2015-07-04", @metrics="ga:totalEvents">
irb(main):002:0> querier.authorize_with_services
ArgumentError: Could not parse PKey: no start line
from /app/app/services/analytics_querier.rb:56:in `read'
from /app/app/services/analytics_querier.rb:56:in `authorize_with_services'
from (irb):2
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /app/vendor/bundle/ruby/2.1.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:8:in `require'
from bin/rails:8:in `<main>'
そして、私の開発コンソールでの同等のセッション:
# 11:17:47 (ruby-2.1.5@yt-ga-playground) ~/projects/confreaks/yt-ga-playground (master)$ be rails c
Loading development environment (Rails 4.2.0)
2.1.5 :001 > querier = AnalyticsQuerier.new
=> #<AnalyticsQuerier:0x007fe97d380928 @options={"ids"=>"ga:104082366", "start-date"=>"2015-01-01", "end-date"=>"2015-07-04", "metrics"=>"ga:totalEvents"}, @ids="ga:104082366", @start_date="2015-01-01", @end_date="2015-07-04", @metrics="ga:totalEvents">
2.1.5 :002 > querier.authorize_with_services
=> #<Google::APIClient:0x007fe97d36bc80 @host="www.googleapis.com", @port=443, @discovery_path="/discovery/v1", @user_agent="Playground/1 google-api-ruby-client/0.8.2 Mac OS X/10.10.3\n (gzip)", etc.>
そして、を使用するコントローラーメソッドがありますAnalyticsQuerier
。うまくいくと思ったとき、私はそれを本番にプッシュしました。これがログでどのように再生されるかを次に示します。
[...] app[web.1]: Started POST "/events" for 104.231.12.227 at 2015-07-04 15:14:11 +0000
[...] app[web.1]: Completed 500 Internal Server Error in 16ms
[...] app[web.1]: Processing by EventsController#create as HTML
[...] app[web.1]: Parameters: {"authenticity_token"=>"1fvzDI1n+AlTssDybGFHAyiG4M+kir2UDLsA4dZGiAJvrWXdK6OnlAf1wK0V+/dI4QXz3lxonmRw15XbFjpOAQ=="}
[...] app[web.1]: (0.8ms) SELECT COUNT(*) FROM "analytics_calls"
[...] app[web.1]:
[...] app[web.1]: ArgumentError (Could not parse PKey: no start line):
[...] app[web.1]: app/services/analytics_querier.rb:56:in `read'
[...] app[web.1]: app/services/analytics_querier.rb:56:in `authorize_with_services'
[...] app[web.1]: app/controllers/events_controller.rb:10:in `create'
2015-07-04T15:14:11.542398+00:00 app[web.1]:
[...] app[web.1]: app/models/analytics_call.rb:19:in `get_batch'
[...] app[web.1]:
[...] heroku[router]: at=info method=POST path="/events" host=desolate-fortress-9280.herokuapp.com request_id=3822f668-6b8c-4cb2-9764-c171fc0dc67b fwd="104.231.12.227" dyno=web.1 connect=3ms service=33ms status=500 bytes=1754
編集 2 - 正しい方向に進む可能性はありますか?
そのため、Val Asensio が指摘したように、Heroku が提供する SSH セットアップには問題があります (これは私にとって多かれ少なかれなじみのない領域ですが、私の理解には肉付けが必要であるため、できるだけ明確に言葉で表現しようとします)ここ)。
heroku-buildback-sshという gem を見つけました。これは、秘密鍵を適切に使用するには、env 変数に秘密鍵をロードするだけでなく、それ以上のことを行う必要があることを明確に示しています。ただし、readme では、プライベートにアクセスするためにパスフレーズを使用できないと指定されています。またrsa
、これが .pem ファイルに対して機能することを示すものはありませんが、 something というファイルを使用していると想定しているようです。
ここで、Heroku からの ssh トンネリングに関する別の議論を見つけました。これが進むべき道だと思います。私の理解では、環境変数 PRIVATE_KEY を使用して秘密鍵ファイルを舞台裏で「再構築」できるようにする必要があり、Heroku の起動時にこれを行うスクリプトを作成できるということです。
ただし、ここでの私の理解は非常に不安定であり、回答スクリプトで説明されているユースケースは十分に異なっているため、この種の方法を使用してソリューションを構築する方法を推測する方法がわかりません.
ここで知りたいのは、Heroku がバックグラウンドで実行する bash スクリプトを使用して .pem キー ファイルを作成できるかということです。そうであれば、スクリプトの実行時にそのファイルが読み取られていることを確認するにはどうすればよいOpenSSL::PKey.read
でしょうか? 代わりに、元の .pk12 ファイル自体をビルドすることもできると思いますか?
ALSO - 大きな疑問: 私は混乱したコードのもつれた結び目に残され、アプリケーション全体を破棄しなければならないほどひどく台無しにするつもりですか?ここに答えがあります) 実稼働環境でファイルを作成し、それらのファイルのアクセス許可を管理するスクリプトを書き始めたら?