diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets.json new file mode 100644 index 0000000000000..8c6940690f59b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets.json @@ -0,0 +1,19 @@ +{ + "version": "34.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js new file mode 100644 index 0000000000000..9d841e15260d7 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3/index.js @@ -0,0 +1 @@ +"use strict";var C=Object.create;var i=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var L=(e,t)=>{for(var o in t)i(e,o,{get:t[o],enumerable:!0})},d=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of w(t))!A.call(e,s)&&s!==o&&i(e,s,{get:()=>t[s],enumerable:!(r=I(t,s))||r.enumerable});return e};var l=(e,t,o)=>(o=e!=null?C(P(e)):{},d(t||!e||!e.__esModule?i(o,"default",{value:e,enumerable:!0}):o,e)),k=e=>d(i({},"__esModule",{value:!0}),e);var U={};L(U,{autoDeleteHandler:()=>S,handler:()=>_});module.exports=k(U);var h=require("@aws-sdk/client-s3");var y=l(require("https")),m=l(require("url")),a={sendHttpRequest:T,log:b,includeStackTraces:!0,userHandlerIndex:"./index"},p="AWSCDK::CustomResourceProviderFramework::CREATE_FAILED",B="AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID";function R(e){return async(t,o)=>{let r={...t,ResponseURL:"..."};if(a.log(JSON.stringify(r,void 0,2)),t.RequestType==="Delete"&&t.PhysicalResourceId===p){a.log("ignoring DELETE event caused by a failed CREATE event"),await u("SUCCESS",t);return}try{let s=await e(r,o),n=D(t,s);await u("SUCCESS",n)}catch(s){let n={...t,Reason:a.includeStackTraces?s.stack:s.message};n.PhysicalResourceId||(t.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(t)}`)),await u("FAILED",n)}}}function D(e,t={}){let o=t.PhysicalResourceId??e.PhysicalResourceId??e.RequestId;if(e.RequestType==="Delete"&&o!==e.PhysicalResourceId)throw new Error(`DELETE: cannot change the physical resource ID from "${e.PhysicalResourceId}" to "${t.PhysicalResourceId}" during deletion`);return{...e,...t,PhysicalResourceId:o}}async function u(e,t){let o={Status:e,Reason:t.Reason??e,StackId:t.StackId,RequestId:t.RequestId,PhysicalResourceId:t.PhysicalResourceId||B,LogicalResourceId:t.LogicalResourceId,NoEcho:t.NoEcho,Data:t.Data};a.log("submit response to cloudformation",o);let r=JSON.stringify(o),s=m.parse(t.ResponseURL),n={hostname:s.hostname,path:s.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(r,"utf8")}};await O({attempts:5,sleep:1e3},a.sendHttpRequest)(n,r)}async function T(e,t){return new Promise((o,r)=>{try{let s=y.request(e,n=>o());s.on("error",r),s.write(t),s.end()}catch(s){r(s)}})}function b(e,...t){console.log(e,...t)}function O(e,t){return async(...o)=>{let r=e.attempts,s=e.sleep;for(;;)try{return await t(...o)}catch(n){if(r--<=0)throw n;await x(Math.floor(Math.random()*s)),s*=2}}}async function x(e){return new Promise(t=>setTimeout(t,e))}var g="aws-cdk:auto-delete-objects",H=JSON.stringify({Version:"2012-10-17",Statement:[]}),c=new h.S3({}),_=R(S);async function S(e){switch(e.RequestType){case"Create":return;case"Update":return F(e);case"Delete":return f(e.ResourceProperties?.BucketName)}}async function F(e){let t=e,o=t.OldResourceProperties?.BucketName,r=t.ResourceProperties?.BucketName;if(r!=null&&o!=null&&r!==o)return f(o)}async function N(e){try{let t=(await c.getBucketPolicy({Bucket:e}))?.Policy??H,o=JSON.parse(t);o.Statement.push({Principal:"*",Effect:"Deny",Action:["s3:PutObject"],Resource:[`arn:aws:s3:::${e}/*`]}),await c.putBucketPolicy({Bucket:e,Policy:JSON.stringify(o)})}catch(t){if(t.name==="NoSuchBucket")throw t;console.log(`Could not set new object deny policy on bucket '${e}' prior to deletion.`)}}async function E(e){let t=await c.listObjectVersions({Bucket:e}),o=[...t.Versions??[],...t.DeleteMarkers??[]];if(o.length===0)return;let r=o.map(s=>({Key:s.Key,VersionId:s.VersionId}));await c.deleteObjects({Bucket:e,Delete:{Objects:r}}),t?.IsTruncated&&await E(e)}async function f(e){if(!e)throw new Error("No BucketName was provided.");try{if(!await W(e)){console.log(`Bucket does not have '${g}' tag, skipping cleaning.`);return}await N(e),await E(e)}catch(t){if(t.name==="NoSuchBucket"){console.log(`Bucket '${e}' does not exist.`);return}throw t}}async function W(e){return(await c.getBucketTagging({Bucket:e})).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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/cdk.out new file mode 100644 index 0000000000000..2313ab5436501 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"34.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/integ.json new file mode 100644 index 0000000000000..583f343b0fa7b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/integ.json @@ -0,0 +1,12 @@ +{ + "version": "34.0.0", + "testCases": { + "apigateway-access-logs-firehose/DefaultTest": { + "stacks": [ + "test-apigateway-access-logs-firehose" + ], + "assertionStack": "apigateway-access-logs-firehose/DefaultTest/DeployAssert", + "assertionStackName": "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/manifest.json new file mode 100644 index 0000000000000..735da326c8cf2 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/manifest.json @@ -0,0 +1,191 @@ +{ + "version": "34.0.0", + "artifacts": { + "test-apigateway-access-logs-firehose.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "test-apigateway-access-logs-firehose.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "test-apigateway-access-logs-firehose": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "test-apigateway-access-logs-firehose.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}/82152e7007729e7e3c85aee383e9aa74f272a1c2b9eec64572fc7592d7303e25.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "test-apigateway-access-logs-firehose.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": [ + "test-apigateway-access-logs-firehose.assets" + ], + "metadata": { + "/test-apigateway-access-logs-firehose/Bucket/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Bucket83908E77" + } + ], + "/test-apigateway-access-logs-firehose/Bucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketPolicyE9A3008A" + } + ], + "/test-apigateway-access-logs-firehose/Bucket/AutoDeleteObjectsCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "BucketAutoDeleteObjectsCustomResourceBAFD23C2" + } + ], + "/test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + } + ], + "/test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F" + } + ], + "/test-apigateway-access-logs-firehose/Role/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Role1ABCC5F0" + } + ], + "/test-apigateway-access-logs-firehose/MyStream": [ + { + "type": "aws:cdk:logicalId", + "data": "MyStream" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApi49610EDF" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/CloudWatchRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiCloudWatchRole2BEC1A9C" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/Account": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiAccount13882D84" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/Deployment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/DeploymentStage.prod/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiDeploymentStageprodE1054AF0" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/Endpoint": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiEndpoint869ABE96" + } + ], + "/test-apigateway-access-logs-firehose/MyApi/Default/GET/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyApiGETD0C7AA0C" + } + ], + "/test-apigateway-access-logs-firehose/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/test-apigateway-access-logs-firehose/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "test-apigateway-access-logs-firehose" + }, + "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.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": [ + "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.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": [ + "apigatewayaccesslogsfirehoseDefaultTestDeployAssert6376A91B.assets" + ], + "metadata": { + "/apigateway-access-logs-firehose/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/apigateway-access-logs-firehose/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "apigateway-access-logs-firehose/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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.assets.json new file mode 100644 index 0000000000000..62f7deb0f018d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.assets.json @@ -0,0 +1,32 @@ +{ + "version": "34.0.0", + "files": { + "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3": { + "source": { + "path": "asset.2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "82152e7007729e7e3c85aee383e9aa74f272a1c2b9eec64572fc7592d7303e25": { + "source": { + "path": "test-apigateway-access-logs-firehose.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "82152e7007729e7e3c85aee383e9aa74f272a1c2b9eec64572fc7592d7303e25.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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.template.json new file mode 100644 index 0000000000000..3d3af140711ba --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/test-apigateway-access-logs-firehose.template.json @@ -0,0 +1,355 @@ +{ + "Resources": { + "Bucket83908E77": { + "Type": "AWS::S3::Bucket", + "Properties": { + "Tags": [ + { + "Key": "aws-cdk:auto-delete-objects", + "Value": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "BucketPolicyE9A3008A": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "Bucket83908E77" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "/*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "BucketAutoDeleteObjectsCustomResourceBAFD23C2": { + "Type": "Custom::S3AutoDeleteObjects", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderHandler9D90184F", + "Arn" + ] + }, + "BucketName": { + "Ref": "Bucket83908E77" + } + }, + "DependsOn": [ + "BucketPolicyE9A3008A" + ], + "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": "2ec8ad9e91dcd6e7ad6a5c84ffc6c9c05c408aca3b26ceb2816d81043e6c4dc3.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + }, + "Runtime": "nodejs18.x", + "Description": { + "Fn::Join": [ + "", + [ + "Lambda function for auto-deleting objects in ", + { + "Ref": "Bucket83908E77" + }, + " S3 bucket." + ] + ] + } + }, + "DependsOn": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092" + ] + }, + "Role1ABCC5F0": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "firehose.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "MyStream": { + "Type": "AWS::KinesisFirehose::DeliveryStream", + "Properties": { + "DeliveryStreamName": "amazon-apigateway-delivery-stream", + "S3DestinationConfiguration": { + "BucketARN": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "RoleARN": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + }, + "MyApi49610EDF": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "MyApi" + } + }, + "MyApiCloudWatchRole2BEC1A9C": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "MyApiAccount13882D84": { + "Type": "AWS::ApiGateway::Account", + "Properties": { + "CloudWatchRoleArn": { + "Fn::GetAtt": [ + "MyApiCloudWatchRole2BEC1A9C", + "Arn" + ] + } + }, + "DependsOn": [ + "MyApi49610EDF" + ], + "UpdateReplacePolicy": "Retain", + "DeletionPolicy": "Retain" + }, + "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "Automatically created by the RestApi construct", + "RestApiId": { + "Ref": "MyApi49610EDF" + } + }, + "DependsOn": [ + "MyApiGETD0C7AA0C" + ] + }, + "MyApiDeploymentStageprodE1054AF0": { + "Type": "AWS::ApiGateway::Stage", + "Properties": { + "AccessLogSetting": { + "DestinationArn": { + "Fn::GetAtt": [ + "MyStream", + "Arn" + ] + }, + "Format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"},\"clientCertPem\":\"$context.identity.clientCert.clientCertPem\",\"subjectDN\":\"$context.identity.clientCert.subjectDN\",\"issunerDN\":\"$context.identity.clientCert.issuerDN\",\"serialNumber\":\"$context.identity.clientCert.serialNumber\",\"validityNotBefore\":\"$context.identity.clientCert.validity.notBefore\",\"validityNotAfter\":\"$context.identity.clientCert.validity.notAfter\"}" + }, + "DeploymentId": { + "Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710" + }, + "RestApiId": { + "Ref": "MyApi49610EDF" + }, + "StageName": "prod" + }, + "DependsOn": [ + "MyApiAccount13882D84" + ] + }, + "MyApiGETD0C7AA0C": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "AuthorizationType": "NONE", + "HttpMethod": "GET", + "Integration": { + "Type": "MOCK" + }, + "ResourceId": { + "Fn::GetAtt": [ + "MyApi49610EDF", + "RootResourceId" + ] + }, + "RestApiId": { + "Ref": "MyApi49610EDF" + } + } + } + }, + "Outputs": { + "MyApiEndpoint869ABE96": { + "Value": { + "Fn::Join": [ + "", + [ + "https://", + { + "Ref": "MyApi49610EDF" + }, + ".execute-api.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Ref": "MyApiDeploymentStageprodE1054AF0" + }, + "/" + ] + ] + } + } + }, + "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-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/tree.json new file mode 100644 index 0000000000000..0bd7b1881b237 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.js.snapshot/tree.json @@ -0,0 +1,544 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "test-apigateway-access-logs-firehose": { + "id": "test-apigateway-access-logs-firehose", + "path": "test-apigateway-access-logs-firehose", + "children": { + "Bucket": { + "id": "Bucket", + "path": "test-apigateway-access-logs-firehose/Bucket", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/Bucket/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": "test-apigateway-access-logs-firehose/Bucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/Bucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "Bucket83908E77" + }, + "policyDocument": { + "Statement": [ + { + "Action": [ + "s3:DeleteObject*", + "s3:GetBucket*", + "s3:List*", + "s3:PutBucketPolicy" + ], + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::GetAtt": [ + "CustomS3AutoDeleteObjectsCustomResourceProviderRole3B1BD092", + "Arn" + ] + } + }, + "Resource": [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Bucket83908E77", + "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": "test-apigateway-access-logs-firehose/Bucket/AutoDeleteObjectsCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "test-apigateway-access-logs-firehose/Bucket/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" + } + }, + "Custom::S3AutoDeleteObjectsCustomResourceProvider": { + "id": "Custom::S3AutoDeleteObjectsCustomResourceProvider", + "path": "test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "test-apigateway-access-logs-firehose/Custom::S3AutoDeleteObjectsCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProvider", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "test-apigateway-access-logs-firehose/Role", + "children": { + "ImportRole": { + "id": "ImportRole", + "path": "test-apigateway-access-logs-firehose/Role/ImportRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/Role/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "firehose.amazonaws.com" + } + } + ], + "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" + } + }, + "MyStream": { + "id": "MyStream", + "path": "test-apigateway-access-logs-firehose/MyStream", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KinesisFirehose::DeliveryStream", + "aws:cdk:cloudformation:props": { + "deliveryStreamName": "amazon-apigateway-delivery-stream", + "s3DestinationConfiguration": { + "bucketArn": { + "Fn::GetAtt": [ + "Bucket83908E77", + "Arn" + ] + }, + "roleArn": { + "Fn::GetAtt": [ + "Role1ABCC5F0", + "Arn" + ] + } + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_kinesisfirehose.CfnDeliveryStream", + "version": "0.0.0" + } + }, + "MyApi": { + "id": "MyApi", + "path": "test-apigateway-access-logs-firehose/MyApi", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/MyApi/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::RestApi", + "aws:cdk:cloudformation:props": { + "name": "MyApi" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnRestApi", + "version": "0.0.0" + } + }, + "CloudWatchRole": { + "id": "CloudWatchRole", + "path": "test-apigateway-access-logs-firehose/MyApi/CloudWatchRole", + "children": { + "ImportCloudWatchRole": { + "id": "ImportCloudWatchRole", + "path": "test-apigateway-access-logs-firehose/MyApi/CloudWatchRole/ImportCloudWatchRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/MyApi/CloudWatchRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Account": { + "id": "Account", + "path": "test-apigateway-access-logs-firehose/MyApi/Account", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Account", + "aws:cdk:cloudformation:props": { + "cloudWatchRoleArn": { + "Fn::GetAtt": [ + "MyApiCloudWatchRole2BEC1A9C", + "Arn" + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnAccount", + "version": "0.0.0" + } + }, + "Deployment": { + "id": "Deployment", + "path": "test-apigateway-access-logs-firehose/MyApi/Deployment", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/MyApi/Deployment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Deployment", + "aws:cdk:cloudformation:props": { + "description": "Automatically created by the RestApi construct", + "restApiId": { + "Ref": "MyApi49610EDF" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnDeployment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Deployment", + "version": "0.0.0" + } + }, + "DeploymentStage.prod": { + "id": "DeploymentStage.prod", + "path": "test-apigateway-access-logs-firehose/MyApi/DeploymentStage.prod", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/MyApi/DeploymentStage.prod/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage", + "aws:cdk:cloudformation:props": { + "accessLogSetting": { + "destinationArn": { + "Fn::GetAtt": [ + "MyStream", + "Arn" + ] + }, + "format": "{\"requestId\":\"$context.requestId\",\"sourceIp\":\"$context.identity.sourceIp\",\"method\":\"$context.httpMethod\",\"callerAccountId\":\"$context.identity.accountId\",\"ownerAccountId\":\"$context.accountId\",\"userContext\":{\"sub\":\"$context.authorizer.claims.sub\",\"email\":\"$context.authorizer.claims.email\"},\"clientCertPem\":\"$context.identity.clientCert.clientCertPem\",\"subjectDN\":\"$context.identity.clientCert.subjectDN\",\"issunerDN\":\"$context.identity.clientCert.issuerDN\",\"serialNumber\":\"$context.identity.clientCert.serialNumber\",\"validityNotBefore\":\"$context.identity.clientCert.validity.notBefore\",\"validityNotAfter\":\"$context.identity.clientCert.validity.notAfter\"}" + }, + "deploymentId": { + "Ref": "MyApiDeploymentECB0D05E81594d6748b4b291f993111a5070d710" + }, + "restApiId": { + "Ref": "MyApi49610EDF" + }, + "stageName": "prod" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnStage", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Stage", + "version": "0.0.0" + } + }, + "Endpoint": { + "id": "Endpoint", + "path": "test-apigateway-access-logs-firehose/MyApi/Endpoint", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnOutput", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "test-apigateway-access-logs-firehose/MyApi/Default", + "children": { + "GET": { + "id": "GET", + "path": "test-apigateway-access-logs-firehose/MyApi/Default/GET", + "children": { + "Resource": { + "id": "Resource", + "path": "test-apigateway-access-logs-firehose/MyApi/Default/GET/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGateway::Method", + "aws:cdk:cloudformation:props": { + "authorizationType": "NONE", + "httpMethod": "GET", + "integration": { + "type": "MOCK" + }, + "resourceId": { + "Fn::GetAtt": [ + "MyApi49610EDF", + "RootResourceId" + ] + }, + "restApiId": { + "Ref": "MyApi49610EDF" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.CfnMethod", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.Method", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.ResourceBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigateway.RestApi", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "test-apigateway-access-logs-firehose/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "test-apigateway-access-logs-firehose/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "apigateway-access-logs-firehose": { + "id": "apigateway-access-logs-firehose", + "path": "apigateway-access-logs-firehose", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "apigateway-access-logs-firehose/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "apigateway-access-logs-firehose/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "apigateway-access-logs-firehose/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "apigateway-access-logs-firehose/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "apigateway-access-logs-firehose/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-apigateway/test/integ.restapi.access-log-firehose.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.ts new file mode 100644 index 0000000000000..b0783206bcfb0 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi.access-log-firehose.ts @@ -0,0 +1,65 @@ +import * as iam from 'aws-cdk-lib/aws-iam'; +import * as firehose from 'aws-cdk-lib/aws-kinesisfirehose'; +import * as s3 from 'aws-cdk-lib/aws-s3'; +import * as cdk from 'aws-cdk-lib'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import * as apigateway from 'aws-cdk-lib/aws-apigateway'; + +class RestApiAccessLogFirehoseTest extends cdk.Stack { + constructor(scope: cdk.App, id: string) { + super(scope, id); + + const testFormat = apigateway.AccessLogFormat.custom(JSON.stringify({ + requestId: apigateway.AccessLogField.contextRequestId(), + sourceIp: apigateway.AccessLogField.contextIdentitySourceIp(), + method: apigateway.AccessLogField.contextHttpMethod(), + callerAccountId: apigateway.AccessLogField.contextCallerAccountId(), + ownerAccountId: apigateway.AccessLogField.contextOwnerAccountId(), + userContext: { + sub: apigateway.AccessLogField.contextAuthorizerClaims('sub'), + email: apigateway.AccessLogField.contextAuthorizerClaims('email'), + }, + clientCertPem: apigateway.AccessLogField.contextIdentityClientCertPem(), + subjectDN: apigateway.AccessLogField.contextIdentityClientCertSubjectDN(), + issunerDN: apigateway.AccessLogField.contextIdentityClientCertIssunerDN(), + serialNumber: apigateway.AccessLogField.contextIdentityClientCertSerialNumber(), + validityNotBefore: apigateway.AccessLogField.contextIdentityClientCertValidityNotBefore(), + validityNotAfter: apigateway.AccessLogField.contextIdentityClientCertValidityNotAfter(), + })); + + const destinationBucket = new s3.Bucket(this, 'Bucket', { + removalPolicy: cdk.RemovalPolicy.DESTROY, + autoDeleteObjects: true, + }); + + const deliveryStreamRole = new iam.Role(this, 'Role', { + assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), + }); + + const stream = new firehose.CfnDeliveryStream(this, 'MyStream', { + deliveryStreamName: 'amazon-apigateway-delivery-stream', + s3DestinationConfiguration: { + bucketArn: destinationBucket.bucketArn, + roleArn: deliveryStreamRole.roleArn, + }, + }); + + const api = new apigateway.RestApi(this, 'MyApi', { + cloudWatchRole: true, + deployOptions: { + accessLogDestination: new apigateway.FirehoseLogDestination(stream), + accessLogFormat: testFormat, + }, + }); + api.root.addMethod('GET'); + } +} + +const app = new cdk.App(); + +const stack = new RestApiAccessLogFirehoseTest(app, 'test-apigateway-access-logs-firehose'); +new IntegTest(app, 'apigateway-access-logs-firehose', { + testCases: [stack], +}); + +app.synth(); diff --git a/packages/aws-cdk-lib/aws-apigateway/README.md b/packages/aws-cdk-lib/aws-apigateway/README.md index d9380f01c9fd3..fc3af88c46443 100644 --- a/packages/aws-cdk-lib/aws-apigateway/README.md +++ b/packages/aws-cdk-lib/aws-apigateway/README.md @@ -1218,10 +1218,10 @@ Gateway](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-log ```ts // production stage -const prdLogGroup = new logs.LogGroup(this, "PrdLogs"); +const prodLogGroup = new logs.LogGroup(this, "PrdLogs"); const api = new apigateway.RestApi(this, 'books', { deployOptions: { - accessLogDestination: new apigateway.LogGroupLogDestination(prdLogGroup), + accessLogDestination: new apigateway.LogGroupLogDestination(prodLogGroup), accessLogFormat: apigateway.AccessLogFormat.jsonWithStandardFields(), }, }); @@ -1308,6 +1308,34 @@ const api = new apigateway.RestApi(this, 'books', { }); ``` +To write access log files to a Firehose delivery stream destination use the `FirehoseLogDestination` class: + +```ts +const destinationBucket = new s3.Bucket(this, 'Bucket'); +const deliveryStreamRole = new iam.Role(this, 'Role', { + assumedBy: new iam.ServicePrincipal('firehose.amazonaws.com'), +}); + +const stream = new firehose.CfnDeliveryStream(this, 'MyStream', { + deliveryStreamName: 'amazon-apigateway-delivery-stream', + s3DestinationConfiguration: { + bucketArn: destinationBucket.bucketArn, + roleArn: deliveryStreamRole.roleArn, + }, +}); + +const api = new apigateway.RestApi(this, 'books', { + deployOptions: { + accessLogDestination: new apigateway.FirehoseLogDestination(stream), + accessLogFormat: apigateway.AccessLogFormat.jsonWithStandardFields(), + }, +}); +``` + +**Note:** The delivery stream name must start with `amazon-apigateway-`. + +> Visit [Logging API calls to Kinesis Data Firehose](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-logging-to-kinesis.html) for more details. + ## Cross Origin Resource Sharing (CORS) [Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) is a mechanism diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts b/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts index ea40681f7b60c..c445fbc71450b 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/access-log.ts @@ -1,4 +1,5 @@ import { IStage } from './stage'; +import * as firehose from '../../aws-kinesisfirehose'; import { ILogGroup } from '../../aws-logs'; /** @@ -38,6 +39,26 @@ export class LogGroupLogDestination implements IAccessLogDestination { } } +/** + * Use a Firehose delivery stream as a custom access log destination for API Gateway. + */ +export class FirehoseLogDestination implements IAccessLogDestination { + constructor(private readonly stream: firehose.CfnDeliveryStream) { + } + + /** + * Binds this destination to the Firehose delivery stream. + */ + public bind(_stage: IStage): AccessLogDestinationConfig { + if (!this.stream.deliveryStreamName?.startsWith('amazon-apigateway-')) { + throw new Error(`Firehose delivery stream name for access log destination must begin with 'amazon-apigateway-', got '${this.stream.deliveryStreamName}'`); + } + return { + destinationArn: this.stream.attrArn, + }; + } +} + /** * $context variables that can be used to customize access log pattern. */ diff --git a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts index f7b37ef0a2a39..093a526eb2509 100644 --- a/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts +++ b/packages/aws-cdk-lib/aws-apigateway/lib/stage.ts @@ -40,7 +40,7 @@ export interface StageOptions extends MethodDeploymentOptions { readonly stageName?: string; /** - * The CloudWatch Logs log group. + * The CloudWatch Logs log group or Firehose delivery stream where to write access logs. * * @default - No destination */ diff --git a/packages/aws-cdk-lib/aws-apigateway/test/stage.test.ts b/packages/aws-cdk-lib/aws-apigateway/test/stage.test.ts index 95034a37deb24..572626ef50550 100644 --- a/packages/aws-cdk-lib/aws-apigateway/test/stage.test.ts +++ b/packages/aws-cdk-lib/aws-apigateway/test/stage.test.ts @@ -1,4 +1,5 @@ import { Template } from '../../assertions'; +import * as firehose from '../../aws-kinesisfirehose'; import * as logs from '../../aws-logs'; import * as cdk from '../../core'; import * as apigateway from '../lib'; @@ -360,6 +361,70 @@ describe('stage', () => { }); }); + test('if only the custom log destination firehose delivery stream is set', () => { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigateway.RestApi(stack, 'test-api', { cloudWatchRole: false, deploy: false }); + const deployment = new apigateway.Deployment(stack, 'my-deployment', { api }); + api.root.addMethod('GET'); + + // WHEN + const testDeliveryStream = new firehose.CfnDeliveryStream(stack, 'MyStream', { + deliveryStreamName: 'amazon-apigateway-delivery-stream', + }); + new apigateway.Stage(stack, 'my-stage', { + deployment, + accessLogDestination: new apigateway.FirehoseLogDestination(testDeliveryStream), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Stage', { + AccessLogSetting: { + DestinationArn: { + 'Fn::GetAtt': [ + 'MyStream', + 'Arn', + ], + }, + Format: '$context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] "$context.httpMethod $context.resourcePath $context.protocol" $context.status $context.responseLength $context.requestId', + }, + StageName: 'prod', + }); + }); + + test('if the custom log destination firehose delivery stream and format is set', () => { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigateway.RestApi(stack, 'test-api', { cloudWatchRole: false, deploy: false }); + const deployment = new apigateway.Deployment(stack, 'my-deployment', { api }); + api.root.addMethod('GET'); + + // WHEN + const testDeliveryStream = new firehose.CfnDeliveryStream(stack, 'MyStream', { + deliveryStreamName: 'amazon-apigateway-delivery-stream', + }); + const testFormat = apigateway.AccessLogFormat.jsonWithStandardFields(); + new apigateway.Stage(stack, 'my-stage', { + deployment, + accessLogDestination: new apigateway.FirehoseLogDestination(testDeliveryStream), + accessLogFormat: testFormat, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::ApiGateway::Stage', { + AccessLogSetting: { + DestinationArn: { + 'Fn::GetAtt': [ + 'MyStream', + 'Arn', + ], + }, + Format: '{"requestId":"$context.requestId","ip":"$context.identity.sourceIp","user":"$context.identity.user","caller":"$context.identity.caller","requestTime":"$context.requestTime","httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath","status":"$context.status","protocol":"$context.protocol","responseLength":"$context.responseLength"}', + }, + StageName: 'prod', + }); + }); + describe('access log check', () => { test('fails when access log format does not contain `contextRequestId()` or `contextExtendedRequestId()', () => { // GIVEN @@ -500,6 +565,25 @@ describe('stage', () => { accessLogFormat: testFormat, })).toThrow(/Access log format is specified without a destination/); }); + + test('fails if firehose delivery stream name does not start with amazon-apigateway-', () => { + // GIVEN + const stack = new cdk.Stack(); + const api = new apigateway.RestApi(stack, 'test-api', { cloudWatchRole: false, deploy: false }); + const deployment = new apigateway.Deployment(stack, 'my-deployment', { api }); + api.root.addMethod('GET'); + + // WHEN + const testDeliveryStream = new firehose.CfnDeliveryStream(stack, 'MyStream', { + deliveryStreamName: 'invalid', + }); + expect(() => { + new apigateway.Stage(stack, 'my-stage', { + deployment, + accessLogDestination: new apigateway.FirehoseLogDestination(testDeliveryStream), + }); + }).toThrow(/Firehose delivery stream name for access log destination must begin with 'amazon-apigateway-', got 'invalid'/); + }); }); test('default throttling settings', () => { diff --git a/packages/aws-cdk-lib/rosetta/aws_apigateway/default.ts-fixture b/packages/aws-cdk-lib/rosetta/aws_apigateway/default.ts-fixture index c5c06c6bb459e..6dfd84b974e43 100644 --- a/packages/aws-cdk-lib/rosetta/aws_apigateway/default.ts-fixture +++ b/packages/aws-cdk-lib/rosetta/aws_apigateway/default.ts-fixture @@ -7,6 +7,7 @@ import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; +import * as firehose from 'aws-cdk-lib/aws-kinesisfirehose'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions'; import * as sagemaker from 'aws-cdk-lib/aws-sagemaker';