S3とGitHub WorkflowsでAPI仕様書を自動公開してみる
⚠️内部向けの公開を意図しており、外部向けに公開するにはCloudFront経由でアクセスさせるような仕組みが必要になろうかと思います。Amplifyなんていうのもあるようです。
OpenAPIで記述したAPI仕様書を、GitHub Workflowsを使って自動でビルドし、S3の静的ウェブサイトホスティング機能で公開する仕組みです。
前提条件
- 内部の開発者向けに公開することを目的とし、S3バケットへのアクセスはIPアドレス等で制限されているものとします。
- API仕様書のデザインにはRedocを利用しています。
構成図
今回構築するシステムの全体像は以下の通りです。
<br>
- 開発者がファイルを編集し、GitHubにプッシュします。
- プッシュをトリガーにGitHub Actionsのワークフローが実行されます。
- OIDCを利用してAWSの一時的な認証情報を取得します。
- Redocで生成されたHTMLファイルをS3バケットにアップロードします。
- 開発者はS3のURLにアクセスし、API仕様書を閲覧します。
ステップ1: S3バケットの準備 (前提)
まず、生成した静的ファイルをホスティングするためのS3バケットを事前に用意しておきます。
静的ウェブサイトホスティングを有効化したS3バケットを作成してください。インデックスドキュメントは index.html に設定します。
内部からのアクセスのみを許可するため、必要に応じてバケットポリシーでIPアドレス制限をかけるなどしておきます。
このバケットは、GitHub Actionsからファイルをアップロードする先になります。
ステップ2: GitHubとAWSのOIDC連携設定
次に、GitHub ActionsがS3を安全に操作できるように、OIDCを設定します。これにより、アクセスキーをSecretsに保存せずにすみます。
-
IAM IDプロバイダの作成:
- AWSのIAMコンソールで「IDプロバイダ」を開き、「プロバイダを追加」をクリックします。
- プロバイダのタイプで
OpenID Connectを選択します。 - プロバイダのURLに
https://token.actions.githubusercontent.comを入力します。 - 「サムプリントを取得」をクリックします。
- 対象者(Audience)に
sts.amazonaws.comを入力して、プロバイダを追加します。
-
IAMロールの作成:
- IAMコンソールで「ロール」を開き、「ロールを作成」をクリックします。
- 信頼されたエンティティのタイプとして「カスタム信頼ポリシー」を選択し、以下のJSONを貼り付けます。
信頼ポリシーの例:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<YOUR_AWS_ACCOUNT_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:<YOUR_GITHUB_ORG>/<YOUR_REPOSITORY_NAME>:*" } } } ] }-
<YOUR_AWS_ACCOUNT_ID>,<YOUR_GITHUB_ORG>,<YOUR_REPOSITORY_NAME>を実際の値に置き換えてください。*の部分をref:refs/heads/mainのように特定のブランチに限定することも可能です。StringLikeで定義すること、ワイルドカードにしておくことで手動実行時にも好きにブランチを決められます。
-
許可ポリシーのアタッチ:
- 次に、このロールにアタッチする許可ポリシーを作成します。
- 以下のJSONを参考に、S3バケットへの操作を許可するポリシーを作成します。
-
aws s3 syncで--deleteを使うためDeleteObjectも付与しています。
許可ポリシーの例:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:ListBucket", "s3:DeleteObject" ], "Resource": [ "arn:aws:s3:::<YOUR_BUCKET_NAME>", "arn:aws:s3:::<YOUR_BUCKET_NAME>/*" ] } ] }- 作成した許可ポリシーを、先ほど作成したIAMロールにアタッチします。
- 最後に、作成したIAMロールのARNを控えておきます。
ステップ3: GitHub Workflowsの構築
リポジトリにGitHub Actionsのワークフローファイルを作成します。
リポジトリのルートに .github/workflows/deploy-api-docs.yml という名前でファイルを作成し、以下の内容を記述します。
name: Deploy API Docs to S3
# ワークフローのトリガー設定
on:
# mainブランチにpushされた時
push:
branches:
- main
# 手動実行を可能にする
workflow_dispatch:
# OIDC認証に必要な権限
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Get branch name
id: get_branch
run: |
BRANCH_NAME=$(echo "${{ github.ref }}" | sed -e 's,refs/heads/,,')
if [ "$BRANCH_NAME" = "main" ]; then
echo "S3_PATH=latest" >> $GITHUB_OUTPUT
else
echo "S3_PATH=$BRANCH_NAME" >> $GITHUB_OUTPUT
fi
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
# package.jsonに設定しているものを呼ぶだけにしています
- name: Build HTML with Redoc
run: |
npm run generate
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<YOUR_AWS_ACCOUNT_ID>:role/<YOUR_IAM_ROLE_NAME>
aws-region: ap-northeast-1 # 東京リージョンの例
# aws s3 cp でも十分かと思います。その場合はDeleteObjectアクションは不要です。
- name: Deploy to S3
run: |
aws s3 sync <生成したファイル> s3://${{ secrets.S3_BUCKET_NAME }}/${{ steps.get_branch.outputs.S3_PATH }} --delete
リポジトリのSecrets設定:
ワークフロー内でS3バケット名を直接記述するのを避けるため、GitHubリポジトリのSecretsに登録します。
- 以下のSecretを登録します。
-
S3_BUCKET_NAME: ステップ1で作成したS3バケット名
-
実行と確認
ワークフローをデフォルトブランチにマージしたら、あとは実行するだけです。
-
自動実行:
mainブランチにコミットをプッシュすると、自動的にワークフローが実行され、http://<バケット名>.s3-website.../<リージョン>.amazonaws.com/latest/に最新の仕様書が公開されます。 -
手動実行:
- リポジトリの「Actions」タブを開きます。
- 左のサイドバーから「Deploy API Docs to S3」ワークフローを選択します。
- 「Run workflow」ドロップダウンをクリックします。
- デプロイしたいブランチ名を選択し、「Run workflow」ボタンを押します。
- 完了後、
http://<バケット名>.s3-website.../<リージョン>.amazonaws.com/<ブランチ名>/でプレビューが確認できます。
まとめ
今回は、AWS S3とGitHub Workflowsを連携させ、API仕様書を自動で公開する仕組みを構築しました。
内部向けの資料を展開するにはそこそこ便利です。外部向けはちょっと考える必要がありますが、静的なファイルとして生成される系はこの感じで公開できるため、誰かに意見を聞きたいときも説明が楽になりました。
Discussion