tech.guitarrapc.cóm

Technical updates

GitHub Actions で configure-aws-credentials を使った OIDCではまったこと

GitHub Actions の OpenID Connector と AWS の OIDC Provider を使うことで、IAM Role を Assume できるというのは前回書きました。

tech.guitarrapc.com

構築中によく出るエラーに関しても書いたのですが、いざ実際に使おうとしたら別のエラーではまったので忘れないようにメモしておきます。

tl;dr;

  • OpenID Connect で認証すると、AWS OIDC Provider の認証の上限に引っ掛かりやすい。
  • Composite Action の中で、 configure-aws-credentials を呼び出すときは注意。

GitHub Actions で並列実行すると時々失敗する。

エラーメッセージ Error: Couldn't retrieve verification key from your identity provider, please reference AssumeRoleWithWebIdentity documentation for requirements

対策: configure-aws-credentials で OIDC 認証を頻繁に呼び出す場合は、キャッシュかリトライしましょう。

並列でジョブを実行するなど、短時間に頻繁に認証を取得ようとすると、時々認証に失敗します。 IAM Userを使っていると当然でないのですが、OIDC Providerで認証をかけようとするとぐさっと刺さります。

これを回避するには、リトライかキャッシュ作戦をとる必要があります。

github.com

workflow で一回だけ認証ととって、キャッシュを使いまわす場合次のような workflow になります。

gist.github.com

ただ、GitHub Actions の cache は 「パブリックリポジトリのキャッシュには、センシティブな情報を保存しないことをおすすめします。」とある通り取扱いには注意だと思います。トークン自体 は 900sec (min) か 1 hour (default) で切れますが、時間の問題ではないという。

Warning: We recommend that you don't store any sensitive information in the cache of public repositories. For example, sensitive information can include access tokens or login credentials stored in a file in the cache path. Also, command line interface (CLI) programs like docker login can save access credentials in a configuration file. Anyone with read access can create a pull request on a repository and access the contents of the cache. Forks of a repository can also create pull requests on the base branch and access caches on the base branch. https://docs.github.com/en/actions/advanced-guides/caching-dependencies-to-speed-up-workflows

configure-aws-credentials を1 jobで複数回呼び出したときに初回の認証を上書きできない

対策: configure-aws-credentials の呼び出しは一回の composite action で行うか、workflow で呼び出しましょう。

通常 configure-aws-credentials は、呼び出しのたびに job 内の認証を後勝ちで上書きします。 ただし、composite action の中で、configure-aws-credentials を呼び出すと、意図しない結果になるパターンがあります。

configure-aws-credentials を呼び出す処理を composite action に書いて、1 job内で 別の IAM Role の Assume を呼びだすと 2 回目の configure-aws-credentials で上書きできないので避けましょう。

github.com

正常動作例1

次のように workflow 上で連続でconfigure-aws-credentialsを呼び出すと、2回目の configure-aws-credentials で myrole_Bに上書きできていることが確認できます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
     # 1st
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          aws-region: ap-northeast-1
          role-to-assume: arn:aws:iam::123456789012:role/myrole_A
          role-session-name: GitHubActions-${{ github.run_id }}
      - name: get-caller-identity shows myrole_A as expected
        run: aws sts get-caller-identity
      # 2nd
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@master
        with:
          aws-region: ap-northeast-1
          role-to-assume: arn:aws:iam::123456789012:role/myrole_B
          role-session-name: GitHubActions-${{ github.run_id }}
      - name: get-caller-identity shows myrole_B as expected
        run: aws sts get-caller-identity

1回目のget-caller-identity は myrole_A です。

{
    "UserId": "AROASJXUOK5UM7XZKRYTB:GitHubActions-1426675663",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_A/GitHubActions-1426675663"
}

2回目のget-caller-identity は myrole_B です。

{
    "UserId": "AROASJXUOK5UM7XZKRYTB:GitHubActions-1426675663",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_B/GitHubActions-1426675663"
}

意図通りの挙動です。

正常動作例2

Composite Action の中で configure-aws-credentials をまとめて2回呼び出すと、2回目の呼び出しで myrole_B に上書きできていることが確認できます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Configure AWS Credentials
        uses: ./.github/actions/aws_oidc_auth_all

aws_oidc_auth_all はこうなっています。

# ./.github/actions/aws_oidc_auth_all/action.yaml
name: aws oidc auth
description: |
  Get aws oidc auth.
runs:
  using: "composite"
  steps:
    # 1st
    - name: Configure AWS Credentials (Role A)
      uses: aws-actions/configure-aws-credentials@master
      with:
        aws-region: ap-northeast-1
        role-to-assume: arn:aws:iam::123456789012:role/myrole_A
        role-session-name: GitHubActions-${{ github.run_id }}
    - name: get-caller-identity shows myrole_A as expected
      run: aws sts get-caller-identity
      shell: bash
    # 2nd
    - name: Configure AWS Credentials (Role B)
      uses: aws-actions/configure-aws-credentials@master
      with:
        aws-region: ap-northeast-1
        role-to-assume: arn:aws:iam::123456789012:role/myrole_B
        role-session-name: GitHubActions-${{ github.run_id }}
    - name: get-caller-identity shows myrole_B as expected
      run: aws sts get-caller-identity
      shell: bash

1回目のget-caller-identity は myrole_A です。

{
    "UserId": "AROASJXUOK5UM7XZKRYTB:GitHubActions-1426687022",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_A/GitHubActions-1426687022"
}

2回目のget-caller-identity は myrole_B です。

{
    "UserId": "AROASJXUOK5UHN4XWD3XF:GitHubActions-1426687022",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_B/GitHubActions-1426687022"
}

意図通りの挙動です。

問題の動作

Composite Action の中で configure-aws-credentials を それぞれのIAM Role について呼び出すと、2回目の呼び出しが myrole_A のままで myrole_B で上書きできていないことが確認できます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      # 1st <- Shows myrole_A, expected.
      - name: Configure AWS Credentials (Role A)
        uses: ./.github/actions/aws_oidc_auth_single
        with:
[https://docs.github.com/en/actions/creating-actions/creating-a-composite-action:embed:cite]


          role-to-assume: arn:aws:iam::123456789012:role/myrole_A
      # 2nd <- Shows myrole_A, unexpected!!
      - name: Configure AWS Credentials (Role B)
        uses: ./.github/actions/aws_oidc_auth_single
        with:
          role-to-assume: arn:aws:iam::123456789012:role/myrole_B

aws_oidc_auth_single はこうなっています。

# ./.github/actions/aws_oidc_auth_single/action.yaml
name: aws oidc auth
description: |
  Get aws oidc auth.
inputs:
  role-to-assume:
    description: "AWS IAM Role to assume 1"
    required: true
runs:
  using: "composite" # this is key point
  steps:
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@master
      with:
        aws-region: ap-northeast-1
        role-to-assume: ${{ inputs.role-to-assume }}
        role-session-name: GitHubActions-${{ github.run_id }}
    - name:  get-caller-identity shows myrole_A on both 1st and 2nd run. (2nd run must be myrole_B but incorrect result.)
      run: aws sts get-caller-identity
      shell: bash

1回目のget-caller-identity は myrole_A です。

{
    "UserId": "AROASJXUOK5UM7XZKRYTB:GitHubActions-1426687028",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_A/GitHubActions-1426687028"
}

2回目のget-caller-identity も myrole_A です。myrole_B に上書きできていません。

{
    "UserId": "AROASJXUOK5UHN4XWD3XF:GitHubActions-1426687028",
    "Account": "***",
    "Arn": "arn:aws:sts::***:assumed-role/myrole_A/GitHubActions-1426687028"
}

aws-actions/configure-aws-credentials の中身を見ても、composite action 特有の処理は当然存在しません。 composite action の仕様かと思いつつ、そういった記述もないので謎です。

仕方ないので、正常動作例1,2 のいずれかを用いることになるでしょう。

あるいは、両方の権限をもつ単一Roleでやるのも手でしょう。