はじめに

コンテナセキュリティのガイドライン NIST SP800-190(アプリケーションコンテナセキュリティガイド) では、イメージのリスクの1つとして 「イメージの設定の不備」 について言及されています。
さらに、NIST SP800-190 では、このリスクへの対策として、 「セキュアな設定のベストプラクティスへの準拠を検証および実施するためのツールとプロセスを採用すること」 を推奨しています。

本記事では、この 「イメージの設定の不備」 へのリスク対策ツールとして、Docklegit-secrets を採用し、このツール群を組み込んだCI パイプライン(ビルドのプロセス)をTerraform でAWS 環境に構築する方法を記載しています。

コンテナイメージのセキュリティ対策の一例として参考になれば幸いです。

Terraform で構築する全体構成図

構成の概要

1.Dockerfile を含むコードをCodeCommit にプッシュするとCodePipeline が実行されます。
2.CodeBuild 内で、git-secrets がリポジトリをスキャンします。
3.git-secrets がAWSのアクセスキー等の秘密情報を検出した場合は、CodePipeline を停止します。(CI を停止)
4.検出されなかった場合は、次のCodeBuild 内でDockleがイメージをスキャンします。
5.その結果、FATAL レベルのアラートを検出した場合は、イメージをECR にはプッシュせず、CIを停止させます。
6.スキャンした結果は、アーティファクトストアに出力され、確認できるようにしています。
7.イメージに FATAL レベルのアラートを検出しなかった場合は、安全なイメージとしてECR にプッシュしています。

Dockle とは

Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start - GitHub - goodwithtech/dockle: Container Image Linter for Security, Helping build the Best-Practice...

引用:

特徴
コンテナの脆弱性を検出する
ベストプラクティスのDockerfileの構築を支援
簡単な使い方
画像名のみを指定してください
クイックスタートと一般的な例を参照してください
CISベンチマークサポート
高精度
DevSecOps
Travis CI、CircleCI、JenkinsなどのCIに適しています。

Dockle によるチェック項目ついて

Dockle では、CIS BenchmarksのDockerに関する項目(Container Images and Build File)Dockerfileのベストプラクティスについてチェックしてくれます。

各チェック項目の詳細は、下記になります。

Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start - dockle/CHECKPOINT.md at master · goodwithtech/dockle

git-secrets とは

Prevents you from committing secrets and credentials into git repositories - GitHub - awslabs/git-secrets: Prevents you from committing secrets and credentials into git repositories

引用:

パスワードやその他の機密情報を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 のリポジトリ名

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 = "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 にプッシュします。

dummy_secrets

[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

Dockerfile

FROM nginx:alpine
ADD index.html /usr/share/nginx/html/

index.html

Dockle Check CIS-DI-0009

CodePipeline > CodeCommit > CodeBuild の実行

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

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

Dockle のコンテナイメージのスキャンによって、FATAL レベルのアラートを検出した場合、ビルドのステータスが失敗となり、CodePipeline は停止されます。

ビルドログ

フェーズ詳細

スキャン結果の確認方法

[ビルドの詳細]の[アーティファクトのアップロード場所]から、アーティファクト(Dockle のスキャン結果)をダウンロードして確認します。

Dockle のスキャン結果

results.json

{
  "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 を失敗としています。

buildspec_secrets_check.yml

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

Container Image Linter for Security, Helping build the Best-Practice Docker Image, Easy to start - GitHub - goodwithtech/dockle: Container Image Linter for Security, Helping build the Best-Practice...

buildspec_dockle_check.yml

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 に組み込んで運用するとコンテナイメージのセキュリティ対策が推進されるかと思います。

参考:

はじめに本記事では、Trivy によるコンテナイメージの脆弱性スキャンとSecurity Hub を統合したCI(Continuous Integration)環境を構築するTerraform のコードをサンプルとして共有していま...

元記事はこちら

Terraform でAWS 環境にDockle + git-secrets を組み込んだCIを構築する
著者:
@okubot55


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

AWS 運用・保守サービスページ

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