0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コードが書けないインフラエンジニアが、Claudeと作る S3+CloudFront+GitHub Actions のCI/CD

0
Posted at

はじめに

アプリのコードが書けないインフラエンジニアでも、AIと組めば半日でWebアプリを公開し、自動デプロイまで作れました。費用は月0円です。

私はAWSの構築経験はありますが、ReactやTypeScriptは書けません。ある朝、ブラウザで使えるポモドーロタイマーを見かけ、「同じようなものをAWSでなるべく安く作れないか」とClaudeに相談したのが始まりです。

この記事では、構成を決めるところから、S3とCloudFrontでの公開、GitHub Actionsによる自動デプロイ、そして一番ハマったOIDCのエラーまで、実際にやった順に書きます。

設定値やポリシーのJSON、ワークフローの全文など、再現するための具体的な手順は手順書にまとめました。
【手順書】S3+CloudFront(OAC)+GitHub Actions(OIDC)で静的サイトのCI/CDを構築する

構成を決める:サーバーを持たない

結論は「S3にファイルを置き、CloudFrontで配信するだけ」の静的サイトです。ポモドーロタイマーは、時間を数える・音を鳴らす・設定を覚えるがすべてブラウザ内で完結するため、サーバーもデータベースも要りません。

設定や今日の集中回数はブラウザのlocalStorageに保存します。ログインや複数端末の同期が欲しくなったら、Cognito、API Gateway、Lambda、DynamoDBのサーバーレス構成を後から足す、という二段構えにしました。

役割 使ったもの
画面 React + TypeScript + Vite
ファイル置き場 Amazon S3(非公開のまま)
配信とHTTPS Amazon CloudFront(OACでS3に接続)
ソース管理 GitHub
自動デプロイ GitHub Actions(OIDCでIAMロールを引き受け)

EC2とRDSで組むと最低でも月数千円かかりますが、この構成ならCloudFrontの無料プランに収まります。

アプリはAIに作ってもらう

「コードは書けない」と伝えると、Claudeがその場でアプリを作り、ビルド済みの成果物(dist/)とソース一式をzipで渡してくれました。ビルド後に画面を実際に起動し、スクリーンショットで崩れがないかまで確認済みでした。

最初の版は25分集中と5分休憩を回す、シンプルなタイマーです。公開後に気になった点を伝えると、すぐ直った版が返ってきました。

  • PCで左右の余白が広すぎる → 2カラムにして、左に大きなタイマー、右に「今日のサイクル」「今日の記録」「設定」を並べた
  • 集中・休憩・長い休憩のタブが分かりにくい → タブをやめ、集中→休憩→…→長い休憩の流れを縦に並べ、今どこにいて次が何かを表示
  • タイマーの下が空いている → 通知音を5種類(ベル、チャイム、電子音、マリンバ、やさしい鐘)と音量スライダーを追加

通知音は音声ファイルではなく、ブラウザのWeb Audio APIで合成しています。そのためファイルが増えず、S3の容量も料金も変わりません。

S3とCloudFrontで公開する

S3は「パブリックアクセスをすべてブロック」をオンのまま作り、CloudFrontのOAC経由でだけ読めるようにしました。作業は30分ほどです。

  1. 東京リージョンにバケットを作る。静的ウェブサイトホスティングは有効にしない
  2. dist/ の中身(index.html、favicon.svg、assets/)をバケット直下にアップロードする
  3. CloudFrontのディストリビューションを作る。オリジンにバケットを選び、オリジンパスは空欄、オリジンアクセスはOAC
  4. デフォルトルートオブジェクトに index.html を設定する
  5. https://xxxx.cloudfront.net を開いて表示を確認する

新しい作成ウィザードでは料金プランを選べ、無料プラン(月0ドル)にはWAFの基本保護も含まれていました。「Grant CloudFront access to origin」をYesにすると、CloudFrontのサービスプリンシパルにこのディストリビューションからの s3:GetObject だけを許すバケットポリシーが自動で書き込まれます。手で貼る必要はありませんでした。

ハマりかけたのは手順4です。ウィザードに項目がなく未設定のままで、作成後に設定画面から入れ直しました。ここが空だと、トップURLでAccessDeniedになります。

GitHub Actionsで自動デプロイにする

main にpushすると、1〜2分でビルドからS3同期、CloudFrontの無効化まで自動で走るようにしました。アクセスキーは発行せず、OIDCで一時的な認証情報をもらいます。

  1. GitHubにリポジトリを作り、ソースをpushする
  2. IAMで、OIDCプロバイダー token.actions.githubusercontent.com(対象者 sts.amazonaws.com)を作る
  3. デプロイ用のIAMロールを作る。信頼ポリシーでリポジトリと main ブランチに限定し、権限はS3の ListBucket、PutObject、DeleteObject と、CloudFrontの CreateInvalidation だけにする
  4. GitHubのRepository variablesに、AWS_ROLE_ARN、S3_BUCKET、CLOUDFRONT_DISTRIBUTION_ID を登録する
  5. .github/workflows/deploy.yml を置いて実行する

小さな落とし穴が2つありました。

  • ブラウザからアップロードすると .github が抜ける。 隠しフォルダは除外されるので、GitHubの画面で「Create new file」から作りました
  • Environment variablesに入れても読まれない。 ワークフローで environment: を指定していないので、Repository variablesに登録します

料金は、Publicリポジトリなら無料、Privateでも月2,000分の無料枠があります。1回1〜2分なので、まず超えません。

最大のハマりどころ:subの形式が違っていた

初回のデプロイは「Configure AWS credentials」で失敗しました。原因は、GitHubから届く sub にユーザーIDとリポジトリIDが含まれていたことです。

Error: Could not assume role with OIDC: Not authorized to perform sts:AssumeRoleWithWebIdentity

ロールのARN、audience、ワークフローの id-token: write は、どれも正しく設定されていました。推測で直すのをやめ、CloudTrailのイベント履歴で AssumeRoleWithWebIdentity の失敗イベントを開くと、userIdentity.userName に実際に届いた値がありました。

信頼ポリシーの条件: repo:<ユーザー名>/pomodoro:ref:refs/heads/main
実際に届いた sub :  repo:<ユーザー名>@<ユーザーID>/pomodoro@<リポジトリID>:ref:refs/heads/main

IAMコンソールのロール作成ウィザードが作るのは、名前だけの従来形式です。信頼ポリシーの sub を届いた値にそろえ、StringEquals の完全一致にしたら通りました。

数字のIDが入る形式は、むしろ安全です。アカウント名を変えたあとに第三者が同じ名前でリポジトリを作っても、IDが違うのでロールを引き受けられません。

教訓は「権限エラーは、相手側が実際に送ってきた値を見る」です。CloudTrailは、拒否されたリクエストの中身まで残してくれていました。

ビルドとは何だったのか

S3には index.html、favicon.svg、assets/ しかないのに、App.tsx の変更が反映されました。S3に置いているのはソースではなく、ソースを変換した成果物だからです。

ブラウザは .tsx をそのまま実行できません。そこで npm run build が、src/ のコードとReact本体を普通のJavaScriptに変換して1つにまとめ、assets/index-xxxx.js を作ります。中身が変わるとファイル名のハッシュも変わるので、index.html だけをキャッシュさせなければ古い版は残りません。

ビルド用のサーバーも持っていません。runs-on: ubuntu-latest の1行で、GitHubが毎回まっさらなVMを用意し、終わったら捨ててくれます。Javaのソースから .jar を作って配置するのと同じで、ソースはGitHub、成果物はS3という分担です。

最初はClaudeの作業環境がこのランナーの役割をしていて、成果物をzipで受け取り、手作業でS3に上げていました。今はpushするだけです。

かかった時間と費用

最初の相談から自動デプロイの動作確認まで、約1時間半でした。毎月の費用は0円です。

項目 月額
S3(数百KBのファイル) ほぼ0円
CloudFront(無料プラン、WAFの基本保護込み) 0円
GitHub Actions(1回1〜2分) 0円(無料枠内)
IAM、OIDCプロバイダー、CloudTrailのイベント履歴 0円

まとめ

コードが書けなくても、インフラの知識があれば「AIにアプリを作らせ、自分は基盤を作る」という分担で十分戦えます。権限、キャッシュ、ログといったインフラ側の勘所は、AIと組んでもそのまま武器になりました。

次は、独自ドメイン(Route 53とACM)、作業名の入力と週間グラフ、PWA化に挑戦する予定です。

同じ構成を自分で作りたい方は、手順書をどうぞ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?