はじめに
コンテナセキュリティのガイドライン NIST SP800-190(アプリケーションコンテナセキュリティガイド) では、イメージのリスクの1つとして 「イメージの設定の不備」 について言及されています。
さらに、NIST SP800-190 では、このリスクへの対策として、 「セキュアな設定のベストプラクティスへの準拠を検証および実施するためのツールとプロセスを採用すること」 を推奨しています。
本記事では、この 「イメージの設定の不備」 へのリスク対策ツールとして、Dockle とgit-secrets を採用し、このツール群を組み込んだCI パイプライン(ビルドのプロセス)をTerraform でAWS 環境に構築する方法を記載しています。
コンテナイメージのセキュリティ対策の一例として参考になれば幸いです。
Terraform で構築する全体構成図
構成の概要
- Dockerfile を含むコードをCodeCommit にプッシュするとCodePipeline が実行されます。
- CodeBuild 内で、git-secrets がリポジトリをスキャンします。
- git-secrets がAWSのアクセスキー等の秘密情報を検出した場合は、CodePipeline を停止します。(CI を停止)
- 検出されなかった場合は、次のCodeBuild 内でDockle がイメージをスキャンします。
- その結果、FATAL レベルのアラートを検出した場合は、イメージをECR にはプッシュせず、CIを停止させます。
- スキャンした結果は、アーティファクトストアに出力され、確認できるようにしています。
- イメージに FATAL レベルのアラートを検出しなかった場合は、安全なイメージとしてECR にプッシュしています。
Dockle とは
引用:
特徴
コンテナの脆弱性を検出する
ベストプラクティスのDockerfileの構築を支援
簡単な使い方
画像名のみを指定してください
クイックスタートと一般的な例を参照してください
CISベンチマークサポート
高精度
DevSecOps
Travis CI、CircleCI、JenkinsなどのCIに適しています。
Dockle によるチェック項目ついて
Dockle では、CIS BenchmarksのDockerに関する項目(Container Images and Build File)とDockerfileのベストプラクティスについてチェックしてくれます。
各チェック項目の詳細は、下記になります。
git-secrets とは
引用:
パスワードやその他の機密情報をgitリポジトリにコミットできないようにします。
git-secrets は開発者の端末側で設定することが一般的ですが、ここでは、commit されたリポジトリを再スキャンする処理をCI に組み込むことで、ガードレールの第2層目として機能させることを目的としています。(開発者の設定忘れといったケースはよくありますので。)
Terraform のコードと構成
$ tree aws-tf-dockle-secrets-scan-ci
aws-tf-dockle-secrets-scan-ci
├── main.tf
└── modules
└── codepipeline
├── buildspec_dockle_check.yml
├── buildspec_secrets_check.yml
├── cloudwatch_event.tf
├── cloudwatch_logs.tf
├── codebuild.tf
├── codecommit.tf
├── codepipeline.tf
├── ecr.tf
├── iam.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.17.0
変数の設定
main.tf に下記の変数を設定します。
変数名 | 説明 |
---|---|
profile | 各AWSのプロファイル名 |
region | リージョン |
prefix | 各AWSのリソースに付与するプレフィックス |
env | 環境を識別するプレフィックス |
repository_name | CodeCommit のリポジトリ名 |
branch_name | ブランチ名 |
ecr_name | ECR のリポジトリ名 |
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 = "dockle-secrets-scan-ci"
# Branch Name
branch_name = "master"
# ECR Repository Name
ecr_name = "dockle-secrets-scan-ci"
}
Terraform の実行
$ terraform init
$ terraform plan
$ terraform apply
テスト用の秘密情報のファイルをCodeCommit にプッシュ
git-secrets の動作確認として、ダミーの秘密情報が含まれるファイルをCodeCommit にプッシュします。
[default]
aws_access_key_id=AKIAIOSFODNN7TEST123
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCTESTKEY123
password = "p@ssword123"
CodePipeline > CodeCommit > CodeBuild の実行
CodeCommit の変更イベントを検知してCodePipeline > CodeBuild が実行されます。
CodeBuildでgit-secrets によるリポジトリのスキャン
git-secrets のリポジトリのスキャンによって、秘密情報が検出され、ビルドのステータスが失敗となり、CodePipeline が失敗し、停止されます。
Dockerfile をCodeCommit にプッシュ
続いて、Dockle の動作確認として、設定の不備を含むテスト用のDockerfileとファイル をCodeCommit にプッシュします。
$ tree dockle-secrets-scan-ci
dockle-secrets-scan-ci
├── Dockerfile
└── index.html
FROM nginx:alpine
ADD index.html /usr/share/nginx/html/
Dockle Check CIS-DI-0009
CodePipeline > CodeCommit > CodeBuild の実行
CodeCommit の変更イベントを検知してCodePipeline > CodeBuild が実行されます。
CodeBuildでDockle による脆弱性スキャン
Dockle のコンテナイメージのスキャンによって、FATAL レベルのアラートを検出した場合、ビルドのステータスが失敗となり、CodePipeline は停止されます。
スキャン結果の確認方法
[ビルドの詳細]の[アーティファクトのアップロード場所]から、アーティファクト(Dockle のスキャン結果)をダウンロードして確認します。
Dockle のスキャン結果
{
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/dockle-secrets-scan-ci:de01562",
"summary": {
"fatal": 1,
"warn": 1,
"info": 2,
"skip": 0,
"pass": 12
},
"details": [
{
"code": "CIS-DI-0009",
"title": "Use COPY instead of ADD in Dockerfile",
"level": "FATAL",
"alerts": [
"Use COPY : ADD index.html /usr/share/nginx/html/ # buildkit"
]
},
{
"code": "CIS-DI-0001",
"title": "Create a user for the container",
"level": "WARN",
"alerts": [
"Last user should not be root"
]
},
{
"code": "CIS-DI-0005",
"title": "Enable Content trust for Docker",
"level": "INFO",
"alerts": [
"export DOCKER_CONTENT_TRUST=1 before docker pull/build"
]
},
{
"code": "CIS-DI-0006",
"title": "Add HEALTHCHECK instruction to the container image",
"level": "INFO",
"alerts": [
"not found HEALTHCHECK statement"
]
}
]
}
補足: 各CodeBuild のビルドの仕様について
git-secrets によるスキャンのビルド仕様
git-secrets をインストールしてから、CodeCommit のリポジトリをクローンして、そのディレクトリに対してスキャンしています。秘密情報を検出した場合は、CodeBuild を失敗としています。
version: 0.2
phases:
install:
commands:
- echo git-secrets Install...
- git clone https://github.com/awslabs/git-secrets /opt/git-secrets
- echo Install completed on `date`
build:
commands:
- echo git-secrets Scan started on `date`
- cd /opt/git-secrets
- make install
- cd ~
- git config --global credential.helper '!aws codecommit credential-helper $@'
- git config --global credential.UseHttpPath true
- git clone ${CODE_REPO_URL}
- cd ${CODE_REPO_NAME}
- git secrets --install
- git secrets --register-aws
- git secrets --add 'password\s*=\s*.+'
- cat .git/config
- git secrets --scan -r .
Dockle によるスキャンのビルド仕様
Dockle をインストールして、イメージをスキャンし、結果をJSONフォーマットで出力しています。FATAL レベルのアラートを検出した場合、CodeBuild を失敗としています。
参考: Common Examples
version: 0.2
env:
variables:
DOCKER_BUILDKIT: "1"
phases:
install:
runtime-versions:
docker: 19
commands:
- echo Dockle Install...
#- DOCKLE_VERSION=0.4.5
- |
DOCKLE_VERSION=$(
curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/' \
)
- rpm -ivh https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.rpm
- echo Install completed on `date`
- dockle --version
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 Dockle Scan started on `date`
- dockle --format json -o results.json --exit-code 1 --exit-level "FATAL" ${REPOSITORY_URI}:${IMAGE_TAG}
post_build:
commands:
- echo Dockle Scan completed on `date`
- cat results.json
- |
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`
fi
artifacts:
files:
- imagedefinitions.json
- results.json
さいごに
NIST SP800-190 では、イメージのリスクの1つとして 「イメージの脆弱性」 についても言及されているのですが、この 「イメージの脆弱性」 へのリスク対策ツールとしては、例として、Trivy があります。
このTrivy も合わせてCI に組み込んで運用するとコンテナイメージのセキュリティ対策が推進されるかと思います。
参考: