OpenID Connectを使用してGitHub Actionsでアクセスキーレスなデプロイをおこなう

セキュリティ強化を目指して、なるべくIAMユーザーの使用を最小限に抑えて、IAMロールで一時的な権限付与を行う手法を取り入れてきました。

ただ、GitHub Actionsのデプロイワークフローにおいては、AssumeRoleする際にIAMユーザーのクレデンシャル(アクセスキーとシークレットアクセスキー)が必要だと思っていて、以下の記事でもその方法を採用しました。

https://qiita.com/suzuki0430/items/b3c35e888561ee99f6aa

しかし、よく調べてみたら、OpenID Connectを使うと、クレデンシャルを使わずにワークフロー内でAssumeRoleできることがわかり、ワークフローを改善しました。

DevOps経験のあるエンジニアには既知の内容だと思いますが、初心者の方々への参考として、改善内容を共有します。

# OpenID Connectとは
OpenID Connect(OIDC)は、ユーザー認証を行うためのオープンスタンダードプロトコルです。OAuth 2.0プロトコルを基にしていて、安全な方法でユーザーの身元情報を確認することができます。

OIDCを使うと、GitHub ActionsのワークフローがGitHub(OpenID Connectプロバイダとして)から特定のワークフローに関連する情報(リポジトリ名、ワークフローIDなど)を含む一時的なトークンを要求します。GitHubはこの要求に応じてトークンを生成し、これがワークフローの実行中のみ有効となります。そのため、IAMユーザーのアクセスキーを用いる方法に比べて、セキュリティが向上し、管理が容易になります。

生成されたOIDCトークンは、GitHub ActionsワークフローからAWSに送信されます。AWS上では、あらかじめ設定されたIAMロールがOIDCプロバイダ(GitHub)からのトークンを受け入れるように設定されています。このIAMロールは特定のポリシー(権限のセット)と関連付けられていて、OIDCトークンに基づいて、GitHub Actionsワークフローに特定のAWSリソースへのアクセスを許可します。

GitHub Actionsワークフローは、AWSの「AssumeRoleWithWebIdentity」APIを呼び出して、提供されたOIDCトークンを使用して、指定されたIAMロールのアクセス許可を取得します。このステップで、AWSはOIDCトークンを検証し、トークン内の情報が設定されたIAMロールと一致する場合にのみアクセスを許可します。

簡単に言うと、OIDCを使うことで、GitHub Actionsは「一時的な証明書」を受け取り、それを使って必要な操作を行うことができるようになります。これによって、IAMユーザーのクレデンシャルをワークフロー内に保持する必要がなくなり、セキュリティリスクが大幅に軽減されます。

# 実装
順番に説明します。

## IDプロバイダの追加(AWS)
IDプロバイダを設定することで、GitHub Actionsからのリクエストが正当であることをAWS側が確認できます。OIDC IDプロバイダの設定によって、GitHub Actionsのワークフローから生成された認証トークンが検証され、そのトークンに基づいて特定のAWSリソースへのアクセスが許可されます。

AWSのマネジメントコンソールの「IAM > IDプロバイダ > IDプロバイダを作成」から以下の設定でIDプロバイダの追加を行います。

- プロバイダのタイプ：OpenID Connect
- プロバイダのURL：`https://token.actions.githubusercontent.com`
- 対象者：`sts.amazonaws.com`

GitHubのOIDCプロバイダ(token.actions.githubusercontent.com)のサムプリントを取得し、AWSのOIDC IDプロバイダ設定に追加することで、GitHub ActionsがAWSサービスに安全にアクセスできるようになります。

![スクリーンショット 2024-01-06 22.12.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/4259fea1-0041-27be-c8fe-ac66fc9db1bd.png)

## IAMロールの作成
AssumeRoleするIAMロールを作成します。
デプロイに必要なIAMポリシー(ECSへのデプロイだったらECSやECRへのアクセス権限など)を付与し、信頼関係タブで以下のJSONを用いて信頼されたエンティティを設定します。

```json
{
    "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:aud": "sts.amazonaws.com",
                    "token.actions.githubusercontent.com:sub": "repo:<organization-name>/<repository-name>:*"
                }
            }
        }
    ]
}
```

こちらのJSONでは、GitHub Actionsからの認証リクエストを許可するための条件を定義します。

- Principal: GitHub ActionsのOIDCプロバイダ(`token.actions.githubusercontent.com`)を指定します。
- Action: `sts:AssumeRoleWithWebIdentity`は、Webアイデンティティ(OIDCトークン)を使用してIAMロールを引き受けるアクションを指します。
- Condition: 特定のGitHubリポジトリ(`<organization-name>/<repository-name>`)からのリクエストを指定します。

このIAMロールと信頼関係の設定によって、GitHub Actionsの特定のワークフローが、AWS上で指定されたサービスにアクセスするための権限を持つようになります。

## デプロイワークフローの改修
ワークフローを以下のように改修します。

改修前
```yml
name: Lambda Deploy
on:
  push:
    branches:
      - develop
    paths:
      - "**"
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: install dependencies
        run: yarn install
        working-directory: ./

      - name: configure aws
        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 }}
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME }}
          role-duration-seconds: 3600
```
↓
改修後
```yml
name: Lambda Deploy
on:
  push:
    branches:
      - develop
    paths:
      - "**"
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: install dependencies
        run: yarn install
        working-directory: ./

      - name: configure aws
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_TO_ASSUME }}
          aws-region: ${{ secrets.AWS_REGION }}
          role-session-name: GitHubActions
          role-duration-seconds: 3600
```

以下が改修点となります。

1. `permissions`の追加: 改修後のワークフローには、新たに`permissions`セクションが追加されています。これはGitHub ActionsがOIDCトークンを要求し、利用するために必要な設定です。`id-token: write`はGitHubからOIDCトークンを取得するための権限を与え、`contents: read`はリポジトリの内容を読むための権限を設定しています。

2. クレデンシャルの除去: 改修前のワークフローでは、`aws-access-key-id`と`aws-secret-access-key`を使用してAWSに認証していましたが、改修後のワークフローではこれらが削除されています。これにより、IAMユーザーのクレデンシャルを公開するリスクがなくなり、セキュリティが向上します。

3. `configure-aws-credentials`アクションの変更: `aws-actions/configure-aws-credentials`アクションの使用方法が変更されており、OIDCトークンを用いてAWSに認証するように変更されています。`role-to-assume`は引き続き使用されており、OIDCにより承認されたGitHub Actionsワークフローが指定されたIAMロールを引き受けることを可能にします。