[アップデート] CodePipeline に新しく ECRBuildAndPublish, InspectorScan アクションが追加されました
こんにちは!AWS 事業本部コンサルティング部のたかくに(@takakuni_)です。
CodePipeline に新しく ECRBuildAndPublish, InspectorScan アクションが追加されました。とてもいいですね。
何が嬉しいのか
今まで CodePipeline でコンテナイメージの構築、Inspector Scan をパイプライン組み込みたい場合、自前で CodeBuild 等を用いて、実装する必要がありました。
コンテナイメージの構築
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
Inspector のイメージスキャン
version: 0.2
env:
shell: bash
variables:
DOCKER_BUILDKIT: '1'
AWS_PAGER: ''
exported-variables:
- BUILD_URL
phases:
install:
commands:
- aws --version
- echo AWS CLI update...
- curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
- unzip awscliv2.zip
- ./aws/install --bin-dir /root/.pyenv/shims --install-dir /usr/local/aws-cli --update
- aws --version
- echo Install Amazon Inspector SBOM Generator...
- curl -O https://amazon-inspector-sbomgen.s3.amazonaws.com/latest/linux/amd64/inspector-sbomgen.zip
- unzip inspector-sbomgen.zip
- mv inspector-sbomgen-* inspector-sbomgen-latest
- chmod +x inspector-sbomgen-latest/linux/amd64/inspector-sbomgen
- ./inspector-sbomgen-latest/linux/amd64/inspector-sbomgen --version
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
build:
commands:
- ./inspector-sbomgen-latest/linux/amd64/inspector-sbomgen container --image $IMAGE_URL --outfile /tmp/sbom.json --quiet
- aws inspector-scan scan-sbom --sbom file:///tmp/sbom.json --output-format INSPECTOR --query 'sbom.vulnerabilities'
post_build:
commands:
- export BUILD_URL=$CODEBUILD_BUILD_URL
今回、この設定が簡素化され CodePipeline 側のマネージドアクションとして利用可能になりました。
とくに Insector Scan アクションに対しては「これだよ、これ!」ですごく嬉しいです。(去年の re:Invent を思い出しました)
CodeBuild の管理コスト(設定ファイル、環境イメージ、inspector-sbomgen)が減るのは、かなり嬉しいポイントではないでしょうか。
やってみる
それでは実際にリソースを作成して試してみましょう。
GitHub との接続
まずは以下のブログを参考に CodeConnection を利用して、GitHub との接続を行います。
(実際に試す場合は私のリポジトリをフォークする形で設定してください。)
パイプラインの作成
続いてパイプラインの構築です。
今回も Terraform を利用してパイプラインを作成します。
今回はビルド、デプロイした ECR イメージを Inspector でスキャンするようなフローにしてみました。アクションがすべて CodePipeline で完結するためとてもスッキリしますね。
なお、今回のアップデートは CodePipeline v1 ではサポートしていないようでした。
> │ Error: updating CodePipeline Pipeline (inspector-scan-pipeline): operation error CodePipeline: UpdatePipeline, https response error StatusCode: 400, RequestID: 069eb5aa-30ee-4abc-bcae-1d28d9f0ab94, InvalidActionDeclarationException: ECRBuildAndPublish Action can only be used with V2 pipelines.
IAM
今回の ECRBuildAndPublish, InspectorScan は CodePipeline がマネージドに利用しているビルド環境を利用します。
裏では CodeBuild が動いてますが、ユーザー側からは見えない CodeBuild Project を動かしているようです。
This action uses CodePipeline managed CodeBuild compute to run commands in a build environment. Running the action will incur separate charges in AWS CodeBuild.
イメージは Commands に近いイメージです。
そのため、 IAM は CodePipeline に付与する必要があります。
ログを記録するためのポリシー
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:YOUR_AWS_ACCOUNT_ID:log-group:/aws/codepipeline/YOUR_PIPELINE_NAME",
"arn:aws:logs:*:YOUR_AWS_ACCOUNT_ID:log-group:/aws/codepipeline/YOUR_PIPELINE_NAME:*"
]
}
ECRBuildAndPublish
ドキュメントには "ecr:DescribeRepositories"
が記載がないのですが、必要だったため足しています。
{
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability",
"ecr:DescribeRepositories"
],
"Resource": "PrivateECR_Resource_ARN"
},
{
"Effect": "Allow",
"Action": [
"ecr-public:GetAuthorizationToken",
"ecr-public:DescribeRepositories",
"ecr-public:InitiateLayerUpload",
"ecr-public:UploadLayerPart",
"ecr-public:CompleteLayerUpload",
"ecr-public:PutImage",
"ecr-public:BatchCheckLayerAvailability",
"sts:GetServiceBearerToken"
],
"Resource": "PublicECR_Resource_ARN"
},
{
"Effect": "Allow",
"Action": ["sts:GetServiceBearerToken"],
"Resource": "*"
}
]
}
InspectorScan
{
"Effect": "Allow",
"Action": "inspector-scan:ScanSbom",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
],
"Resource": "resource_ARN"
}
最終的な IAM ポリシーは以下になりました。Resource 句の部分は適宜変更してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketAcl",
"s3:GetBucketLocation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["codestar-connections:UseConnection"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchCheckLayerAvailability",
"ecr:DescribeRepositories"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr-public:GetAuthorizationToken",
"ecr-public:DescribeRepositories",
"ecr-public:InitiateLayerUpload",
"ecr-public:UploadLayerPart",
"ecr-public:CompleteLayerUpload",
"ecr-public:PutImage",
"ecr-public:BatchCheckLayerAvailability",
"sts:GetServiceBearerToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": ["sts:GetServiceBearerToken"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "inspector-scan:ScanSbom",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability"
],
"Resource": "*"
}
]
}
ECRBuildAndPublish
各アクションの内容に移ります。まずは ECRBuildAndPublish
から。
ImageTags はデフォルトの場合、 latest
タグになります。
If a value for ImageTags is not specified, the value defaults to latest.
コミット ID をイメージタグに付与している場合はマッチしないので、コミット ID を拾ってくる必要があります。
そのため、今回は Source ステージから変数で受け渡すよう設定します。
#################################################
# CodePipeline
#################################################
resource "aws_codepipeline" "main" {
name = "${local.prefix}-pipeline"
pipeline_type = "V2"
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.artifact.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
+ namespace = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = 1
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = var.connection_arn
FullRepositoryId = "takakuni-classmethod/inspector-cicd-codebuild" # 任意の値を入力
BranchName = "v2"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
namespace = "Build"
owner = "AWS"
provider = "ECRBuildAndPublish"
version = 1
input_artifacts = ["source_output"]
configuration = {
ECRRepositoryName = aws_ecr_repository.main.name
DockerFilePath = "./docker"
+ ImageTags = "#{Source.CommitId}"
}
}
}
stage {
name = "Scan"
action {
name = "Scan"
category = "Invoke"
namespace = "Scan"
owner = "AWS"
provider = "InspectorScan"
version = 1
input_artifacts = []
output_artifacts = ["scan_output"]
configuration = {
InspectorRunMode = "ECRImageScan"
ECRRepositoryName = aws_ecr_repository.main.name
ImageTag = "#{Source.CommitId}"
}
}
}
stage {
name = "Approval"
action {
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = 1
configuration = {
CustomData = "Container image scan result."
# ExternalEntityLink = "#{Scan.BUILD_URL}"
}
}
}
}
InspectorScan
続いて InspectorScan に関してです。
InspectorRunMode は SourceCodeScan, ECRImageScan があります。
今回は ECRImageScan を選びますが、 SourceCodeScan でコンテナイメージのビルド前に確認できるのもいいですね。
Build ステージから、イメージタグを持って来れるとベストでしたが、ECRImageDigestId, ECRRepositoryName のみサポートしていたため、Source ステージから変数を持ってきました。
#################################################
# CodePipeline
#################################################
resource "aws_codepipeline" "main" {
name = "${local.prefix}-pipeline"
pipeline_type = "V2"
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.artifact.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
+ namespace = "Source"
owner = "AWS"
provider = "CodeStarSourceConnection"
version = 1
output_artifacts = ["source_output"]
configuration = {
ConnectionArn = var.connection_arn
FullRepositoryId = "takakuni-classmethod/inspector-cicd-codebuild" # 任意の値を入力
BranchName = "v2"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
namespace = "Build"
owner = "AWS"
provider = "ECRBuildAndPublish"
version = 1
input_artifacts = ["source_output"]
configuration = {
ECRRepositoryName = aws_ecr_repository.main.name
DockerFilePath = "./docker"
ImageTags = "#{Source.CommitId}"
}
}
}
stage {
name = "Scan"
action {
name = "Scan"
category = "Invoke"
namespace = "Scan"
owner = "AWS"
provider = "InspectorScan"
version = 1
input_artifacts = []
output_artifacts = ["scan_output"]
configuration = {
InspectorRunMode = "ECRImageScan"
ECRRepositoryName = aws_ecr_repository.main.name
+ ImageTag = "#{Source.CommitId}"
}
}
}
stage {
name = "Approval"
action {
name = "Approval"
category = "Approval"
owner = "AWS"
provider = "Manual"
version = 1
configuration = {
CustomData = "Container image scan result."
}
}
}
}
結果を確認
コードをプッシュして CodePipeline をみてみましょう。
CodePipeline
InspectorScan
スキャン結果がログに出ていますね。重要度別に表示されていることがわかります。
結果の詳細はどこにある?
出力アーティファクト(S3)に保管されてます。 CycloneDX 形式で SBOM が生成されており、 vulnerabilities
の配列に記録されています。
{
"bomFormat": "CycloneDX",
"components": [
{
"bom-ref": "comp-1",
"name": "Amazon Linux",
"type": "operating-system",
"version": "2023"
},
{
"bom-ref": "comp-2",
"name": "tzdata",
"properties": [
{
"name": "amazon:inspector:sbom_scanner:info",
"value": "Component skipped: no rules found."
}
],
"purl": "pkg:rpm/amazon/tzdata@2023c-1.amzn2023.0.1?arch=noarch\u0026distro=2023\u0026epoch=0\u0026source=tzdata-2023c-1.amzn2023.0.1.src.rpm",
"type": "application",
"version": "2023c-1.amzn2023.0.1"
},
{
"bom-ref": "comp-3",
"name": "pcre2-syntax",
"purl": "pkg:rpm/amazon/pcre2-syntax@10.40-1.amzn2023.0.2?arch=noarch\u0026distro=2023\u0026epoch=0\u0026source=pcre2-10.40-1.amzn2023.0.2.src.rpm",
"type": "application",
"version": "10.40-1.amzn2023.0.2"
}
],
"metadata": {
"properties": [
{
"name": "amazon:inspector:sbom_scanner:critical_vulnerabilities",
"value": "5"
},
{
"name": "amazon:inspector:sbom_scanner:high_vulnerabilities",
"value": "31"
},
{
"name": "amazon:inspector:sbom_scanner:medium_vulnerabilities",
"value": "54"
},
{
"name": "amazon:inspector:sbom_scanner:low_vulnerabilities",
"value": "4"
},
{
"name": "amazon:inspector:sbom_scanner:other_vulnerabilities",
"value": "0"
}
],
"timestamp": "2024-11-26T05:40:24.497Z",
"tools": {
"services": [
{
"name": "Amazon Inspector Scan SBOM API",
"version": "56008c36+5ce64b41+1f1b76d5"
}
]
}
},
"serialNumber": "urn:uuid:79f2b0e1-e1cb-49ff-a891-14756810599b",
"specVersion": "1.5",
"vulnerabilities": [
{
"advisories": [
{
"url": "https://lists.debian.org/debian-lts-announce/2023/12/msg00015.html"
},
{
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/UOGXU25FMMT2X6UUITQ7EZZYMJ42YWWD/"
},
{
"url": "https://hackerone.com/reports/2212193"
},
{
"url": "https://www.debian.org/security/2023/dsa-5587"
},
{
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/3ZX3VW67N4ACRAPMV2QS2LVYGD7H2MVE/"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:2094"
},
{
"url": "https://ubuntu.com/security/notices/USN-6535-1"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:2093"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:1383"
},
{
"url": "https://www.cve.org/CVERecord?id=CVE-2023-46218"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:2092"
},
{
"url": "https://alas.aws.amazon.com/AL2023/ALAS-2024-606.html"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:1317"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:0428"
},
{
"url": "https://alas.aws.amazon.com/AL2/ALAS-2024-2531.html"
},
{
"url": "https://ubuntu.com/security/notices/USN-6641-1"
},
{
"url": "https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1057646"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:0452"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:0585"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:0434"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:1316"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:1129"
},
{
"url": "https://access.redhat.com/errata/RHSA-2024:1601"
}
],
"affects": [
{
"ref": "comp-95"
},
{
"ref": "comp-96"
}
],
"analysis": {
"state": "in_triage"
},
"bom-ref": "vuln-1",
"created": "2023-10-19T01:00:12Z",
"description": "This flaw allows a malicious HTTP server to set \"super cookies\" in curl that are then passed back to more origins than what is otherwise allowed or possible. This allows a site to set cookies that then would get sent to different and unrelated sites and domains.\n\nIt could do this by exploiting a mixed case flaw in curl's function that verifies a given cookie domain against the Public Suffix List (PSL). For example a cookie could be set with `domain=co.UK` when the URL used a lower case hostname `curl.co.uk`, even though `co.uk` is listed as a PSL domain.",
"id": "CVE-2023-46218",
"properties": [
{
"name": "amazon:inspector:sbom_scanner:priority",
"value": "moderate"
},
{
"name": "amazon:inspector:sbom_scanner:priority_intelligence",
"value": "unverified"
},
{
"name": "amazon:inspector:sbom_scanner:fixed_version:comp-95",
"value": "0:8.5.0-1.amzn2023.0.2"
},
{
"name": "amazon:inspector:sbom_scanner:fixed_version:comp-96",
"value": "0:8.5.0-1.amzn2023.0.2"
}
],
"published": "2023-12-07T01:15:07Z",
"ratings": [
{
"method": "other",
"score": 8.6e-4,
"severity": "none",
"source": {
"name": "EPSS",
"url": "https://api.first.org/data/v1/epss?cve=CVE-2023-46218"
},
"vector": "model:v2023.03.01,date:2024-11-25T00:00:00+0000"
},
{
"method": "CVSSv31",
"score": 6.5,
"severity": "medium",
"source": {
"name": "Amazon Linux",
"url": "https://alas.aws.amazon.com/cve/json/v1/CVE-2023-46218.json"
},
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N"
},
{
"method": "CVSSv31",
"score": 6.5,
"severity": "medium",
"source": {
"name": "NVD",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46218"
},
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N"
}
],
"references": [
{
"id": "ALAS2023-2024-606",
"source": {
"name": "ALAS2023",
"url": "https://alas.aws.amazon.com/AL2023/ALAS-2024-606.html"
}
}
],
"source": {
"name": "NVD",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46218"
},
"updated": "2024-01-25T14:15:26Z"
}
]
}
まとめ
以上、「CodePipeline に新しく ECRBuildAndPublish, InspectorScan アクションが追加されました。」でした。
CodePipeline のアクションに追加され、CodeBuild や IAM ロールなど登場人物が減るのは嬉しいですね。
ぜひ活用していきたいです。このブログがどなたかの参考になれば幸いです。
AWS 事業本部コンサルティング部のたかくに(@takakuni_)でした!