PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

AWS から Google Cloud の Workload Identity Federation を使う時にハマったところ

杉嵜です。肩甲骨のコリが最近の悩みです。

今回は、AWS の Lambda 関数から Google Cloud の Workload Identity Federation を使おうとした際に遭遇したエラーの話です。特に SAM や CloudFormation で AWS リソースを作成している場合に発生しやすいです。

The size of mapped attribute google.subject exceeds the 127 bytes limit. Either modify your attribute mapping or the incoming assertion to produce a mapped attribute that is less than 127 bytes.

自分は以下記事の実装をした際に遭遇したのですが、AWS と Google Cloud にまたがるためややこしい事象なのと、社内でも同じような事象に遭遇した人が出たので、小ネタとしてまとめておきます。

developers.play.jp

Workload Identity Federation(WIF)

Workload Identity Federation (Workload Identity連携、以下 WIF)は Google Cloud の外部からリソースにアクセスする際の認証方式です。ここでいう外部とは AWS や Azure、GitHub Actions などを指します。長期的な認証情報を使わなくて済むので、よりセキュアに認証できます。

cloud.google.com

どこでハマったか

AWS と連携する際の Workload Identity Pool (以下 WIP)の属性マッピングは、認証情報を借りようとしているユーザの識別子 google.subject として、デフォルトでは assumed-role の ARN がマッピングされます。この google.subject は127バイト以下にしないといけないですが、Lambda 関数から連携するケースでは基本的に assumed-role の ARN に IAM ロール名と Lambda 関数名が使われるので、これが長いと ARN が127バイトを超えてしまい、WIF 側でエラーになってしまいます

対応方針としては以下のどちらかになります。

  • Google Cloud の WIP の属性マッピングを変更し、google.subject を短くする
  • AWS のリソース名を短くし、生成される ARN を短くする
    • IAM ロール名、Lambda 関数名など

Lambda 関数1つだけなら名前変更で対応できなくもないですが、可能なら属性マッピングを変更して127バイトを超えないようにしておきたいところです。

事象発生から原因判明まで

以前書いた記事で出したツールの構成図です。

この構成に至るまでの技術調査で、手動で Lambda 関数を作成して WIF と連携した際には起きませんでした。しかし AWS SAM テンプレートに書き起こして Lambda 関数などを生成し実行したところ、WIF との連携が上手くいかずに動作しませんでした。その後、ログ出力などを調整して確認できたエラーが、冒頭にも書いたこのようなエラーでした。

The size of mapped attribute google.subject exceeds the 127 bytes limit. Either modify your attribute mapping or the incoming assertion to produce a mapped attribute that is less than 127 bytes.

Google Cloud の WIP 側で google.subject にマッピングしようとした値が、上限である127バイトを超えてる旨のエラーです。ここで、AWS と連携する時に作成した WIP では、デフォルトで入っていた CEL 式 assertion.arn が入っていました( 参考 )。この値は最終的に AWS の Assumed Role の ARN が渡されるのですが、その ARN が127バイトを超えているためにエラーが出ているとわかりました。

AWS Assumed Role

デフォルトで google.subject に割り当てられる、Assumed Role の ARN を見てみましょう。このドキュメントによると、ARN はこのような形式の文字列になります。

arn:aws:sts::ACCOUNT:assumed-role/ROLE-NAME/ROLE-SESSION-NAME

ARN のうち固定の文字列とアカウント ID(12バイト)の合計は40バイトなので*1、全体で127バイトに収めるためにはロール名とセッション名で87バイトまでにしなければなりません。ここで、Lambda から使用する際のセッション名にはデフォルトで Lambda 関数名が使われるので、今回のケースでは IAM ロール名とLambda 関数名を合計87バイト以内に収める必要があります 。現状は半角文字だけなので、そのまま87文字ということになります。

AWS SAM などで生成したリソース名が、2つ合わせて87文字を超えるケースは珍しくありません。そのため、今回のように「手動で Lambda 関数を作って接続してみた時は問題なかったのに、SAM テンプレートにして生成した時は動かなくなった」という事象が起きたりします。

属性マッピングを編集して解消する

今回は ARN をそのままgoogle.subjectにマッピングせず、部分文字列をマッピングすることで解消させます。CEL 式のextract()関数を用いて部分文字列を抽出することで、文字数を削減します。色んな切り出し方が考えられますが、IAM ロール名だけなら上限64文字なので、Lambda 関数名の部分を切り落とすことで確実に127バイトに収められます。将来的に Assumed Role 以外のロールでアクセスされた場合も考慮すると、例えば以下のような式になります。

assertion.arn.contains('assumed-role') ? assertion.arn.extract('assumed-role/{role_name}/') : assertion.arn

マッピングを変更した場合、当然ながらgoogle.subjectが取りえる値は変わるので、後段の権限制御で値を使う場合は注意が必要です。

マッピングの妥当性

google.subjectの値に求められる要件として、Google Cloud のドキュメントにはこのように書かれています。

An external identity maps to exactly one google.subject value.
A google.subject value maps to exactly one external identity.
You can look up an external identity by its google.subject value.

Best practices for using Workload Identity Federation  |  Identity and Access Management (IAM)  |  Google Cloud Documentation

要するに「external identity」と1対1で紐付け、google.subjectの値から逆引きできるようにするということです。

今回のケースでは IAM ロールが逆引きできます。従って、IAM ロールを使い回している場合は Lambda 関数名を特定することはできません。もっとも、複数の Lambda 関数で同じロールを使い回す構築は望ましくないので、多くのケースでは IAM ロールが特定できれば十分かと思います。

終わりに

以上、AWS から Google Cloud の Workload Identity Federation を利用する際にハマったエラーの話でした。普段の私の業務は AWS と Google Cloud を連携させるシステムを扱ってなかったので、Google Cloud 側の仕組みの理解に時間がかかり、解決までとても苦労しました。わかってしまえば単純ですが、本記事が同じような事象で困ってる人の助けになればと思います。

*1:arn:aws:sts::123456789012:assumed-role/ の39バイトと、ロール名の直後のスラッシュで合計40バイトとなる。