🛢

ECRのイメージスキャン結果をCodeBuild内で取得する

2022/10/05に公開

初めに

Zenn初投稿です。
現在プロジェクトでAWS Codepipelineを活用してビルド・デプロイの自動化を行なっています。そのCodepipeline内ではAWS CodeBuildを使用してECRへのDockerイメージプッシュと、ECSタスク定義の更新を行なっています。

今回やりたいこと

ECRにはイメージスキャンというイメージの脆弱性を特定してくれる機能があります。
(手動またはプッシュ時に自動で行う方法の2種類がありますが、今回は自動で行うようECRリポジトリに設定しています。)
今回CodeBuildからイメージをプッシュした後、もしそのスキャン結果に深刻な脆弱性が見つかった場合は処理を中止し、もし問題が無ければ次の処理を行う(タスク定義を更新する)ように処理を分岐させたいです。

やったこと

イメージプッシュ後にaws ecr describe-image-scan-findingsを実行しイメージに対してスキャン結果の問い合わせを行います。
ただしプッシュした直後はスキャン中で結果が返却されない為、CodeBuild内でポーリングする(定期的に問い合わせる)必要があります。
またスキャン結果はCritical Lowのように脆弱性の重要度によってランク毎に出力されるのですが、今回特に重要度が高い脆弱性に絞って対応する要件があったため、取得した結果の中身を見て処理を分ける必要がありました。
これらの処理をシェルスクリプトにまとめて実行するようにしました。

スクリプト

今回作成したスクリプトは以下です。

#!/bin/bash
ALERT_SEVERITY_ARRAY=("CRITICAL" "HIGH" "MEDIUM")

JQ=$(which jq) ||:
if [ -z "$JQ" ]
then
  # install jq
  sudo yum -y update
  sudo yum -y install jq
fi

echo "ECRイメージスキャン結果の取得処理を開始します"
while : ;
do
  SCAN_FINDINGS=$(aws ecr describe-image-scan-findings --repository-name $ECR_REPOSITORY_NAME --image-id imageTag=$IMAGE_TAG)
  SCAN_STATUS=$(echo $SCAN_FINDINGS | $JQ -r '.imageScanStatus.status')

  if [ "$SCAN_STATUS" == "COMPLETE" ];then
    break
  else
    echo "スキャン結果の取得中です..."
    sleep 3
    CNT=$(( CNT+1 ))
    if [ $CNT -gt 20 ];then
      echo "スキャン結果の取得に失敗したため、処理を中止します"
      exit 1
    fi
  fi
done

echo "スキャンが完了しました。結果は以下です"
echo $SCAN_FINDINGS
echo "スキャン結果の確認を開始します"

SEVERITIES=$(echo $SCAN_FINDINGS | $JQ -r '.imageScanFindings.findings[].severity')
for s in $SEVERITIES;do
  if [[ " ${ALERT_SEVERITY_ARRAY[*]} " =~ " ${s} " ]]; then
    echo "「 ${s} 」レベルの脆弱性が確認されたため、処理を中止します"
    exit 1
  fi
done

echo "ECRイメージスキャン結果の取得処理を終了します"
exit 0

説明

  • ALERT_SEVERITY_ARRAYで見つかった場合処理を中止する脆弱性の一覧を指定します。今回はMIDDLE以上の脆弱性を対象としました。
  • whileのところで3秒毎に最大20回スキャン結果の問い合わせを行なっています。
    • 万が一取得できなかったら処理を中止します。
    • 実際に何度か実行していますが、大体4~5回目の問い合わせで取得できており、これまで取得に失敗したことはないです。
  • forのところで取得できた脆弱性の一覧から、ALERT_SEVERITY_ARRAYで指定した脆弱性がないか確認しています。もし見つかった場合は処理を中止します。
  • 以下の値はCodeBuildの環境変数で指定、またはbuildspec.yaml内で出力してください。
    • ECR_REPOSITORY_NAME ECRリポジトリ名
    • IMAGE_TAG イメージタグ名

スクリプトをCodeBuild内で実行する

実行させる場合はbuildspec.yaml内で以下のように設定します。

post_build:
  commands:
    - bash <今回作成したスクリプト>.sh

CodeBuildの環境設定についてですが、aws ecr describe-image-scan-findingsはAWS CLI v2から使えるコマンドなのでAWSが管理するDockerイメージを使用する場合は新しいものでないと動きません。
このスクリプトはaws/codebuild/standard:6.0で動くことを確認しています。
参考:CodeBuild に用意されている Docker イメージ

Discussion