From 847ccdabaf667c96a9ab244a45bac206158e13c1 Mon Sep 17 00:00:00 2001 From: Thomas Roos Date: Tue, 15 Oct 2024 12:33:47 +0200 Subject: [PATCH] Add AWS CodeBuild Project This will create an Embedded Linux ready AWS CodeBuild project that can be used to connect to a source e.g. GitHub Actions --- assets/build-image/ubuntu_22_04/Dockerfile | 2 +- lib/build-image-repo.ts | 2 +- lib/constructs/source-repo.ts | 2 + lib/embedded-linux-codebuild-project.ts | 265 ++++++++++++++++++ lib/index.ts | 1 + package-lock.json | 155 ++++++---- package.json | 4 +- .../build-image-data.test.ts.snap | 5 +- .../build-image-repo.test.ts.snap | 98 +------ .../embedded-linux-pipeline.test.ts.snap | 11 +- test/__snapshots__/network.test.ts.snap | 12 + test/embedded-linux-pipeline-nag.test.ts | 11 + 12 files changed, 404 insertions(+), 164 deletions(-) create mode 100644 lib/embedded-linux-codebuild-project.ts diff --git a/assets/build-image/ubuntu_22_04/Dockerfile b/assets/build-image/ubuntu_22_04/Dockerfile index 4159341..f00423a 100644 --- a/assets/build-image/ubuntu_22_04/Dockerfile +++ b/assets/build-image/ubuntu_22_04/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gawk wget git diffstat unzip texinfo gcc build-essential chrpath \ socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \ iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \ - python3-subunit mesa-common-dev zstd liblz4-tool file locales + python3-subunit mesa-common-dev zstd liblz4-tool file locales xterm # Install packages used elsewhere in the build RUN apt-get install -y --no-install-recommends \ diff --git a/lib/build-image-repo.ts b/lib/build-image-repo.ts index 43630e8..5b87e01 100644 --- a/lib/build-image-repo.ts +++ b/lib/build-image-repo.ts @@ -16,7 +16,7 @@ export class BuildImageRepoStack extends cdk.Stack { this.repository = new ecr.Repository(this, 'BuildImageRepo', { removalPolicy: cdk.RemovalPolicy.DESTROY, - autoDeleteImages: true, + emptyOnDelete: true, }); } } diff --git a/lib/constructs/source-repo.ts b/lib/constructs/source-repo.ts index bc18ead..ccc0724 100644 --- a/lib/constructs/source-repo.ts +++ b/lib/constructs/source-repo.ts @@ -20,6 +20,8 @@ export enum ProjectKind { Renesas = 'renesas', /** Build an IMX image using NXP layers. */ NxpImx = 'nxp-imx', + /** Build no pipeline, just CodeBuild project to connect with GitHub actions. */ + CodeBuild = 'codebuild', } export interface SourceRepoProps extends cdk.StackProps { diff --git a/lib/embedded-linux-codebuild-project.ts b/lib/embedded-linux-codebuild-project.ts new file mode 100644 index 0000000..101304b --- /dev/null +++ b/lib/embedded-linux-codebuild-project.ts @@ -0,0 +1,265 @@ +import * as cdk from "aws-cdk-lib"; +import { Construct } from "constructs"; +import * as events from "aws-cdk-lib/aws-events"; +import * as targets from "aws-cdk-lib/aws-events-targets"; +import * as lambda from "aws-cdk-lib/aws-lambda"; +import * as iam from "aws-cdk-lib/aws-iam"; +import * as efs from "aws-cdk-lib/aws-efs"; +import * as kms from "aws-cdk-lib/aws-kms"; +import * as s3 from "aws-cdk-lib/aws-s3"; + +import { + BuildSpec, + ComputeType, + FileSystemLocation, + LinuxBuildImage, + Project, +} from "aws-cdk-lib/aws-codebuild"; +import { IRepository } from "aws-cdk-lib/aws-ecr"; + +import { + ISecurityGroup, + IVpc, + Peer, + Port, + SecurityGroup, +} from "aws-cdk-lib/aws-ec2"; +import { ProjectKind } from "./constructs/source-repo"; +import { VMImportBucket } from "./vm-import-bucket"; +import { Asset } from "aws-cdk-lib/aws-s3-assets"; +import { LogGroup, RetentionDays } from "aws-cdk-lib/aws-logs"; +import { RemovalPolicy } from "aws-cdk-lib"; + +/** + * Properties to allow customizing the build. + */ +export interface EmbeddedLinuxCodebuildProjectProps + extends cdk.StackProps { + /** ECR Repository where the Build Host Image resides. */ + readonly imageRepo: IRepository; + /** Tag for the Build Host Image */ + readonly imageTag?: string; + /** VPC where the networking setup resides. */ + readonly vpc: IVpc; + /** The type of project being built. */ + readonly projectKind?: ProjectKind; + /** A name for the layer-repo that is created. Default is 'layer-repo' */ + readonly layerRepoName?: string; + /** Additional policy statements to add to the build project. */ + readonly buildPolicyAdditions?: iam.PolicyStatement[]; + /** Access logging bucket to use */ + readonly accessLoggingBucket?: s3.Bucket; + /** Access logging prefix to use */ + readonly serverAccessLogsPrefix?: string; + /** Artifact bucket to use */ + readonly artifactBucket?: s3.Bucket; + /** Output bucket to use */ + readonly outputBucket?: s3.Bucket | VMImportBucket; + /** Prefix for S3 object within bucket */ + readonly subDirectoryName?: string; +} + +/** + * The stack for creating a build pipeline. + * + * See {@link EmbeddedLinuxCodebuildProjectProps} for configration options. + */ +export class EmbeddedLinuxCodebuildProjectStack extends cdk.Stack { + constructor( + scope: Construct, + id: string, + props: EmbeddedLinuxCodebuildProjectProps + ) { + super(scope, id, props); + + /** Set up networking access and EFS FileSystems. */ + + const projectSg = new SecurityGroup(this, "BuildProjectSecurityGroup", { + vpc: props.vpc, + description: "Security Group to allow attaching EFS", + }); + projectSg.addIngressRule( + Peer.ipv4(props.vpc.vpcCidrBlock), + Port.tcp(2049), + "NFS Mount Port" + ); + + const sstateFS = this.addFileSystem("SState", props.vpc, projectSg); + const dlFS = this.addFileSystem("Downloads", props.vpc, projectSg); + const tmpFS = this.addFileSystem("Temp", props.vpc, projectSg); + + let accessLoggingBucket: s3.IBucket; + + if (props.accessLoggingBucket) { + accessLoggingBucket = props.accessLoggingBucket; + } else { + accessLoggingBucket = new s3.Bucket(this, "ArtifactAccessLogging", { + versioned: true, + enforceSSL: true, + }); + } + + /** Create our CodeBuild Project. */ + const project = new Project( + this, + "EmbeddedLinuxCodebuildProject", + { + buildSpec: BuildSpec.fromObject({ + version: "0.2", + phases: { + build: { + commands: ['echo "DUMMY BUILDSPEC - can not be empty"'], + }, + }, + artifacts: { + files: ["**/*"], + "base-directory": ".", + }, + }), + environment: { + computeType: ComputeType.X2_LARGE, + buildImage: LinuxBuildImage.fromEcrRepository( + props.imageRepo, + props.imageTag + ), + privileged: true, + }, + timeout: cdk.Duration.hours(4), + vpc: props.vpc, + securityGroups: [projectSg], + fileSystemLocations: [ + FileSystemLocation.efs({ + identifier: "tmp_dir", + location: tmpFS, + mountPoint: "/build-output", + }), + FileSystemLocation.efs({ + identifier: "sstate_cache", + location: sstateFS, + mountPoint: "/sstate-cache", + }), + FileSystemLocation.efs({ + identifier: "dl_dir", + location: dlFS, + mountPoint: "/downloads", + }), + ], + logging: { + cloudWatch: { + logGroup: new LogGroup(this, "PipelineBuildLogs", { + retention: RetentionDays.TEN_YEARS, + }), + }, + }, + } + ); + + if (props.buildPolicyAdditions) { + props.buildPolicyAdditions.map((p) => project.addToRolePolicy(p)); + } + + project.addToRolePolicy(this.addProjectPolicies()); + + project.role?.addManagedPolicy( + iam.ManagedPolicy.fromAwsManagedPolicyName("AWSCodeBuildAdminAccess") + ); + + /** Here we create the logic to check for presence of ECR image on the CodePipeline automatic triggering upon resource creation, + * and stop the execution if the image does not exist. */ + const fnOnPipelineCreate = new lambda.Function( + this, + "OSImageCheckOnStart", + { + runtime: lambda.Runtime.PYTHON_3_10, + handler: "index.handler", + code: lambda.Code.fromInline(` +import boto3 +import json + +ecr_client = boto3.client('ecr') +codepipeline_client = boto3.client('codepipeline') + +def handler(event, context): + print("Received event: " + json.dumps(event, indent=2)) + response = ecr_client.describe_images(repositoryName='${props.imageRepo.repositoryName}', filter={'tagStatus': 'TAGGED'}) + for i in response['imageDetails']: + if '${props.imageTag}' in i['imageTags']: + break + else: + print('OS image not found. Stopping execution.') + response = codepipeline_client.stop_pipeline_execution( + pipelineName=event['detail']['pipeline'], + pipelineExecutionId=event['detail']['execution-id'], + abandon=True, + reason='OS image not found in ECR repository. Stopping pipeline until image is present.') + `), + logRetention: RetentionDays.TEN_YEARS, + } + ); + + const pipelineCreateRule = new events.Rule(this, "OnPipelineStartRule", { + eventPattern: { + detailType: ["CodePipeline Pipeline Execution State Change"], + source: ["aws.codepipeline"], + detail: { + state: ["STARTED"], + "execution-trigger": { + "trigger-type": ["CreatePipeline"], + }, + }, + }, + }); + pipelineCreateRule.addTarget( + new targets.LambdaFunction(fnOnPipelineCreate) + ); + } + + /** + * Adds an EFS FileSystem to the VPC and SecurityGroup. + * + * @param name - A name to differentiate the filesystem. + * @param vpc - The VPC the Filesystem resides in. + * @param securityGroup - A SecurityGroup to allow access to the filesystem from. + * @returns The filesystem location URL. + * + */ + private addFileSystem( + name: string, + vpc: IVpc, + securityGroup: ISecurityGroup + ): string { + const fs = new efs.FileSystem( + this, + `EmbeddedLinuxPipeline${name}Filesystem`, + { + vpc, + removalPolicy: cdk.RemovalPolicy.DESTROY, + } + ); + + fs.connections.allowFrom(securityGroup, Port.tcp(2049)); + + const fsId = fs.fileSystemId; + const region = cdk.Stack.of(this).region; + + return `${fsId}.efs.${region}.amazonaws.com:/`; + } + + private addProjectPolicies(): iam.PolicyStatement { + return new iam.PolicyStatement({ + actions: [ + "ec2:DescribeSecurityGroups", + "codestar-connections:GetConnection", + "codestar-connections:GetConnectionToken", + "codeconnections:GetConnectionToken", + "codeconnections:GetConnection", + "codeconnections:UseConnection", + "codebuild:ListConnectedOAuthAccounts", + "codebuild:ListRepositories", + "codebuild:PersistOAuthToken", + "codebuild:ImportSourceCredentials", + ], + resources: ["*"], + }); + } +} diff --git a/lib/index.ts b/lib/index.ts index aceb715..55721df 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -3,4 +3,5 @@ export * from './build-image-data'; export * from './build-image-repo'; export * from './build-image-pipeline'; export * from './embedded-linux-pipeline'; +export * from './embedded-linux-codebuild-project'; export * from './constructs/source-repo'; diff --git a/package-lock.json b/package-lock.json index bc06fef..ce51776 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "aws4embeddedlinux-cdk-lib", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aws4embeddedlinux-cdk-lib", - "version": "0.1.2", + "version": "0.1.3", "devDependencies": { "@types/jest": "^29.5.1", "@types/node": "20.1.0", "@typescript-eslint/eslint-plugin": "^5.59.6", "@typescript-eslint/parser": "^5.59.6", - "aws-cdk-lib": "2.86.0", + "aws-cdk-lib": "2.156.0", "cdk-nag": "^2.27.131", "eslint": "^8.40.0", "eslint-config-prettier": "^8.8.0", @@ -26,7 +26,7 @@ "typescript": "~5.0.4" }, "peerDependencies": { - "aws-cdk-lib": "^2.86.0", + "aws-cdk-lib": "^2.156.0", "constructs": "^10.0.0" } }, @@ -53,9 +53,9 @@ } }, "node_modules/@aws-cdk/asset-awscli-v1": { - "version": "2.2.200", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.200.tgz", - "integrity": "sha512-Kf5J8DfJK4wZFWT2Myca0lhwke7LwHcHBo+4TvWOGJrFVVKVuuiLCkzPPRBQQVDj0Vtn2NBokZAz8pfMpAqAKg==", + "version": "2.2.206", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.206.tgz", + "integrity": "sha512-l2eAROXoPOXNyXt3lGUEveHo/U8c0IX7RTjgf2qy1LcZw6IkUIIIy/erQ6bBqZ5SibRfFAoXSBBC+gFfGyZDcA==", "dev": true }, "node_modules/@aws-cdk/asset-kubectl-v20": { @@ -64,12 +64,50 @@ "integrity": "sha512-3M2tELJOxQv0apCIiuKQ4pAbncz9GuLwnKFqxifWfe77wuMxyTRPmxssYHs42ePqzap1LT6GDcPygGs+hHstLg==", "dev": true }, - "node_modules/@aws-cdk/asset-node-proxy-agent-v5": { - "version": "2.0.166", - "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.166.tgz", - "integrity": "sha512-j0xnccpUQHXJKPgCwQcGGNu4lRiC1PptYfdxBIH1L4dRK91iBxtSQHESRQX+yB47oGLaF/WfNN/aF3WXwlhikg==", + "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", + "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==", "dev": true }, + "node_modules/@aws-cdk/cloud-assembly-schema": { + "version": "36.3.0", + "resolved": "https://registry.npmjs.org/@aws-cdk/cloud-assembly-schema/-/cloud-assembly-schema-36.3.0.tgz", + "integrity": "sha512-mLSYgcMFTNCXrGAD7xob95p9s47/7WwEWUJiexxM46H2GxiijhlhLQJs31AS5uRRP6Cx1DLEu4qayKAUOOVGrw==", + "bundleDependencies": [ + "jsonschema", + "semver" + ], + "dev": true, + "dependencies": { + "jsonschema": "^1.4.1", + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 18.18.0" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { + "version": "1.4.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { + "version": "7.6.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -1848,9 +1886,9 @@ } }, "node_modules/aws-cdk-lib": { - "version": "2.86.0", - "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.86.0.tgz", - "integrity": "sha512-76yZ2MawAGXLD3ox4FjhUIPmAMXteGKkeo3tPMthemusDCCkD2X6DBssXBHjB7r9GnrOMMf8JH5BGq2lOZ539g==", + "version": "2.156.0", + "resolved": "https://registry.npmjs.org/aws-cdk-lib/-/aws-cdk-lib-2.156.0.tgz", + "integrity": "sha512-iZJEWlJYGcwtHcaLVps5IjMegaka5btXcOH8hgTTjcFMFwR83KVBix6mDkhbGcLMIoIZBYBpp5t9fgG+ZuyNoA==", "bundleDependencies": [ "@balena/dockerignore", "case", @@ -1861,22 +1899,25 @@ "punycode", "semver", "table", - "yaml" + "yaml", + "mime-types" ], "dev": true, "dependencies": { - "@aws-cdk/asset-awscli-v1": "^2.2.177", - "@aws-cdk/asset-kubectl-v20": "^2.1.1", - "@aws-cdk/asset-node-proxy-agent-v5": "^2.0.148", + "@aws-cdk/asset-awscli-v1": "^2.2.202", + "@aws-cdk/asset-kubectl-v20": "^2.1.2", + "@aws-cdk/asset-node-proxy-agent-v6": "^2.0.3", + "@aws-cdk/cloud-assembly-schema": "^36.0.5", "@balena/dockerignore": "^1.0.2", "case": "1.6.3", - "fs-extra": "^11.1.1", - "ignore": "^5.2.4", + "fs-extra": "^11.2.0", + "ignore": "^5.3.1", "jsonschema": "^1.4.1", + "mime-types": "^2.1.35", "minimatch": "^3.1.2", - "punycode": "^2.3.0", - "semver": "^7.5.1", - "table": "^6.8.1", + "punycode": "^2.3.1", + "semver": "^7.6.2", + "table": "^6.8.2", "yaml": "1.10.2" }, "engines": { @@ -1893,15 +1934,15 @@ "license": "Apache-2.0" }, "node_modules/aws-cdk-lib/node_modules/ajv": { - "version": "8.12.0", + "version": "8.16.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -2003,7 +2044,7 @@ "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/fs-extra": { - "version": "11.1.1", + "version": "11.2.0", "dev": true, "inBundle": true, "license": "MIT", @@ -2023,7 +2064,7 @@ "license": "ISC" }, "node_modules/aws-cdk-lib/node_modules/ignore": { - "version": "5.2.4", + "version": "5.3.1", "dev": true, "inBundle": true, "license": "MIT", @@ -2073,16 +2114,25 @@ "inBundle": true, "license": "MIT" }, - "node_modules/aws-cdk-lib/node_modules/lru-cache": { - "version": "6.0.0", + "node_modules/aws-cdk-lib/node_modules/mime-db": { + "version": "1.52.0", "dev": true, "inBundle": true, - "license": "ISC", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aws-cdk-lib/node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "inBundle": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "mime-db": "1.52.0" }, "engines": { - "node": ">=10" + "node": ">= 0.6" } }, "node_modules/aws-cdk-lib/node_modules/minimatch": { @@ -2098,7 +2148,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/punycode": { - "version": "2.3.0", + "version": "2.3.1", "dev": true, "inBundle": true, "license": "MIT", @@ -2116,13 +2166,10 @@ } }, "node_modules/aws-cdk-lib/node_modules/semver": { - "version": "7.5.2", + "version": "7.6.2", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -2174,7 +2221,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/table": { - "version": "6.8.1", + "version": "6.8.2", "dev": true, "inBundle": true, "license": "BSD-3-Clause", @@ -2190,7 +2237,7 @@ } }, "node_modules/aws-cdk-lib/node_modules/universalify": { - "version": "2.0.0", + "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", @@ -2207,12 +2254,6 @@ "punycode": "^2.1.0" } }, - "node_modules/aws-cdk-lib/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, "node_modules/aws-cdk-lib/node_modules/yaml": { "version": "1.10.2", "dev": true, @@ -2330,12 +2371,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -3095,9 +3136,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -4323,12 +4364,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { diff --git a/package.json b/package.json index 287a3b6..c87e0b6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "@types/node": "20.1.0", "@typescript-eslint/eslint-plugin": "^5.59.6", "@typescript-eslint/parser": "^5.59.6", - "aws-cdk-lib": "2.86.0", + "aws-cdk-lib": "2.156.0", "cdk-nag": "^2.27.131", "eslint": "^8.40.0", "eslint-config-prettier": "^8.8.0", @@ -37,7 +37,7 @@ "typescript": "~5.0.4" }, "peerDependencies": { - "aws-cdk-lib": "^2.86.0", + "aws-cdk-lib": "^2.156.0", "constructs": "^10.0.0" } } diff --git a/test/__snapshots__/build-image-data.test.ts.snap b/test/__snapshots__/build-image-data.test.ts.snap index fdb5218..43fa82b 100644 --- a/test/__snapshots__/build-image-data.test.ts.snap +++ b/test/__snapshots__/build-image-data.test.ts.snap @@ -296,6 +296,7 @@ exports[`Build Image Data Snapshot 1`] = ` }, { "Action": [ + "s3:PutBucketPolicy", "s3:GetBucket*", "s3:List*", "s3:DeleteObject*", @@ -365,7 +366,7 @@ exports[`Build Image Data Snapshot 1`] = ` "Arn", ], }, - "Runtime": "python3.9", + "Runtime": "python3.11", "Timeout": 900, }, "Type": "AWS::Lambda::Function", @@ -399,7 +400,7 @@ exports[`Build Image Data Snapshot 1`] = ` "Arn", ], }, - "Runtime": "nodejs16.x", + "Runtime": "nodejs20.x", "Timeout": 900, }, "Type": "AWS::Lambda::Function", diff --git a/test/__snapshots__/build-image-repo.test.ts.snap b/test/__snapshots__/build-image-repo.test.ts.snap index 9c8edb6..fbbe919 100644 --- a/test/__snapshots__/build-image-repo.test.ts.snap +++ b/test/__snapshots__/build-image-repo.test.ts.snap @@ -10,110 +10,14 @@ exports[`Build Image Repository Snapshot 1`] = ` }, }, "Resources": { - "BuildImageRepoAutoDeleteImagesCustomResource5022C4B4": { - "DeletionPolicy": "Delete", - "DependsOn": [ - "BuildImageRepoDCD988F4", - ], - "Properties": { - "RepositoryName": { - "Ref": "BuildImageRepoDCD988F4", - }, - "ServiceToken": { - "Fn::GetAtt": [ - "CustomECRAutoDeleteImagesCustomResourceProviderHandler8D89C030", - "Arn", - ], - }, - }, - "Type": "Custom::ECRAutoDeleteImages", - "UpdateReplacePolicy": "Delete", - }, "BuildImageRepoDCD988F4": { "DeletionPolicy": "Delete", "Properties": { - "Tags": [ - { - "Key": "aws-cdk:auto-delete-images", - "Value": "true", - }, - ], + "EmptyOnDelete": true, }, "Type": "AWS::ECR::Repository", "UpdateReplacePolicy": "Delete", }, - "CustomECRAutoDeleteImagesCustomResourceProviderHandler8D89C030": { - "DependsOn": [ - "CustomECRAutoDeleteImagesCustomResourceProviderRole665F2773", - ], - "Properties": { - "Code": { - "S3Bucket": "cdk-hnb659fds-assets-111111111111-eu-central-1", - "S3Key": "42ece299d9a576096dc4857eaff93ff3960a29f86902c3e829c1d030f7a3cd82.zip", - }, - "Description": "Lambda function for auto-deleting images in undefined repository.", - "Handler": "index.handler", - "MemorySize": 128, - "Role": { - "Fn::GetAtt": [ - "CustomECRAutoDeleteImagesCustomResourceProviderRole665F2773", - "Arn", - ], - }, - "Runtime": "nodejs16.x", - "Timeout": 900, - }, - "Type": "AWS::Lambda::Function", - }, - "CustomECRAutoDeleteImagesCustomResourceProviderRole665F2773": { - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": "lambda.amazonaws.com", - }, - }, - ], - "Version": "2012-10-17", - }, - "ManagedPolicyArns": [ - { - "Fn::Sub": "arn:\${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", - }, - ], - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": [ - "ecr:BatchDeleteImage", - "ecr:DescribeRepositories", - "ecr:ListImages", - "ecr:ListTagsForResource", - ], - "Effect": "Allow", - "Resource": [ - { - "Fn::GetAtt": [ - "BuildImageRepoDCD988F4", - "Arn", - ], - }, - ], - }, - ], - "Version": "2012-10-17", - }, - "PolicyName": "Inline", - }, - ], - }, - "Type": "AWS::IAM::Role", - }, }, "Rules": { "CheckBootstrapVersion": { diff --git a/test/__snapshots__/embedded-linux-pipeline.test.ts.snap b/test/__snapshots__/embedded-linux-pipeline.test.ts.snap index 8cc9ecf..43821d6 100644 --- a/test/__snapshots__/embedded-linux-pipeline.test.ts.snap +++ b/test/__snapshots__/embedded-linux-pipeline.test.ts.snap @@ -1818,7 +1818,8 @@ exports[`Pipeline Poky AMI Pipeline - check role name trim 1`] = ` "Arn", ], }, - "Runtime": "nodejs16.x", + "Runtime": "nodejs20.x", + "Timeout": 900, }, "Type": "AWS::Lambda::Function", }, @@ -4288,7 +4289,8 @@ exports[`Pipeline Snapshot Poky AMI Pipeline 1`] = ` "Arn", ], }, - "Runtime": "nodejs16.x", + "Runtime": "nodejs20.x", + "Timeout": 900, }, "Type": "AWS::Lambda::Function", }, @@ -6542,7 +6544,7 @@ exports[`Pipeline Snapshot Poky Pipeline 1`] = ` "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-12341234-eu-central-1", - "S3Key": "5fa1330271b8967d9254ba2d4a07144f8acefe8b77e6d6bba38261373a50d5f8.zip", + "S3Key": "4e26bf2d0a26f2097fb2b261f22bb51e3f6b4b52635777b1e54edbd8e2d58c35.zip", }, "Handler": "index.handler", "Role": { @@ -6551,7 +6553,8 @@ exports[`Pipeline Snapshot Poky Pipeline 1`] = ` "Arn", ], }, - "Runtime": "nodejs16.x", + "Runtime": "nodejs20.x", + "Timeout": 900, }, "Type": "AWS::Lambda::Function", }, diff --git a/test/__snapshots__/network.test.ts.snap b/test/__snapshots__/network.test.ts.snap index 5c57e8b..2e1e3f6 100644 --- a/test/__snapshots__/network.test.ts.snap +++ b/test/__snapshots__/network.test.ts.snap @@ -560,6 +560,12 @@ exports[`Pipeline Networking Snapshot 1`] = ` "Ref": "PipelineVpc0543904A", }, "ResourceType": "VPC", + "Tags": [ + { + "Key": "Name", + "Value": "PipelineNetwork/VPCFlowLogs", + }, + ], "TrafficType": "ALL", }, "Type": "AWS::EC2::FlowLog", @@ -618,6 +624,12 @@ exports[`Pipeline Networking Snapshot 1`] = ` ], "Version": "2012-10-17", }, + "Tags": [ + { + "Key": "Name", + "Value": "PipelineNetwork/VPCFlowLogs", + }, + ], }, "Type": "AWS::IAM::Role", }, diff --git a/test/embedded-linux-pipeline-nag.test.ts b/test/embedded-linux-pipeline-nag.test.ts index 0bdb203..263afe0 100644 --- a/test/embedded-linux-pipeline-nag.test.ts +++ b/test/embedded-linux-pipeline-nag.test.ts @@ -133,6 +133,17 @@ describe('Pipeline cdk-nag AwsSolutions Pack', () => { }, ] ); + NagSuppressions.addResourceSuppressionsByPath( + stack, + '/MyTestStack/OSImageCheckOnStart/Resource', + [ + { + id: 'AwsSolutions-L1', + reason: + 'There is no latest PYTHON version to set.', + }, + ] + ); // WHEN Aspects.of(stack).add(new AwsSolutionsChecks({ verbose: true })); });