Google Cloud Runで実行され、Google Cloudストレージにファイルが保存されているプログラムを開発しています。
私が経験している問題は、通常はプライベートなCloud Storageからファイルをダウンロードするための署名付きURLを生成しようとしたときに発生します。私のローカルマシンでは問題なく動作しますが、Cloud Runで実行すると動作しません。
ローカルで、Storage Object Admin
の役割が割り当てられているサービスアカウントを使用しています。クラウドコンソールからダウンロードしたキーの.jsonファイルへの絶対パスを値に含むGOOGLE_APPLICATION_CREDENTIALS
という環境変数を使用して、権限をロードします。
Cloud Runでは、サービスを実行するのと同じ役割をサービスアカウントに付与しました。しかし、そこに署名しようとすると、例外が発生します。
Java.io.IOException:提供されたバイトに署名しようとするエラーコード403:呼び出し元に権限がありません
私のコードでは、サービスアカウントを明示的に選択していません。SDKのドキュメントでは、これが自動的に行われると信じているからです。 Cloud Runでは、GOOGLE_APPLICATION_CREDENTIALS
変数が設定されていません。これも自動的に行われると思ったためです。
私を混乱させるのは、Cloud Runで実行されているアプリケーションがファイルをCloud Storageに正常にアップロードできることです。そのため、どこかにある形式の認証情報があると思います。
何が悪いのですか?
TL; DR:サービスアカウントに_iam.serviceAccounts.signBlob
_権限があることを確認します。
Cloud Runで認証情報を取得するために使用した方法をさらに調査した後:
_GoogleCredentials credentials = ComputeEngineCredentials.create();
Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();
_
ComputeEngineCredentials
の- javadoc を読みます:
Google Compute Engine VMの組み込みサービスアカウントを表すOAuth2認証情報。 Google Compute Engineメタデータサーバーからアクセストークンをフェッチします。これらの認証情報は、IAM APIを使用してデータに署名します。詳細については、sign(byte [])を参照してください。
この後、私は javadoc for sign(byte[])
を読みました(私の強調):
サービスアカウントに関連付けられた秘密鍵を使用して、提供されたバイトに署名します。 Compute EngineのプロジェクトでIdentity and Access Management(IAM)APIを有効にする必要があり、インスタンスのサービスアカウントにiam.serviceAccounts.signBlob権限が必要です。
そのため、_iam.serviceAccounts.signBlob
_権限のみを持つ新しい役割を作成し、それをCloud Run構成が使用するサービスアカウントに割り当てました。この後、問題はすぐになくなりました(再展開する必要はありません)