🛠️

OIDC を使って GitHub Actions から AWS CDK を動かす

2024/08/31に公開

概要

OIDC(OpenID Connect)

GitHub Actions は OIDC(OpenID Connect)を使って動作させることができます。AWS でいうと、クレデンシャルを GitHub 上にシークレットとして埋め込まずに、IAM ロールの ARN をシークレットに埋め込んで利用できます。

クレデンシャルを ARN に変更できると、セキュリティリスクを大きく減らすことができます。また IAM ロールも CDK の bootstarp で作られたものだけを使うので、最小権限で環境を作れます。

https://docs.github.com/ja/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

リポジトリ

下記リポジトリにて本記事の動作を確認できます。
https://github.com/hiyanger/github-actions-oidc-cdk

構築

1. CDK 環境構築

① bootstrap

ローカルに CDK でデプロイできる環境を作ります。cdk bootstrap で Assume Role 用の IAM ロールを作っておきます。

$ cdk init app --language typescript
$ npm run build
$ cdk bootstrap --profile XXX

② cdk deploy

ローカルからのデプロイを確認しておきます。デプロイするリソースはなんでもよいです。ここでは簡単なS3を作成しています。

💡コードは下記から拝借しつつ、若干変更を加えています。
https://zenn.dev/zgw426/articles/0afa4156e92391

lib/github-actions-oidc-cdk-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';

export class GithubActionsOidcCdkServerlessStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const bucket = new s3.Bucket(this, 'CreateBucket', {
      bucketName: "github-actions-oidc-cdk-20240831",
      versioned: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });
  }
}
bin/github-actions-oidc-cdk.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { GithubActionsOidcCdkServerlessStack } from '../lib/github-actions-oidc-cdk-stack';

const app = new cdk.App();
new GithubActionsOidcCdkServerlessStack(app, 'GithubActionsOidcCdkStack', {
});
  • 差分の確認
$ cdk diff --profile XXX
  • デプロイ
$ cdk deploy --profile XXX

2. IAM ロールの作成

この記事ではAWSコンソールで作成します。

① ID プロバイダの作成

IAM ロール → ID プロバイダ → プロバイダを追加

② IAM ロールの作成

  • カスタム信頼ポリシー
    pull requestでは、cdk diffmergeでは、cdk deploy という動作を想定して作ります。ブランチは簡易的なものとして、feature/XXX から master にpull requestmergeされることを想定しています。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<アカウントID>:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
                },
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:<GitHubユーザー名>/<GitHubリポジトリ名>:*"
                }
            }
        }
    ]
}

💡 ブランチを絞りたい場合
Condition の部分を変更します。

"Condition": {
    "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
        "token.actions.githubusercontent.com:sub": "repo:<GitHubユーザー名>/<GitHubリポジトリ名>:ref:refs/heads/<ブランチ名>"
    }
}
  • IAM ポリシー
    cdk bootstrap で作成される IAM ロール名は共通です。アカウント ID だけかえましょう。
  {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": [
                "arn:aws:iam::<アカウントID>:role/cdk-hnb659fds-deploy-role-<アカウントID>-ap-northeast-1",
                "arn:aws:iam::<アカウントID>:role/cdk-hnb659fds-file-publishing-role-<アカウントID>-ap-northeast-1",
                "arn:aws:iam::<アカウントID>:role/cdk-hnb659fds-image-publishing-role-<アカウントID>-ap-northeast-1",
                "arn:aws:iam::<アカウントID>:role/cdk-hnb659fds-lookup-role-<アカウントID>-ap-northeast-1"
            ]
        }
    ]
}

3. GitHub Actions 設定

① IAM ロールの ARN シークレット登録

Settings → Security → Secrets and variables → Actions → New repository secret

コード上で使うシークレット名をいれて、実際の ARN は Secret に入力する

② GitHub Actions 設定ファイルの作成

.github/workflows/cdk.yml
name: cdk

on:
  push:
    branches:
        - master
  pull_request:
jobs:
  aws_cdk:
    runs-on: ubuntu-latest
    env: 
      AWS_REGION: "ap-northeast-1"
    
    permissions:
      id-token: write
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup dependencies
        run: npm ci

      - name: Assume Role
        uses: aws-actions/configure-aws-credentials@v2
        with:
          role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }} 
          aws-region: ${{ env.AWS_REGION }}
          
      - name: CDK Diff Check
        if: contains(github.event_name, 'pull_request')
        run: npm run cdk:diff

      - name: CDK Deploy
        if: contains(github.event_name, 'push')
        run: npm run cdk:deploy

③ package.json の編集

scripts に cdk:diff と cdk:deploy を追記する。

package.json
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk",
    "cdk:diff": "cdk diff",
    "cdk:deploy": "cdk deploy --require-approval never"
  },

動作確認

あとは master ブランチに対して pull request すれば、 cdk diff が動作、 merge をすれば、 cdk deploy が動作します。

  • cdk diff

  • cdk deloy

一度ローカルからデプロイしてるので、no changes になっています。実際にデプロイさせたい場合は CDK のコードを変更させてみましょう。

おわり☺️

参考

感謝です🙏
https://zenn.dev/kou_pg_0131/articles/gh-actions-oidc-aws
https://makky12.hatenablog.com/entry/2023/07/31/120500

アイレット株式会社

Discussion