AWS AWSCloudFormation documentation change
Summary
Updated documentation for Lambda-backed custom resources with improved template examples, clarified resource behavior, and formatting changes
Security assessment
Changes focus on template structure clarification, code formatting improvements, and updated recommendations about using Systems Manager parameters instead of custom resources for AMI IDs. No specific security vulnerabilities or mitigations are mentioned. The IAM policy changes are syntax simplifications ('logs:*' permission remains unchanged)
Diff
diff --git a/AWSCloudFormation/latest/UserGuide/walkthrough-lambda-backed-custom-resources.md b/AWSCloudFormation/latest/UserGuide/walkthrough-lambda-backed-custom-resources.md index 98e74e5e8..59640c1a4 100644 --- a//AWSCloudFormation/latest/UserGuide/walkthrough-lambda-backed-custom-resources.md +++ b//AWSCloudFormation/latest/UserGuide/walkthrough-lambda-backed-custom-resources.md @@ -7 +7 @@ OverviewSample templateSample template walkthroughPrerequisitesLaunching the sta -This walkthrough show you the resource configuration of a Lambda-backed custom resource using a sample template, and how to launch a Lambda-backed custom resource using the same sample template. The sample custom resource template creates a Lambda-backed custom resource that creates a delay mechanism. +This walkthrough shows you how to configure and launch a Lambda-backed custom resource using a sample template. This template creates a delay mechanism that pauses stack deployments for a specified time. This can be useful when you need to introduce deliberate delays during resource provisioning, such as when waiting for resources to stabilize before dependent resources are created. @@ -11,5 +11 @@ This walkthrough show you the resource configuration of a Lambda-backed custom r -Be aware of the following: - -CloudFormation is a free service; however, you are charged for the AWS resources, such as the Lambda function and EC2 instance, that you include in your stacks at the current rate for each. For more information about AWS pricing, see the detail page for each product at [http://aws.amazon.com](http://aws.amazon.com). - -A Lambda-backed custom resource used to be the recommended method for retrieving AMI IDs. Rather than creating a custom resource and Lambda function to retried AMI IDs, you can use AWS Systems Manager parameters in your template to retrieve the latest AMI ID value stored in a Systems Manager parameter. This makes your templates more reusable and easier to maintain. For more information, see [Specify existing resources at runtime with CloudFormation-supplied parameter types](./cloudformation-supplied-parameter-types.html). +While Lambda-backed custom resources were previously recommended for retrieving AMI IDs, we now recommend using AWS Systems Manager parameters. This approach makes your templates more reusable and easier to maintain. For more information, see [Get a plaintext value from Systems Manager Parameter Store](./dynamic-references-ssm.html). @@ -38 +34,14 @@ A Lambda-backed custom resource used to be the recommended method for retrieving -The following steps provide an overview of this implementation. +The sample stack template used in this walkthrough creates a Lambda-backed custom resource. This custom resource introduces a configurable delay (60 seconds by default) during stack creation. The delay occurs during stack updates only when the custom resource's properties are modified. + +The template provisions the following resources: + + * a custom resource, + + * a Lambda function, and + + * an IAM role that enables Lambda to write logs to CloudWatch. + + + + +It also defines two outputs: @@ -40 +49 @@ The following steps provide an overview of this implementation. - 1. Save a sample template containing the Lambda function code as a file on your machine with the name `samplelambdabackedcustomresource.template`. + * `TimeWaited`. The actual time the function waited. @@ -42 +51 @@ The following steps provide an overview of this implementation. - 2. Use the sample template to create your stack with a custom resource, a Lambda function, and an IAM role that uses Lambda to write logs to CloudWatch. + * `WaiterId`: A unique identifier generated during execution. @@ -44 +52,0 @@ The following steps provide an overview of this implementation. - 3. The custom resource implements a delay mechanism. The Lambda function sleeps for the specified duration during create and update operations. The resource will only be invoked for an update operation if the properties are modified. @@ -46 +53,0 @@ The following steps provide an overview of this implementation. - 4. The template `Outputs` exports two values, `TimeWaited` and the `WaiterId`. `TimeWaited` is the length of time the resource waited, and `WaiterId` is the unique ID generated during the execution. @@ -48,0 +56 @@ The following steps provide an overview of this implementation. +###### Note @@ -49,0 +58 @@ The following steps provide an overview of this implementation. +CloudFormation is a free service but Lambda charges based on the number of requests for your functions and the time your code executes. For more information about Lambda pricing, see [AWS Lambda pricing](https://aws.amazon.com/lambda/pricing/). @@ -65,2 +74 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Statement": [ - { + "Statement": [{ @@ -68,10 +76,3 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] - }, - "Action": [ - "sts:AssumeRole" - ] - } - ] + "Principal": { "Service": ["lambda.amazonaws.com"] }, + "Action": ["sts:AssumeRole"] + }] @@ -80,2 +81 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Policies": [ - { + "Policies": [{ @@ -84,2 +84 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Statement": [ - { + "Statement": [{ @@ -87,3 +86 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Action": [ - "logs:*" - ], + "Action": ["logs:*"], @@ -90,0 +88 @@ You can see the Lambda-backed custom resource sample template with the delay mec + }] @@ -92,4 +90 @@ You can see the Lambda-backed custom resource sample template with the delay mec - ] - } - } - ] + }] @@ -104,6 +99 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Role": { - "Fn::GetAtt": [ - "LambdaExecutionRole", - "Arn" - ] - }, + "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] }, @@ -111,3 +101,18 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "ZipFile": { - "Fn::Sub": "from time import sleep\nimport json\nimport cfnresponse\nimport uuid\n\ndef handler(event, context):\n wait_seconds = 0\n id = str(uuid.uuid1())\n if event[\"RequestType\"] in [\"Create\", \"Update\"]:\n wait_seconds = int(event[\"ResourceProperties\"].get(\"WaitSeconds\", 0))\n sleep(wait_seconds)\n response = {\n \"TimeWaited\": wait_seconds,\n \"Id\": id \n }\n cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)" - } + "ZipFile": { "Fn::Join": ["\n", [ + "from time import sleep", + "import json", + "import cfnresponse", + "import uuid", + "", + "def handler(event, context):", + " wait_seconds = 0", + " id = str(uuid.uuid1())", + " if event[\"RequestType\"] in [\"Create\", \"Update\"]:", + " wait_seconds = int(event[\"ResourceProperties\"].get(\"WaitSeconds\", 0))", + " sleep(wait_seconds)", + " response = {", + " \"TimeWaited\": wait_seconds,", + " \"Id\": id ", + " }", + " cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)" + ]]} @@ -120,6 +125 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "ServiceToken": { - "Fn::GetAtt": [ - "CFNWaiter", - "Arn" - ] - }, + "ServiceToken": { "Fn::GetAtt": ["CFNWaiter", "Arn"] }, @@ -132,9 +132,2 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Value": { - "Fn::GetAtt": [ - "CFNWaiterCustomResource", - "TimeWaited" - ] - }, - "Export": { - "Name": "TimeWaited" - } + "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "TimeWaited"] }, + "Export": { "Name": "TimeWaited" } @@ -143,9 +136,2 @@ You can see the Lambda-backed custom resource sample template with the delay mec - "Value": { - "Fn::GetAtt": [ - "CFNWaiterCustomResource", - "Id" - ] - }, - "Export": { - "Name": "WaiterId" - } + "Value": { "Fn::GetAtt": ["CFNWaiterCustomResource", "Id"] }, + "Export": { "Name": "WaiterId" } @@ -212 +197,0 @@ You can see the Lambda-backed custom resource sample template with the delay mec - @@ -263,6 +248 @@ The `Code` property defines the function code inline using a Python function. Th - "Role": { - "Fn::GetAtt": [ - "LambdaExecutionRole", - "Arn" - ] - }, + "Role": { "Fn::GetAtt": ["LambdaExecutionRole", "Arn"] }, @@ -270,3 +250,18 @@ The `Code` property defines the function code inline using a Python function. Th - "ZipFile": { - "Fn::Sub": "from time import sleep\nimport json\nimport cfnresponse\nimport uuid\n\ndef handler(event, context):\n wait_seconds = 0\n id = str(uuid.uuid1())\n if event[\"RequestType\"] in [\"Create\", \"Update\"]:\n wait_seconds = int(event[\"ResourceProperties\"].get(\"WaitSeconds\", 0))\n sleep(wait_seconds)\n response = {\n \"TimeWaited\": wait_seconds,\n \"Id\": id \n }\n cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)" - } + "ZipFile": { "Fn::Join": ["\n", [ + "from time import sleep", + "import json", + "import cfnresponse", + "import uuid", + "", + "def handler(event, context):", + " wait_seconds = 0", + " id = str(uuid.uuid1())", + " if event[\"RequestType\"] in [\"Create\", \"Update\"]:", + " wait_seconds = int(event[\"ResourceProperties\"].get(\"WaitSeconds\", 0))", + " sleep(wait_seconds)", + " response = {", + " \"TimeWaited\": wait_seconds,", + " \"Id\": id ", + " }", + " cfnresponse.send(event, context, cfnresponse.SUCCESS, response, \"Waiter-\"+id)" + ]]} @@ -323,2 +318 @@ The `AWS::IAM:Role` resource creates an execution role for the Lambda function, - "Statement": [ - { + "Statement": [{ @@ -326,10 +320,3 @@ The `AWS::IAM:Role` resource creates an execution role for the Lambda function, - "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] - }, - "Action": [ - "sts:AssumeRole" - ] - } - ] + "Principal": { "Service": ["lambda.amazonaws.com"] }, + "Action": ["sts:AssumeRole"] + }] @@ -338,2 +325 @@ The `AWS::IAM:Role` resource creates an execution role for the Lambda function, - "Policies": [ - { + "Policies": [{ @@ -342,2 +328 @@ The `AWS::IAM:Role` resource creates an execution role for the Lambda function,