4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【30日でAWSをマスターするハンズオン問題集】Day11:ECR 脆弱性スキャンと CodePipeline で安全な自動デプロイを構築しよう

4
Posted at

こちらの投稿は2025 Japan AWS Jr.Championsの有志メンバーで作成した『30日間で主要AWSサービスを構築できるようになる』をテーマにした初学者向けのハンズオン問題集のDAY11になります!
問題集の趣旨や作成に至るまでの経緯は以下の記事をご覧いただければと思います。

📝 概要

項目 内容
所要時間 約1時間
メインサービス Amazon ECR, AWS CodePipeline, AWS CodeBuild, Amazon Inspector
学べること コンテナイメージの脆弱性検出と、自動ビルド・テスト・デプロイの仕組み
想定費用 数百円程度(ECR/CodePipeline の実行回数や Inspector のスキャン数により変動)

⚠️ 注意:リソース削除を忘れると課金が継続します。
CodePipelineとCodeBuildは実行ベース、ECRはストレージ、ECSは実行時間で課金されます。

🎯 課題内容

ECRにプッシュされたコンテナイメージを自動でスキャンし、脆弱性の有無を検出します。
さらにCodePipelineを使って、コード変更のたびにビルド・テスト・デプロイを自動化します。
高危険度の脆弱性が残る場合はパイプラインのデプロイを中止し、リリース前に重大な既知の脆弱性を検知できるようにします。

📊 アーキテクチャ図

image.png

🔧 実装機能

  • ECRリポジトリで脆弱性スキャンを有効化する
  • コンテナpush時にInspectorでスキャンを自動実行
  • CodePipelineでリリース手順(Build→Test→Deploy)を定義
  • 高危険度脆弱性が残る場合はパイプラインが失敗し、デプロイを停止

💡 実装のヒント

ECR スキャン設定
ECR には従来の「基本スキャン」と Amazon Inspector 連携の「拡張スキャン」があります。  
本ハンズオンでは拡張スキャンを利用するため、リポジトリ作成時の「スキャンを自動的に実行」は OFF のままで構いません。
拡張スキャンの有効化は後述のステップでレジストリ単位で設定します。
CodePipeline の構成

Source → Build → Deploy の3ステージ構成が基本です。
BuildステージでDockerイメージを作成してECRにpushし、DeployステージでECSサービスを更新します。

✅ 完成後のチェックポイント

  • ECRにpushすると自動でスキャンが実行される
  • CodePipelineがコミット検知で自動起動する
  • 高危険度の脆弱性が残るとデプロイが止まる
  • 安全な状態ではECSサービスに自動反映される
  • スキャン結果がInspector/ECRで確認できる

🧰 使用資材

  • buildspec.yml:Dockerビルドとスキャン確認を自動化(CodeBuild用)
  • Dockerfile: 正常なイメージ
  • Dockerfile.vulnerable:脆弱性検証用イメージ

コードは下記に置いてあります。

🔗 リファレンスリンク

🛠️ 解答・構築手順(クリックで開く)

✅ ステップ1:ECR リポジトリ作成

  1. ECRコンソールから「リポジトリの作成」を選択します。

image.png

  1. リポジトリ名をtest/demo-appとして作成します。

image.png

image.png

ECRリポジトリ単位のスキャン設定は「非推奨」となっています。
リポジトリ作成時の「イメージのスキャン設定」はOFFの状態で問題ありません。
詳細はこちら

image.png

# AWS CLIの場合
aws ecr create-repository \
    --repository-name test/demo-app \

✅ ステップ2:拡張スキャン(Amazon Inspector)の有効化

このハンズオンでは、 拡張スキャン(Amazon Inspector) を使用します。

基本スキャンはECRの機能で、主にOS由来の脆弱性をプッシュ時や手動で検出します。

一方で、拡張スキャンはAmazon Inspector連携で、OSとプログラミング言語パッケージを監視し、結果の更新とEventBridge経由の通知が可能です。

項目 基本スキャン 拡張スキャン
検出対象 主にOS脆弱性を検出 OS+言語パッケージ脆弱性を検出
実行タイミング リポジトリの「プッシュ時」設定または手動実行 レジストリ設定に基づく継続スキャン(新脆弱性公開時に自動更新)
構成単位 レジストリ既定+フィルタでリポジトリ選択 レジストリで有効化し、フィルタで対象を選択
結果更新と通知 プッシュ/手動スキャンの結果をECRで確認 検出時に結果を更新し、EventBridgeへイベント送出。ECR/Inspector双方で確認
料金 無料 Inspectorの課金対象(ECR追加料金なしだがInspector料金が発生)

📌 拡張スキャンの有効化

  1. ECRコンソールから test/demo-app リポジトリを選択します。

  2. ECR コンソールの設定画面から「Scanning(スキャン)」の設定を開きます。

  3. 「拡張スキャン」を有効化し、スキャンフィルターを test/* に設定します。

    • 連続スキャンとプッシュ時スキャンの両方に一致した場合、連続スキャン側が優先されます。
    • 拡張スキャン有効化時点で、直近 14 日以内にプッシュされたイメージのみが自動でスキャン対象になります。(古いイメージを対象にしたい場合は、改めてプッシュし直します)。

image.png

デフォルト設定では 「すべてのリポジトリ」 がスキャン対象となっています。
既存のイメージが意図せずスキャンの対象となり、大量のイメージを保持している環境では、利用料金が増加する可能性があります。

✅ ステップ3:テスト用イメージのビルドとプッシュ

📦 パターンA:安全なイメージ(スキャン合格パターン)

  1. ECRにDockerイメージをプッシュします。
# リポジトリのクローン
git clone https://github.com/2025-Japan-AWS-Jr-Champions/30days-handson.git
cd Beginner/code/07-CodePipeline

# AWSアカウントIDを取得
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# ECRにログイン
aws ecr get-login-password --region ap-northeast-1 | \
    docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com

# 安全なイメージをビルド(Dockerfileを使用)
docker build --provenance=false -t demo-app:safe -f Dockerfile .

# タグ付け
docker tag demo-app:safe ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/test/demo-app:safe

# ECRにプッシュ
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/test/demo-app:safe

provenance オプションとは

「そのイメージを、いつ・どこで・何を使って・どう作ったか」という来歴が provenance です。--provenance=false を付けない場合、イメージの他にインデックス(索引)ファイルが一緒にプッシュされます。

今回使うECRの拡張スキャンでは、このようなインデックスファイルはスキャンの対象外なので除外しています。

  1. ECRコンソール上でイメージがプッシュされていることを確認します。

image.png

  1. Inspectorのコンソール上でスキャン結果を確認します。

[リソースのカバレッジ] > [コンテナイメージ]からイメージタグが safe のコンテナイメージに関して 「検出結果なし」 になっているのが分かります。

image.png

AWS CLIの場合:

# AWSアカウントIDを環境変数に設定(取得済みの場合はスキップ)
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# 拡張スキャンはスキャン完了まで5〜15分程度かかる場合があります
# スキャン完了を確認(結果が返ってくるまで繰り返し実行)
aws inspector2 list-findings \
    --filter-criteria '{
      "resourceType":[{"comparison":"EQUALS","value":"AWS_ECR_CONTAINER_IMAGE"}],
      "ecrImageRepositoryName":[{"comparison":"EQUALS","value":"test/demo-app"}],
      "ecrImageTags":[{"comparison":"EQUALS","value":"safe"}]
    }' \
    --region ap-northeast-1

出力例(安全なイメージ):

{
    "findings": []
}

⚠️ パターンB:脆弱性のあるイメージ(スキャン失敗パターン)

  1. ECRにDockerイメージをプッシュします。
# 脆弱性のあるイメージをビルド(Dockerfile.vulnerableを使用)
docker build --provenance=false -t demo-app:vulnerable -f Dockerfile.vulnerable .

# タグ付け
docker tag demo-app:vulnerable ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/test/demo-app:vulnerable

# ECRにプッシュ
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/test/demo-app:vulnerable
  1. ECRコンソール上でイメージがプッシュされていることを確認します。

08_ecr-pushed-img-vulnerable.png

  1. Inspectorのコンソール上でスキャン結果を確認します。

[リソースのカバレッジ] > [コンテナイメージ] からイメージタグが vulnerable のコンテナイメージを確認してみましょう。

image.png

上記のイメージをクリックすると、[検出結果] > [コンテナイメージ別] に遷移し、検出された脆弱性の詳細を確認することができます。この場合、古いパッケージを使っているため「Critical」レベルの脆弱性として検出されています。

10_inspector_vulnarable_details.png

AWS CLIの場合:

# スキャン完了を待ってから結果を確認(5〜15分待つ必要があります)
# まず結果が返ってくるか確認
aws inspector2 list-findings \
    --filter-criteria '{"ecrImageRepositoryName":[{"comparison":"EQUALS","value":"test/demo-app"}],"ecrImageTags":[{"comparison":"EQUALS","value":"vulnerable"}]}' \
    --region ap-northeast-1 
# または、重大度別の詳細を表形式で表示
aws inspector2 list-findings \
    --filter-criteria '{"ecrImageRepositoryName":[{"comparison":"EQUALS","value":"test/demo-app"}],"ecrImageTags":[{"comparison":"EQUALS","value":"vulnerable"}]}' \
    --region ap-northeast-1 \
    --query 'findings[].{Severity:severity,Title:title,PackageName:packageVulnerabilityDetails.vulnerablePackages[0].name}' \
    --output table

出力例(脆弱性のあるイメージ):

# 出力例
-----------------------------------------------------------
|                      ListFindings                       |
+--------------------+-----------+------------------------+
|     PackageName    | Severity  |         Title          |
+--------------------+-----------+------------------------+
|  ALPINE_LINUX_3_13 |  CRITICAL |  Platform End Of Life  |
+--------------------+-----------+------------------------+

✅ ステップ4:CodeBuild プロジェクト作成

このステップからCI/CDパイプラインを構築していきます。
コンテナイメージの脆弱性がある場合にデプロイを止める仕組みを作ることが目的です。

  1. CodeBuildコンソールでプロジェクトを作成

    • プロジェクト名:demo-app-build
    • ソース:GitHub
    • 認証情報タイプ: GitHubアプリ(CodeConnections 経由でAWSが管理するもの)
    • リポジトリ:GitHubアカウントに接続し、リポジトリを選択
    • 環境:すべてデフォルトのまま
    • オペレーティングシステム:Ubuntu
    • ランタイム:Standard
    • イメージ:aws/codebuild/standard:7.0
    • Buildspec:「buildspecファイルを使用する」

AWS CodeCommit について
AWS CodeCommitは2024年7月25日から新規アカウントでのリポジトリ作成を停止しています。
詳細は こちら をご確認ください。

【追記】
2025年11月25日、AWS CodeCommit がGA(一般提供)として復活することが発表されました! 投稿日(2025年12月6日)時点で新規アカウントでもリポジトリ作成が可能な状態です。
参照: AWS CodeCommit の今後について

このハンズオンでは、問題集執筆時点のままGitHubをソースリポジトリとして使用します。

  1. buildspec.ymlの配置

GitHubのソースリポジトリのルートにbuildspec.ymlを配置します。このファイルが自動的にビルド仕様として使用されます。

  1. IAMロールの権限確認

CodeBuildのサービスロールに以下の権限を追加します。
IAMロールのコンソールから [許可ポリシー] > [許可を追加] > [インラインポリシー] を選択し、JSONを編集します。

拡張スキャン用の権限:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload",
                "ecr:DescribeImages"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "inspector2:ListFindings",
                "inspector2:ListCoverage"
            ],
            "Resource": "*"
        }
    ]
}

✅ ステップ5:CodePipeline 構築

  1. CodePipelineコンソールでパイプラインを作成

    • 作成オプション:カスタムパイプラインを構築する
    • パイプライン名:demo-app-pipeline
    • 実行モード:キュー
    • サービスロール:新しいサービスロールを作成
  2. ソースステージ

    • ソースプロバイダー:GitHub(GitHub アプリ経由)
    • リポジトリとブランチを選択
    • ウェブフックイベント:「プッシュおよびプルリクエストでパイプラインを開始します」
  3. ビルドステージ

    • ビルドプロバイダー:その他のプロバイダーから AWS CodeBuild を選択
    • プロジェクト名:demo-app-build(先ほど作成したもの)
  4. テストステージ

    • テストステージをスキップ
  5. デプロイステージ(オプション)

    • デプロイプロバイダー:Amazon ECS
    • クラスター名とサービス名を指定
    • イメージ定義ファイル:imagedefinitions.json

✅ ステップ6:パイプライン動作確認

✅ 成功パターンの確認

  1. Dockerfileを使用するようにbuildspec.ymlが設定されていることを確認
  2. コードをコミット&プッシュ
  3. CodePipelineが自動起動
  4. Buildステージでスキャン合格
  5. Deployステージへ進む
  6. パイプライン成功

❌ 失敗パターンの確認

  1. buildspec.ymlのビルドコマンドを以下のように変更:
# 変更前
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .

# 変更後
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG -f Dockerfile.vulnerable .
  1. コードをコミット&プッシュ
  2. CodePipelineが自動起動
  3. Buildステージでスキャン実行
  4. CRITICAL脆弱性を検出 → exit 1
  5. パイプライン失敗(Buildステージで停止)

CodeBuildのログ出力例(失敗時):

[Container] 2024/10/19 12:34:56 Running command echo "Enhanced Scanning のスキャン完了を待機中..."
Enhanced Scanning のスキャン完了を待機中(5-15分程度)...
初回スキャン時は最大15分かかる場合があります

[Container] 2024/10/19 12:40:26 Running command aws inspector2 list-findings ...
待機中... (1/30)
待機中... (2/30)
...
スキャン完了を確認しました

[Container] 2024/10/19 12:45:30 Running command CRITICAL_COUNT=$(aws inspector2 list-findings ...)
CRITICAL レベルの脆弱性: 3 件
HIGH レベルの脆弱性: 12 件
❌ CRITICAL レベルの脆弱性が検出されました!デプロイをブロックします。

[Container] 2024/10/19 12:45:31 Command did not exit successfully exit status 1
[Container] 2024/10/19 12:45:31 Phase complete: POST_BUILD State: FAILED

🧹 片付け(リソース削除)

作成したリソースを削除して課金を停止します:

# 1. CodePipelineの削除
aws codepipeline delete-pipeline --name demo-app-pipeline

# 2. CodeBuildプロジェクトの削除
aws codebuild delete-project --name demo-app-build

# 3. ECRリポジトリの削除(全イメージも削除)
aws ecr delete-repository \
    --repository-name test/demo-app \
    --force \
    --region ap-northeast-1

# 4. ECSサービスの削除(作成した場合)
aws ecs update-service \
    --cluster demo-cluster \
    --service demo-service \
    --desired-count 0

aws ecs delete-service \
    --cluster demo-cluster \
    --service demo-service

# 5. ECSクラスターの削除
aws ecs delete-cluster --cluster demo-cluster

# 6. Enhanced Scanning を無効化する場合
# Amazon Inspectorコンソール > Settings > ECR scanning で無効化
# または CLI で:
aws inspector2 disable --resource-types ECR --region ap-northeast-1

マネジメントコンソールでの確認:

  • ECRリポジトリが削除されている
  • CodePipelineが削除されている
  • CodeBuildプロジェクトが削除されている
  • ECSサービス・クラスターが削除されている
  • Enhanced Scanning を有効化していた場合、Amazon Inspector の ECR スキャンを無効化

Amazon Inspector の課金について
本ハンズオン用の検証環境など、継続的なスキャンが不要な場合は課金を止めるために無効化してください。
本番環境など継続的な監視が必要な環境では、運用ポリシーに応じて有効化を維持してください。

🏁 おつかれさまでした!

この課題では、ECRの脆弱性スキャンとCodePipelineによる自動化を通して、脆弱性スキャンと自動デプロイを組み合わせた再現性のあるデリバリー基盤を構築しました。
次は、テスト自動化やセキュリティゲートの強化にも挑戦してみましょう!

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?