はじめに

本記事では、Trivy によるコンテナイメージの脆弱性スキャンとSecurity Hub を統合したCI(Continuous Integration)環境を構築するTerraform のコードをサンプルとして共有しています。コンテナイメージのセキュリティ対策の一例として参考になればと思います。

また、補足として、CodeBuild のビルド内のTrivy に関する処理について、簡単に説明をしています。

Terraform で構築する全体構成図

構成の概要

In this post, I’ll show you how to build a continuous integration and continuous delivery (CI/CD) pipeline using AWS Developer Tools, as well as Aqua Security‘s open source container vulnerability scanner, Trivy. You’ll build two Docker images, on...

アーキテクチャは上記のAWS Security Blog を元にしています。

Dockerfile を含むコードをCodeCommit にプッシュするとCodePipeline が実行され、CodeBuild でビルドしたコンテナイメージを、Trivy で脆弱性スキャンをしています。

その結果、深刻度が CRITICAL な脆弱性を検出した場合は、ECR にはプッシュせずに、CIを停止させ、Findings(結果)をSecurity Hub に送信し、確認できるようにしています。

コンテナイメージに CRITICAL な脆弱性を検出しなかった場合は、安全なイメージとしてECR にプッシュしています。

Trivy とは

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI

It is designed to be used in CI. Before pushing to a container registry or deploying your application, you can scan your local container image and > other artifacts easily. See Integrations for details.
CIで使用することを想定しています。コンテナレジストリへのプッシュやアプリケーションのデプロイの前に、ローカルのコンテナイメージや他のアーティファクトを簡単にスキャンすることができます。詳細はIntegrationsを参照してください。

Security Hub とは

AWS Security Hub について説明します。

Security Hubは、AWSアカウント、サービス、およびサポートされているサードパーティパートナー製品全体からセキュリティデータを収集し、セキュリティトレンドを分析して、最も優先度の高いセキュリティ問題を特定するのに役立ちます。

Terraform のコードと構成

Terraform でTrivy の脆弱性スキャンとSecurity Hub を統合したCIを構築する - GitHub - okubo-t/aws-tf-trivy-securityhub-ci: Terraform でTrivy の脆弱性スキャンとSecurity Hub を統合したCIを構築する
$ tree aws-tf-trivy-securityhub-ci 
aws-tf-trivy-securityhub-ci
├── main.tf
└── modules
    └── codepipeline
        ├── buildspec.yml
        ├── cloudwatch_event.tf
        ├── cloudwatch_logs.tf
        ├── codebuild.tf
        ├── codecommit.tf
        ├── codepipeline.tf
        ├── ecr.tf
        ├── iam.tf
        ├── kms.tf
        ├── provider.tf
        ├── s3.tf
        └── variables.tf

2 directories, 13 files

使い方

Terraform の動作確認環境

$ terraform -version
Terraform v1.1.9
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v4.15.1

変数の設定

main.tf に下記の変数を設定します。

変数名 説明
profile 各AWSのプロファイル名
region リージョン
prefix 各AWSのリソースに付与するプレフィックス
env 環境を識別するプレフィックス
repository_name CodeCommit のリポジトリ名
branch_name ブランチ名
ecr_name ECR のリポジトリ名

main.tf

module "codepipeline" {
  source = "./modules/codepipeline"

  Account = {
    profile = "YOUR AWS ACCOUNT PROFILE NAME"
    region  = "ap-northeast-1"
  }

  # Project Prefix
  prefix = "prefix"

  # Environment Prefix
  env = "test"

  # Codecommit Repository Name
  repository_name = "trivy-securityhub-ci"
  # Branch Name
  branch_name = "master"

  # ECR Repository Name
  ecr_name = "trivy-securityhub-ci"
}

Terraform の実行

$ terraform init
$ terraform plan
$ terraform apply

Security Hub の有効化

Security Hub を有効化していない環境であれば、有効化します。

Security Hub と Aqua Security の統合

Security Hub と Aqua Security を統合します。
[Security Hub] > [統合] > Aqua Security で検索 > [結果を受け入れる]

Dockerfile をCodeCommit にプッシュ

動作確認として、脆弱性を含むテスト用のDockerfile をCodeCommit にプッシュします。

Contribute to aws-samples/aws-security-hub-scan-with-trivy development by creating an account on GitHub.

Dockerfile

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

FROM composer:1.7.2

RUN git clone https://github.com/aquasecurity/trivy-ci-test.git && cd trivy-ci-test && rm Cargo.lock && rm Pipfile.lock

CMD apk add --no-cache mysql-client
ENTRYPOINT ["mysql"]

CodePipeline > CodeCommit > CodeBuild の実行

CodeCommit の変更イベントを検知してCodePipeline > CodeBuild が実行されます。

CodeBuildでTrivy による脆弱性スキャン

Trivy のコンテナイメージのスキャンによって、脆弱性が検出され、ビルドのステータスが失敗となり、Findings がSecurity Hub に送信されます。

ビルドログ

フェーズ詳細

Security Hub でFindings を確認

Security Hub で検出結果を確認できます。
[Security Hub] > [統合] > [結果を参照]

検出結果

補足: CodeBuild のビルドの仕様について

Trivy を使った脆弱性スキャンを組み込んだビルドの各フェーズごとの処理について説明します。

参考:

AWS CodeBuild でのビルドの仕様 (buildspec) ファイルに関するリファレンス情報を提供します。

buildspec

buildspec.yml は下記で構成しています。

buildspec.yml

version: 0.2

env:
  variables:
    DOCKER_BUILDKIT: "1"

phases:
  install:
    runtime-versions:
      docker: 19
    commands:
      - echo Trivy Install...
      # - TRIVY_VERSION=0.28.0
      - TRIVY_VERSION=$(curl -sS https://api.github.com/repos/aquasecurity/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
      - rpm -ivh https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.rpm
      - trivy --version
      - echo Install completed on `date`
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - echo $AWS_DEFAULT_REGION
      - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
      - REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
      - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t ${REPOSITORY_URI}:${IMAGE_TAG} .
      - echo Build completed on `date`
      - echo Trivy Scan started on `date`
      - AWS_REGION=$AWS_DEFAULT_REGION
      - AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID
      - trivy image --no-progress --format template --template "@/usr/local/share/trivy/templates/asff.tpl" -o tmp-report.asff --ignore-unfixed --exit-code 1 --severity CRITICAL ${REPOSITORY_URI}:${IMAGE_TAG}
  post_build:
    commands:
      - echo Trivy Scan completed on `date`
      - |
        if [ $CODEBUILD_BUILD_SUCCEEDING == "1" ]; then
          docker push ${REPOSITORY_URI}:${IMAGE_TAG} ;
          printf "[{\"name\":\"${IMAGE_REPO_NAME}\",\"imageUri\":\"%s\"}]" $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json ;
          echo Build stage successfully completed on `date`
        else
          cat tmp-report.asff | jq '.Findings' > report.asff ;
          aws securityhub batch-import-findings --findings file://report.asff --region $AWS_DEFAULT_REGION ;
        fi
artifacts:
  files:
    - imagedefinitions.json

phases/install

このビルドフェーズでは、Trivy を下記コマンドでインストールしています。

#TRIVY_VERSION=0.28.0 バージョンを固定したい場合は変数にバージョンを指定してください
TRIVY_VERSION=$(curl -sS https://api.github.com/repos/aquasecurity/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
rpm -ivh https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.rpm

参考: Installation

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI

phases/build

このビルドフェーズでは、ビルドしたイメージをTrivy でスキャンし、深刻度が CRITICAL な脆弱性を検出した場合は、イメージに問題があるとし、ビルドステージを失敗とします。(CIを停止とします。)
そして、Amazon Security Finding Format (ASFF) に準拠した Findings を生成しています。

AWS_REGION=$AWS_DEFAULT_REGION
AWS_ACCOUNT_ID=$AWS_ACCOUNT_ID
trivy image --no-progress --format template --template "@/usr/local/share/trivy/templates/asff.tpl" -o tmp-report.asff --ignore-unfixed --exit-code 1 --severity CRITICAL ${REPOSITORY_URI}:${IMAGE_TAG}

参考: Scan Option と ASFFについて

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI
A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI
AWS Security Finding 形式 (ASFF) について説明します。

phases/post_build

このビルドフェーズでは、コンテナイメージに CRITICAL な脆弱性を検出しなかった場合は、安全なイメージとしてECR にプッシュし、ビルドステージを正常とします。

CRITICAL な脆弱性を検出した場合は、生成したFindings をSecurity Hubに送信しています。
このサンプルでは、AWS CLI を使って送信しています。

if [ $CODEBUILD_BUILD_SUCCEEDING == "1" ]; then
   docker push ${REPOSITORY_URI}:${IMAGE_TAG} ;
   printf "[{\"name\":\"${IMAGE_REPO_NAME}\",\"imageUri\":\"%s\"}]" $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json ;
   echo Build stage successfully completed on `date`
else
   cat tmp-report.asff | jq '.Findings' > report.asff ;
   aws securityhub batch-import-findings --findings file://report.asff --region $AWS_DEFAULT_REGION ;
fi

参考: Upload findings to Security Hub

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI
AWS CodeBuild には、ビルドコマンドで使用できるいくつかの環境変数が用意されています。

さいごに

初歩的な内容ですが、DevSecOps の仕組みを検討する上で少しでも参考になれば幸いです。

元記事はこちら

https://qiita.com/okubot55/items/985781d1eef4894f862c
著者:
@okubot55


アイレットなら、AWS で稼働するサーバーを対象とした監視・運用・保守における煩わしい作業をすべて一括して対応し、経験豊富なプロフェッショナルが最適なシステム環境を実現いたします。AWS プレミアコンサルティングパートナーであるアイレットに、ぜひお任せください。

AWS 運用・保守サービスページ:
https://cloudpack.jp/service/aws/maintenance.html

その他のサービスについてのお問合せ、お見積り依頼は下記フォームよりお気軽にご相談ください。
https://cloudpack.jp/contact/form/