はじめに
セキュリティシフトレフト記事第四弾。
前回は、アプリケーションのSASTツールをどのようにAWS CodeBuild上で使うのが良いのかを検証した。
今回は、第二回の記事の内容に戻り、Trivyによって検出した脆弱性に関連した情報をAWS Security Hubを送り、問題管理を行えるようにしていく。AWS CodeBuildのバッチビルドの構成はそのままに、Trivyを動作させるビルド部分のみを変更するため、第二回の記事の内容を参照しておいていただきたい。
脆弱性のあるDockerfileの準備
今回は、あえて脆弱性を仕込んだDockerfileを作って検知までしてみたいため、以下のようなDockerfileを準備する。Dockerfile内でnginx.confを差し替えていないので、実際の運用ができるものではないが、サンプルのため細かいことは気にしないでいただきたい。
FROM public.ecr.aws/nginx/nginx:1.27
RUN apt-get update \
&& apt-get install --no-install-recommends -y curl=7.88.1-10+deb12u7 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
HEALTHCHECK CMD /usr/bin/curl http://localhost/
WORKDIR /
CMD ["nginx", "-g", "daemon off;"]
AWS Security Hubの有効化
AWS Security Hubを以下のように有効化する。
aws_securityhub_account
はその名の通り、アカウント全体の設定なので、既に有効化されている場合は特に作成する必要はない。
なお、AWS Security Hubはスキャン単位で課金されるため、今回はスキャンする量を減らすためにenable_default_standards = false
を設定しているが、実際の運用時には必要なセキュリティチェックは有効にしておこう。
Security Hub の価格は、セキュリティチェックの数、検出結果の取り込みイベントの数、1 か月あたりに処理されるルール評価の量という 3 つの観点から設定されます。
resource "aws_securityhub_account" "example" {
enable_default_standards = false
auto_enable_controls = false
}
AWS Security HubとTrivyを統合する
さて、Security Hubを有効化したら次はTrivyのレポートを受けられる状態にする。
他のプロダクトと統合する際は、Terraformのaws_securityhub_product_subscription
のリソースを使用する。
具体的にどんなプロダクトと統合可能かの全容は以下のAWS公式のユーザーガイドに記載されている。
Trivyについても記載されているので、その値をproduct_arn
に設定する。
resource "aws_securityhub_product_subscription" "example" {
depends_on = [aws_securityhub_account.example]
product_arn = "arn:aws:securityhub:${data.aws_region.current.name}::product/aquasecurity/aquasecurity"
}
AWS CodeBuildのIAM権限設定
今回、AWS Security Hubに情報を送信するにあたり、AWS CodeBuildのサービスロールにsecurityhub:BatchImportFindings
の権限付与が必要になるため、忘れず設定しておこう。
# (前略)
statement {
effect = "Allow"
actions = [
"securityhub:BatchImportFindings",
]
resources = [
"*",
]
}
# (後略)
AWS CodeBuildのBuildspecの設定
次に、AWS CodeBuildのBuildspecを準備していく。
第二回で作成したBuildspecは以下の通り簡易なものであったが、これを書き換えていく。その際、ハマりどころがいくつかあるので、ポイントを抑えて説明していく。
version: 0.2
env:
variables:
IMAGE_NAME: "container_image"
IMAGE_TAG : "1.0"
TRIVY_PATH: "/usr/bin/trivy"
phases:
install:
commands:
# install Trivy
- VERSION=$(curl --silent 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${VERSION}/trivy_${VERSION}_Linux-64bit.rpm
build:
commands:
- docker build . -t ${IMAGE_NAME}:${IMAGE_TAG}
- ${TRIVY_PATH} image --quiet --exit-code 1 ${IMAGE_NAME}:${IMAGE_TAG}
変更後のBuildspecの全体像
変更後のBuildspecは以下の通りとなる。phases.build
以前は変える必要がないのでそのままにして良い。
# (前略)
build:
commands:
- docker build . -t ${IMAGE_NAME}:${IMAGE_TAG}
# Settings are required to reference the AWS_ACCOUNT_ID environment variable in Trivy's ASFF template.
- AWS_ACCOUNT_ID=$(echo ${CODEBUILD_BUILD_ARN} | cut -f 5 -d :)
- ${TRIVY_PATH} image
--no-progress
--db-repository public.ecr.aws/aquasecurity/trivy-db:2
--java-db-repository public.ecr.aws/aquasecurity/trivy-java-db:1
--format template
--template "@/usr/local/share/trivy/templates/asff.tpl"
--output /tmp/tmp-report.asff
--severity HIGH
--ignore-unfixed
--exit-code 1
${IMAGE_NAME}:${IMAGE_TAG}
post_build:
commands:
# Send report to AWS Security Hub on build failure
- |
if [ $CODEBUILD_BUILD_SUCCEEDING != "1" ]; then
jq '.Findings' /tmp/tmp-report.asff > /tmp/report.asff
aws securityhub batch-import-findings --findings file:///tmp/report.asff --region ${AWS_DEFAULT_REGION}
fi
Trivyのレポート形式をASFFに指定する
Trivyのレポートの形式は以下のページで詳細が書かれている。
ここに
If Trivy is installed using rpm then default templates can be found at
/usr/local/share/trivy/templates
.
と書いてある通り、ASFFのテンプレートは/usr/local/share/trivy/templates/asff.tpl
に置かれている。GitHubにもあるので、参考までにリンクを貼っておく。
気を付けなければいけないのは、このテンプレート内でAWS_REGION
とAWS_ACCOUNT_ID
の二つの環境変数を参照していることだ。
AWS_REGION
はAWS CodeBuildのデフォルト環境変数で、「AWS CodeBuildを実行しているリージョン」が設定されてくるので、何も設定しなくて良い(もちろん、AWS CodeBuildとAWS Security Hubを別リージョンで動かしている場合は変更が必要)。
AWS_ACCOUNT_ID
はデフォルト環境変数になっていないため、AWS_ACCOUNT_ID=$(echo ${CODEBUILD_BUILD_ARN} | cut -f 5 -d :)
で値を取り出して設定をしておく(AWS CodeBuildに環境変数で渡しても良いが、クロスアカウントでない限りはこちらの方が簡単だろう)。
Trivyのデータベース更新のレジストリ変更
Trivyのデフォルトの脆弱性情報のデータベースはghcr.io
であり、AWS CodeBuildから何も指定せずに動作させると、GitHub側のRateLimitにぶつかってしまいうまく動作しない(しかも、このエラーログがRateLimitと分かるログでないので、ハマるとつらい)。
ということで、ECR Public GalleryのレジストリURLを--db-repository
と--java-db-repository
に設定しておこう。--no-progress
オプションを付けるとDB更新の進捗が表示されなくなる。
重要度等の設定
すべての修正をしているとキリがないので、HIGHかCRITICAL以上のものを管理対象としよう。
これは--severity HIGH
で設定可能だ。
また、修正されていない脆弱性を表示されてもつらいだけなので、--ignore-unfixed
のオプションを使い、FIX済みで未適用のもののみAWS Security Hubに送信するようにする。
post_buildの設定
最後に、aws securityhub batch-import-findings
で、出力したASFFを送信する。
.Findings
のJSON要素のみ必要であるため、jq
コマンドで編集をしている。
これで、準備は完了だ。
いざ、動かす!
terraform apply
したらしばらくビルドの完了を待って、AWS Security Hubのコンソールを見てみよう。
以下の手順で、Trivyのレポートに絞って確認することができる。
①「統合」を選択
②検索ボックスで「Aqua」を検索
③「結果を参照」のリンクを押す
上記を行うと、以下のように検出された脆弱性の一覧を確認することができる(今回はHIGH以上は1件のみであった)。
「検出結果」のリンクを押下することで、より詳細な情報を確認が可能だ。
リソースのタブの「詳細」を開くことで、現在どのバージョンのパッケージを利用していて、パッチするためには何を指定すれば良いかもここから分かる。
指摘されているとおり、Dockerfileでlibheifのパッチ済みバージョンを追加インストールしよう。
FROM public.ecr.aws/nginx/nginx:1.27
RUN apt-get update \
&& apt-get install --no-install-recommends -y curl=7.88.1-10+deb12u7 \
+ && apt-get install --no-install-recommends -y libheif-dev=1.15.1-1+deb12u1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
HEALTHCHECK CMD /usr/bin/curl http://localhost/
WORKDIR /
CMD ["nginx", "-g", "daemon off;"]
これで、再度AWS CodeBuildを実行すると、今度は指摘がなく正常終了するはずだ。
エラーが出なくなったら、AWS Security Hub上のステータスもちゃんと更新をしておこう。
これで、より効率的に脆弱性管理をできるようになった!