Github Actions IAM Userが作成不要に - OIDC federated IAM RoleのCDK/Terraform書き方と使ってみてわかったこと


## 概要
GitHub Actions で OpenID Connect federation IAM Role を使用すると Github Actions用のIAM UserとAccessKey/SecretKeyを発行してsecretsを埋め込まずにIAM Roleを作るだけでGitHub Actionsが利用可能になります。

仕組みはこちらの絵がわかりやすかったです。
[本家本元リンク](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)

この記事は、CDK/TerraformでのIAM Roleの書き方と、実際使ってみてわかったこと現時点での問題の共有になります。

## 説明
今までworkflowからAWSにアクセスする場合、以下のようにgithubのリポジトリのsecretsに埋め込んだAccessKey/SecretKeyをcredentialにセットしてworkflowを動かしていたと思います。

```
- name: Configure AWS Credentials
  uses: aws-actions/configure-aws-credentials@v1
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: us-east-1
```

これが以下のようにOpenID Connect tokenを利用してworkflowからAWSへアクセスするcredentailを取得することが出来るという話です。

```
name: GitHub Action AWS OIDC Test
on:
  workflow_dispatch: {}
  pull_request: {}
concurrency: ${{ github.repository }}-github-action
env:
  AWS_ROLE_ARN: arn:aws:iam::0123456789012:role/ExampleGithubRole
  AWS_REGION: us-east-1
jobs:
  plan:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Set Environment Variables
        run: echo "REPO_NAME=${GITHUB_REPOSITORY#*\/}" >> $GITHUB_ENV
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-region: ${{ env.AWS_REGION }}
          role-to-assume: ${{ env.AWS_ROLE_ARN }}
          role-duration-seconds: 1800
```

Github Actions用のIAM Userの作成、AccessKey/SecretKeyの発行、githubへのcredentailのsecrets埋め込みが不要になりました。
詳細は [AWS federation comes to GitHub Actions](https://awsteele.com/blog/2021/09/15/aws-federation-comes-to-github-actions.html) 記事に書かれている通りです。

## 使ってみてわかったこと
- Github Marketで提供されているworkflowは現時点で一部動くものと動かないもの(対応してないもの)がある
    - OK: aws-actions/amazon-ecr-login@v1, aws-actions/amazon-ecs-deploy-task-definition@v1
    - 動かない: aws-actions/aws-codebuild-run-build@v1 (No credentials. Try adding @aws-actions/configure-aws-credentials earlier in your job to set up AWS credentials.)
        - [issue書いた→workaround教えてもらった](https://github.com/aws-actions/aws-codebuild-run-build/issues/74) ※2022/1時点では解消されていて`aws-actions/configure-aws-credentials@v1`使えばOKです
- 10分を超えるworkflowはtokenの有効期限切れでエラーになる（10分超えたら再度Tokenの取り直せば動いた）
- self hosted runnerでも動作する

## IAM Role for IaC

github actionsがassume roleするIAM RoleのCloudFormationの記載方法は以下Blogに記載があります。
https://awsteele.com/blog/2021/09/15/aws-federation-comes-to-github-actions.html

CDK/Terraformで書き直してみました。

### CDK
```
from aws_cdk import aws_iam

...

    system = "your_subsystem"
    github_owner = "your_github_owner"
    github_repo = "your_github_repo"

    # github actions IAM Role
    aws_iam_openid_connect_provider = aws_iam.OpenIdConnectProvider(
        self,
        id=f"{system}-github-actions-oidc-provider",
        url="https://token.actions.githubusercontent.com",
        client_ids=["sigstore"],
        thumbprints=["a031c46782e6e6c662c2c87c76da9aa62ccabd8e", "6938fd4d98bab03faadb97b34396831e3780aea1"],
    )

    github_actions_role = aws_iam.Role(
        self,
        id=f"{system}-github-actions-role",
        role_name=f"{system}-github-actions-role",
        assumed_by=aws_iam.FederatedPrincipal(
            federated=aws_iam_openid_connect_provider.open_id_connect_provider_arn,
            conditions={
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": f'repo:{github_owner}/{github_repo}:*'
                }
            },
            assume_role_action="sts:AssumeRoleWithWebIdentity"
        )
    )
```

### Terraform
```
resource "aws_iam_openid_connect_provider" "github_actions" {
  url = "https://token.actions.githubusercontent.com"
  client_id_list = ["sigstore"]
  thumbprint_list = ["a031c46782e6e6c662c2c87c76da9aa62ccabd8e", "6938fd4d98bab03faadb97b34396831e3780aea1"]
}

resource "aws_iam_role" "github_actions" {
  name = "${local.system}-github-actions"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "${aws_iam_openid_connect_provider.github_actions.id}"
      },
      "Condition": {
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:${local.github_owner}/${local.github_repo}:*"
        }
      },
      "Action": "sts:AssumeRoleWithWebIdentity"
    }
  ]
}
EOF
}
```


以上、簡単な共有でした。