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を呼び出すときは注意
  • 2021/12/10追記: このPRが入れば自動的にリトライしてくれるで記事のプラクティスは不要になる予定

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

2022/2/4 本バグはhttps://github.com/aws-actions/configure-aws-credentials/issues/299で修正されています。もう気にしなくともリトライもされます。

次のエラーがでます。

エラーメッセージ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で1回だけ認証ととって、キャッシュを使いまわす場合次のような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

次のように連続で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でやるのも手でしょう。