この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
夜にエナドリをキメるとめちゃめちゃ作業が捗ることに気がついてしまった、もこ@札幌オフィスです。
つい先月、ECRでイメージスキャン機能が提供されました!
これにより、ECR単体で「デプロイ前にコンテナイメージに脆弱性がないかをスキャン」することや、「CloudWatch Events / Lambdaと連携して実行中のイメージに新たな脆弱性がないかを定期的にスキャン」することができます。
今回は、GitHub Actionsを使ってコンテナをECSにデプロイする前にスキャンしてクリティカルな脆弱性があったらワークフローを停止するようなものを作っていきます。
テンプレート
裏側ではNode.js + AWS SDKを利用して、イメージのスキャンを開始、スキャン結果を取得、パイプラインを進めるか否かの判定をするようにしています。
GitHub Actionsのテンプレートは公開していますので、ymlから数行追加するだけでワークフローにコンテナスキャンを埋め込めるようにしました。
https://github.com/mokocm/ecr-imagescan-action
使い方
ワークフローでイメージをスキャンしたい任意のタイミングでこのようにmokocm/ecr-imagescan-action@v3
を利用する形で追記してあげればOKです。
- name: Image Scan
id: image-scan
uses: mokocm/ecr-imagescan-action@v3
with:
image-digest: "スキャンするイメージのダイジェスト(SHA256)"
image-tag: "スキャンするイメージのTag"
repository-name: "ECRのリポジトリ"
trigger-severity: "INFORMATIONAL | LOW | MEDIUM | HIGH | CRITICALの中からトリガーするレベルを指定"
イメージのdigestが必要なため、少し工夫する必要があります。
やってみる
実際にやっていきましょう。
3分クッキング感で申し訳ないですが、デプロイするコンテナ、デプロイ先のECS、デプロイまで出来るGitHub Actionsワークフローを用意します。
今回は下記記事にて構築したGitHub Actionsをベースに組み込んでいます。
.github/workflows/aws.yml
- name: Login to Amazon ECR
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: githubactions-nginx
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo ::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo ::set-output name=digest::$(docker images --digests | grep $ECR_REGISTRY/$ECR_REPOSITORY | grep $IMAGE_TAG | awk '{print $3}')
echo ::set-output name=repository-name::$ECR_REPOSITORY
- name: Image Scan
id: image-scan
uses: mokocm/ecr-imagescan-action@v3
with:
image-digest: ${{ steps.build-image.outputs.digest }}
image-tag: ${{ github.sha }}
repository-name: ${{ steps.build-image.outputs.repository-name }}
trigger-severity: "CRITICAL"
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: nginx
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: spot-ecs
cluster: spot-ecs
wait-for-service-stability: true
追記した部分はハイライトした部分のみとなっています。
usesで mokocm/ecr-imagescan-action@v3
を利用するようにし、image-digest
, image-tag
, repository-name
, trigger-severity
を代入します。
GitHub Actionsでは echo ::set-output name={変数名}::{outputしたいデータ}
のように指定することで、
次のステップで {{ steps.{StepId}.outputs.{変数名} }}
のように変数の橋渡しができます!
動作確認
脆弱性があるコンテナを流す
DockerHubで公開されているNginxイメージの中で一番古く、4年前が最終更新のnginx:1.9.9
のイメージで試してみます。
masterブランチにPushすると、正常にイメージスキャンを開始し、ワークフローが停止しました!
脆弱性がないコンテナを流す
続いて脆弱性のないコンテナを流してみましょう。
今回は検証でnginx:mainline-alpine
のイメージを使っています。
コンテナスキャン結果のステータスがCOMPLATE、 findingSeverityCounts
に trigger-severity
で指定したタイプの脆弱性がなければ正常に完了します。
全体のワークフローが流れるとこんな感じになります。
今回GitHub Actionsを利用したリポジトリはこちらに上がっていますので、ご確認ください!
https://github.com/mokocm/ecr-imagescan-cicd
まとめ
GitHub Actionsを利用することで簡単にCI/CDを組み込みつつ、(スキャンした時点で)安全なイメージをデプロイするようなワークフローを簡単に作ることができました。
リリース頻度の高いサービスなどでもユニットテストと同じノリでデプロイ前にコンテナの脆弱性スキャンを出来るようなワークフローを組んで行けると、よりセキュアにコンテナ環境の運用が出来ると思います!
また、ECRのイメージスキャン機能は無料で使えるので、「とりあえずコンテナセキュリティに入門したい」ニーズも捉えられていると思います。
パイプラインに埋め込まないまでも、脆弱性があったらSNSで通知するくらいの機能なら15~30分程度で構築することができますので、是非お試しください!
以上、もこでした。