1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[AWS]CICDパイプラインでDocker脆弱性スキャン

Posted at

導入

背景・目的

  • Amazon Inspectorは継続的に AWS ワークロードをスキャンする自動脆弱性管理サービスです。
  • サービスの1機能を用いることで、Dockerイメージに対する脆弱性検査が可能です。
  • CodeシリーズとInspectorとを組み合わせて、脆弱性検査をPassした安全なDockerイメージのみをデプロイする、CICDパイプラインを構築してみます。

読者に想定する知識レベル

  • CodeシリーズやCDKの概要を理解している前提で記載します。

CICDパイプライン構築

アーキテクチャ紹介

  • CodeBuild内でDockerイメージに対する脆弱性検査を実施します。
  • 重大な脆弱性を検知しなかった場合のみ、DockerイメージをECRへPushします。

image.png
1

buildspecの作成

  • まずは、CodeBuildのビルド仕様ファイルであるbuildspec.ymlを作成します。
    • inspectorのSbomgenを用いてDockerイメージに対する脆弱性検査を実施します。
    • critical若しくはhighに分類される脆弱性を検知した場合にはECRへのPushを中止します。
version: 0.2
phases:
  install:
    commands:
      - echo "Setting timezone to Japan Standard Time (JST)..."
      - cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
      - echo "Installing Amazon Inspector SBOM Generator..."
      - wget https://amazon-inspector-sbomgen.s3.amazonaws.com/latest/linux/amd64/inspector-sbomgen.zip
      - unzip inspector-sbomgen.zip
      - mv inspector-sbomgen-* inspector-sbomgen
      - chmod +x ./inspector-sbomgen/linux/amd64/inspector-sbomgen
      - ./inspector-sbomgen/linux/amd64/inspector-sbomgen --version
      - echo "Logging in to Amazon ECR..."
      - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
      - echo "Installing jq for JSON parsing..."
      - curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
      - apt-get update -y
      - apt-get install -y jq
  build:
    commands:
      - echo "Building Docker image..."
      - TIMESTAMP=$(date +%Y%m%d%H%M%S)
      - IMAGE_TAG="$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | head -c 7)-${TIMESTAMP}"
      - echo "Tagging the image as ${IMAGE_TAG}..."
      - docker build -t ${IMAGE_NAME}:${IMAGE_TAG} .
  post_build:
    commands:
      - echo "Generating SBOM and scanning for vulnerabilities..."
      - ./inspector-sbomgen/linux/amd64/inspector-sbomgen container --image ${IMAGE_NAME}:${IMAGE_TAG} --scan-sbom -o /tmp/sbom.json
      - echo "Checking for critical and high vulnerabilities..."
      - |
        critical_vulnerabilities=$(jq -r '.metadata.properties[] | select(.name=="amazon:inspector:sbom_scanner:critical_vulnerabilities") | .value' /tmp/sbom.json)
        high_vulnerabilities=$(jq -r '.metadata.properties[] | select(.name=="amazon:inspector:sbom_scanner:high_vulnerabilities") | .value' /tmp/sbom.json)
        if [ "$critical_vulnerabilities" -ne 0 ] || [ "$high_vulnerabilities" -ne 0 ]; then
          echo "Critical or high vulnerabilities detected. Failing the build."
          exit 1
        else
          echo "No critical or high vulnerabilities found."
          echo "Tagging and pushing the Docker image..."
          docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}:${IMAGE_TAG}
          docker push ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}:${IMAGE_TAG}
        fi
artifacts:
  files:
    - /tmp/sbom.json

ECRの構築

  • Dockerイメージ格納用にECRを構築します。
    // ------------ Amazon ECR ---------------
    const ecrRepo = new ecr.Repository(this, "EcrRepo", {
      repositoryName: `poc-python-app`,
      imageTagMutability: ecr.TagMutability.IMMUTABLE,
      removalPolicy: cdk.RemovalPolicy.DESTROY // 検証用のため、スタック削除時にECR削除
    })

Codeシリーズの構築

  • 前述のbuildspec.ymlを用いて、Dockerイメージのビルド及び脆弱性検査を実施するCodeBuildを構築します。
  • CodePipelineを構築し、CodeCommit及びCodeBuildを組み込みます。
    // ------------ AWS CodeSeries ---------------
    // ---- AWS CodeCommit
    const gitRepo = codecommit.Repository.fromRepositoryArn(this, "GitRepo", props.codecommitArn)

    // ---- AWS CodeBuild
    // Create IAM Role
    const buildRole = new iam.Role(this, 'BuildRole', {
      roleName: `${props.prefix}-${props.envName}-role-build-docker`,
      assumedBy: new iam.ServicePrincipal('codebuild.amazonaws.com'),
    });
    // 検証用のため、広めの権限を付与
    buildRole.addToPolicy(new iam.PolicyStatement({
      actions: [
        'inspector-scan:*',
        'ecr:*',
      ],
      resources: ['*'],
    }));

    // Create Docker Build Project
    const dockerBuildProject = new codebuild.Project(this, 'DockerBuildProject', {
      projectName: `${props.prefix}-${props.envName}-build-docker`,
      buildSpec: codebuild.BuildSpec.fromAsset(path.join(__dirname, "../../assets/buildspec.yml")),
      role: buildRole,
      environment: {
        privileged: true, // Dockerビルド用に特権付与
        buildImage: codebuild.LinuxBuildImage.STANDARD_7_0,
      },
      environmentVariables: {
        ACCOUNT_ID: {
          type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
          value: props.env?.account
        },
        IMAGE_NAME: {
          type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
          value: ecrRepo.repositoryName
        }
      },
    });

    // ---- AWS CodePipeline
    const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
      pipelineName: `${props.prefix}-${props.envName}-pipeline`,
    });
    // Add Source Stage
    const sourceOutput = new codepipeline.Artifact();
    pipeline.addStage({
      stageName: 'Source',
      actions: [
        new codepipeline_actions.CodeCommitSourceAction({
          actionName: 'CodeCommit_Source',
          repository: gitRepo,
          branch: "main",
          output: sourceOutput,
        }),
      ],
    });
    // Add Build Stage
    const scanOutput = new codepipeline.Artifact();
    pipeline.addStage({
      stageName: 'Scan_Build',
      actions: [
        new codepipeline_actions.CodeBuildAction({
          actionName: 'CodeBuild_Scan_Build_Docker',
          project: dockerBuildProject,
          input: sourceOutput,
          outputs: [scanOutput]
        }),
      ],
    });

動作確認

CodeCommitへのPushをトリガにCodePipelineを実行し、動作確認してみます。
なお、CodeCommitにはDockerfileを格納しておき、イメージ作成時にhighに分類される脆弱性を検出するようにしておきます。

  • CodePipelineから呼び出されたCodeBuild内で、Dockerイメージに対する脆弱性検査を実施します。highに分類される脆弱性を検知したことから、パイプライン実行及びECRへのPushが失敗します。

image.png

Critical or high vulnerabilities detected. Failing the build.
  • buildspecを修正して、Push中止対象とする脆弱性をcriticalに限定してみます。すると、パイプライン実行及びECRへのPushに成功します。
      - echo "Generating SBOM and scanning for vulnerabilities..."
      - ./inspector-sbomgen/linux/amd64/inspector-sbomgen container --image ${IMAGE_NAME}:${IMAGE_TAG} --scan-sbom -o /tmp/sbom.json
      - echo "Checking for critical vulnerabilities..."
      - |
        critical_vulnerabilities=$(jq -r '.metadata.properties[] | select(.name=="amazon:inspector:sbom_scanner:critical_vulnerabilities") | .value' /tmp/sbom.json)
        if [ "$critical_vulnerabilities" -ne 0 ]; then
          echo "Critical vulnerabilities detected. Failing the build."
          exit 1
        else
          echo "No critical vulnerabilities found."
          echo "Tagging and pushing the Docker image..."
          docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}:${IMAGE_TAG}
          docker push ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_NAME}:${IMAGE_TAG}
        fi

image.png

image.png

No critical vulnerabilities found.
Tagging and pushing the Docker image...
  • 脆弱性検査結果はCodeBuildのArtifactとしてS3にアップロードされます。CycloneDX形式のSBOMファイルになります。

image.png

{
  "bomFormat": "CycloneDX",
  "components": [
    (一部略)
  ],
  "metadata": {
    "properties": [
      {
        "name": "amazon:inspector:sbom_scanner:critical_vulnerabilities",
        "value": "0"
      },
      {
        "name": "amazon:inspector:sbom_scanner:high_vulnerabilities",
        "value": "3"
      },
      {
        "name": "amazon:inspector:sbom_scanner:medium_vulnerabilities",
        "value": "2"
      },
      {
        "name": "amazon:inspector:sbom_scanner:low_vulnerabilities",
        "value": "0"
      },
      {
        "name": "amazon:inspector:sbom_scanner:other_vulnerabilities",
        "value": "0"
      }
    ],
    (一部略)
    "vulnerabilities": [
    ]
}

参考資料

  1. AWS公式のアナウンス通り、CodeCommitは新規顧客の利用不可になりました。本記事はCodeBuild及びInspectorの挙動確認に重きを置いているため、CodeCommitを利用しています。本番ワークロードで本構成を採用する場合には、他選択肢を候補に検討ください。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?