Contents
前提条件と環境構築
このセクションでは、本ガイド全体で前提となる AWS リソースとローカル開発環境について説明します。
何が必要か、なぜ重要か、そして最終的にどのようになるか を把握したうえで作業を進めてください。
AWS アカウント
GitHub Actions からは OIDC ロール を用いて認証するため、永続的なアクセスキーは不要です。
- IAM ユーザーは作成しなくても構いません(ただし、管理者権限を持つアカウントで以下のリソースは作成してください)。
Amazon ECR リポジトリ
コンテナイメージを保存するプライベートレジストリです。
|
1 2 3 4 5 |
aws ecr create-repository \ --repository-name my-app \ --region ap-northeast-1 \ --image-scanning-configuration scanOnPush=true |
- 作成したリポジトリの ARN と URI は後続の IAM ポリシーで使用します。
Amazon ECS クラスタ & Fargate サービス
本ガイドは Fargate を前提にしています。
- クラスタ名 my-cluster、サービス名 my-service(ALB とターゲットグループは別途作成)を例示します。
GitHub リポジトリ
ソースコード(Dockerfile など)と GitHub Actions ワークフロー を格納する場所です。
- デフォルトブランチ main にプッシュされたときにデプロイが走ります。
ローカル開発環境
| 必要ツール | 推奨バージョン |
|---|---|
| Docker Desktop | ≥ 24.0 |
| AWS CLI (v2) | 2.13.0 以上 |
| Git | 任意の最新安定版 |
GNU gettext(envsubst) |
macOS: brew install gettext; Linux: パッケージマネージャでインストール |
aws configure は OIDC 認証では不要ですが、ローカルテスト時に一度だけ実行しておくと便利です。
参考:公式ドキュメントは常に最新です →
- AWS CLI: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html
- Amazon ECR: https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-create.html
- Amazon ECS (Fargate): https://docs.aws.amazon.com/AmazonECS/latest/developerguide/getting-started-fargate.html
OIDC プロバイダーと IAM ロールの作成
GitHub Actions から AWS へ安全にアクセスするための OpenID Connect (OIDC) 設定手順です。
この段階で「サムプリントは変わる可能性がある」ことを考慮し、動的取得スクリプトと最小権限ポリシーを用意します。
OIDC プロバイダーの作成
GitHub が提供する OIDC エンドポイント https://token.actions.githubusercontent.com のサムプリントは定期的に更新される可能性があります。
以下スクリプトで最新サムプリントを取得し、プロバイダー作成コマンドに埋め込みます(一度だけ実行すれば OK)。
|
1 2 3 4 5 6 7 8 9 10 11 |
# 1. GitHub OIDC エンドポイントの証明書から SHA‑1 フィンガープリントを取得 THUMBPRINT=$(openssl s_client -connect token.actions.githubusercontent.com:443 -servername token.actions.githubusercontent.com </dev/null \ | openssl x509 -noout -fingerprint -sha1 \ | sed 's/.*=//;s/://g' | tr '[:upper:]' '[:lower:]') # 2. プロバイダー作成 aws iam create-open-id-connect-provider \ --url https://token.actions.githubusercontent.com \ --client-id-list sts.amazonaws.com \ --thumbprint-list $THUMBPRINT |
ポイント:
opensslがインストールされていない環境は事前にapt-get install openssl(Ubuntu)やbrew install openssl(macOS)で導入してください。
GitHub 用 IAM ロールと最小権限ポリシー
1. 信頼ポリシー(AssumeRole)
以下は リポジトリ単位 に限定した信頼ポリシーです。YOUR_ACCOUNT_ID と your-org/your-repo は実環境に合わせて置換してください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringLike": { "token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:*" }, "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" } } } ] } |
2. アクセスポリシー(最小権限)
- ECR:対象リポジトリの ARN に絞ります。
- ECS:クラスタ・サービス単位で限定し、タスク定義登録だけを許可します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:CompleteLayerUpload", "ecr:UploadLayerPart", "ecr:PutImage" ], "Resource": "arn:aws:ecr:ap-northeast-1:YOUR_ACCOUNT_ID:repository/my-app" }, { "Effect": "Allow", "Action": [ "ecs:RegisterTaskDefinition", "ecs:UpdateService", "ecs:DescribeServices", "ecs:DescribeTaskDefinition" ], "Resource": [ "arn:aws:ecs:ap-northeast-1:YOUR_ACCOUNT_ID:cluster/my-cluster", "arn:aws:ecs:ap-northeast-1:YOUR_ACCOUNT_ID:service/my-cluster/my-service" ] } ] } |
ベストプラクティス:ポリシーは
AWS IAM Access Analyzerでシミュレーションし、過不足がないか必ず検証してください。
3. ロール ARN を GitHub Secrets に保存
GitHub リポジトリ → Settings > Secrets and variables > Actions
- AWS_ROLE_ARN:作成したロールの ARN(例: arn:aws:iam::123456789012:role/github-actions-ecs-deploy)を登録します。
参考:公式ガイド – OIDC with GitHub https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
GitHub Actions ワークフロー実装例
この章では、Docker ビルド → ECR プッシュ → ECS デプロイ までを一つの YAML にまとめた完全サンプルを示します。
各ステップは公式アクションと AWS CLI を組み合わせているため、保守性が高くカスタマイズしやすい構成です。
Docker イメージのビルドと ECR へのプッシュ
まずは docker/setup-buildx-action と docker/build-push-action によるマトリックスビルドを行います。
環境変数 ECR_REGISTRY と ECR_REPO は GitHub Secrets(または Environments)で管理します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v2 # 事前に AWS 認証が完了していることが前提 - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPO }}:${{ github.sha }} |
OIDC 認証設定(GitHub Actions 用)
aws-actions/configure-aws-credentials が自動で一時的なクレデンシャルを取得し、以降のステップで使用できるようにします。
|
1 2 3 4 5 6 |
- 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 }} |
タスク定義テンプレートと envsubst の前提条件
タスク定義は JSON テンプレートとして .github/task-def-template.json に保存します。
このファイルはリポジトリのルートにある .github/ ディレクトリ配下に置くことが推奨され、GitHub Actions の作業ディレクトリから直接参照できます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "family": "my-app", "networkMode": "awsvpc", "requiresCompatibilities": ["FARGATE"], "cpu": "256", "memory": "512", "executionRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/ecsTaskExecutionRole", "taskRoleArn": "arn:aws:iam::YOUR_ACCOUNT_ID:role/github-actions-ecs-deploy", "containerDefinitions": [ { "name": "my-app", "image": "${IMAGE_URI}", "portMappings": [{ "containerPort": 80, "protocol": "tcp" }], "essential": true, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/my-app", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" } } } ] } |
envsubst のインストール
- Ubuntu / Debian:
apt-get update && apt-get install -y gettext-base - Amazon Linux 2:
yum install -y gettext - macOS(GitHub Actions ランナーはデフォルトでインストール済み):特に追加不要
|
1 2 3 4 5 6 |
- name: Render task definition (envsubst) run: | export IMAGE_URI=${{ env.ECR_REGISTRY }}/${{ env.ECR_REPO }}:${{ github.sha }} export AWS_REGION=${{ env.AWS_REGION }} envsubst < .github/task-def-template.json > task-def.json |
タスク定義登録と ECS サービス更新
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
- name: Register new task definition id: register_task run: | aws ecs register-task-definition \ --cli-input-json file://task-def.json \ --query 'taskDefinition.taskDefinitionArn' \ --output text - name: Deploy to ECS service (force new deployment) run: | aws ecs update-service \ --cluster my-cluster \ --service my-service \ --task-definition ${{ steps.register_task.outputs.stdout }} \ --force-new-deployment |
完全サンプル YAML(ci-cd.yml)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
name: CI / CD for ECS (Fargate) on: push: branches: [ main ] env: ECR_REGISTRY: ${{ secrets.ECR_REGISTRY }} # e.g. 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com ECR_REPO: my-app AWS_REGION: ap-northeast-1 jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 # ------------------------------------------------- # Docker ビルド & ECR プッシュ # ------------------------------------------------- - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v2 - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPO }}:${{ github.sha }} # ------------------------------------------------- # OIDC 認証設定 # ------------------------------------------------- - 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: Render task definition (envsubst) run: | export IMAGE_URI=${{ env.ECR_REGISTRY }}/${{ env.ECR_REPO }}:${{ github.sha }} export AWS_REGION=${{ env.AWS_REGION }} envsubst < .github/task-def-template.json > task-def.json # ------------------------------------------------- # タスク定義登録 & サービス更新 # ------------------------------------------------- - name: Register new task definition id: register_task run: | aws ecs register-task-definition \ --cli-input-json file://task-def.json \ --query 'taskDefinition.taskDefinitionArn' \ --output text - name: Deploy to ECS service (force new deployment) run: | aws ecs update-service \ --cluster my-cluster \ --service my-service \ --task-definition ${{ steps.register_task.outputs.stdout }} \ --force-new-deployment |
公式リファレンス
- GitHub Actions OIDC について: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
- AWS CLIecs register-task-definition: https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html
監視・アラート設定ベストプラクティス
デプロイ後の可観測性を高めるため、CloudWatch アラーム と SNS 通知 を組み合わせた構成例を示します。
以下は「タスクが期待通りに起動しない」ケースを検出し、Slack へ即時通知するパターンです。
1. SNS トピックと Slack Webhook の作成
|
1 2 3 4 5 6 7 8 9 10 11 12 |
# SNS トピック作成 aws sns create-topic --name ecs-deploy-alerts # トピック ARN を取得(例: arn:aws:sns:ap-northeast-1:123456789012:ecs-deploy-alerts) TOPIC_ARN=$(aws sns list-topics --query "Topics[?contains(TopicArn, 'ecs-deploy-alerts')].TopicArn" --output text) # Slack の Incoming Webhook URL をシークレットとして保存(例: SLACK_WEBHOOK_URL) aws sns set-topic-attributes \ --topic-arn $TOPIC_ARN \ --attribute-name SubscriptionProtocol \ --attribute-value https://hooks.slack.com/services/XXXX/YYYY/ZZZZ |
ポイント:実運用では
aws secretsmanagerに Webhook URL を保存し、Lambda 関数で中継させる方がセキュアです。
2. CloudWatch アラームの作成
- メトリクス:
ECS > Service > DesiredTaskCountとRunningTaskCountの差分 - 閾値:差分が 1 以上(=タスク未起動)になったらアラート
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
aws cloudwatch put-metric-alarm \ --alarm-name "ECS-Service-NotRunning-${AWS::Region}" \ --metric-name DesiredTaskCount \ --namespace AWS/ECS \ --statistic Maximum \ --period 60 \ --evaluation-periods 3 \ --threshold 1 \ --comparison-operator GreaterThanThreshold \ --dimensions Name=ClusterName,Value=my-cluster Name=ServiceName,Value=my-service \ --alarm-actions $TOPIC_ARN \ --ok-actions $TOPIC_ARN \ --treat-missing-data missing |
ベストプラクティス
1. 複数のメトリクス(CPU、Memory)も同時に監視し、総合的なヘルスチェックを行う。
2. アラームは ステート変化のみ通知 する設定 (--datapoints-to-alarm 3) にするとノイズが減ります。
デバッグ・ロールバックと運用上のベストプラクティス
| 項目 | 推奨手順 / ポイント |
|---|---|
| ログ確認 | - GitHub Actions のジョブ画面で aws ecs update-service の出力を必ず確認。- ECS コンソールの「タスク」→「イベント」でも詳細エラーが取得できる。 |
| タスク定義バージョン管理 | register-task-definition は自動的にリビジョン番号を付与。ロールバックは古い ARN を指定して再度 update-service すれば完了。 |
| IAM の最小権限徹底 | - ポリシーは対象リポジトリ・サービスの ARN に限定。 - 定期的に IAM Access Analyzer で過剰権限がないかスキャンする。 |
| GitHub Environments の活用 | 本番、ステージング、開発環境ごとに別々の AWS_ROLE_ARN とシークレットを管理し、誤デプロイを防止。 |
| ビルドキャッシュ戦略 | 再現性が重要なら docker/build-push-action@v5 の cache: false(=--no-cache)でビルドするか、Cache Export/Import を明示的に設定。 |
| 監視・アラートの自動化 | CloudWatch アラームと SNS → Lambda → ChatOps(Slack, Microsoft Teams)を組み合わせると即時対応が可能になる。 |
| 定期的なローテーションテスト | 本番環境で実際に aws sts assume-role が失敗しないか、GitHub Actions の dry‑run ワークフローで検証しておく。 |
従来方式との比較とまとめ
| 項目 | OIDC 連携(本稿の方法) | 静的認証情報 (Access Key / Secret) |
|---|---|---|
| 認証方式 | 短時間有効な一時クレデンシャルを自動取得 | 永続的なアクセスキーが必要 |
| ローテーション | GitHub が自動でトークン更新、手作業不要 | 定期的に鍵の再発行とシークレット更新が必須 |
| 最小権限実現度 | ロール単位で細かく制御可能(ARN 絞り込み) | キーは広範囲に付与しがち、ポリシーの粒度が粗い |
| 漏洩リスク | シークレット自体は GitHub Secrets に暗号化保存 | 誤ってコードベースやログへ埋め込む危険性あり |
| 設定手間 | OIDC プロバイダーとロール作成が最初だけ必要 | 既存キーを貼り付けるだけで簡単(しかし管理負荷大) |
| 監査性 | CloudTrail に AssumeRole が記録され、実行者が明確 |
キー使用は残すが「誰が保持したか」までは追跡できない |
結論
- OIDC 連携はセキュリティと運用負荷の両面で圧倒的に優位です。特に本番環境へのデプロイでは、永続的なアクセスキーを排除し、一時クレデンシャルだけで済む点が大きなメリットになります。
- 本稿で示した 最小権限ポリシー・動的サムプリント取得・監視設定 をそのまま採用すれば、将来的な認証エラーや過剰権限問題を未然に防げます。
本記事の要点まとめ
- 前提リソース:ECR リポジトリ、Fargate クラスタ・サービス、GitHub Secrets を用意。
- OIDC プロバイダーはサムプリントを動的取得し、ハードコードを回避。
- IAM ロールは信頼ポリシーでリポジトリ限定、アクセス許可は対象 ARN のみ。
- GitHub Actionsは公式アクションと
envsubstを組み合わせ、タスク定義テンプレートを安全に差し替えてデプロイ。 - 監視・通知は CloudWatch アラーム+SNS → Slack で即時検知できる構成例を提示。
- デバッグ・ロールバックの手順と、環境別シークレット管理、ビルドキャッシュ戦略など運用ベストプラクティスを網羅。
- 従来方式との比較表で OIDC の優位性を明確化し、導入判断材料を提供。
最新情報は常に公式ドキュメント(AWS、GitHub)をご確認ください。
作成日: 2024‑06‑18 執筆者: ChatGPT (OpenAI) ライセンス: CC BY‑SA 4.0