はじめに
これまで本サイトのWordPressテーマ(PHP)の更新は、手動でEC2サーバーへアップロードしていました。
しかし前回、セキュリティの向上とSSH用Elastic IPの解放(コストダウン)のためSSH接続は閉じました。というわけで、今までのデプロイ方式は使えないので、GitHub Actions+SSMを使ってのデプロイの仕組みを構築することにしました。
しかも、
- アクセスキー未使用
- OIDC認証
- SSM経由デプロイ
という、なかなかモダンな構成です(当社比)。
チャッピーに聞きつつデプロイ基盤ができたので記事に残していきます。
構成概要
今回のデプロイフローは以下。
Local(ローカルでのWebサイト修正&テスト)→ GitHub → OIDC → S3 → SSM → EC2
流れ
- GitHub にプッシュしてmainブランチへマージ
- GitHub Actionsが起動
- OIDCでAWSにログイン
- WordPressのテーマをzip化してS3へアップロード
- SSMでEC2へコマンド送信
- 本番テーマを展開
SSHは一切使わないので閉じていてOK。
なぜOIDCを使ったのか?
従来のやり方だと、
- AWSアクセスキーをGitHub Secretsに保存
- 長期クレデンシャル(証明情報)管理
という形になるので、現在はOIDCを使用するのが良いとのことでした。(チャッピーによる)
OIDCがわからない僕のためにチャッピーに説明してもらいました。
「OIDC = OpenID Connect
ざっくり言うと:
「ログインしてるよって証明する仕組み」Googleログインとか、ああいうやつの中身。」とのこと。
OIDCを使うことで:
- アクセスキー不要
- 一時的な認証のみ発行
- mainブランチ限定でロール使用可能
となり、安全な構成になるとのことです。
OIDCの何がイケてるかというと
❌ 昔
GitHub SecretsにAccessKeyベタ置き
✅ 今
GitHubがトークン発行 → AWS IAMが信頼関係で検証 → STSで※一時ロール発行 → 期限付きクレデンシャルで実行
鍵をGitHub上に「保管」してないのがポイント!
※STS = Security Token Service AWSのサービス名で、一時的な認証情報を発行する
実装手順
1. S3バケット作成
まずはデプロイ資源を保管するためS3バケットを作成します。AWSコンソールからS3サービスを選択し、バケットを作成します。バケットタイプは汎用、オブジェクト所有者はACL無効、パブリックアクセスをすべて ブロック、バケットのバージョニングは有効、暗号化設定は特に変更なし、でS3バケット名をつけて作成します。
2. GitHub用IAMロール作成
続いてGitHub用のIAMロールを作成します。AWSコンソールからIAMサービスを選択し、ロールからロールを作成で、作成していきます。この際、信頼されたエンティティタイプはウェブアイデンティティ、アイデンティティプロバイダーにtoken.actions.githubusercontent.comを選択、Audienceにはsts.amazonaws.comを選択、GitHub organizationはGitHubのユーザー名を入力、GitHub repositoryはGitHubのリポジトリ名を入力、GitHub branchはデプロイ対象とするGitHub ブランチ名を入力。で、許可ポリシーは一旦設定せずにロールの名前を決めて作成してしまいます。
ロールを作成した後、作成したロールを選んで 許可を追加ーインラインポリシーを作成 を選択します。そこでチャッピーに作ってもらったJSONを貼り付けて作成。正直内容はイマイチです。いやAI時代のこのご時世ですから、AIがJSON作る→貼るっていうのでJSONが貼れるになってるんですよ。きっと。
ちなみにインラインポリシーのJSONの内容はこちら
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowUploadToDeployBucket",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:AbortMultipartUpload"
],
"Resource": "arn:aws:s3:::S3バケットだよ"
},
{
"Sid": "AllowSendCommandToEC2",
"Effect": "Allow",
"Action": [
"ssm:SendCommand"
],
"Resource": [
"arn:aws:ssm:ap-northeast-1::document/AWS-RunShellScript",
"arn:aws:ec2:ap-northeast-1:EC2だよ"
]
},
{
"Sid": "AllowReadCommandResult",
"Effect": "Allow",
"Action": [
"ssm:GetCommandInvocation"
],
"Resource": "*"
}
]
}
簡単に言うと、S3バケットにプットすることができる、途中で失敗したアップロードを中断できる。EC2インスタンスに対して、命令を実行できる( AWS公式の RunShellScript ドキュメントだけ)。ログ確認のためコマンド結果を読める。という許可を付与です。
3. GitHub Secretsを追加
デプロイ対象のリポジトリをGitHubで開いて Settings → Secrets and variables → Actions にシークレットを追加します。追加するのは2つ。
- GitHub Actionsが一時的に引き受けるIAMロール(手順2でつくったもの)のARN
- デプロイ先のEC2インスタンス(デプロイ先)のインスタンスID
シークレットの名前はあとでGitHubのWorkflowsで指定するのでそこと整合性がとれていればなんでもOK。
4. workflowファイル作成
デプロイするリポジトリのルートに
.github/workflows/deploy-ssm.yml
を作成する。deploy-ssm.ymlの内容は以下の通り。(これもチャッピー作です。)
name: Deploy myblog theme via SSM
on:
push:
branches: ["main"]
permissions:
id-token: write
contents: read
env:
AWS_REGION: ap-northeast-1
S3_BUCKET: S3バケット名
S3_KEY: myblog/myblog-${{ github.sha }}.zip
TARGET_DIR: デプロイ先のパス
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.ロール }}
aws-region: ${{ env.AWS_REGION }}
- name: Build artifact zip
run: |
zip -r myblog.zip . \
-x ".git/*" \
-x ".github/*" \
-x "**/.DS_Store"
- name: Upload to S3
run: |
aws s3 cp myblog.zip "s3://${{ env.S3_BUCKET }}/${{ env.S3_KEY }}"
- name: Deploy on EC2 via SSM
run: |
aws ssm send-command \
--targets "Key=instanceids,Values=${{ secrets.EC2インスタンスID }}" \
--document-name "AWS-RunShellScript" \
--comment "Deploy myblog theme from S3" \
--parameters commands="[
\"set -e\",
\"tmp=/tmp/myblog-${{ github.sha }}.zip\",
\"aws s3 cp s3://${{ env.S3_BUCKET }}/${{ env.S3_KEY }} \$tmp\",
\"rm -rf ${{ env.TARGET_DIR }}/*\",
\"unzip -oq \$tmp -d ${{ env.TARGET_DIR }}\",
\"chown -R ec2-user:ec2-user ${{ env.TARGET_DIR }}\",
\"find ${{ env.TARGET_DIR }} -type d -exec chmod 755 {} \\\\\\;\",
\"find ${{ env.TARGET_DIR }} -type f -exec chmod 644 {} \\\\\\;\",
\"rm -f \$tmp\"
]"
これで、GitHub上のmainブランチにマージした時にActionsによりS3→SSM→といって最終的にEC2にデプロイされます。
まとめ
今回の構成で得たものは:
- セキュアな自動デプロイ
- SSH不要
- アクセスキー不要
- mainブランチ限定本番反映
これでローカル(Local)で開発、GitHubにプッシュ&マージ、AWS EC2にデプロイというCI/CDができました。ちょっとCI部分は弱いですけど、まぁCI/CDってことにしておきます。個人ブログなんで万が一エラーで動かなくても誰にも怒られないんで!余裕があればCI部分も強化したいと思います。
正直、AI(チャッピー)の力がなければ1日ではできなかったと思います。すごい世の中ですね。人知を超えてますよ・・。勉強のやり方も変えないといけないと思います。もはや80点くらい学んでおく必要はなくて、10点くらいで「こういうことができる」っていう認識だけしていればあとはAIが引き上げてくれますからね。薄く広く。あとはAIに聞く。できることは広がっているんでいいことだとは思いますけどね。変えるってことは大変なんですけどね。
次はサイトにコメント機能を入れてコミュニティ化に向けてやっていきたいと思います!
ではまた。