diff --git a/.github/workflows/github-merit-badger.yml b/.github/workflows/github-merit-badger.yml index 56896b5b75f57..449066bbe920f 100644 --- a/.github/workflows/github-merit-badger.yml +++ b/.github/workflows/github-merit-badger.yml @@ -17,4 +17,4 @@ jobs: badges: '[beginning-contributor,repeat-contributor,valued-contributor,admired-contributor,star-contributor,distinguished-contributor]' thresholds: '[0,3,6,13,25,50]' badge-type: 'achievement' - ignore-usernames: '[rix0rrr,iliapolo,otaviomacedo,kaizencc,comcalvi,TheRealAmazonKendra,mrgrain,pahud,kellertk,ashishdhingra,HBobertz,sumupitchayan,colifran,khushail,moelasmar,paulhcsun,GavinZZ,aaythapa,xazhao,gracelu0,jfuss,shikha372,kirtishrinkhala,godwingrs22,bergjaak,IanKonlog,Leo10Gama,samson-keung,scorbiere,michelle-wangg,jiayiwang7,1kaileychen,saiyush,aws-cdk-automation,dependabot[bot],mergify[bot]]' + ignore-usernames: '[rix0rrr,iliapolo,otaviomacedo,kaizencc,comcalvi,TheRealAmazonKendra,mrgrain,pahud,kellertk,ashishdhingra,HBobertz,sumupitchayan,colifran,khushail,moelasmar,paulhcsun,GavinZZ,aaythapa,xazhao,gracelu0,jfuss,shikha372,kirtishrinkhala,godwingrs22,bergjaak,IanKonlog,Leo10Gama,samson-keung,scorbiere,michelle-wangg,jiayiwang7,1kaileychen,saiyush,5d,aws-cdk-automation,dependabot[bot],mergify[bot]]' diff --git a/.mergify.yml b/.mergify.yml index c1f27c9a0866b..b9ffeae147913 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -43,7 +43,7 @@ pull_request_rules: label: add: [ contribution/core ] conditions: - - author~=^(rix0rrr|iliapolo|otaviomacedo|kaizencc|comcalvi|TheRealAmazonKendra|mrgrain|pahud|ashishdhingra|kellertk|HBobertz|sumupitchayan|colifran|moelasmar|paulhcsun|GavinZZ|aaythapa|xazhao|gracelu0|jfuss|shikha372|kirtishrinkhala|godwingrs22|bergjaak|samson-keung|IanKonlog|Leo10Gama|scorbiere|michelle-wangg|jiayiwang7|1kaileychen|saiyush)$ + - author~=^(rix0rrr|iliapolo|otaviomacedo|kaizencc|comcalvi|TheRealAmazonKendra|mrgrain|pahud|ashishdhingra|kellertk|HBobertz|sumupitchayan|colifran|moelasmar|paulhcsun|GavinZZ|aaythapa|xazhao|gracelu0|jfuss|shikha372|kirtishrinkhala|godwingrs22|bergjaak|samson-keung|IanKonlog|Leo10Gama|scorbiere|michelle-wangg|jiayiwang7|1kaileychen|saiyush|5d)$ - -label~="contribution/core" - name: automatic merge actions: diff --git a/ROADMAP.md b/ROADMAP.md index f7de45cc733c2..9197ba8f3917b 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,6 @@ # AWS CDK Roadmap -> Updated 9/3/2024 +> Updated 11/5/2024 The roadmap priorities for the AWS CDK (Cloud Development Kit) are informed by what we hear from customers and interactions on Github, CDK.dev Slack, Stack Overflow, and Twitter. This document outlines the high level direction we are working towards, and for each project there is a tracking issue where you can leave feedback. We update this doc on a quarterly basis to reflect any changing priorities. @@ -37,15 +37,11 @@ Over the course of the last few years, the CDK team has spent time speaking with ### L2 Abstractions The CDK team is committed to supporting our existing library of AWS L2 abstractions. We continue to solicit community feedback on where additional L2 coverage makes it simpler and more efficient to build with AWS. Current L2s that the team’s working on are listed below. Please be aware that this list will update throughout the year. If you have feedback on other L2s that should be prioritized by our team, feel free to submit a separate RFC. - -* πŸš€ [VPC Construct with Full Control](https://github.com/aws/aws-cdk/tree/main/packages/%40aws-cdk/aws-ec2-alpha) -* πŸš€ [AWS APIGateway_v2 graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigatewayv2-readme.html) -* πŸš€ [AWS Batch graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_batch-readme.html) -* πŸš€ [AWS Synthetics graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_synthetics-readme.html) -* πŸ› οΈ [CloudFront Origin Access Control L2](https://github.com/aws/aws-cdk-rfcs/issues/617) -* πŸ› οΈ [AWS Cognito_Identity_pool graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cognito-identitypool-alpha-readme.html) -* πŸ› οΈ [AWS Kinesis_firehose graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-kinesisfirehose-alpha-readme.html) -* 🚦️ [Rewrite EKS L2](https://github.com/aws/aws-cdk-rfcs/issues/605) + +* πŸš€ [CloudFront Origin Access Control L2](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront_origins-readme.html) +* πŸš€ [AWS Cognito_Identity_pool graduation to Developer Preview](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cognito-identitypool-alpha-readme.html) +* πŸš€ [AWS Kinesis_firehose graduation to Developer Preview](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-kinesisfirehose-alpha-readme.html) +* πŸ› οΈ [Rewrite EKS L2](https://github.com/aws/aws-cdk-rfcs/issues/605) * πŸ” [aws-lambda-python graduation](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-lambda-python-alpha-readme.html) * πŸ” [Auto-generation of L2 constructs](https://github.com/aws/aws-cdk-rfcs/issues/611) * πŸ” [Glue Alpha Construct Graduation](https://github.com/aws/aws-cdk/issues/7534) @@ -58,9 +54,10 @@ The CDK team is committed to supporting our existing library of AWS L2 abstracti ### User Experience -- πŸ› οΈ [Garbage Collection for Assets](https://github.com/aws/aws-cdk-rfcs/issues/64) -- 🚦️ [Programmatic Access of the AWS CDK CLI](https://github.com/aws/aws-cdk-rfcs/issues/300) -- πŸ‘‚πŸ½ [CDK Refactoring](https://github.com/aws/aws-cdk-rfcs/issues/162) +- πŸš€ [Garbage Collection for Assets](https://github.com/aws/aws-cdk-rfcs/issues/64) +- πŸ› οΈ [Programmatic Access of the AWS CDK CLI](https://github.com/aws/aws-cdk-rfcs/issues/300) +- 🚦 [CDK Refactoring](https://github.com/aws/aws-cdk-rfcs/issues/162) +- 🚦 [cli: Enable client-side telemetry and analytics](https://github.com/aws/aws-cdk/issues/32010) ### Community contribution call-outs diff --git a/docs/DESIGN_GUIDELINES.md b/docs/DESIGN_GUIDELINES.md index 03953981534be..d55a2fcab35f1 100644 --- a/docs/DESIGN_GUIDELINES.md +++ b/docs/DESIGN_GUIDELINES.md @@ -9,7 +9,7 @@ the AWS Construct Library in order to ensure a consistent and integrated experience across the entire AWS surface area. * [Preface](#preface) -* [What's Included](#what-s-included) +* [What's Included](#whats-included) * [API Design](#api-design) * [Modules](#modules) * [Construct Class](#construct-class) @@ -66,7 +66,7 @@ experience across the entire AWS surface area. * [Unit tests](#unit-tests) * [Integration tests](#integration-tests) * [Versioning](#versioning) -* [Naming & Style](#naming---style) +* [Naming & Style](#naming--style) * [Naming Conventions](#naming-conventions) * [Coding Style](#coding-style) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets.json new file mode 100644 index 0000000000000..ceb305d3c2f6e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegCanaryTestDefaultTestDeployAssert3AD5A094.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/IntegCanaryTestDefaultTestDeployAssert3AD5A094.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js new file mode 100644 index 0000000000000..1002ba018e9fb --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61/index.js @@ -0,0 +1 @@ +"use strict";var f=Object.create;var i=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var A=(t,e)=>{for(var o in e)i(t,o,{get:e[o],enumerable:!0})},d=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of C(e))!P.call(t,s)&&s!==o&&i(t,s,{get:()=>e[s],enumerable:!(r=I(e,s))||r.enumerable});return t};var l=(t,e,o)=>(o=t!=null?f(w(t)):{},d(e||!t||!t.__esModule?i(o,"default",{value:t,enumerable:!0}):o,t)),B=t=>d(i({},"__esModule",{value:!0}),t);var q={};A(q,{autoDeleteHandler:()=>S,handler:()=>H});module.exports=B(q);var h=require("@aws-sdk/client-s3");var y=l(require("https")),m=l(require("url")),a={sendHttpRequest:D,log:T,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",L="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(t){return async(e,o)=>{let r={...e,ResponseURL:"..."};if(a.log(JSON.stringify(r,void 0,2)),e.RequestType==="Delete"&&e.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",e);return}try{let s=await t(r,o),n=k(e,s);await u("SUCCESS",n)}catch(s){let n={...e,Reason:a.includeStackTraces?s.stack:s.message};n.PhysicalResourceId||(e.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),n.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(e)}`)),await u("FAILED",n)}}}function k(t,e={}){let o=e.PhysicalResourceId??t.PhysicalResourceId??t.RequestId;if(t.RequestType==="Delete"&&o!==t.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${t.PhysicalResourceId}" to "${e.PhysicalResourceId}" during deletion`);return{...t,...e,PhysicalResourceId:o}}async function u(t,e){let o={Status:t,Reason:e.Reason??t,StackId:e.StackId,RequestId:e.RequestId,PhysicalResourceId:e.PhysicalResourceId||L,LogicalResourceId:e.LogicalResourceId,NoEcho:e.NoEcho,Data:e.Data},r=m.parse(e.ResponseURL),s=`${r.protocol}//${r.hostname}/${r.pathname}?***`;a.log("submit response to cloudformation",s,o);let n=JSON.stringify(o),E={hostname:r.hostname,path:r.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(n,"utf8")}};await O({attempts:5,sleep:1e3},a.sendHttpRequest)(E,n)}async function D(t,e){return new Promise((o,r)=>{try{let s=y.request(t,n=>{n.resume(),!n.statusCode||n.statusCode>=400?r(new Error(`Unsuccessful HTTP response: ${n.statusCode}`)):o()});s.on("error",r),s.write(e),s.end()}catch(s){r(s)}})}function T(t,...e){console.log(t,...e)}function O(t,e){return async(...o)=>{let r=t.attempts,s=t.sleep;for(;;)try{return await e(...o)}catch(n){if(r--<=0)throw n;await b(Math.floor(Math.random()*s)),s*=2}}}async function b(t){return new Promise(e=>setTimeout(e,t))}var g="aws-cdk:auto-delete-objects",x=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),H=R(S);async function S(t){switch(t.RequestType){case"Create":return;case"Update":return{PhysicalResourceId:(await F(t)).PhysicalResourceId};case"Delete":return N(t.ResourceProperties?.BucketName)}}async function F(t){let e=t,o=e.OldResourceProperties?.BucketName;return{PhysicalResourceId:e.ResourceProperties?.BucketName??o}}async function _(t){try{let e=(await c.getBucketPolicy({Bucket:t}))?.Policy??x,o=JSON.parse(e);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${t}/*`]}),await c.putBucketPolicy({Bucket:t,Policy:JSON.stringify(o)})}catch(e){if(e.name==="NoSuchBucket")throw e;console.log(`Could not set new object deny policy on bucket '${t}' prior to deletion.`)}}async function U(t){let e;do{e=await c.listObjectVersions({Bucket:t});let o=[...e.Versions??[],...e.DeleteMarkers??[]];if(o.length===0)return;let r=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:t,Delete:{Objects:r}})}while(e?.IsTruncated)}async function N(t){if(!t)throw new Error("No BucketName was provided.");try{if(!await W(t)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await _(t),await U(t)}catch(e){if(e.name==="NoSuchBucket"){console.log(`Bucket '${t}' does not exist.`);return}throw e}}async function W(t){return(await c.getBucketTagging({Bucket:t})).TagSet?.some(o=>o.Key===g&&o.Value==="true")}0&&(module.exports={autoDeleteHandler,handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d/index.js new file mode 100644 index 0000000000000..f9cc630970c96 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/asset.d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d/index.js @@ -0,0 +1 @@ +"use strict";var I=Object.create;var i=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var P=(o,e)=>{for(var t in e)i(o,t,{get:e[t],enumerable:!0})},l=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of S(e))!A.call(o,s)&&s!==t&&i(o,s,{get:()=>e[s],enumerable:!(n=g(e,s))||n.enumerable});return o};var m=(o,e,t)=>(t=o!=null?I(w(o)):{},l(e||!o||!o.__esModule?i(t,"default",{value:o,enumerable:!0}):t,o)),L=o=>l(i({},"__esModule",{value:!0}),o);var W={};P(W,{autoDeleteHandler:()=>E,handler:()=>_});module.exports=L(W);var c=require("@aws-sdk/client-lambda"),u=require("@aws-sdk/client-synthetics");var y=m(require("https")),R=m(require("url")),a={sendHttpRequest:T,log:F,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",D="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function C(o){return async(e,t)=>{let n={...e,ResponseURL:"..."};if(a.log(JSON.stringify(n,void 0,2)),e.RequestType==="Delete"&&e.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await d("SUCCESS",e);return}try{let s=await o(n,t),r=b(e,s);await d("SUCCESS",r)}catch(s){let r={...e,Reason:a.includeStackTraces?s.stack:s.message};r.PhysicalResourceId||(e.RequestType==="Create"?(a.log("CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored"),r.PhysicalResourceId=p):a.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify(e)}`)),await d("FAILED",r)}}}function b(o,e={}){let t=e.PhysicalResourceId??o.PhysicalResourceId??o.RequestId;if(o.RequestType==="Delete"&&t!==o.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${o.PhysicalResourceId}" to "${e.PhysicalResourceId}" during deletion`);return{...o,...e,PhysicalResourceId:t}}async function d(o,e){let t={Status:o,Reason:e.Reason??o,StackId:e.StackId,RequestId:e.RequestId,PhysicalResourceId:e.PhysicalResourceId||D,LogicalResourceId:e.LogicalResourceId,NoEcho:e.NoEcho,Data:e.Data},n=R.parse(e.ResponseURL),s=`${n.protocol}//${n.hostname}/${n.pathname}?***`;a.log("submit response to cloudformation",s,t);let r=JSON.stringify(t),f={hostname:n.hostname,path:n.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(r,"utf8")}};await x({attempts:5,sleep:1e3},a.sendHttpRequest)(f,r)}async function T(o,e){return new Promise((t,n)=>{try{let s=y.request(o,r=>{r.resume(),!r.statusCode||r.statusCode>=400?n(new Error(`Unsuccessful HTTP response: ${r.statusCode}`)):t()});s.on("error",n),s.write(e),s.end()}catch(s){n(s)}})}function F(o,...e){console.log(o,...e)}function x(o,e){return async(...t)=>{let n=o.attempts,s=o.sleep;for(;;)try{return await e(...t)}catch(r){if(n--<=0)throw r;await N(Math.floor(Math.random()*s)),s*=2}}}async function N(o){return new Promise(e=>setTimeout(e,o))}var h="aws-cdk:auto-delete-underlying-resources",H=new c.LambdaClient({}),U=new u.SyntheticsClient({}),_=C(E);async function E(o){switch(o.RequestType){case"Create":return{PhyscialResourceId:o.ResourceProperties?.CanaryName};case"Update":return{PhysicalResourceId:(await k(o)).PhysicalResourceId};case"Delete":return q(o.ResourceProperties?.CanaryName)}}async function k(o){return{PhysicalResourceId:o.ResourceProperties?.CanaryName}}async function q(o){if(console.log(`Deleting lambda function associated with ${o}`),!o)throw new Error("No CanaryName was provided.");try{let e=await U.send(new u.GetCanaryCommand({Name:o}));if(e.Canary===void 0||e.Canary.Id===void 0)return;if(e.Canary.EngineArn===void 0)return;if(!O(e.Canary.Tags)){console.log(`Canary does not have '${h}' tag, skipping deletion.`);return}let t=e.Canary.EngineArn.split(":");t.at(-1)?.includes(e.Canary.Id)||t.pop();let n=t.join(":");console.log(`Deleting lambda ${n}`),await H.send(new c.DeleteFunctionCommand({FunctionName:n}))}catch(e){if(e.name!=="ResourceNotFoundException")throw e}}function O(o){return o?Object.keys(o).some(e=>e===h&&o[e]==="true"):!1}0&&(module.exports={autoDeleteHandler,handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.assets.json new file mode 100644 index 0000000000000..0dbbb97843db7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.assets.json @@ -0,0 +1,45 @@ +{ + "version": "36.0.0", + "files": { + "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61": { + "source": { + "path": "asset.44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d": { + "source": { + "path": "asset.d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "f6aad262db732f8a3d154c577c54fbd4f8d3a3ac9cf0ab7bcf5aa7bcc9f79f50": { + "source": { + "path": "canary-artifact-s3-encryption.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f6aad262db732f8a3d154c577c54fbd4f8d3a3ac9cf0ab7bcf5aa7bcc9f79f50.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.template.json new file mode 100644 index 0000000000000..99f1dca59faf3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/canary-artifact-s3-encryption.template.json @@ -0,0 +1,1043 @@ +{ + "Resources": { + "MyTestBucket81062429": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "MyTestBucketPolicyE11AF29F": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "MyTestBucket81062429" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "MyTestBucketAutoDeleteObjectsCustomResource1E1AC890": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "MyTestBucket81062429" + } + }, + "DependsOn": [ + "MyTestBucketPolicyE11AF29F" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "44e9c4d7a5d3fd2d677e1a7e416b2b56f6b0104bd5eff9cac5557b4c65a9dc61.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": { + "Fn::FindInMap": [ + "LatestNodeRuntimeMap", + { + "Ref": "AWS::Region" + }, + "value" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "MyTestBucket81062429" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + }, + "CanarySseS3ServiceRoleC3DFF4A1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "canaryPolicy" + } + ] + } + }, + "CanarySseS377E9DBF2": { + "Type": "AWS::Synthetics::Canary", + "Properties": { + "ArtifactConfig": { + "S3Encryption": { + "EncryptionMode": "SSE_S3" + } + }, + "ArtifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "Code": { + "Handler": "index.handler", + "Script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "CanarySseS3ServiceRoleC3DFF4A1", + "Arn" + ] + }, + "Name": "canaryartifactseee471", + "RuntimeVersion": "syn-nodejs-puppeteer-7.0", + "Schedule": { + "DurationInSeconds": "0", + "Expression": "rate(1 minute)" + }, + "StartCanaryAfterCreation": true, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-underlying-resources", + "Value": "true" + } + ] + } + }, + "CanarySseS3AutoDeleteUnderlyingResourcesCustomResource683951EB": { + "Type": "Custom::SyntheticsAutoDeleteUnderlyingResources", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderHandler26776D4E", + "Arn" + ] + }, + "CanaryName": { + "Ref": "CanarySseS377E9DBF2" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderRole2D11A112": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "lambda:DeleteFunction" + ], + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":lambda:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":function:cwsyn-*" + ] + ] + } + }, + { + "Effect": "Allow", + "Action": [ + "synthetics:GetCanary" + ], + "Resource": "*" + } + ] + } + } + ] + } + }, + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderHandler26776D4E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "d57a897c2081bda5ce88819548c8b944dff49e721e1f7f7e9e3dd8323e6ccb0d.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderRole2D11A112", + "Arn" + ] + }, + "Runtime": { + "Fn::FindInMap": [ + "LatestNodeRuntimeMap", + { + "Ref": "AWS::Region" + }, + "value" + ] + }, + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting underlying resources created by ", + { + "Ref": "CanarySseS377E9DBF2" + }, + "." + ] + ] + } + }, + "DependsOn": [ + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderRole2D11A112" + ] + }, + "CanarySseKmsWithoutKeySettingServiceRole50435BBC": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "canaryPolicy" + } + ] + } + }, + "CanarySseKmsWithoutKeySettingServiceRoleDefaultPolicyAC49E578": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingKey11BDE817", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CanarySseKmsWithoutKeySettingServiceRoleDefaultPolicyAC49E578", + "Roles": [ + { + "Ref": "CanarySseKmsWithoutKeySettingServiceRole50435BBC" + } + ] + } + }, + "CanarySseKmsWithoutKeySettingKey11BDE817": { + "Type": "AWS::KMS::Key", + "Properties": { + "Description": "Created by canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting", + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "CanarySseKmsWithoutKeySettingD8C26A32": { + "Type": "AWS::Synthetics::Canary", + "Properties": { + "ArtifactConfig": { + "S3Encryption": { + "EncryptionMode": "SSE_KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingKey11BDE817", + "Arn" + ] + } + } + }, + "ArtifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "Code": { + "Handler": "index.handler", + "Script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingServiceRole50435BBC", + "Arn" + ] + }, + "Name": "canaryartifactsefa4b6", + "RuntimeVersion": "syn-nodejs-puppeteer-7.0", + "Schedule": { + "DurationInSeconds": "0", + "Expression": "rate(1 minute)" + }, + "StartCanaryAfterCreation": true, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-underlying-resources", + "Value": "true" + } + ] + } + }, + "CanarySseKmsWithoutKeySettingAutoDeleteUnderlyingResourcesCustomResourceB288EFE0": { + "Type": "Custom::SyntheticsAutoDeleteUnderlyingResources", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderHandler26776D4E", + "Arn" + ] + }, + "CanaryName": { + "Ref": "CanarySseKmsWithoutKeySettingD8C26A32" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "Key961B73FD": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CanarySseKmsWithServiceRoleDE325788": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "Policies": [ + { + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "canaryPolicy" + } + ] + } + }, + "CanarySseKmsWithServiceRoleDefaultPolicyBD214DF4": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CanarySseKmsWithServiceRoleDefaultPolicyBD214DF4", + "Roles": [ + { + "Ref": "CanarySseKmsWithServiceRoleDE325788" + } + ] + } + }, + "CanarySseKmsWith1F191227": { + "Type": "AWS::Synthetics::Canary", + "Properties": { + "ArtifactConfig": { + "S3Encryption": { + "EncryptionMode": "SSE_KMS", + "KmsKeyArn": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + } + }, + "ArtifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "Code": { + "Handler": "index.handler", + "Script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "ExecutionRoleArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithServiceRoleDE325788", + "Arn" + ] + }, + "Name": "canaryartifacts4881f3", + "RuntimeVersion": "syn-nodejs-puppeteer-7.0", + "Schedule": { + "DurationInSeconds": "0", + "Expression": "rate(1 minute)" + }, + "StartCanaryAfterCreation": true, + "Tags": [ + { + "Key": "aws-cdk:auto-delete-underlying-resources", + "Value": "true" + } + ] + } + }, + "CanarySseKmsWithAutoDeleteUnderlyingResourcesCustomResource4F111E39": { + "Type": "Custom::SyntheticsAutoDeleteUnderlyingResources", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderHandler26776D4E", + "Arn" + ] + }, + "CanaryName": { + "Ref": "CanarySseKmsWith1F191227" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Mappings": { + "LatestNodeRuntimeMap": { + "af-south-1": { + "value": "nodejs20.x" + }, + "ap-east-1": { + "value": "nodejs20.x" + }, + "ap-northeast-1": { + "value": "nodejs20.x" + }, + "ap-northeast-2": { + "value": "nodejs20.x" + }, + "ap-northeast-3": { + "value": "nodejs20.x" + }, + "ap-south-1": { + "value": "nodejs20.x" + }, + "ap-south-2": { + "value": "nodejs20.x" + }, + "ap-southeast-1": { + "value": "nodejs20.x" + }, + "ap-southeast-2": { + "value": "nodejs20.x" + }, + "ap-southeast-3": { + "value": "nodejs20.x" + }, + "ap-southeast-4": { + "value": "nodejs20.x" + }, + "ap-southeast-5": { + "value": "nodejs20.x" + }, + "ap-southeast-7": { + "value": "nodejs20.x" + }, + "ca-central-1": { + "value": "nodejs20.x" + }, + "ca-west-1": { + "value": "nodejs20.x" + }, + "cn-north-1": { + "value": "nodejs18.x" + }, + "cn-northwest-1": { + "value": "nodejs18.x" + }, + "eu-central-1": { + "value": "nodejs20.x" + }, + "eu-central-2": { + "value": "nodejs20.x" + }, + "eu-isoe-west-1": { + "value": "nodejs18.x" + }, + "eu-north-1": { + "value": "nodejs20.x" + }, + "eu-south-1": { + "value": "nodejs20.x" + }, + "eu-south-2": { + "value": "nodejs20.x" + }, + "eu-west-1": { + "value": "nodejs20.x" + }, + "eu-west-2": { + "value": "nodejs20.x" + }, + "eu-west-3": { + "value": "nodejs20.x" + }, + "il-central-1": { + "value": "nodejs20.x" + }, + "me-central-1": { + "value": "nodejs20.x" + }, + "me-south-1": { + "value": "nodejs20.x" + }, + "mx-central-1": { + "value": "nodejs20.x" + }, + "sa-east-1": { + "value": "nodejs20.x" + }, + "us-east-1": { + "value": "nodejs20.x" + }, + "us-east-2": { + "value": "nodejs20.x" + }, + "us-gov-east-1": { + "value": "nodejs18.x" + }, + "us-gov-west-1": { + "value": "nodejs18.x" + }, + "us-iso-east-1": { + "value": "nodejs18.x" + }, + "us-iso-west-1": { + "value": "nodejs18.x" + }, + "us-isob-east-1": { + "value": "nodejs18.x" + }, + "us-west-1": { + "value": "nodejs20.x" + }, + "us-west-2": { + "value": "nodejs20.x" + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/integ.json new file mode 100644 index 0000000000000..0546bb1684300 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "36.0.0", + "testCases": { + "IntegCanaryTest/DefaultTest": { + "stacks": [ + "canary-artifact-s3-encryption" + ], + "assertionStack": "IntegCanaryTest/DefaultTest/DeployAssert", + "assertionStackName": "IntegCanaryTestDefaultTestDeployAssert3AD5A094" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/manifest.json new file mode 100644 index 0000000000000..355bcc7683236 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/manifest.json @@ -0,0 +1,233 @@ +{ + "version": "36.0.0", + "artifacts": { + "canary-artifact-s3-encryption.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "canary-artifact-s3-encryption.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "canary-artifact-s3-encryption": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "canary-artifact-s3-encryption.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f6aad262db732f8a3d154c577c54fbd4f8d3a3ac9cf0ab7bcf5aa7bcc9f79f50.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "canary-artifact-s3-encryption.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "canary-artifact-s3-encryption.assets" + ], + "metadata": { + "/canary-artifact-s3-encryption/MyTestBucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTestBucket81062429" + } + ], + "/canary-artifact-s3-encryption/MyTestBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTestBucketPolicyE11AF29F" + } + ], + "/canary-artifact-s3-encryption/MyTestBucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "MyTestBucketAutoDeleteObjectsCustomResource1E1AC890" + } + ], + "/canary-artifact-s3-encryption/LatestNodeRuntimeMap": [ + { + "type": "aws:cdk:logicalId", + "data": "LatestNodeRuntimeMap" + } + ], + "/canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/canary-artifact-s3-encryption/CanarySseS3/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseS3ServiceRoleC3DFF4A1" + } + ], + "/canary-artifact-s3-encryption/CanarySseS3/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseS377E9DBF2" + } + ], + "/canary-artifact-s3-encryption/CanarySseS3/AutoDeleteUnderlyingResourcesCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseS3AutoDeleteUnderlyingResourcesCustomResource683951EB" + } + ], + "/canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderRole2D11A112" + } + ], + "/canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomSyntheticsAutoDeleteUnderlyingResourcesCustomResourceProviderHandler26776D4E" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithoutKeySettingServiceRole50435BBC" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithoutKeySettingServiceRoleDefaultPolicyAC49E578" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/Key/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithoutKeySettingKey11BDE817" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithoutKeySettingD8C26A32" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/AutoDeleteUnderlyingResourcesCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithoutKeySettingAutoDeleteUnderlyingResourcesCustomResourceB288EFE0" + } + ], + "/canary-artifact-s3-encryption/Key/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Key961B73FD" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithServiceRoleDE325788" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithServiceRoleDefaultPolicyBD214DF4" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWith/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWith1F191227" + } + ], + "/canary-artifact-s3-encryption/CanarySseKmsWith/AutoDeleteUnderlyingResourcesCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "CanarySseKmsWithAutoDeleteUnderlyingResourcesCustomResource4F111E39" + } + ], + "/canary-artifact-s3-encryption/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/canary-artifact-s3-encryption/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "canary-artifact-s3-encryption" + }, + "IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegCanaryTestDefaultTestDeployAssert3AD5A094": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegCanaryTestDefaultTestDeployAssert3AD5A094.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "IntegCanaryTestDefaultTestDeployAssert3AD5A094.assets" + ], + "metadata": { + "/IntegCanaryTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/IntegCanaryTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "IntegCanaryTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/tree.json new file mode 100644 index 0000000000000..4cfdc833562e1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.js.snapshot/tree.json @@ -0,0 +1,1122 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "canary-artifact-s3-encryption": { + "id": "canary-artifact-s3-encryption", + "path": "canary-artifact-s3-encryption", + "children": { + "MyTestBucket": { + "id": "MyTestBucket", + "path": "canary-artifact-s3-encryption/MyTestBucket", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/MyTestBucket/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::Bucket", + "aws:cdk:cloudformation:props": { + "tags": [ + { + "key": "aws-cdk:auto-delete-objects", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucket", + "version": "0.0.0" + } + }, + "Policy": { + "id": "Policy", + "path": "canary-artifact-s3-encryption/MyTestBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/MyTestBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "MyTestBucket81062429" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketPolicy", + "version": "0.0.0" + } + }, + "AutoDeleteObjectsCustomResource": { + "id": "AutoDeleteObjectsCustomResource", + "path": "canary-artifact-s3-encryption/MyTestBucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "canary-artifact-s3-encryption/MyTestBucket/AutoDeleteObjectsCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.Bucket", + "version": "0.0.0" + } + }, + "LatestNodeRuntimeMap": { + "id": "LatestNodeRuntimeMap", + "path": "canary-artifact-s3-encryption/LatestNodeRuntimeMap", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnMapping", + "version": "0.0.0" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "canary-artifact-s3-encryption/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "CanarySseS3": { + "id": "CanarySseS3", + "path": "canary-artifact-s3-encryption/CanarySseS3", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseS3/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseS3/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseS3/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "policies": [ + { + "policyName": "canaryPolicy", + "policyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseS3/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Synthetics::Canary", + "aws:cdk:cloudformation:props": { + "artifactConfig": { + "s3Encryption": { + "encryptionMode": "SSE_S3" + } + }, + "artifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "code": { + "handler": "index.handler", + "script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "executionRoleArn": { + "Fn::GetAtt": [ + "CanarySseS3ServiceRoleC3DFF4A1", + "Arn" + ] + }, + "name": "canaryartifactseee471", + "runtimeVersion": "syn-nodejs-puppeteer-7.0", + "schedule": { + "durationInSeconds": "0", + "expression": "rate(1 minute)" + }, + "startCanaryAfterCreation": true, + "tags": [ + { + "key": "aws-cdk:auto-delete-underlying-resources", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.CfnCanary", + "version": "0.0.0" + } + }, + "AutoDeleteUnderlyingResourcesCustomResource": { + "id": "AutoDeleteUnderlyingResourcesCustomResource", + "path": "canary-artifact-s3-encryption/CanarySseS3/AutoDeleteUnderlyingResourcesCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "canary-artifact-s3-encryption/CanarySseS3/AutoDeleteUnderlyingResourcesCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.Canary", + "version": "0.0.0" + } + }, + "Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider": { + "id": "Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider", + "path": "canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "canary-artifact-s3-encryption/Custom::SyntheticsAutoDeleteUnderlyingResourcesCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "CanarySseKmsWithoutKeySetting": { + "id": "CanarySseKmsWithoutKeySetting", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "policies": [ + { + "policyName": "canaryPolicy", + "policyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingKey11BDE817", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "CanarySseKmsWithoutKeySettingServiceRoleDefaultPolicyAC49E578", + "roles": [ + { + "Ref": "CanarySseKmsWithoutKeySettingServiceRole50435BBC" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Key": { + "id": "Key", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/Key", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/Key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "description": "Created by canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting", + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.Key", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Synthetics::Canary", + "aws:cdk:cloudformation:props": { + "artifactConfig": { + "s3Encryption": { + "encryptionMode": "SSE_KMS", + "kmsKeyArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingKey11BDE817", + "Arn" + ] + } + } + }, + "artifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "code": { + "handler": "index.handler", + "script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "executionRoleArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithoutKeySettingServiceRole50435BBC", + "Arn" + ] + }, + "name": "canaryartifactsefa4b6", + "runtimeVersion": "syn-nodejs-puppeteer-7.0", + "schedule": { + "durationInSeconds": "0", + "expression": "rate(1 minute)" + }, + "startCanaryAfterCreation": true, + "tags": [ + { + "key": "aws-cdk:auto-delete-underlying-resources", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.CfnCanary", + "version": "0.0.0" + } + }, + "AutoDeleteUnderlyingResourcesCustomResource": { + "id": "AutoDeleteUnderlyingResourcesCustomResource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/AutoDeleteUnderlyingResourcesCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "canary-artifact-s3-encryption/CanarySseKmsWithoutKeySetting/AutoDeleteUnderlyingResourcesCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.Canary", + "version": "0.0.0" + } + }, + "Key": { + "id": "Key", + "path": "canary-artifact-s3-encryption/Key", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/Key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kms.Key", + "version": "0.0.0" + } + }, + "CanarySseKmsWith": { + "id": "CanarySseKmsWith", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "policies": [ + { + "policyName": "canaryPolicy", + "policyDocument": { + "Statement": [ + { + "Action": "s3:ListAllMyBuckets", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "s3:GetBucketLocation", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + } + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyTestBucket81062429", + "Arn" + ] + }, + "/integ/*" + ] + ] + } + }, + { + "Action": "cloudwatch:PutMetricData", + "Condition": { + "StringEquals": { + "cloudwatch:namespace": "CloudWatchSynthetics" + } + }, + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ], + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":logs:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":log-group:/aws/lambda/cwsyn-*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey*", + "kms:ReEncrypt*" + ], + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "CanarySseKmsWithServiceRoleDefaultPolicyBD214DF4", + "roles": [ + { + "Ref": "CanarySseKmsWithServiceRoleDE325788" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Synthetics::Canary", + "aws:cdk:cloudformation:props": { + "artifactConfig": { + "s3Encryption": { + "encryptionMode": "SSE_KMS", + "kmsKeyArn": { + "Fn::GetAtt": [ + "Key961B73FD", + "Arn" + ] + } + } + }, + "artifactS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Ref": "MyTestBucket81062429" + }, + "/integ" + ] + ] + }, + "code": { + "handler": "index.handler", + "script": "\n exports.handler = async () => {\n console.log('hello world');\n };" + }, + "executionRoleArn": { + "Fn::GetAtt": [ + "CanarySseKmsWithServiceRoleDE325788", + "Arn" + ] + }, + "name": "canaryartifacts4881f3", + "runtimeVersion": "syn-nodejs-puppeteer-7.0", + "schedule": { + "durationInSeconds": "0", + "expression": "rate(1 minute)" + }, + "startCanaryAfterCreation": true, + "tags": [ + { + "key": "aws-cdk:auto-delete-underlying-resources", + "value": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.CfnCanary", + "version": "0.0.0" + } + }, + "AutoDeleteUnderlyingResourcesCustomResource": { + "id": "AutoDeleteUnderlyingResourcesCustomResource", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/AutoDeleteUnderlyingResourcesCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "canary-artifact-s3-encryption/CanarySseKmsWith/AutoDeleteUnderlyingResourcesCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_synthetics.Canary", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "canary-artifact-s3-encryption/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "canary-artifact-s3-encryption/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "IntegCanaryTest": { + "id": "IntegCanaryTest", + "path": "IntegCanaryTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "IntegCanaryTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "IntegCanaryTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "IntegCanaryTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "IntegCanaryTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "IntegCanaryTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.ts new file mode 100644 index 0000000000000..bacc2cc1492b1 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-synthetics/test/integ.canary-artifact-s3-encryption.ts @@ -0,0 +1,68 @@ +/// !cdk-integ canary-one +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as cdk from 'aws-cdk-lib/core'; +import { ArtifactsEncryptionMode, Canary, Cleanup, Code, Runtime, Schedule, Test } from 'aws-cdk-lib/aws-synthetics'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { RemovalPolicy } from 'aws-cdk-lib'; +import { Key } from 'aws-cdk-lib/aws-kms'; + +const app = new cdk.App(); +const stack = new cdk.Stack(app, 'canary-artifact-s3-encryption'); + +const bucket = new s3.Bucket(stack, 'MyTestBucket', { + removalPolicy: RemovalPolicy.DESTROY, + autoDeleteObjects: true, +}); +const prefix = 'integ'; + +new Canary(stack, 'CanarySseS3', { + test: Test.custom({ + handler: 'index.handler', + code: Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + schedule: Schedule.rate(cdk.Duration.minutes(1)), + artifactsBucketLocation: { bucket, prefix }, + runtime: Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + cleanup: Cleanup.LAMBDA, + artifactS3EncryptionMode: ArtifactsEncryptionMode.S3_MANAGED, +}); + +new Canary(stack, 'CanarySseKmsWithoutKeySetting', { + test: Test.custom({ + handler: 'index.handler', + code: Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + schedule: Schedule.rate(cdk.Duration.minutes(1)), + artifactsBucketLocation: { bucket, prefix }, + runtime: Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + cleanup: Cleanup.LAMBDA, + artifactS3EncryptionMode: ArtifactsEncryptionMode.KMS, +}); + +const encryptKey = new Key(stack, 'Key', { removalPolicy: RemovalPolicy.DESTROY }); + +new Canary(stack, 'CanarySseKmsWith', { + test: Test.custom({ + handler: 'index.handler', + code: Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + schedule: Schedule.rate(cdk.Duration.minutes(1)), + artifactsBucketLocation: { bucket, prefix }, + runtime: Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + cleanup: Cleanup.LAMBDA, + artifactS3EncryptionMode: ArtifactsEncryptionMode.KMS, + artifactS3KmsKey: encryptKey, +}); + +new IntegTest(app, 'IntegCanaryTest', { + testCases: [stack], +}); diff --git a/packages/@aws-cdk/aws-scheduler-alpha/README.md b/packages/@aws-cdk/aws-scheduler-alpha/README.md index 6dc21f3098c46..1babcd6e8671b 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/README.md +++ b/packages/@aws-cdk/aws-scheduler-alpha/README.md @@ -16,18 +16,18 @@ [Amazon EventBridge Scheduler](https://aws.amazon.com/blogs/compute/introducing-amazon-eventbridge-scheduler/) is a feature from Amazon EventBridge -that allows you to create, run, and manage scheduled tasks at scale. With EventBridge Scheduler, you can schedule one-time or recurrently tens +that allows you to create, run, and manage scheduled tasks at scale. With EventBridge Scheduler, you can schedule one-time or recurrently tens of millions of tasks across many AWS services without provisioning or managing underlying infrastructure. -1. **Schedule**: A schedule is the main resource you create, configure, and manage using Amazon EventBridge Scheduler. Every schedule has a schedule expression that determines when, and with what frequency, the schedule runs. EventBridge Scheduler supports three types of schedules: rate, cron, and one-time schedules. When you create a schedule, you configure a target for the schedule to invoke. -2. **Targets**: A target is an API operation that EventBridge Scheduler calls on your behalf every time your schedule runs. EventBridge Scheduler -supports two types of targets: templated targets and universal targets. Templated targets invoke common API operations across a core groups of -services. For example, EventBridge Scheduler supports templated targets for invoking AWS Lambda Function or starting execution of Step Function state +1. **Schedule**: A schedule is the main resource you create, configure, and manage using Amazon EventBridge Scheduler. Every schedule has a schedule expression that determines when, and with what frequency, the schedule runs. EventBridge Scheduler supports three types of schedules: rate, cron, and one-time schedules. When you create a schedule, you configure a target for the schedule to invoke. +2. **Target**: A target is an API operation that EventBridge Scheduler calls on your behalf every time your schedule runs. EventBridge Scheduler +supports two types of targets: templated targets and universal targets. Templated targets invoke common API operations across a core groups of +services. For example, EventBridge Scheduler supports templated targets for invoking AWS Lambda Function or starting execution of Step Functions state machine. For API operations that are not supported by templated targets you can use customizable universal targets. Universal targets support calling more than 6,000 API operations across over 270 AWS services. 3. **Schedule Group**: A schedule group is an Amazon EventBridge Scheduler resource that you use to organize your schedules. Your AWS account comes -with a default scheduler group. A new schedule will always be added to a scheduling group. If you do not provide a scheduling group to add to, it -will be added to the default scheduling group. You can create up to 500 schedule groups in your AWS account. Groups can be used to organize the +with a default scheduler group. A new schedule will always be added to a scheduling group. If you do not provide a scheduling group to add to, it +will be added to the default scheduling group. You can create up to 500 schedule groups in your AWS account. Groups can be used to organize the schedules logically, access the schedule metrics and manage permissions at group granularity (see details below). Scheduling groups support tagging: with EventBridge Scheduler, you apply tags to schedule groups, not to individual schedules to organize your resources. @@ -35,7 +35,7 @@ This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aw > This module is in active development. Some features may not be implemented yet. -## Defining a schedule +## Defining a schedule ```ts declare const fn: lambda.Function; @@ -55,10 +55,12 @@ const schedule = new Schedule(this, 'Schedule', { ### Schedule Expressions -You can choose from three schedule types when configuring your schedule: rate-based, cron-based, and one-time schedules. +You can choose from three schedule types when configuring your schedule: rate-based, cron-based, and one-time schedules. -Both rate-based and cron-based schedules are recurring schedules. You can configure each recurring schedule type using a schedule expression. For -cron-based schedule you can specify a time zone in which EventBridge Scheduler evaluates the expression. +Both rate-based and cron-based schedules are recurring schedules. You can configure each recurring schedule type using a schedule expression. + +For +cron-based schedules you can specify a time zone in which EventBridge Scheduler evaluates the expression. ```ts declare const target: targets.LambdaInvoke; @@ -82,7 +84,7 @@ const cronBasedSchedule = new Schedule(this, 'Schedule', { }); ``` -A one-time schedule is a schedule that invokes a target only once. You configure a one-time schedule when by specifying the time of the day, date, +A one-time schedule is a schedule that invokes a target only once. You configure a one-time schedule by specifying the time of day, date, and time zone in which EventBridge Scheduler evaluates the schedule. ```ts @@ -100,13 +102,13 @@ const oneTimeSchedule = new Schedule(this, 'Schedule', { ### Grouping Schedules -Your AWS account comes with a default scheduler group. You can access default group in CDK with: +Your AWS account comes with a default scheduler group. You can access the default group in CDK with: ```ts const defaultGroup = Group.fromDefaultGroup(this, "DefaultGroup"); ``` -If not specified a schedule is added to the default group. However, you can also add the schedule to a custom scheduling group managed by you: +You can add a schedule to a custom scheduling group managed by you. If a custom group is not specified, the schedule is added to the default group. ```ts declare const target: targets.LambdaInvoke; @@ -154,13 +156,18 @@ new Schedule(this, 'Schedule', { ## Scheduler Targets The `@aws-cdk/aws-scheduler-targets-alpha` module includes classes that implement the `IScheduleTarget` interface for -various AWS services. EventBridge Scheduler supports two types of targets: templated targets invoke common API -operations across a core groups of services, and customizable universal targets that you can use to call more -than 6,000 operations across over 270 services. A list of supported targets can be found at `@aws-cdk/aws-scheduler-targets-alpha`. +various AWS services. EventBridge Scheduler supports two types of targets: + +1. **Templated targets** which invoke common API +operations across a core groups of services, and +2. **Universal targets** that you can customize to call more +than 6,000 operations across over 270 services. + +A list of supported targets can be found at `@aws-cdk/aws-scheduler-targets-alpha`. -### Input +### Input -Target can be invoked with a custom input. Class `ScheduleTargetInput` supports free form text input and JSON-formatted object input: +Targets can be invoked with a custom input. The `ScheduleTargetInput`class supports free-form text input and JSON-formatted object input: ```ts const input = ScheduleTargetInput.fromObject({ @@ -182,14 +189,14 @@ const text = `Attempt number: ${ContextAttribute.attemptNumber}`; const input = ScheduleTargetInput.fromText(text); ``` -### Specifying Execution Role +### Specifying an execution role An execution role is an IAM role that EventBridge Scheduler assumes in order to interact with other AWS services on your behalf. The classes for templated schedule targets automatically create an IAM role with all the minimum necessary permissions to interact with the templated target. If you wish you may specify your own IAM role, then the templated targets -will grant minimal required permissions. For example: for invoking Lambda function target `LambdaInvoke` will grant -execution IAM role permission to `lambda:InvokeFunction`. +will grant minimal required permissions. For example, the target `LambdaInvoke` will grant the +IAM execution role `lambda:InvokeFunction` permission to invoke the Lambda function. ```ts declare const fn: lambda.Function; @@ -206,14 +213,14 @@ const target = new targets.LambdaInvoke(fn, { }); ``` -### Specifying Encryption key +### Specifying an encryption key -EventBridge Scheduler integrates with AWS Key Management Service (AWS KMS) to encrypt and decrypt your data using an AWS KMS key. +EventBridge Scheduler integrates with AWS Key Management Service (AWS KMS) to encrypt and decrypt your data using an AWS KMS key. EventBridge Scheduler supports two types of KMS keys: AWS owned keys, and customer managed keys. -By default, all events in Scheduler are encrypted with a key that AWS owns and manages. -If you wish you can also provide a customer managed key to encrypt and decrypt the payload that your schedule delivers to its target using the `key` property. -Target classes will automatically add AWS KMS Decrypt permission to your schedule's execution role permissions policy. +By default, all events in Scheduler are encrypted with a key that AWS owns and manages. +If you wish you can also provide a customer managed key to encrypt and decrypt the payload that your schedule delivers to its target using the `key` property. +Target classes will automatically add AWS `kms:Decrypt` permission to your schedule's execution role permissions policy. ```ts declare const key: kms.Key; @@ -251,7 +258,7 @@ const schedule = new Schedule(this, 'Schedule', { > Visit [Configuring flexible time windows](https://docs.aws.amazon.com/scheduler/latest/UserGuide/managing-schedule-flexible-time-windows.html) for more details. -## Error-handling +## Error-handling You can configure how your schedule handles failures, when EventBridge Scheduler is unable to deliver an event successfully to a target, by using two primary mechanisms: a retry policy, and a dead-letter queue (DLQ). @@ -280,10 +287,10 @@ const target = new targets.LambdaInvoke(fn, { ## Monitoring -You can monitor Amazon EventBridge Scheduler using CloudWatch, which collects raw data -and processes it into readable, near real-time metrics. EventBridge Scheduler emits +You can monitor Amazon EventBridge Scheduler using CloudWatch, which collects raw data +and processes it into readable, near real-time metrics. EventBridge Scheduler emits a set of metrics for all schedules, and an additional set of metrics for schedules that -have an associated dead-letter queue (DLQ). If you configure a DLQ for your schedule, +have an associated dead-letter queue (DLQ). If you configure a DLQ for your schedule, EventBridge Scheduler publishes additional metrics when your schedule exhausts its retry policy. ### Metrics for all schedules diff --git a/packages/@aws-cdk/aws-scheduler-alpha/lib/group.ts b/packages/@aws-cdk/aws-scheduler-alpha/lib/group.ts index 3bd5f5809ec13..7f737a91eca2e 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/lib/group.ts +++ b/packages/@aws-cdk/aws-scheduler-alpha/lib/group.ts @@ -202,7 +202,7 @@ abstract class GroupBase extends Resource implements IGroup { * * @default - sum over 5 minutes */ - metricSentToDLQ(props?: cloudwatch.MetricOptions): cloudwatch.Metric { + public metricSentToDLQ(props?: cloudwatch.MetricOptions): cloudwatch.Metric { return this.metric('InvocationsSentToDeadLetterCount', props); } diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/group.test.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/group.test.ts index 3f59a10903c4b..e0de97b02ce30 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/test/group.test.ts +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/group.test.ts @@ -279,20 +279,33 @@ describe('Schedule Group', () => { }, }); }); +}); - test('Target Error Metrics', () => { +describe('Schedule Group Metrics', () => { + test.each([ + ['metricTargetErrors', 'TargetErrorCount'], + ['metricThrottled', 'InvocationThrottleCount'], + ['metricAttempts', 'InvocationAttemptCount'], + ['metricTargetThrottled', 'TargetErrorThrottledCount'], + ['metricDropped', 'InvocationDroppedCount'], + ['metricSentToDLQ', 'InvocationsSentToDeadLetterCount'], + ['metricSentToDLQTruncated', 'InvocationsSentToDeadLetterCount_Truncated_MessageSizeExceeded'], + ])('calling %s creates alarm for %s metric', (metricMethodName, metricName) => { // GIVEN + const app = new App(); const props: GroupProps = { groupName: 'MyGroup', }; + const stack = new Stack(app, 'Stack', { env: { region: 'us-east-1', account: '123456789012' } }); const group = new Group(stack, 'TestGroup', props); // WHEN - const metricTargetErrors = group.metricTargetErrors({ + const metricMethod = (group as any)[metricMethodName].bind(group); // Get the method dynamically + const metricTargetErrors = metricMethod({ period: Duration.minutes(1), }); - new cw.Alarm(stack, 'GroupTargetErrorAlarm', { + new cw.Alarm(stack, `Group${metricName}Alarm`, { metric: metricTargetErrors, evaluationPeriods: 1, threshold: 1, @@ -306,7 +319,41 @@ describe('Schedule Group', () => { Value: 'MyGroup', }), ]), - MetricName: 'TargetErrorCount', + MetricName: metricName, + Namespace: 'AWS/Scheduler', + }); + }); + + test('Invocations Failed to Deliver to DLQ Metrics', () => { + // GIVEN + const app = new App(); + const props: GroupProps = { + groupName: 'MyGroup', + }; + const stack = new Stack(app, 'Stack', { env: { region: 'us-east-1', account: '123456789012' } }); + const group = new Group(stack, 'TestGroup', props); + const errorCode = '403'; + + // WHEN + const metricFailedToBeSentToDLQ = group.metricFailedToBeSentToDLQ(errorCode, { + period: Duration.minutes(1), + }); + + new cw.Alarm(stack, 'GroupFailedInvocationsToDLQAlarm', { + metric: metricFailedToBeSentToDLQ, + evaluationPeriods: 1, + threshold: 1, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::CloudWatch::Alarm', { + Dimensions: Match.arrayWith([ + Match.objectLike({ + Name: 'ScheduleGroup', + Value: 'MyGroup', + }), + ]), + MetricName: `InvocationsFailedToBeSentToDeadLetterCount_${errorCode}`, Namespace: 'AWS/Scheduler', }); }); diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts index d12ca608820d3..416679e2667d2 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule-expression.test.ts @@ -118,7 +118,7 @@ describe('schedule expression', () => { }); test('one-time expression with invalid date throws', () => { - expect(() => ScheduleExpression.at(new Date('13-20-1969'))).toThrowError('Invalid date'); + expect(() => ScheduleExpression.at(new Date('13-20-1969'))).toThrow('Invalid date'); }); }); @@ -130,13 +130,13 @@ describe('fractional minutes checks', () => { }); test('rate cannot be a fractional amount of minutes (defined with minutes)', () => { - expect(()=> { - ScheduleExpression.rate(Duration.minutes(5/3)); + expect(() => { + ScheduleExpression.rate(Duration.minutes(5 / 3)); }).toThrow(/must be a whole number of/); }); test('rate cannot be a fractional amount of minutes (defined with hours)', () => { - expect(()=> { + expect(() => { ScheduleExpression.rate(Duration.hours(1.03)); }).toThrow(/cannot be converted into a whole number of/); }); @@ -149,7 +149,7 @@ describe('fractional minutes checks', () => { test('rate cannot be less than 1 minute (defined with minutes as fractions)', () => { expect(() => { - ScheduleExpression.rate(Duration.minutes(1/2)); + ScheduleExpression.rate(Duration.minutes(1 / 2)); }).toThrow(/must be a whole number of/); }); @@ -164,4 +164,9 @@ describe('fractional minutes checks', () => { ScheduleExpression.rate(Duration.minutes(10)) .expressionString); }); -}); \ No newline at end of file + + test('literal schedule expression', () => { + expect('rate(1 hour)').toEqual( + ScheduleExpression.expression('rate(1 hour)').expressionString); + }); +}); diff --git a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts index 92b395f6eaf8e..6f21fa7ca3cbf 100644 --- a/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts +++ b/packages/@aws-cdk/aws-scheduler-alpha/test/schedule.test.ts @@ -64,13 +64,22 @@ describe('Schedule', () => { }); }); - test('returns metric for delivery of failed invocations to DLQ', () => { + test.each([ + ['metricAllThrottled', 'InvocationThrottleCount'], + ['metricAllErrors', 'TargetErrorCount'], + ['metricAllAttempts', 'InvocationAttemptCount'], + ['metricAllTargetThrottled', 'TargetErrorThrottledCount'], + ['metricAllDropped', 'InvocationDroppedCount'], + ['metricAllSentToDLQ', 'InvocationsSentToDeadLetterCount'], + ['metricAllSentToDLQTruncated', 'InvocationsSentToDeadLetterCount_Truncated_MessageSizeExceeded'], + + ])('returns expected metric for %s', (metricMethodName: string, metricName: string) => { // WHEN - const metric = Schedule.metricAllFailedToBeSentToDLQ(); + const metric = (Schedule as any)[metricMethodName](); // THEN expect(metric.namespace).toEqual('AWS/Scheduler'); - expect(metric.metricName).toEqual('InvocationsFailedToBeSentToDeadLetterCount'); + expect(metric.metricName).toEqual(metricName); expect(metric.dimensions).toBeUndefined(); expect(metric.statistic).toEqual('Sum'); expect(metric.period).toEqual(Duration.minutes(5)); @@ -88,6 +97,18 @@ describe('Schedule', () => { expect(metric.period).toEqual(Duration.minutes(5)); }); + test('returns metric for delivery of failed invocations to DLQ with no error code', () => { + // WHEN + const metric = Schedule.metricAllFailedToBeSentToDLQ(); + + // THEN + expect(metric.namespace).toEqual('AWS/Scheduler'); + expect(metric.metricName).toEqual('InvocationsFailedToBeSentToDeadLetterCount'); + expect(metric.dimensions).toBeUndefined(); + expect(metric.statistic).toEqual('Sum'); + expect(metric.period).toEqual(Duration.minutes(5)); + }); + test('returns metric for all errors with provided statistic and period', () => { // WHEN const metric = Schedule.metricAllErrors({ diff --git a/packages/aws-cdk-lib/aws-synthetics/README.md b/packages/aws-cdk-lib/aws-synthetics/README.md index 9fc7620f4faae..cbb111433369d 100644 --- a/packages/aws-cdk-lib/aws-synthetics/README.md +++ b/packages/aws-cdk-lib/aws-synthetics/README.md @@ -304,3 +304,29 @@ const canary = new synthetics.Canary(this, 'MyCanary', { }], }); ``` + +Canary artifacts are encrypted at rest using an AWS-managed key by default. + +You can choose the encryption options SSE-S3 or SSE-KMS by setting the `artifactS3EncryptionMode` property. + +When you use SSE-KMS, you can also supply your own external KMS key by specifying the `kmsKey` property. If you don't, a KMS key will be automatically created and associated with the canary. + +```ts +import * as kms from 'aws-cdk-lib/aws-kms'; + +const key = new kms.Key(this, 'myKey'); + +const canary = new synthetics.Canary(this, 'MyCanary', { + schedule: synthetics.Schedule.rate(Duration.minutes(5)), + test: synthetics.Test.custom({ + code: synthetics.Code.fromAsset(path.join(__dirname, 'canary')), + handler: 'index.handler', + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactsBucketLifecycleRules: [{ + expiration: Duration.days(30), + }], + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.KMS, + artifactS3KmsKey: key, +}); +``` \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts b/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts index 530050720f5dc..365b73882f810 100644 --- a/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts +++ b/packages/aws-cdk-lib/aws-synthetics/lib/canary.ts @@ -8,6 +8,7 @@ import { CfnCanary } from './synthetics.generated'; import { Metric, MetricOptions, MetricProps } from '../../aws-cloudwatch'; import * as ec2 from '../../aws-ec2'; import * as iam from '../../aws-iam'; +import * as kms from '../../aws-kms'; import * as s3 from '../../aws-s3'; import * as cdk from '../../core'; import { AutoDeleteUnderlyingResourcesProvider } from '../../custom-resource-handlers/dist/aws-synthetics/auto-delete-underlying-resources-provider.generated'; @@ -262,6 +263,39 @@ export interface CanaryProps { * @default - no rules applied to the generated bucket. */ readonly artifactsBucketLifecycleRules?: Array; + + /** + * Canary Artifacts in S3 encryption mode. + * Artifact encryption is only supported for canaries that use Synthetics runtime + * version `syn-nodejs-puppeteer-3.3` or later. + * + * @default - Artifacts are encrypted at rest using an AWS managed key. `ArtifactsEncryptionMode.KMS` is set if you specify `artifactS3KmsKey`. + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_artifact_encryption.html + */ + readonly artifactS3EncryptionMode?: ArtifactsEncryptionMode; + + /** + * The KMS key used to encrypt canary artifacts. + * + * @default - no kms key if `artifactS3EncryptionMode` is set to `S3_MANAGED`. A key will be created if one is not provided and `artifactS3EncryptionMode` is set to `KMS`. + */ + readonly artifactS3KmsKey?: kms.IKey; +} + +/** + * Encryption mode for canary artifacts. + */ +export enum ArtifactsEncryptionMode { + /** + * Server-side encryption (SSE) with an Amazon S3-managed key. + */ + S3_MANAGED = 'SSE_S3', + + /** + * Server-side encryption (SSE) with an AWS KMS customer managed key. + */ + KMS = 'SSE_KMS', } /** @@ -341,6 +375,7 @@ export class Canary extends cdk.Resource implements ec2.IConnectable { code: this.createCode(props), runConfig: this.createRunConfig(props), vpcConfig: this.createVpcConfig(props), + artifactConfig: this.createArtifactConfig(props), }); this._resource = resource; @@ -633,6 +668,43 @@ export class Canary extends cdk.Resource implements ec2.IConnectable { }; } + private createArtifactConfig(props: CanaryProps): CfnCanary.ArtifactConfigProperty | undefined { + if (!props.artifactS3EncryptionMode && !props.artifactS3KmsKey) { + return undefined; + } + + const isNodeRuntime = props.runtime.family === RuntimeFamily.NODEJS; + + if ( + props.artifactS3EncryptionMode === ArtifactsEncryptionMode.S3_MANAGED && + props.artifactS3KmsKey + ) { + throw new Error(`A customer-managed KMS key was provided, but the encryption mode is not set to SSE-KMS, got: ${props.artifactS3EncryptionMode}.`); + } + + // Only check runtime family is Node.js because versions prior to `syn-nodejs-puppeteer-3.3` are deprecated and can no longer be configured. + if (!isNodeRuntime && props.artifactS3EncryptionMode) { + throw new Error(`Artifact encryption is only supported for canaries that use Synthetics runtime version \`syn-nodejs-puppeteer-3.3\` or later, got \`${props.runtime.name}\`.`); + } + + const encryptionMode = props.artifactS3EncryptionMode ? props.artifactS3EncryptionMode : + props.artifactS3KmsKey ? ArtifactsEncryptionMode.KMS : undefined; + + let encryptionKey: kms.IKey | undefined; + if (encryptionMode === ArtifactsEncryptionMode.KMS) { + encryptionKey = props.artifactS3KmsKey ?? new kms.Key(this, 'Key', { description: `Created by ${this.node.path}` }); + } + + encryptionKey?.grantEncryptDecrypt(this.role); + + return { + s3Encryption: { + encryptionMode, + kmsKeyArn: encryptionKey?.keyArn, + }, + }; + } + /** * Creates a unique name for the canary. The generated name is the physical ID of the canary. */ diff --git a/packages/aws-cdk-lib/aws-synthetics/lib/runtime.ts b/packages/aws-cdk-lib/aws-synthetics/lib/runtime.ts index e41cfae47fa11..0454c61084942 100644 --- a/packages/aws-cdk-lib/aws-synthetics/lib/runtime.ts +++ b/packages/aws-cdk-lib/aws-synthetics/lib/runtime.ts @@ -234,6 +234,19 @@ export class Runtime { */ public static readonly SYNTHETICS_NODEJS_PUPPETEER_9_0 = new Runtime('syn-nodejs-puppeteer-9.0', RuntimeFamily.NODEJS); + /** + * `syn-nodejs-puppeteer-9.1` includes the following: + * - Lambda runtime Node.js 20.x + * - Puppeteer-core version 22.12.1 + * - Chromium version 126.0.6478.126 + * + * New Features: + * - **Bug fixes** Bug fix related to date ranges and pending requests in HAR files. + * + * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Synthetics_Library_nodejs_puppeteer.html#CloudWatch_Synthetics_runtimeversion-nodejs-puppeteer-9.1 + */ + public static readonly SYNTHETICS_NODEJS_PUPPETEER_9_1 = new Runtime('syn-nodejs-puppeteer-9.1', RuntimeFamily.NODEJS); + /** * `syn-python-selenium-1.0` includes the following: * - Lambda runtime Python 3.8 diff --git a/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts b/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts index f11f08ebe02bd..286997bd98de9 100644 --- a/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts +++ b/packages/aws-cdk-lib/aws-synthetics/test/canary.test.ts @@ -2,6 +2,7 @@ import * as path from 'path'; import { Match, Template } from '../../assertions'; import * as ec2 from '../../aws-ec2'; import * as iam from '../../aws-iam'; +import * as kms from '../../aws-kms'; import * as s3 from '../../aws-s3'; import { Duration, Lazy, Size, Stack } from '../../core'; import * as synthetics from '../lib'; @@ -933,3 +934,158 @@ describe('handler validation', () => { }).toThrow(/Canary Handler length must be between 1 and 128/); }); }); + +describe('artifact encryption test', () => { + test('SSE_S3 without a key', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.S3_MANAGED, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + ArtifactConfig: { + S3Encryption: { + EncryptionMode: 'SSE_S3', + KmsKeyArn: Match.absent(), + }, + }, + }); + }); + + test('auto-creates KMS key if encryption type is SSE_KMS but no key is provided', () => { + // GIVEN + const stack = new Stack(); + + // WHEN + const canary = new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.KMS, + }); + + Template.fromStack(stack).hasResourceProperties('AWS::KMS::Key', { + Description: 'Created by Default/Canary', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + ArtifactConfig: { + S3Encryption: { + EncryptionMode: 'SSE_KMS', + KmsKeyArn: { + 'Fn::GetAtt': [ + 'CanaryKey36A631B4', + 'Arn', + ], + }, + }, + }, + }); + }); + + test('SSE_KMS with a key', () => { + // GIVEN + const stack = new Stack(); + const key = new kms.Key(stack, 'myKey'); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline(` + exports.handler = async () => { + console.log(\'hello world\'); + };`), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.KMS, + artifactS3KmsKey: key, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + ArtifactConfig: { + S3Encryption: { + EncryptionMode: 'SSE_KMS', + KmsKeyArn: stack.resolve(key.keyArn), + }, + }, + }); + }); + + test('No artifactS3EncryptionMode setting with a key is set to SSE_KMS', () => { + // GIVEN + const stack = new Stack(); + const key = new kms.Key(stack, 'myKey'); + + // WHEN + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactS3KmsKey: key, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Synthetics::Canary', { + ArtifactConfig: { + S3Encryption: { + EncryptionMode: 'SSE_KMS', + KmsKeyArn: stack.resolve(key.keyArn), + }, + }, + }); + }); + + test('SSE-S3 with a key throws', () => { + const stack = new Stack(); + const key = new kms.Key(stack, 'myKey'); + + expect(() => { + new synthetics.Canary(stack, 'Canary', { + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('/* Synthetics handler code */'), + }), + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_7_0, + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.S3_MANAGED, + artifactS3KmsKey: key, + }); + }).toThrow('A customer-managed KMS key was provided, but the encryption mode is not set to SSE-KMS, got: SSE_S3.'); + }); + + test('Artifact encryption for non-Node.js runtime throws an error', () => { + const stack = new Stack(); + + expect(() => { + new synthetics.Canary(stack, 'Canary', { + runtime: synthetics.Runtime.SYNTHETICS_PYTHON_SELENIUM_3_0, + test: synthetics.Test.custom({ + handler: 'index.handler', + code: synthetics.Code.fromInline('# Synthetics handler code'), + }), + artifactS3EncryptionMode: synthetics.ArtifactsEncryptionMode.S3_MANAGED, + }); + }).toThrow('Artifact encryption is only supported for canaries that use Synthetics runtime version `syn-nodejs-puppeteer-3.3` or later, got `syn-python-selenium-3.0`.'); + }); +}); diff --git a/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts b/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts index 46cb62b27c218..686968298475c 100644 --- a/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts +++ b/packages/aws-cdk-lib/core/lib/stack-synthesizers/_shared.ts @@ -26,15 +26,22 @@ export function addStackArtifactToAssembly( // nested stack tags are applied at the AWS::CloudFormation::Stack resource // level and are not needed in the cloud assembly. if (Object.entries(stackTags).length > 0) { - for (const [k, v] of Object.entries(stackTags)) { - if (Token.isUnresolved(k) || Token.isUnresolved(v)) { - throw new Error(`Stack tags may not contain deploy-time values (tag: ${k}=${v}). Apply tags containing deploy-time values to resources only, avoid tagging stacks.`); - } + const resolvedTags = Object.entries(stackTags).filter(([k, v]) => !(Token.isUnresolved(k) || Token.isUnresolved(v))); + const unresolvedTags = Object.entries(stackTags).filter(([k, v]) => Token.isUnresolved(k) || Token.isUnresolved(v)); + + if (unresolvedTags.length > 0) { + const rendered = unresolvedTags.map(([k, v]) => `${Token.isUnresolved(k) ? '': k}=${Token.isUnresolved(v) ? '' : v}`).join(', '); + stack.node.addMetadata( + cxschema.ArtifactMetadataEntryType.WARN, + `Ignoring stack tags that contain deploy-time values (found: ${rendered}). Apply tags containing deploy-time values to resources only, avoid tagging stacks (for example using { excludeResourceTypes: ['aws:cdk:stack'] }).`, + ); } - stack.node.addMetadata( - cxschema.ArtifactMetadataEntryType.STACK_TAGS, - Object.entries(stackTags).map(([key, value]) => ({ Key: key, Value: value }))); + if (resolvedTags.length > 0) { + stack.node.addMetadata( + cxschema.ArtifactMetadataEntryType.STACK_TAGS, + resolvedTags.map(([key, value]) => ({ Key: key, Value: value }))); + } } const deps = [ diff --git a/packages/aws-cdk-lib/core/test/stack.test.ts b/packages/aws-cdk-lib/core/test/stack.test.ts index 0f67d1ad6ac7b..399e355063dfb 100644 --- a/packages/aws-cdk-lib/core/test/stack.test.ts +++ b/packages/aws-cdk-lib/core/test/stack.test.ts @@ -2075,7 +2075,7 @@ describe('stack', () => { expect(asm.getStackArtifact(stack2.artifactId).tags).toEqual(expected); }); - test('stack tags may not contain tokens', () => { + test('warning when stack tags contain tokens', () => { // GIVEN const app = new App({ stackTraces: false, @@ -2087,7 +2087,14 @@ describe('stack', () => { }, }); - expect(() => app.synth()).toThrow(/Stack tags may not contain deploy-time values/); + const asm = app.synth(); + const stackArtifact = asm.stacks[0]; + expect(stackArtifact.manifest.metadata?.['/stack1']).toEqual([ + { + type: 'aws:cdk:warning', + data: expect.stringContaining('Ignoring stack tags that contain deploy-time values'), + }, + ]); }); test('stack notification arns are reflected in the stack artifact properties', () => {