GitHub ActionsとAWSのOIDC連携で特定のRepositoryやBranchにのみAssumeRoleを許可させてみた

2022.04.25

こんにちは、CX事業本部 IoT事業部の若槻です。

今回は、GitHub ActionsとAWSのOIDC連携で特定のRepositoryやBranchにのみAssumeRoleを許可させてみました。

設定箇所

GitHubとAWSのOIDC連携をさせるためには、AWSには次の2つのリソースを作成する必要があります。

  • ID Provider
  • IAM Role(およびInline Policy)

そしてOIDC可能なGitHubのRepositoryやBranchを制限する場合は、IAM RoleのTrusted entitiesのConditionを設定する必要があります。

Trusted entities

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<Account ID>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:<Account>/<Repository>:ref:refs/heads/<Branch>"
                }
            }
        }
    ]
}

IAM RoleのTrusted entitiesは、マネジメントコンソールで上だと[Trust relationships]の[Trusted entities]で確認および設定できます。

AWS CDKで作成するならaws_iam.FederatedPrincipalの第二引数がConditionに該当する部分です。(詳細は以前のエントリを参照)

lib/aws-cdk-v2-project-stack.ts

    const oidcDeployRole = new aws_iam.Role(this, 'GitHubOidcRole', {
      roleName: 'github-oidc-role',
      assumedBy: new aws_iam.FederatedPrincipal(
        gitHubIdProvider.openIdConnectProviderArn,
        {
          StringLike: {
            'token.actions.githubusercontent.com:sub':
              props.principalFederatedSub,
          },
        },
        'sts:AssumeRoleWithWebIdentity'
      ),
    });

やってみた

次のWorkflowで試してみます。Secretから取得したIAM RoleのArnをaws-actions/configure-aws-credentialsで使用してOIDCによるAssumeRoleを行っていまうす。

.github/workflows/cicd.yaml

on: 
  push:
    paths-ignore:
      - '**/*.md'

jobs:
  assumerole:
    runs-on: ubuntu-latest
    env:
      AWS_OIDC_ROLE_ARN: ${{ secrets.AWS_OIDC_ROLE_ARN }}
      AWS_REGION: ap-northeast-1
    permissions:
      id-token: write
      contents: read
    steps:
      - name: debug
        run: |
          echo AWS_OIDC_ROLE_ARN: ${AWS_OIDC_ROLE_ARN/::*:/::XXXXXXXXXXXX:}

      - name: Assume Role
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ env.AWS_OIDC_ROLE_ARN }}
          aws-region: ${{env.AWS_REGION}}

Repository名がaws-cdk-から始まり、Branch名がfeature/から始まるというConditionで試してみます。StringLikeOperatorによりこのようなワイルドカード(*)の使用が可能となります。

Trusted entities

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::XXXXXXXXXXXX:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:cm-rwakatsuki/aws-cdk-*:ref:refs/heads/feature/*"
                }
            }
        }
    ]
}

使用できるCondition operatorについては下記をご参照ください。

パターン1

  • Repositoryaws-cdk-v2-project(一致)
  • Branchfeature/hoge1にCommitをPush(一致)

Workflowの実行が成功しました。

パターン2

  • Repositoryaws-cdk-v2-project(一致)
  • feature/hoge1からdevelopにBranchをMerge(一致?)

AssumeRoleがNot authorized to perform sts:AssumeRoleWithWebIdentityとなりWorkflowの実行が失敗しました。Merge時はCompare Branchではなく、Base BranchがConditionで許可されている必要があるようです。

パターン3

  • Repositoryaws-cdk-v2-project(一致)
  • BranchaaaaaaaaaaにCommitをPush(不一致)

BranchaaaaaaaaaaにCommitをPushすると、AssumeRoleがNot authorized to perform sts:AssumeRoleWithWebIdentityとなりWorkflowの実行が失敗しました。

パターン4

  • Repositoryaws_cdk_app(不一致)
  • Branchfeature/hoge1にCommitをPush(一致)

AssumeRoleがNot authorized to perform sts:AssumeRoleWithWebIdentityとなりWorkflowの実行が失敗しました。

補足

StringEqualsで指定する場合

Conditionでワイルドカードを使わずに、StringEqualsOperatorで複数の値を指定することもできます。

Trusted entities(抜粋)

    }
}

おわりに

GitHub ActionsとAWSのOIDC連携で特定のRepositoryやBranchにのみAssumeRoleを許可させてみました。

IAM Role側で今回のような制限を行うことにより、Roleが不本意なRepositoryで使われてしまったり、不必要なAWSアカウントへのAssumeRoleが可能となってしまったりするリスクを権限することができます。OIDC連携をする際には要確認しておきたいですね。

以上