はじめに
AWS使ったシステムのコンテナの脆弱性スキャンに、Inspectorを採用しているケースは多いと思います。
ただ、Inspectorには以下のような課題がありました。
私の経験上にはなるんですが、開発者の方々は開発で手一杯で、開発中のコンテナイメージに脆弱性が含まれているかまでは、あまり意識しておらず、Push後に脆弱性が検出されても、その修正までは直ぐには手が回らないケースが多いです。
その為、リリース前のセキュリティ監査で大量の脆弱性を指摘され、対応に追われる・・・は、よくあるパターンな気がします。
世に出てなかった新規の脆弱性は除き、既知の脆弱性は常に潰しながら開発を進めることが、ベストプラクティスだと私は考えています。
これを実現する方法として、Snykなどのサードパーティ製の脆弱性スキャンツールをCI/CDパイプラインを組む方法があるのですが、サードパーティ製のツールの採用は地味にハードルが高く、実際に取り入れることができていませんでした。
そんな中、2024年にInspectorとCodePipelineとの統合の発表、GitHubアクションとの統合の発表がありました。
今回は、後者のGitHubアクションとの統合を使って、コンテナイメージの脆弱性スキャンをCI/CD上で行う方法を試してみたいと思います。
試してみた
GitHubアクションとの統合ですが、具体的にはAWS公式から提供されているactionであるvulnerability-scan-github-action-for-amazon-inspectorを、Workflowに組み込む形になります。
このactionには、スキャンタイプとしてレポジトリ、コンテナ、バイナリー、アーカイブの4つがあります。
今回はコンテナイメージの脆弱性スキャンなので、コンテナタイプのスキャンを試します。
その為、コンテナイメージの脆弱性スキャンが目的なのであれば、スキャンタイプにはコンテナを選択することをオススメします。
この場合、静的スキャンで検出できる範囲の脆弱性であれば、コンテナイメージのビルド前に、CIを失敗させることができるので、無駄なコンテナイメージのビルドが防げます。
nginxのコンテナイメージのビルドが成功するか否かをテストしている以下のWorkflow(CI)にコンテナタイプのスキャンを組み込んで行きます。
name: CI
on:
pull_request:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate docker metadata
uses: docker/metadata-action@v5.7.0
id: meta
with:
images: nginx
tags: type=sha,prefix=,format=short
- name: Set up docker buildx
uses: docker/setup-buildx-action@v3
- name: Test build
id: build
uses: docker/build-push-action@v6
with:
context: .
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64
provenance: false
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Create comment file for build result
run: |
if [[ "${{ steps.build.outcome }}" == "success" ]]; then
echo "### :white_check_mark: Build - Passed" > build_comment.md
else
echo "### :x: Build - Failed" > build_comment.md
fi
- name: Create pr comment for build result
run: gh pr comment ${{ github.event.number }} --body-file build_comment.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fail workflow if build failed
if: steps.build.outcome != 'success'
run: exit 1
OIDC用ロールの作成
公式ドキュメントにも記載されてる通り、GitHubアクションとの統合には、GitHubアクションにinspector-scan:ScanSbom権限を与える必要があります。
この権限をOIDC用のロールに付与します(OIDC用ロールの作成方法は本質からズレるので、割愛します)。

Workflowの設定
先程のWorkflow(CI)を以下のように書き換えます。
- permissions: OIDC認証でid-tokenのwrite権限が必要
- Test build: loadがfalseだと、Inspectorのスキャンが失敗(コンテナイメージが見つからず)するので、trueにする
- Configure AWS credentials: 先程作成したOIDC用のロールを指定
- Scan built image with Inspector: READMEに従って各パラメータを設定
- Create pr comment for inspector scan result: スキャン結果(マークダウン)をPRにコメント
- Fail job if vulnerability threshold is exceeded: 検知した脆弱性が指定した閾値を超えてる場合、Workflow(CI)を失敗させる

PRの作成
脆弱性が含まれているnginxをベースイメージに指定した以下Dockerfileを作業ブラウザにPushして、PRを作成する
FROM nginx:1.29
脆弱性の検知
PRが作成されると、先程設定したWorkflowが発火し、PRにスキャン結果がコメントされ、Workflow(CI)が失敗することが確認できます。

さいごに
既存のGithubアクションのWorkflowに少し手を加えるだけで、Inspectorを使ったコンテナイメージの脆弱性スキャンをCI/CD上で行うことが出来ました。
新規の脆弱性は引き続き、InspectorのECR継続スキャンで検知し、既知の脆弱性は今回紹介した方法などで、デプロイ前に潰しておくのが、ベストになりそうですね!