【CI/CD編】プロフィールサイトAWS移行メモ 〜インフラ初心者を添えて〜
はじめに
この記事では、プロフィールサイトAWS移行の最終回として GitHub Actions を用いたCI/CDの構築をしていきたいと思います。
アーキテクチャ図では、以下の部分を構築します。

やりたいこととしては、主に以下の2つになります。
- GitHub Actions を用いた S3 へのデプロイ自動化
- microCMS の Webhook 連携を使用した GitHub Actions の自動実行
また、上記を行う際に IAM OIDC IDプロバイダーを使用した AssumeRole によるAWSアクセスを実現し、セキュリティー面も考慮していますので併せて記載します。
OIDC ロールの作成
まずは AWS CDK に OIDC ロールの作成を行うコードを追加していきます。
追加するファイルは以下になります。
My_profile-cdk/
...
├── lib/
│ ...
│ └── stacks/
│ │ ...
│ │ └── cicd-oidc-role-stack.ts
│ ...
├── parameters/
│ ...
│ └── oidc-parameter.ts
...
OIDC ロールとは?
OIDC ロールとは長期アクセスキーを使わずに、GitHub Actions などの外部サービスから AWS の一時的な権限を安全に取得する仕組みのことです。
主に以下のような利点がります。
- 秘密鍵いらず:リポジトリやCIに長期アクセスキーを置かないため、漏洩リスク激減になる。
- 自動ローテーション:毎回使い捨ての短命キーを使用する。
- 最小権限:ロールに必要最小限の権限だけ付けることが可能。
- 細かい制限:トークンの中身(claims)で repo/branch 単位に実行元を縛れる。
OIDC フェデレーション - AWS Identity and Access Management
AWS 上で実行しないアプリケーションが AWS にアクセスするための一時的な AWS セキュリティ認証情報を作成します。
docs.aws.amazon.com

AssumeRole + OIDC方式の全体フロー
以下はGitHub ActionsからS3バケットへアクセスする際のフロー図です。

CDK コードの実装
GitHub Actions から OIDC で 最小権限のデプロイ用ロールを払い出し、指定の S3 バケットにアップロード&CloudFront のキャッシュ無効化だけを許可するスタックになっています。
具体的には以下の処理を行っています。
- デプロイ対象ブランチの決定。
- GitHub OIDC プロバイダの用意。
・既存の OIDC Provider ARN があればそれを利用し、なければ新規作成。 - 信頼ポリシーの設定
- GitHub Actions 用 IAM ロールの作成
- S3, CloudFront に対する最小権限を設定。
・S3:バケットの一覧取得(s3:ListBucket
)、オブジェクトの作成/削除(s3:PutObject
,s3:DeleteObject
)
・CloudFront:cloudfront:CreateInvalidation
を 対象ディストリビューション ARN に限定して付与。 - GitHub Actions の
role-to-assume
で使うロール ARN を出力。
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from "aws-cdk-lib/aws-iam";
import { CicdOidcRoleStackProperty } from "@/parameters/oidc-parameter";
export interface CicdOidcRoleStackProps
extends cdk.StackProps,
Omit<CicdOidcRoleStackProperty, "env"> {
bucketName: string;
distributionId: string;
}
export class CicdOidcRoleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: CicdOidcRoleStackProps) {
super(scope, id, props);
const branch = props.props.gitHub.branch ?? "main"; // 未指定なら main 限定
// GitHub OIDC Provider(既存再利用 or 新規作成)
const provider = props.props.useExistingProviderArn
? iam.OpenIdConnectProvider.fromOpenIdConnectProviderArn(
this,
"GithubOidcProviderImported",
props.props.useExistingProviderArn
)
: new iam.OpenIdConnectProvider(this, "GithubOidcProvider", {
url: "https://token.actions.githubusercontent.com",
clientIds: ["sts.amazonaws.com"],
});
// OIDC 信頼条件(repo/branch を厳密化)
const principal = new iam.OpenIdConnectPrincipal(provider).withConditions({
StringEquals: {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
},
StringLike: {
"token.actions.githubusercontent.com:sub": `repo:${props.props.gitHub.owner}/${props.props.gitHub.repo}:ref:refs/heads/${branch}`,
},
});
// IAM Role(GitHub Actions 用)
const role = new iam.Role(this, "GithubActionsDeployerRole", {
assumedBy: principal,
description:
"OIDC for GitHub Actions: least-privilege deploy to S3 + CloudFront invalidation",
roleName: "github-actions-oidc-deployer",
});
// S3 最小権限(対象バケット限定)
role.addToPolicy(
new iam.PolicyStatement({
actions: ["s3:ListBucket"],
resources: [`arn:aws:s3:::${props.bucketName}`],
})
);
role.addToPolicy(
new iam.PolicyStatement({
actions: ["s3:PutObject", "s3:DeleteObject"],
resources: [`arn:aws:s3:::${props.bucketName}/*`],
})
);
// CloudFront 無効化(Distribution 限定)
role.addToPolicy(
new iam.PolicyStatement({
actions: ["cloudfront:CreateInvalidation"],
resources: [
`arn:aws:cloudfront::${cdk.Stack.of(this).account}:distribution/${
props.distributionId
}`,
],
})
);
// 出力(GitHub Actions 側で使う Assume Role ARN)
new cdk.CfnOutput(this, "DeployerRoleArn", {
value: role.roleArn,
description: "AssumeRole ARN for GitHub Actions (role-to-assume)",
});
// OIDC Provider の ARN を出力
new cdk.CfnOutput(this, "OidcProviderArn", {
value: provider.openIdConnectProviderArn,
description: "GitHub OIDC Provider ARN referenced by this stack",
});
}
}
デプロイ
これまでと同様に、「テンプレート生成 → 差分確認 → デプロイ」の手順で追加したリソースをデプロイします。
$ cdk synth
$ cdk diff MyProfileCdkStage/*
$ cdk deploy MyProfileCdkStage/DnsStack \
MyProfileCdkStage/EdgeCertStack \
MyProfileCdkStage/MailApiStack \
MyProfileCdkStage/WebsiteStack \
MyProfileCdkStage/CicdOidcRoleStack \
--concurrency 1
ここで、デプロイした際に出力される「DeployerRoleArn
」をメモしておきます。
S3 へのデプロイワークフロー
GitHub Secrets の設定
GitHub Actions が使用する環境変数を設定します。
Next.jsプロジェクトが使用する環境変数と併せて、先ほどメモした「DeployerRoleArn
」も設定します。

deploy.ymlの作成
.github/workflows/
ディレクトリに GitHub Actions のワークフローを定義していきます。
処理内容
on
push
:main
ブランチにpush
されたら実行。workflow_dispatch
:Actions 画面から 手動実行も可。
permissions
id-token: write
:OIDC トークン発行を許可(AssumeRole 用)。contents: read
:リポジトリをチェックアウトする権限。
defaults.run.working-directory
- 以降の
run
: はmy_profile
ディレクトリ配下で実行。
- 以降の
concurrency
deploy-static
グループで 同時実行を1つに制限。新しい実行が来たら 古い実行をキャンセル(重複デプロイ防止)。
env
:ビルド&デプロイ時に使う環境変数を設定。jobs.deploy.steps
:Checkout
:リポジトリのソースを取得。Setup Node
:依存キャッシュ対象をmy_profile/package-lock.json
に固定して npm キャッシュを有効化。Install deps
:npm ci
でクリーンインストール。Build
:npm run build:static
を実行(Next.js を静的書き出し)。Configure AWS credentials
:role-to-assume
に Secrets のAWS_ROLE_ARN
を指定して STS で一時クレデンシャル取得(先ほど作成した OIDC ロールをここで引き受ける)。Sync to S3
:ローカルと S3 のファイルを一致させ、アップロード。Invalidate CloudFront
:/*
を 全無効化して最新ファイルを即時配信。
name: Deploy static site to S3
on:
push:
branches: [main]
workflow_dispatch:
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: my_profile
concurrency:
group: deploy-static
cancel-in-progress: true
env:
AWS_REGION: ${{ secrets.AWS_REGION }}
S3_BUCKET: ${{ secrets.S3_BUCKET }}
CLOUDFRONT_DISTRIBUTION_ID: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}
MICROCMS_SERVICE_DOMAIN: ${{ secrets.MICROCMS_SERVICE_DOMAIN }}
MICROCMS_API_KEY: ${{ secrets.MICROCMS_API_KEY }}
MICROCMS_PREVIEW_SECRET: ${{ secrets.MICROCMS_PREVIEW_SECRET }}
NEXT_PUBLIC_CONTACT_API_ENDPOINT: ${{ secrets.NEXT_PUBLIC_CONTACT_API_ENDPOINT }}
NEXT_TELEMETRY_DISABLED: "1"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
cache-dependency-path: "my_profile/package-lock.json"
- name: Install deps
run: npm ci
- name: Build (static export via script)
run: npm run build:static
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Sync to S3
run: |
aws s3 sync ./out s3://$S3_BUCKET --delete --exact-timestamps
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id "${CLOUDFRONT_DISTRIBUTION_ID}" \
--paths "/*"
動作確認
では、作成したワークフローをmain
にプッシュして、正常に Actions が実行されるか試してみます。

エラーなく実行されたことが確認できました!
AWS コンソールから S3 バケットにあるファイルの更新日時を確認すると最新のものになっていたので問題ないかと思います。
microCMS の Webhook 連携
ここからは、microCMSでコンテンツ更新時に、WebhookでGitHub Actionsを実行する設定を行っていきます。
GitHub側での設定
deploy.yml
の修正
先ほど作成したdeploy.yml
に、Webhook 連携のための設定を追加します。
on
repository_dispatch
:microcms_build
イベントで実行(microCMS → GitHub API 経由のトリガ)。
name: Deploy static site to S3
on:
push:
branches: [main]
repository_dispatch:
types: [microcms_build]
workflow_dispatch:
...
GitHubトークンの作成
そして、GitHub側で認証に必要なトークンを発行します。
※ ここでは Fine-grained tokens(Beta)で設定しています。
- GitHubのユーザー設定ページにアクセスします。
- ユーザー設定ページにて、左カラムの最下部にある「Developer settings」にアクセスします。
- 左カラムから「Personal access tokens」のメニューを押下し、Fine-grained tokensを押下します。
- トークン一覧画面にて「Generate new token」ボタンを押下します。
- 「New fine-grained personal access token」の画面で、以下の情報を入力します。
・Token name(必須):任意の名前を入力してください。
・Expiration(必須):任意の有効期限を選択してください。
・Description:任意の説明文を入力してください。
・Resource owner:連携したいリポジトリのオーナーを選択してください。 - 次に、「Repository access」セクションへ進み、「Only select repositories」を選択します。ここで連携したいリポジトリを選択してください。
- 次に、「Permissions」セクションへ進み、「Repository permissions」のメニューを展開します。ここで、「Contents」の権限に Read and write を付与します。なお、「Account permissions」の設定はデフォルトのままとします。
- ページ下部の「Generate token」ボタンを押下します。
- トークンの一覧画面に戻り、作成したばかりのトークンが表示されているので、コピーして保存しておきます。トークンの作成はここで終了です。
microCMS側での設定
次に、microCMS側での設定方法について、手順を示します。
- Webhookの設定をしたいAPIの「API設定」>「Webhook」画面にアクセスし、「+ 追加」ボタンを押下します。
- 次に、Webhook通知を行いたいサービスの選択画面が表示されるので、GitHub Actionsを選択します。
- GitHub Actionsの設定画面内の「基本設定」セクションにて、以下のように入力します。
・Webhookの識別名
・GitHubトークン:ここで、GitHub側で取得したアクセストークンを入力してください。
・リポジトリのユーザー名
・リポジトリ名
・トリガーイベント名:ワークフローファイル内の repository_dispatch 欄で定義した event_types の値を入力してください。 - 次に「通知タイミングの設定」セクションにて、任意の通知タイミングを選択してください。
- 最後に「設定する」を押下し、設定は完了です。
動作確認
では、microCMS側でコンテンツを公開するとGitHub Actions が実行されるか試してみます。

無事に実行され、エラーなく完了していました!
さいごに
いかがでしたでしょうか。
ここまで、インフラ初心者がプロフィールサイトを Vercel から AWS へ移行した時の手順を備忘録として記載してきました。
初めは、資格勉強で得た知識だけを持っている状態でしたが、AWS移行を通して各サービスの詳細な設定内容や連携方法について学ぶことができました。
また、CDK を用いてインフラを定義したことで、IaC の概念についても理解することができ、より実践的な知識が得られたのではないかと感じています。
今回は、静的サイトを構築するための最低限の構成でしたが、今後は、さらに詳細な設定を行ったりバックエンドを持つインフラの構築など、よりレベルアップした内容にも挑戦していきたと思います。
最後までご覧いただきありがとうございました!
参考
GitHub ActionsでウェブサイトをAmazon S3にデプロイする | DevelopersIO
No description available.
dev.classmethod.jp

【コンテンツのWebhook連携】GitHub Actionsの設定方法について
microCMSではコンテンツの状態やAPI変更時にWebhookを発行し、外部のシステムと連携することができます。 このヘルプでは、コンテンツのWebhook連携におけるGitHub Actionsの設定方法について解説します。Webhook機能の詳細につきましては、microCMSドキュメント「コンテンツのWebhookを設定」をご覧ください。 GitHub Actionsと連携する際には、G
help.microcms.io

microCMSでコンテンツ更新時に、WebhookでGitHub Actionsを実行する
microCMSで記事を作成したり、編集・削除等更新した際にそのままサイトに反映されるようにWebh...
blog.tesoro-crea.com

【IAM OIDC IDプロバイダーの仕組みを見てみる】GitHub ActionsからAWSに一時認証情報を使用してアクセスする
No description available.
zenn.dev

【CI/CD】AssumeRole + OIDC方式の仕組みを整理してみた - Qiita
はじめに 以前、CI/CDパイプラインでAWSリソースにアクセスする際に「AssumeRole + OIDC方式」を使った仕組みを構築しました。手順通りに設定して動作することは確認できましたが、振り返ってみると仕組みについての理解があいまいなままでした。そこで、自分の理解...
qiita.com
