Skip to content

Commit

Permalink
chore: a couple more places where ResponseURL is logged (aws#20977)
Browse files Browse the repository at this point in the history
Follow-up to aws#20899, missed a couple of spots.

Marking this a `chore` instead of a `fix` since the previous commit will
already show up in the CHANGELOG and both this and aws#20899 will go into
the same release.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr authored and daschaa committed Jul 9, 2022
1 parent e69e14e commit fe1701a
Show file tree
Hide file tree
Showing 42 changed files with 64 additions and 1,437 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export type HandlerResponse = undefined | {
};

export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent, context: AWSLambda.Context) {
external.log(JSON.stringify(event, undefined, 2));
const sanitizedEvent = { ...event, ResponseURL: '...' };
external.log(JSON.stringify(sanitizedEvent, undefined, 2));

// ignore DELETE event when the physical resource ID is the marker that
// indicates that this DELETE is a subsequent DELETE to a failed CREATE
Expand All @@ -39,7 +40,7 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent
// cloudformation (otherwise cfn waits).
// eslint-disable-next-line @typescript-eslint/no-require-imports
const userHandler: Handler = require(external.userHandlerIndex).handler;
const result = await userHandler(event, context);
const result = await userHandler(sanitizedEvent, context);

// validate user response and create the combined event
const responseEvent = renderResponse(event, result);
Expand Down
10 changes: 10 additions & 0 deletions packages/@aws-cdk/custom-resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ def is_complete(event, context):
return { 'IsComplete': is_ready }
```

> **Security Note**: the Custom Resource Provider Framework will write the value of `ResponseURL`,
> which is a pre-signed S3 URL used to report the success or failure of the Custom Resource execution
> back to CloudFormation, in a readable form to the AWS Step Functions execution history.
>
> Anybody who can list and read AWS StepFunction executions in your account will be able to write
> a fake response to this URL and make your CloudFormation deployments fail.
>
> Do not use this library if your threat model requires that you cannot trust actors who are able
> to list StepFunction executions in your account.
### Handling Lifecycle Events: onEvent

The user-defined `onEvent` AWS Lambda function is invoked whenever a resource
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ export = {
* @param cfnRequest The cloudformation custom resource event.
*/
async function onEvent(cfnRequest: AWSLambda.CloudFormationCustomResourceEvent) {
log('onEventHandler', { ...cfnRequest, ResponseURL: '...' });
const sanitizedRequest = { ...cfnRequest, ResponseURL: '...' } as const;
log('onEventHandler', sanitizedRequest);

cfnRequest.ResourceProperties = cfnRequest.ResourceProperties || { };

const onEventResult = await invokeUserFunction(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, cfnRequest) as OnEventResponse;
const onEventResult = await invokeUserFunction(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, sanitizedRequest) as OnEventResponse;
log('onEvent returned:', onEventResult);

// merge the request and the result from onEvent to form the complete resource event
Expand Down Expand Up @@ -57,9 +58,10 @@ async function onEvent(cfnRequest: AWSLambda.CloudFormationCustomResourceEvent)

// invoked a few times until `complete` is true or until it times out.
async function isComplete(event: AWSCDKAsyncCustomResource.IsCompleteRequest) {
log('isComplete', event);
const sanitizedRequest = { ...event, ResponseURL: '...' } as const;
log('isComplete', sanitizedRequest);

const isCompleteResult = await invokeUserFunction(consts.USER_IS_COMPLETE_FUNCTION_ARN_ENV, event) as IsCompleteResponse;
const isCompleteResult = await invokeUserFunction(consts.USER_IS_COMPLETE_FUNCTION_ARN_ENV, sanitizedRequest) as IsCompleteResponse;
log('user isComplete returned:', isCompleteResult);

// if we are not complete, return false, and don't send a response back.
Expand All @@ -68,6 +70,7 @@ async function isComplete(event: AWSCDKAsyncCustomResource.IsCompleteRequest) {
throw new Error('"Data" is not allowed if "IsComplete" is "False"');
}

// This must be the full event, it will be deserialized in `onTimeout` to send the response to CloudFormation
throw new cfnResponse.Retry(JSON.stringify(event));
}

Expand All @@ -93,9 +96,9 @@ async function onTimeout(timeoutEvent: any) {
});
}

async function invokeUserFunction(functionArnEnv: string, payload: any) {
async function invokeUserFunction<A extends { ResponseURL: '...' }>(functionArnEnv: string, sanitizedPayload: A) {
const functionArn = getEnv(functionArnEnv);
log(`executing user function ${functionArn} with payload`, payload);
log(`executing user function ${functionArn} with payload`, sanitizedPayload);

// transient errors such as timeouts, throttling errors (429), and other
// errors that aren't caused by a bad request (500 series) are retried
Expand All @@ -104,7 +107,7 @@ async function invokeUserFunction(functionArnEnv: string, payload: any) {
FunctionName: functionArn,

// Strip 'ResponseURL' -- the downstream CR doesn't need it and can only log it by accident
Payload: JSON.stringify({ ...payload, ResponseURL: undefined }),
Payload: JSON.stringify({ ...sanitizedPayload, ResponseURL: undefined }),
});

log('user function response:', resp, typeof(resp));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "20.0.0",
"files": {
"17cb4b37288c269a54418db6e9c7c3763b2d1a82bdc374be4653bd366345eccb": {
"60767da3831353fede3cfe92efef10580a600592dec8ccbb06c051e95b9c1b26": {
"source": {
"path": "asset.17cb4b37288c269a54418db6e9c7c3763b2d1a82bdc374be4653bd366345eccb",
"path": "asset.60767da3831353fede3cfe92efef10580a600592dec8ccbb06c051e95b9c1b26",
"packaging": "zip"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "17cb4b37288c269a54418db6e9c7c3763b2d1a82bdc374be4653bd366345eccb.zip",
"objectKey": "60767da3831353fede3cfe92efef10580a600592dec8ccbb06c051e95b9c1b26.zip",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand All @@ -27,15 +27,15 @@
}
}
},
"7f17b1fbdb3783f2f992a94602a37c674f58741617a65f348b43ba1a7637a115": {
"ff8909e2b3e01298b53c87d97e8e745b4f0b2e4b6d29d5680c44e5da87a207a4": {
"source": {
"path": "PipelineSecurityStack.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "7f17b1fbdb3783f2f992a94602a37c674f58741617a65f348b43ba1a7637a115.json",
"objectKey": "ff8909e2b3e01298b53c87d97e8e745b4f0b2e4b6d29d5680c44e5da87a207a4.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"S3Bucket": {
"Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
},
"S3Key": "17cb4b37288c269a54418db6e9c7c3763b2d1a82bdc374be4653bd366345eccb.zip"
"S3Key": "60767da3831353fede3cfe92efef10580a600592dec8ccbb06c051e95b9c1b26.zip"
},
"Timeout": 900,
"MemorySize": 128,
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit fe1701a

Please sign in to comment.