🤧
Workload IdentityでGoogle Coud Storageの署名付きURLを発行する
やること
google-cloud-ruby で、Workload Identityを使用した認証を行う場合に、 Google Cloud Storageの 署名付きURLの発行が行い得ない問題を解消するものである
発生している問題
前提
- workload identityによって接続されるサービスアカウントを ワークロードサービスアカウント とする
- 筆者の環境では、GKEのnode上に存在するRuby on Railsにワークロードサービスアカウントが接続される
- ワークロードサービスアカウントに対する権限の設定は問題がない。 (使用するStorage bucketに対して
roles/storage.objectAdmin
)
署名付きURLの発行を試みる
storage = Google::Cloud::Storage.new
storage.bucket('任意のバケット名', skip_lookup: true).file('バケットに存在するファイル名', skip_lookup: true).signed_url(method: 'GET', expires: 300)
=> Google::Cloud::Storage::SignedUrlUnavailable (Service account credentials 'issuer (client_email)' is missing. To generate service account credentials see https://cloud.google.com/iam/docs/service-accounts)
Google::Cloud::Storage::SignedUrlUnavailable
によって怒られる
一方でファイル情報は取得できる
念の為、権限が正しそうかを確認する
storage = Google::Cloud::Storage.new
storage.bucket('任意のバケット名', skip_lookup: true).file('バケットに存在するファイル名')
=> #<Google::Cloud::Storage::File:0x00005624a9833208 @service=Google::Cloud::Storage::Service(project_id), @gapi=#<Google::Apis::StorageV1::Object:0x00005624a9887740 @bucket="hogehoge", @content_type="image/jpeg", @id="hogehoge/sample.jpeg/000", @kind="storage#object", ....>
OK
なぜか
一部、妄想も含まれてるかもなので参考程度に...
- (workload identityを通じて)環境に適用されるサービスアカウントの資格情報は、色々省略された情報しか保持されていない
- 多くのAPIを使用する場合には問題がないが、 Google Cloud Storageの署名付きURLの発行に必要な資格情報が含まれないケースが有る
参考
解決するには
1. ワークロードサービスアカウントの資格情報を直接所持させる
pod内にワークロードサービスアカウントの資格情報を保有させるというやり方。鍵の管理やサービスアカウントの資格情報は10年で切れるという点で、あまりお薦めはできない。
2. Cloud IAMCredentials signBlob によって署名を作成して使用する
今回はこの方法を取る。署名を行う際に、直接APIを叩いて署名を実行するというやり方である。
署名付きのURLを発行するときに、 サービスアカウントの識別子(Issuer)を使用するが、環境に適用されるサービスアカウントの場合は取得できない。Issuerを環境に設定されているサービスアカウントとは別に設定した上で、署名付きURLを発行するときに指定する必要がある。しかし、google-cloud-rubyにはIssuer だけ を外から流し込む事はできないので、署名ロジックも一緒に以下の様に変更する。
サービスアカウントへの権限を追加
このやり方の場合、ワークロードサービスアカウントに roles/iam.serviceAccountTokenCreator
の権限が必要となるため付与する
署名付きURLの発行方法を変更する
ここの Using Cloud IAMCredentials signBlob to create the signature
によるやり方で、 issuerとしてワークロードサービスアカウントを指定すればOK
参考
Discussion