customresources

package
v2.142.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 17, 2024 License: Apache-2.0 Imports: 13 Imported by: 1

README

AWS CDK Custom Resources

This module is part of the AWS Cloud Development Kit project.

Provider Framework

AWS CloudFormation custom resources are extension points to the provisioning engine. When CloudFormation needs to create, update or delete a custom resource, it sends a lifecycle event notification to a custom resource provider. The provider handles the event (e.g. creates a resource) and sends back a response to CloudFormation.

The @aws-cdk/custom-resources.Provider construct is a "mini-framework" for implementing providers for AWS CloudFormation custom resources. The framework offers a high-level API which makes it easier to implement robust and powerful custom resources. If you are looking to implement a custom resource provider, we recommend you use this module unless you have good reasons not to. For an overview of different provider types you could be using, see the Custom Resource Providers section in the core library documentation.

N.B.: if you use the provider framework in this module you will write AWS Lambda Functions that look a lot like, but aren't exactly the same as the Lambda Functions you would write if you wrote CloudFormation Custom Resources directly, without this framework.

Specifically, to report success or failure, have your Lambda Function exit in the right way: return data for success, or throw an exception for failure. Do not post the success or failure of your custom resource to an HTTPS URL as the CloudFormation documentation tells you to do.

The framework has the following capabilities:

  • Handles responses to AWS CloudFormation and protects against blocked deployments
  • Validates handler return values to help with correct handler implementation
  • Supports asynchronous handlers to enable operations that require a long waiting period for a resource, which can exceed the AWS Lambda timeout
  • Implements default behavior for physical resource IDs.

The following code shows how the Provider construct is used in conjunction with a CustomResource and a user-provided AWS Lambda function which implements the actual handler.

var onEvent function
var isComplete function
var myRole role


myProvider := cr.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: onEvent,
	IsCompleteHandler: isComplete,
	 // optional async "waiter"
	LogGroup: logs.NewLogGroup(this, jsii.String("MyProviderLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	Role: myRole,
})

awscdk.NewCustomResource(this, jsii.String("Resource1"), &CustomResourceProps{
	ServiceToken: myProvider.ServiceToken,
})
awscdk.NewCustomResource(this, jsii.String("Resource2"), &CustomResourceProps{
	ServiceToken: myProvider.*ServiceToken,
})

Providers are implemented through AWS Lambda functions that are triggered by the provider framework in response to lifecycle events.

At the minimum, users must define the onEvent handler, which is invoked by the framework for all resource lifecycle events (Create, Update and Delete) and returns a result which is then submitted to CloudFormation.

The following example is a skeleton for a Python implementation of onEvent:

def on_event(event, context):
  print(event)
  request_type = event['RequestType']
  if request_type == 'Create': return on_create(event)
  if request_type == 'Update': return on_update(event)
  if request_type == 'Delete': return on_delete(event)
  raise Exception("Invalid request type: %s" % request_type)

def on_create(event):
  props = event["ResourceProperties"]
  print("create new resource with props %s" % props)

  # add your create code here...
  physical_id = ...

  return { 'PhysicalResourceId': physical_id }

def on_update(event):
  physical_id = event["PhysicalResourceId"]
  props = event["ResourceProperties"]
  print("update resource %s with props %s" % (physical_id, props))
  # ...

def on_delete(event):
  physical_id = event["PhysicalResourceId"]
  print("delete resource %s" % physical_id)
  # ...

When writing your handlers, there are a couple of non-obvious corner cases you need to pay attention to. See the important cases to handle section for more information.

Users may also provide an additional handler called isComplete, for cases where the lifecycle operation cannot be completed immediately. The isComplete handler will be retried asynchronously after onEvent until it returns IsComplete: true, or until the total provider timeout has expired.

The following example is a skeleton for a Python implementation of isComplete:

def is_complete(event, context):
  physical_id = event["PhysicalResourceId"]
  request_type = event["RequestType"]

  # check if resource is stable based on request_type
  is_ready = ...

  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 lifecycle event occurs. The function is expected to handle the event and return a response to the framework that, at least, includes the physical resource ID.

If onEvent returns successfully, the framework will submit a "SUCCESS" response to AWS CloudFormation for this resource operation. If the provider is asynchronous (isCompleteHandler is defined), the framework will only submit a response based on the result of isComplete.

If onEvent throws an error, the framework will submit a "FAILED" response to AWS CloudFormation.

The input event includes the following fields derived from the Custom Resource Provider Request:

Field Type Description
RequestType String The type of lifecycle event: Create, Update or Delete.
LogicalResourceId String The template developer-chosen name (logical ID) of the custom resource in the AWS CloudFormation template.
PhysicalResourceId String This field will only be present for Update and Delete events and includes the value returned in PhysicalResourceId of the previous operation.
ResourceProperties JSON This field contains the properties defined in the template for this custom resource.
OldResourceProperties JSON This field will only be present for Update events and contains the resource properties that were declared previous to the update request.
ResourceType String The resource type defined for this custom resource in the template. A provider may handle any number of custom resource types.
RequestId String A unique ID for the request.
StackId String The ARN that identifies the stack that contains the custom resource.

The return value from onEvent must be a JSON object with the following fields:

Field Type Required Description
PhysicalResourceId String No The allocated/assigned physical ID of the resource. If omitted for Create events, the event's RequestId will be used. For Update, the current physical ID will be used. If a different value is returned, CloudFormation will follow with a subsequent Delete for the previous ID (resource replacement). For Delete, it will always return the current physical resource ID, and if the user returns a different one, an error will occur.
Data JSON No Resource attributes, which can later be retrieved through Fn::GetAtt on the custom resource object.
NoEcho Boolean No Whether to mask the output of the custom resource when retrieved by using the Fn::GetAtt function.
any any No Any other field included in the response will be passed through to isComplete. This can sometimes be useful to pass state between the handlers.
Asynchronous Providers: isComplete

It is not uncommon for the provisioning of resources to be an asynchronous operation, which means that the operation does not immediately finish, and we need to "wait" until the resource stabilizes.

The provider framework makes it easy to implement "waiters" by allowing users to specify an additional AWS Lambda function in isCompleteHandler.

The framework will repeatedly invoke the handler every queryInterval. When isComplete returns with IsComplete: true, the framework will submit a "SUCCESS" response to AWS CloudFormation. If totalTimeout expires and the operation has not yet completed, the framework will submit a "FAILED" response with the message "Operation timed out".

If an error is thrown, the framework will submit a "FAILED" response to AWS CloudFormation.

The input event to isComplete includes all request fields, combined with all fields returned from onEvent. If PhysicalResourceId has not been explicitly returned from onEvent, it's value will be calculated based on the heuristics described above.

The return value must be a JSON object with the following fields:

Field Type Required Description
IsComplete Boolean Yes Indicates if the operation has finished or not.
Data JSON No May only be sent if IsComplete is true and includes additional resource attributes. These attributes will be merged with the ones returned from onEvent
Physical Resource IDs

Every resource in CloudFormation has a physical resource ID. When a resource is created, the PhysicalResourceId returned from the Create operation is stored by AWS CloudFormation and assigned to the logical ID defined for this resource in the template. If a Create operation returns without a PhysicalResourceId, the framework will use RequestId as the default. This is sufficient for various cases such as "pseudo-resources" which only query data.

For Update and Delete operations, the resource event will always include the current PhysicalResourceId of the resource.

When an Update operation occurs, the default behavior is to return the current physical resource ID. if the onEvent returns a PhysicalResourceId which is different from the current one, AWS CloudFormation will treat this as a resource replacement, and it will issue a subsequent Delete operation for the old resource.

As a rule of thumb, if your custom resource supports configuring a physical name (e.g. you can specify a BucketName when you define an AWS::S3::Bucket), you must return this name in PhysicalResourceId and make sure to handle replacement properly. The S3File example demonstrates this through the objectKey property.

When there are errors

As mentioned above, if any of the user handlers fail (i.e. throws an exception) or times out (due to their AWS Lambda timing out), the framework will trap these errors and submit a "FAILED" response to AWS CloudFormation, along with the error message.

Since errors can occur in multiple places in the provider (framework, onEvent, isComplete), it is important to know that there could situations where a resource operation fails even though the operation technically succeeded (i.e. isComplete throws an error).

When AWS CloudFormation receives a "FAILED" response, it will attempt to roll back the stack to it's last state. This has different meanings for different lifecycle events:

  • If a Create event fails, the resource provider framework will automatically ignore the subsequent Delete operation issued by AWS CloudFormation. The framework currently does not support customizing this behavior (see https://github.com/aws/aws-cdk/issues/5524).
  • If an Update event fails, CloudFormation will issue an additional Update with the previous properties.
  • If a Delete event fails, CloudFormation will abandon this resource.
Important cases to handle

You should keep the following list in mind when writing custom resources to make sure your custom resource behaves correctly in all cases:

  • During Create:

    • If the create fails, the provider framework will make sure you don't get a subsequent Delete event. If your create involves multiple distinct operations, it is your responsibility to catch and rethrow and clean up any partial updates that have already been performed. Make sure your API call timeouts and Lambda timeouts allow for this.
  • During Update:

    • If the update fails, you will get a subsequent Update event to roll back to the previous state (with ResourceProperties and OldResourceProperties reversed).
    • If you return a different PhysicalResourceId, you will subsequently receive a Delete event to clean up the previous state of the resource.
  • During Delete:

    • If the behavior of your custom resource is tied to another AWS resource (for example, it exists to clean the contents of a stateful resource), keep in mind that your custom resource may be deleted independently of the other resource and you must confirm that it is appropriate to perform the action.
    • (only if you are not using the provider framework) a Delete event may be caused by a failed Create. You must be able to handle the case where the resource you are trying to delete hasn't even been created yet.
  • If you update the code of your custom resource and change the format of the resource properties, be aware that there may still be already-deployed instances of your custom resource out there, and you may still receive the old property format in ResourceProperties (during Delete and rollback Updates) or in OldResourceProperties (during rollforward Update). You must continue to handle all possible sets of properties your custom resource could have ever been created with in the past.

Provider Framework Execution Policy

Similarly to any AWS Lambda function, if the user-defined handlers require access to AWS resources, you will have to define these permissions by calling "grant" methods such as myBucket.grantRead(myHandler)), using myHandler.addToRolePolicy or specifying an initialPolicy when defining the function.

Bear in mind that in most cases, a single provider will be used for multiple resource instances. This means that the execution policy of the provider must have the appropriate privileges.

The following example grants the onEvent handler s3:GetObject* permissions to all buckets:

lambda.NewFunction(this, jsii.String("OnEventHandler"), &FunctionProps{
	Runtime: lambda.Runtime_NODEJS_LATEST(),
	Handler: jsii.String("index.handler"),
	Code: lambda.Code_FromInline(jsii.String("my code")),
	InitialPolicy: []policyStatement{
		iam.NewPolicyStatement(&PolicyStatementProps{
			Actions: []*string{
				jsii.String("s3:GetObject*"),
			},
			Resources: []*string{
				jsii.String("*"),
			},
		}),
	},
})
Timeouts

Users are responsible to define the timeouts for the AWS Lambda functions for user-defined handlers. It is recommended not to exceed a 14 minutes timeout, since all framework functions are configured to time out after 15 minutes, which is the maximal AWS Lambda timeout.

If your operation takes over 14 minutes, the recommended approach is to implement an asynchronous provider, and then configure the timeouts for the asynchronous retries through the queryInterval and the totalTimeout options.

Provider Framework Examples

This module includes a few examples for custom resource implementations:

S3File

Provisions an object in an S3 bucket with textual contents. See the source code for the construct and handler.

The following example will create the file folder/file1.txt inside myBucket with the contents hello!.

// This example exists only for TypeScript

declare const myBucket: s3.Bucket;
new cr.S3File(this, 'MyFile', {
  bucket: myBucket,
  objectKey: 'folder/file1.txt', // optional
  content: 'hello!',
  public: true, // optional
});

This sample demonstrates the following concepts:

  • Synchronous implementation (isComplete is not defined)
  • Automatically generates the physical name if objectKey is not defined
  • Handles physical name changes
  • Returns resource attributes
  • Handles deletions
  • Implemented in TypeScript
S3Assert

Checks that the textual contents of an S3 object matches a certain value. The check will be retried for 5 minutes as long as the object is not found or the value is different. See the source code for the construct and handler.

The following example defines an S3Assert resource which waits until myfile.txt in myBucket exists and includes the contents foo bar:

// This example exists only for TypeScript

declare const myBucket: s3.Bucket;
new cr.S3Assert(this, 'AssertMyFile', {
  bucket: myBucket,
  objectKey: 'myfile.txt',
  expectedContent: 'foo bar',
});

This sample demonstrates the following concepts:

  • Asynchronous implementation
  • Non-intrinsic physical IDs
  • Implemented in Python
Customizing Provider Function name

In multi-account environments or when the custom resource may be re-utilized across several stacks it may be useful to manually set a name for the Provider Function Lambda and therefore have a predefined service token ARN.

var onEvent function
var isComplete function
var myRole role

myProvider := cr.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: onEvent,
	IsCompleteHandler: isComplete,
	LogGroup: logs.NewLogGroup(this, jsii.String("MyProviderLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	Role: myRole,
	ProviderFunctionName: jsii.String("the-lambda-name"),
})
Customizing Provider Function environment encryption key

Sometimes it may be useful to manually set a AWS KMS key for the Provider Function Lambda and therefore be able to view, manage and audit the key usage.

import kms "github.com/aws/aws-cdk-go/awscdk"

var onEvent function
var isComplete function
var myRole role


key := kms.NewKey(this, jsii.String("MyKey"))
myProvider := cr.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: onEvent,
	IsCompleteHandler: isComplete,
	LogGroup: logs.NewLogGroup(this, jsii.String("MyProviderLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	Role: myRole,
	ProviderFunctionEnvEncryption: key,
})

Custom Resources for AWS APIs

Sometimes a single API call can fill the gap in the CloudFormation coverage. In this case you can use the AwsCustomResource construct. This construct creates a custom resource that can be customized to make specific API calls for the CREATE, UPDATE and DELETE events. Additionally, data returned by the API call can be extracted and used in other constructs/resources (creating a real CloudFormation dependency using Fn::GetAtt under the hood).

The physical id of the custom resource can be specified or derived from the data returned by the API call.

The AwsCustomResource uses the AWS SDK for JavaScript. Services, actions and parameters can be found in the API documentation.

Path to data must be specified using a dot notation, e.g. to get the string value of the Title attribute for the first item returned by dynamodb.query it should be Items.0.Title.S.

To make sure that the newest API calls are available the latest AWS SDK v3 is installed in the Lambda function implementing the custom resource. The installation takes around 60 seconds. If you prefer to optimize for speed, you can disable the installation by setting the installLatestAwsSdk prop to false.

Custom Resource Execution Policy

The policy property defines the IAM Policy that will be applied to the API calls. This must be provided if an existing role is not specified and is optional otherwise. The library provides two factory methods to quickly configure this:

  • AwsCustomResourcePolicy.fromSdkCalls - Use this to auto-generate IAM Policy statements based on the configured SDK calls. Keep two things in mind when using this policy:

    • This policy variant assumes the IAM policy name has the same name as the API call. This is true in 99% of cases, but there are exceptions (for example, S3's PutBucketLifecycleConfiguration requires s3:PutLifecycleConfiguration permissions, Lambda's Invoke requires lambda:InvokeFunction permissions). Use fromStatements if you want to do a call that requires different IAM action names.
    • You will have to either provide specific ARNs, or explicitly use AwsCustomResourcePolicy.ANY_RESOURCE to allow access to any resource.
  • AwsCustomResourcePolicy.fromStatements - Use this to specify your own custom statements.

The custom resource also implements iam.IGrantable, making it possible to use the grantXxx() methods.

As this custom resource uses a singleton Lambda function, it's important to note that the function's role will eventually accumulate the permissions/grants from all resources.

Chained API calls can be achieved by creating dependencies:

awsCustom1 := cr.NewAwsCustomResource(this, jsii.String("API1"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("...")),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

awsCustom2 := cr.NewAwsCustomResource(this, jsii.String("API2"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		Parameters: map[string]*string{
			"text": awsCustom1.getResponseField(jsii.String("Items.0.text")),
		},
		PhysicalResourceId: cr.PhysicalResourceId_*Of(jsii.String("...")),
	},
	Policy: cr.AwsCustomResourcePolicy_*FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})
Physical Resource Id Parameter

Some AWS APIs may require passing the physical resource id in as a parameter for doing updates and deletes. You can pass it by using PhysicalResourceIdReference.

awsCustom := cr.NewAwsCustomResource(this, jsii.String("aws-custom"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		Parameters: map[string]*string{
			"text": jsii.String("..."),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("...")),
	},
	OnUpdate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		Parameters: map[string]interface{}{
			"text": jsii.String("..."),
			"resourceId": cr.NewPhysicalResourceIdReference(),
		},
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

You can omit PhysicalResourceId property in onUpdate to passthrough the value in onCreate. This behavior is useful when using Update APIs that response with an empty body.

AwsCustomResource.getResponseField() and .getResponseFieldReference() will not work if the Create and Update APIs don't consistently return the same fields.

Handling Custom Resource Errors

Every error produced by the API call is treated as is and will cause a "FAILED" response to be submitted to CloudFormation. You can ignore some errors by specifying the ignoreErrorCodesMatching property, which accepts a regular expression that is tested against the code property of the response. If matched, a "SUCCESS" response is submitted. Note that in such a case, the call response data and the Data key submitted to CloudFormation would both be an empty JSON object. Since a successful resource provisioning might or might not produce outputs, this presents us with some limitations:

  • PhysicalResourceId.fromResponse - Since the call response data might be empty, we cannot use it to extract the physical id.
  • getResponseField and getResponseFieldReference - Since the Data key is empty, the resource will not have any attributes, and therefore, invoking these functions will result in an error.

In both the cases, you will get a synth time error if you attempt to use it in conjunction with ignoreErrorCodesMatching.

Customizing the Lambda function implementing the custom resource

Use the role, timeout, memorySize, logGroup, functionName and removalPolicy properties to customize the Lambda function implementing the custom resource:

var myRole role

cr.NewAwsCustomResource(this, jsii.String("Customized"), &AwsCustomResourceProps{
	Role: myRole,
	 // must be assumable by the `lambda.amazonaws.com` service principal
	Timeout: awscdk.Duration_Minutes(jsii.Number(10)),
	 // defaults to 2 minutes
	MemorySize: jsii.Number(1025),
	 // defaults to 512 if installLatestAwsSdk is true
	LogGroup: logs.NewLogGroup(this, jsii.String("AwsCustomResourceLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	FunctionName: jsii.String("my-custom-name"),
	 // defaults to a CloudFormation generated name
	RemovalPolicy: awscdk.RemovalPolicy_RETAIN,
	 // defaults to `RemovalPolicy.DESTROY`
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

Additionally, the Lambda function can be placed in a private VPC by using the vpc and vpcSubnets properties.

var vpc vpc

cr.NewAwsCustomResource(this, jsii.String("CustomizedInVpc"), &AwsCustomResourceProps{
	Vpc: Vpc,
	VpcSubnets: &SubnetSelection{
		SubnetType: ec2.SubnetType_PRIVATE_WITH_EGRESS,
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

Note that Lambda functions in a VPC require Network Address Translation (NAT) in order to access the internet. The subnets specified in vpcSubnets must be private subnets.

Restricting the output of the Custom Resource

CloudFormation imposes a hard limit of 4096 bytes for custom resources response objects. If your API call returns an object that exceeds this limit, you can restrict the data returned by the custom resource to specific paths in the API response:

cr.NewAwsCustomResource(this, jsii.String("ListObjects"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		Service: jsii.String("s3"),
		Action: jsii.String("ListObjectsV2"),
		Parameters: map[string]*string{
			"Bucket": jsii.String("my-bucket"),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("id")),
		OutputPaths: []*string{
			jsii.String("Contents.0.Key"),
			jsii.String("Contents.1.Key"),
		},
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

Note that even if you restrict the output of your custom resource you can still use any path in PhysicalResourceId.fromResponse().

Custom Resource Logging for SDK Calls

By default, logging occurs during execution of the singleton Lambda used by a custom resource. The data being logged includes:

  • The event object that is received by the Lambda handler
  • The response received after making an API call
  • The response object that the Lambda handler will return
  • SDK versioning information
  • Caught and uncaught errors

The logging property defined on the AwsSdkCall interface allows control over what data is being logged on a per SDK call basis. This is configurable via an instance of the Logging class. The Logging class exposes two options that can be used to configure logging:

  1. Logging.all() which enables logging of all data. This is the default logging configuration.
  2. Logging.withDataHidden() which prevents logging of all data associated with the API call response, including logging the raw API call response and the Data field on the Lambda handler response object. This configuration option is particularly useful for situations where the API call response may contain sensitive information.

For further context about Logging.withDataHidden(), consider a user who might be making an API call that is returning sensitive information that they may want to keep hidden. To do this, they would configure logging with Logging.withDataHidden():

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
		Logging: cr.Logging_WithDataHidden(),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

With this configuration option set, the raw API call response would not be logged and the Data field of the response object would be hidden:

{
  "Status": "SUCCESS",
  "Reason": "OK",
  "PhysicalResourceId": "1234567890123",
  "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/Test/043tyub2-194e-4cy2-a969-9891ghj6cd0d",
  "RequestId": "a16y677a-a8b6-41a6-bf7b-7644586861a5",
  "LogicalResourceId": "Sercret",
  "NoEcho": false,
}

For comparison, configuring logging with Logging.all() would result in the raw API call response being logged, as well as the full response object:

{
  "Status": "SUCCESS",
  "Reason": "OK",
  "PhysicalResourceId": "1234567890123",
  "StackId": "arn:aws:cloudformation:us-west-2:123456789012:stack/Test/043tyub2-194e-4cy2-a969-9891ghj6cd0d",
  "RequestId": "a16y677a-a8b6-41a6-bf7b-7644586861a5",
  "LogicalResourceId": "Sercret",
  "NoEcho": false,
  "Data": {
    "region": "us-west-2",
    "Parameter.ARN": "arn:aws:ssm:us-west-2:123456789012:parameter/Test/Parameter",
    "Parameter.DataType": "text",
    "Parameter.Name": "/Test/Parameter",
    "Parameter.Type": "SecureString",
    "Parameter.Value": "ThisIsSecret!123",
    "Parameter.Version": 1
  }
}
Custom Resource Examples
Get the latest version of a secure SSM parameter
getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

// Use the value in another construct with
getParameter.GetResponseField(jsii.String("Parameter.Value"))
Associate a PrivateHostedZone with VPC shared from another account
getParameter := cr.NewAwsCustomResource(this, jsii.String("AssociateVPCWithHostedZone"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		AssumedRoleArn: jsii.String("arn:aws:iam::OTHERACCOUNT:role/CrossAccount/ManageHostedZoneConnections"),
		Service: jsii.String("Route53"),
		Action: jsii.String("AssociateVPCWithHostedZone"),
		Parameters: map[string]interface{}{
			"HostedZoneId": jsii.String("hz-123"),
			"VPC": map[string]*string{
				"VPCId": jsii.String("vpc-123"),
				"VPCRegion": jsii.String("region-for-vpc"),
			},
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("${vpcStack.SharedVpc.VpcId}-${vpcStack.Region}-${PrivateHostedZone.HostedZoneId}")),
	},
	//Will ignore any resource and use the assumedRoleArn as resource and 'sts:AssumeRole' for service:action
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})
Using AWS SDK for JavaScript v3

AwsCustomResource uses Node 18 and AWS SDK v3 by default. You can specify the service as either the name of the SDK module, or just the service name. Using API Gateway as an example, the following formats are all accepted for service:

  • The SDKv3 service name: api-gateway (recommended)
  • The full SDKv3 package name: @aws-sdk/client-api-gateway
  • The SDKv2 constructor name: APIGateway
  • The SDKv2 constructor name in all lower case: apigateway

The following formats are accepted for action:

  • The API call name: GetRestApi (recommended)
  • The API call name with a lowercase starting letter method name: getRestApi
  • The SDKv3 command class name: GetRestApiCommand

For readability, we recommend using the short forms going forward:

cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	ResourceType: jsii.String("Custom::SSMParameter"),
	OnUpdate: &AwsSdkCall{
		Service: jsii.String("ssm"),
		 // 'SSM' in v2
		Action: jsii.String("GetParameter"),
		 // 'getParameter' in v2
		Parameters: map[string]interface{}{
			"Name": jsii.String("foo"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_FromResponse(jsii.String("Parameter.ARN")),
	},
})
Making Cross Account Calls

Example of making a cross account call using an assumed role. If deploying the custom resource in a region where the cross account role is not defined (i.e. an opt-in region that is not enabled in the account owning the role), set the region parameter to a region enabled in that account.

crossAccountRoleArn := "arn:aws:iam::OTHERACCOUNT:role/CrossAccountRoleName" // arn of role deployed in separate account

callRegion := "us-west-1" // sdk call to be made in specified region (optional)

 // sdk call to be made in specified region (optional)
cr.NewAwsCustomResource(this, jsii.String("CrossAccount"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		AssumedRoleArn: crossAccountRoleArn,
		Region: callRegion,
		 // optional
		Service: jsii.String("sts"),
		Action: jsii.String("GetCallerIdentity"),
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("id")),
	},
	Policy: cr.AwsCustomResourcePolicy_FromStatements([]policyStatement{
		iam.*policyStatement_FromJson(map[string]*string{
			"Effect": jsii.String("Allow"),
			"Action": jsii.String("sts:AssumeRole"),
			"Resource": crossAccountRoleArn,
		}),
	}),
})

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AwsCustomResourcePolicy_ANY_RESOURCE

func AwsCustomResourcePolicy_ANY_RESOURCE() *[]*string

func AwsCustomResource_IsConstruct

func AwsCustomResource_IsConstruct(x interface{}) *bool

Checks if `x` is a construct.

Use this method instead of `instanceof` to properly detect `Construct` instances, even when the construct library is symlinked.

Explanation: in JavaScript, multiple copies of the `constructs` library on disk are seen as independent, completely different libraries. As a consequence, the class `Construct` in each copy of the `constructs` library is seen as a different class, and an instance of one class will not test as `instanceof` the other class. `npm install` will not create installations like this, but users may manually symlink construct libraries together or use a monorepo tool: in those cases, multiple copies of the `constructs` library can be accidentally installed, and `instanceof` will behave unpredictably. It is safest to avoid using `instanceof`, and using this type-testing method instead.

Returns: true if `x` is an object created from a class which extends `Construct`.

func AwsCustomResource_PROVIDER_FUNCTION_UUID added in v2.65.0

func AwsCustomResource_PROVIDER_FUNCTION_UUID() *string

func NewAwsCustomResource_Override

func NewAwsCustomResource_Override(a AwsCustomResource, scope constructs.Construct, id *string, props *AwsCustomResourceProps)

func NewLogging_Override added in v2.138.0

func NewLogging_Override(l Logging, props *LoggingProps)

func NewPhysicalResourceIdReference_Override

func NewPhysicalResourceIdReference_Override(p PhysicalResourceIdReference)

func NewProvider_Override

func NewProvider_Override(p Provider, scope constructs.Construct, id *string, props *ProviderProps)

func NewWaiterStateMachine_Override added in v2.116.0

func NewWaiterStateMachine_Override(w WaiterStateMachine, scope constructs.Construct, id *string, props *WaiterStateMachineProps)

func Provider_IsConstruct

func Provider_IsConstruct(x interface{}) *bool

Checks if `x` is a construct.

Use this method instead of `instanceof` to properly detect `Construct` instances, even when the construct library is symlinked.

Explanation: in JavaScript, multiple copies of the `constructs` library on disk are seen as independent, completely different libraries. As a consequence, the class `Construct` in each copy of the `constructs` library is seen as a different class, and an instance of one class will not test as `instanceof` the other class. `npm install` will not create installations like this, but users may manually symlink construct libraries together or use a monorepo tool: in those cases, multiple copies of the `constructs` library can be accidentally installed, and `instanceof` will behave unpredictably. It is safest to avoid using `instanceof`, and using this type-testing method instead.

Returns: true if `x` is an object created from a class which extends `Construct`.

func WaiterStateMachine_IsConstruct added in v2.116.0

func WaiterStateMachine_IsConstruct(x interface{}) *bool

Checks if `x` is a construct.

Use this method instead of `instanceof` to properly detect `Construct` instances, even when the construct library is symlinked.

Explanation: in JavaScript, multiple copies of the `constructs` library on disk are seen as independent, completely different libraries. As a consequence, the class `Construct` in each copy of the `constructs` library is seen as a different class, and an instance of one class will not test as `instanceof` the other class. `npm install` will not create installations like this, but users may manually symlink construct libraries together or use a monorepo tool: in those cases, multiple copies of the `constructs` library can be accidentally installed, and `instanceof` will behave unpredictably. It is safest to avoid using `instanceof`, and using this type-testing method instead.

Returns: true if `x` is an object created from a class which extends `Construct`.

Types

type AwsCustomResource

type AwsCustomResource interface {
	constructs.Construct
	awsiam.IGrantable
	// The principal to grant permissions to.
	GrantPrincipal() awsiam.IPrincipal
	// The tree node.
	Node() constructs.Node
	// Returns response data for the AWS SDK call as string.
	//
	// Example for S3 / listBucket : 'Buckets.0.Name'
	//
	// Note that you cannot use this method if `ignoreErrorCodesMatching`
	// is configured for any of the SDK calls. This is because in such a case,
	// the response data might not exist, and will cause a CloudFormation deploy time error.
	GetResponseField(dataPath *string) *string
	// Returns response data for the AWS SDK call.
	//
	// Example for S3 / listBucket : 'Buckets.0.Name'
	//
	// Use `Token.asXxx` to encode the returned `Reference` as a specific type or
	// use the convenience `getDataString` for string attributes.
	//
	// Note that you cannot use this method if `ignoreErrorCodesMatching`
	// is configured for any of the SDK calls. This is because in such a case,
	// the response data might not exist, and will cause a CloudFormation deploy time error.
	GetResponseFieldReference(dataPath *string) awscdk.Reference
	// Returns a string representation of this construct.
	ToString() *string
}

Defines a custom resource that is materialized using specific AWS API calls.

These calls are created using a singleton Lambda function.

Use this to bridge any gap that might exist in the CloudFormation Coverage. You can specify exactly which calls are invoked for the 'CREATE', 'UPDATE' and 'DELETE' life cycle events.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

// Use the value in another construct with
getParameter.GetResponseField(jsii.String("Parameter.Value"))

func NewAwsCustomResource

func NewAwsCustomResource(scope constructs.Construct, id *string, props *AwsCustomResourceProps) AwsCustomResource

type AwsCustomResourcePolicy

type AwsCustomResourcePolicy interface {
	// resources for auto-generated from SDK calls.
	Resources() *[]*string
	// statements for explicit policy.
	Statements() *[]awsiam.PolicyStatement
}

The IAM Policy that will be applied to the different calls.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

// Use the value in another construct with
getParameter.GetResponseField(jsii.String("Parameter.Value"))

func AwsCustomResourcePolicy_FromSdkCalls

func AwsCustomResourcePolicy_FromSdkCalls(options *SdkCallsPolicyOptions) AwsCustomResourcePolicy

Generate IAM Policy Statements from the configured SDK calls.

Each SDK call with be translated to an IAM Policy Statement in the form of: `call.service:call.action` (e.g `s3:PutObject`).

This policy generator assumes the IAM policy name has the same name as the API call. This is true in 99% of cases, but there are exceptions (for example, S3's `PutBucketLifecycleConfiguration` requires `s3:PutLifecycleConfiguration` permissions, Lambda's `Invoke` requires `lambda:InvokeFunction` permissions). Use `fromStatements` if you want to do a call that requires different IAM action names.

func AwsCustomResourcePolicy_FromStatements

func AwsCustomResourcePolicy_FromStatements(statements *[]awsiam.PolicyStatement) AwsCustomResourcePolicy

Explicit IAM Policy Statements.

type AwsCustomResourceProps

type AwsCustomResourceProps struct {
	// A name for the singleton Lambda function implementing this custom resource.
	//
	// The function name will remain the same after the first AwsCustomResource is created in a stack.
	// Default: - AWS CloudFormation generates a unique physical ID and uses that
	// ID for the function's name. For more information, see Name Type.
	//
	FunctionName *string `field:"optional" json:"functionName" yaml:"functionName"`
	// Whether to install the latest AWS SDK v2.
	//
	// If not specified, this uses whatever JavaScript SDK version is the default in
	// AWS Lambda at the time of execution.
	//
	// Otherwise, installs the latest version from 'npmjs.com'. The installation takes
	// around 60 seconds and requires internet connectivity.
	//
	// The default can be controlled using the context key
	// `@aws-cdk/customresources:installLatestAwsSdkDefault` is.
	// Default: - The value of `@aws-cdk/customresources:installLatestAwsSdkDefault`, otherwise `true`.
	//
	InstallLatestAwsSdk *bool `field:"optional" json:"installLatestAwsSdk" yaml:"installLatestAwsSdk"`
	// The Log Group used for logging of events emitted by the custom resource's lambda function.
	//
	// Providing a user-controlled log group was rolled out to commercial regions on 2023-11-16.
	// If you are deploying to another type of region, please check regional availability first.
	// Default: - a default log group created by AWS Lambda.
	//
	LogGroup awslogs.ILogGroup `field:"optional" json:"logGroup" yaml:"logGroup"`
	// The number of days log events of the singleton Lambda function implementing this custom resource are kept in CloudWatch Logs.
	//
	// This is a legacy API and we strongly recommend you migrate to `logGroup` if you can.
	// `logGroup` allows you to create a fully customizable log group and instruct the Lambda function to send logs to it.
	// Default: logs.RetentionDays.INFINITE
	//
	LogRetention awslogs.RetentionDays `field:"optional" json:"logRetention" yaml:"logRetention"`
	// The memory size for the singleton Lambda function implementing this custom resource.
	// Default: 512 mega in case if installLatestAwsSdk is false.
	//
	MemorySize *float64 `field:"optional" json:"memorySize" yaml:"memorySize"`
	// The AWS SDK call to make when the resource is created.
	// Default: - the call when the resource is updated.
	//
	OnCreate *AwsSdkCall `field:"optional" json:"onCreate" yaml:"onCreate"`
	// The AWS SDK call to make when the resource is deleted.
	// Default: - no call.
	//
	OnDelete *AwsSdkCall `field:"optional" json:"onDelete" yaml:"onDelete"`
	// The AWS SDK call to make when the resource is updated.
	// Default: - no call.
	//
	OnUpdate *AwsSdkCall `field:"optional" json:"onUpdate" yaml:"onUpdate"`
	// The policy that will be added to the execution role of the Lambda function implementing this custom resource provider.
	//
	// The custom resource also implements `iam.IGrantable`, making it possible
	// to use the `grantXxx()` methods.
	//
	// As this custom resource uses a singleton Lambda function, it's important
	// to note the that function's role will eventually accumulate the
	// permissions/grants from all resources.
	//
	// Note that a policy must be specified if `role` is not provided, as
	// by default a new role is created which requires policy changes to access
	// resources.
	// See: Policy.fromSdkCalls
	//
	// Default: - no policy added.
	//
	Policy AwsCustomResourcePolicy `field:"optional" json:"policy" yaml:"policy"`
	// The policy to apply when this resource is removed from the application.
	// Default: cdk.RemovalPolicy.Destroy
	//
	RemovalPolicy awscdk.RemovalPolicy `field:"optional" json:"removalPolicy" yaml:"removalPolicy"`
	// Cloudformation Resource type.
	// Default: - Custom::AWS.
	//
	ResourceType *string `field:"optional" json:"resourceType" yaml:"resourceType"`
	// The execution role for the singleton Lambda function implementing this custom resource provider.
	//
	// This role will apply to all `AwsCustomResource`
	// instances in the stack. The role must be assumable by the
	// `lambda.amazonaws.com` service principal.
	// Default: - a new role is created.
	//
	Role awsiam.IRole `field:"optional" json:"role" yaml:"role"`
	// The timeout for the singleton Lambda function implementing this custom resource.
	// Default: Duration.minutes(2)
	//
	Timeout awscdk.Duration `field:"optional" json:"timeout" yaml:"timeout"`
	// The vpc to provision the lambda function in.
	// Default: - the function is not provisioned inside a vpc.
	//
	Vpc awsec2.IVpc `field:"optional" json:"vpc" yaml:"vpc"`
	// Which subnets from the VPC to place the lambda function in.
	//
	// Only used if 'vpc' is supplied. Note: internet access for Lambdas
	// requires a NAT gateway, so picking Public subnets is not allowed.
	// Default: - the Vpc default strategy if not specified.
	//
	VpcSubnets *awsec2.SubnetSelection `field:"optional" json:"vpcSubnets" yaml:"vpcSubnets"`
}

Properties for AwsCustomResource.

Note that at least onCreate, onUpdate or onDelete must be specified.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

// Use the value in another construct with
getParameter.GetResponseField(jsii.String("Parameter.Value"))

type AwsSdkCall

type AwsSdkCall struct {
	// The service action to call.
	//
	// This is the name of an AWS API call, in one of the following forms:
	//
	// - An API call name as found in the API Reference documentation (`GetObject`)
	// - The API call name starting with a lowercase letter (`getObject`)
	// - The AWS SDK for JavaScript v3 command class name (`GetObjectCommand`).
	// See: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html
	//
	Action *string `field:"required" json:"action" yaml:"action"`
	// The service to call.
	//
	// This is the name of an AWS service, in one of the following forms:
	//
	// - An AWS SDK for JavaScript v3 package name (`@aws-sdk/client-api-gateway`)
	// - An AWS SDK for JavaScript v3 client name (`api-gateway`)
	// - An AWS SDK for JavaScript v2 constructor name (`APIGateway`)
	// - A lowercase AWS SDK for JavaScript v2 constructor name (`apigateway`).
	// See: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html
	//
	Service *string `field:"required" json:"service" yaml:"service"`
	// API version to use for the service.
	// See: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/locking-api-versions.html
	//
	// Default: - use latest available API version.
	//
	ApiVersion *string `field:"optional" json:"apiVersion" yaml:"apiVersion"`
	// Used for running the SDK calls in underlying lambda with a different role.
	//
	// Can be used primarily for cross-account requests to for example connect
	// hostedzone with a shared vpc.
	// Region controls where assumeRole call is made.
	//
	// Example for Route53 / associateVPCWithHostedZone.
	// Default: - run without assuming role.
	//
	AssumedRoleArn *string `field:"optional" json:"assumedRoleArn" yaml:"assumedRoleArn"`
	// The regex pattern to use to catch API errors.
	//
	// The `code` property of the
	// `Error` object will be tested against this pattern. If there is a match an
	// error will not be thrown.
	// Default: - do not catch errors.
	//
	IgnoreErrorCodesMatching *string `field:"optional" json:"ignoreErrorCodesMatching" yaml:"ignoreErrorCodesMatching"`
	// A property used to configure logging during lambda function execution.
	//
	// Note: The default Logging configuration is all. This configuration will enable logging on all logged data
	// in the lambda handler. This includes:
	//  - The event object that is received by the lambda handler
	//  - The response received after making a API call
	//  - The response object that the lambda handler will return
	//  - SDK versioning information
	// - Caught and uncaught errors.
	// Default: Logging.all()
	//
	Logging Logging `field:"optional" json:"logging" yaml:"logging"`
	// Restrict the data returned by the custom resource to specific paths in the API response.
	//
	// Use this to limit the data returned by the custom
	// resource if working with API calls that could potentially result in custom
	// response objects exceeding the hard limit of 4096 bytes.
	//
	// Example for ECS / updateService: ['service.deploymentConfiguration.maximumPercent']
	// Default: - return all data.
	//
	OutputPaths *[]*string `field:"optional" json:"outputPaths" yaml:"outputPaths"`
	// The parameters for the service action.
	// See: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html
	//
	// Default: - no parameters.
	//
	Parameters interface{} `field:"optional" json:"parameters" yaml:"parameters"`
	// The physical resource id of the custom resource for this call.
	//
	// Mandatory for onCreate call.
	// In onUpdate, you can omit this to passthrough it from request.
	// Default: - no physical resource id.
	//
	PhysicalResourceId PhysicalResourceId `field:"optional" json:"physicalResourceId" yaml:"physicalResourceId"`
	// The region to send service requests to.
	//
	// **Note: Cross-region operations are generally considered an anti-pattern.**
	// **Consider first deploying a stack in that region.**
	// Default: - the region where this custom resource is deployed.
	//
	Region *string `field:"optional" json:"region" yaml:"region"`
}

An AWS SDK call.

Example:

cr.NewAwsCustomResource(this, jsii.String("GetParameterCustomResource"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("getParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_FromResponse(jsii.String("Parameter.ARN")),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

type LogOptions added in v2.116.0

type LogOptions struct {
	// The log group where the execution history events will be logged.
	// Default: - a new log group will be created.
	//
	Destination awslogs.ILogGroup `field:"optional" json:"destination" yaml:"destination"`
	// Determines whether execution data is included in your log.
	// Default: - false.
	//
	IncludeExecutionData *bool `field:"optional" json:"includeExecutionData" yaml:"includeExecutionData"`
	// Defines which category of execution history events are logged.
	// Default: - ERROR.
	//
	Level awsstepfunctions.LogLevel `field:"optional" json:"level" yaml:"level"`
}

Log Options for the state machine.

Example:

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"

var logGroup logGroup

logOptions := &LogOptions{
	Destination: logGroup,
	IncludeExecutionData: jsii.Boolean(false),
	Level: awscdk.Aws_stepfunctions.LogLevel_OFF,
}

type Logging added in v2.138.0

type Logging interface {
}

A class used to configure Logging during AwsCustomResource SDK calls.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
		Logging: cr.Logging_WithDataHidden(),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

func Logging_All added in v2.138.0

func Logging_All() Logging

Enables logging of all logged data in the lambda handler.

This includes the event object, the API call response, all fields in the response object returned by the lambda, and any errors encountered.

func Logging_WithDataHidden added in v2.138.0

func Logging_WithDataHidden() Logging

Hides logging of data associated with the API call response.

This includes hiding the raw API call response and the `Data` field associated with the lambda handler response.

type LoggingProps added in v2.138.0

type LoggingProps struct {
	// Whether or not to log data associated with the API call response.
	// Default: true.
	//
	LogApiResponseData *bool `field:"optional" json:"logApiResponseData" yaml:"logApiResponseData"`
}

Properties used to initialize Logging.

Example:

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import "github.com/aws/aws-cdk-go/awscdk"

loggingProps := &LoggingProps{
	LogApiResponseData: jsii.Boolean(false),
}

type PhysicalResourceId

type PhysicalResourceId interface {
	// Literal string to be used as the physical id.
	Id() *string
	// Path to a response data element to be used as the physical id.
	ResponsePath() *string
}

Physical ID of the custom resource.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("AssociateVPCWithHostedZone"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		AssumedRoleArn: jsii.String("arn:aws:iam::OTHERACCOUNT:role/CrossAccount/ManageHostedZoneConnections"),
		Service: jsii.String("Route53"),
		Action: jsii.String("AssociateVPCWithHostedZone"),
		Parameters: map[string]interface{}{
			"HostedZoneId": jsii.String("hz-123"),
			"VPC": map[string]*string{
				"VPCId": jsii.String("vpc-123"),
				"VPCRegion": jsii.String("region-for-vpc"),
			},
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("${vpcStack.SharedVpc.VpcId}-${vpcStack.Region}-${PrivateHostedZone.HostedZoneId}")),
	},
	//Will ignore any resource and use the assumedRoleArn as resource and 'sts:AssumeRole' for service:action
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

func PhysicalResourceId_FromResponse

func PhysicalResourceId_FromResponse(responsePath *string) PhysicalResourceId

Extract the physical resource id from the path (dot notation) to the data in the API call response.

func PhysicalResourceId_Of

func PhysicalResourceId_Of(id *string) PhysicalResourceId

Explicit physical resource id.

type PhysicalResourceIdReference

type PhysicalResourceIdReference interface {
	awscdk.IResolvable
	// The creation stack of this resolvable which will be appended to errors thrown during resolution.
	//
	// This may return an array with a single informational element indicating how
	// to get this property populated, if it was skipped for performance reasons.
	CreationStack() *[]*string
	// Produce the Token's value at resolution time.
	Resolve(_context awscdk.IResolveContext) interface{}
	// toJSON serialization to replace `PhysicalResourceIdReference` with a magic string.
	ToJSON() *string
	// Return a string representation of this resolvable object.
	//
	// Returns a reversible string representation.
	ToString() *string
}

Reference to the physical resource id that can be passed to the AWS operation as a parameter.

Example:

awsCustom := cr.NewAwsCustomResource(this, jsii.String("aws-custom"), &AwsCustomResourceProps{
	OnCreate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		Parameters: map[string]*string{
			"text": jsii.String("..."),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(jsii.String("...")),
	},
	OnUpdate: &AwsSdkCall{
		Service: jsii.String("..."),
		Action: jsii.String("..."),
		Parameters: map[string]interface{}{
			"text": jsii.String("..."),
			"resourceId": cr.NewPhysicalResourceIdReference(),
		},
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

func NewPhysicalResourceIdReference

func NewPhysicalResourceIdReference() PhysicalResourceIdReference

type Provider

type Provider interface {
	constructs.Construct
	// The user-defined AWS Lambda function which is invoked asynchronously in order to determine if the operation is complete.
	IsCompleteHandler() awslambda.IFunction
	// The tree node.
	Node() constructs.Node
	// The user-defined AWS Lambda function which is invoked for all resource lifecycle operations (CREATE/UPDATE/DELETE).
	OnEventHandler() awslambda.IFunction
	// The service token to use in order to define custom resources that are backed by this provider.
	ServiceToken() *string
	// Returns a string representation of this construct.
	ToString() *string
}

Defines an AWS CloudFormation custom resource provider.

Example:

var onEvent function
var isComplete function
var myRole role

myProvider := cr.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: onEvent,
	IsCompleteHandler: isComplete,
	LogGroup: logs.NewLogGroup(this, jsii.String("MyProviderLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	Role: myRole,
	ProviderFunctionName: jsii.String("the-lambda-name"),
})

func NewProvider

func NewProvider(scope constructs.Construct, id *string, props *ProviderProps) Provider

type ProviderProps

type ProviderProps struct {
	// The AWS Lambda function to invoke for all resource lifecycle operations (CREATE/UPDATE/DELETE).
	//
	// This function is responsible to begin the requested resource operation
	// (CREATE/UPDATE/DELETE) and return any additional properties to add to the
	// event, which will later be passed to `isComplete`. The `PhysicalResourceId`
	// property must be included in the response.
	OnEventHandler awslambda.IFunction `field:"required" json:"onEventHandler" yaml:"onEventHandler"`
	// Whether logging for the waiter state machine is disabled.
	// Default: - false.
	//
	DisableWaiterStateMachineLogging *bool `field:"optional" json:"disableWaiterStateMachineLogging" yaml:"disableWaiterStateMachineLogging"`
	// The AWS Lambda function to invoke in order to determine if the operation is complete.
	//
	// This function will be called immediately after `onEvent` and then
	// periodically based on the configured query interval as long as it returns
	// `false`. If the function still returns `false` and the alloted timeout has
	// passed, the operation will fail.
	// Default: - provider is synchronous. This means that the `onEvent` handler
	// is expected to finish all lifecycle operations within the initial invocation.
	//
	IsCompleteHandler awslambda.IFunction `field:"optional" json:"isCompleteHandler" yaml:"isCompleteHandler"`
	// The Log Group used for logging of events emitted by the custom resource's lambda function.
	//
	// Providing a user-controlled log group was rolled out to commercial regions on 2023-11-16.
	// If you are deploying to another type of region, please check regional availability first.
	// Default: - a default log group created by AWS Lambda.
	//
	LogGroup awslogs.ILogGroup `field:"optional" json:"logGroup" yaml:"logGroup"`
	// The number of days framework log events are kept in CloudWatch Logs.
	//
	// When
	// updating this property, unsetting it doesn't remove the log retention policy.
	// To remove the retention policy, set the value to `INFINITE`.
	//
	// This is a legacy API and we strongly recommend you migrate to `logGroup` if you can.
	// `logGroup` allows you to create a fully customizable log group and instruct the Lambda function to send logs to it.
	// Default: logs.RetentionDays.INFINITE
	//
	LogRetention awslogs.RetentionDays `field:"optional" json:"logRetention" yaml:"logRetention"`
	// AWS KMS key used to encrypt provider lambda's environment variables.
	// Default: -  AWS Lambda creates and uses an AWS managed customer master key (CMK).
	//
	ProviderFunctionEnvEncryption awskms.IKey `field:"optional" json:"providerFunctionEnvEncryption" yaml:"providerFunctionEnvEncryption"`
	// Provider Lambda name.
	//
	// The provider lambda function name.
	// Default: -  CloudFormation default name from unique physical ID.
	//
	ProviderFunctionName *string `field:"optional" json:"providerFunctionName" yaml:"providerFunctionName"`
	// Time between calls to the `isComplete` handler which determines if the resource has been stabilized.
	//
	// The first `isComplete` will be called immediately after `handler` and then
	// every `queryInterval` seconds, and until `timeout` has been reached or until
	// `isComplete` returns `true`.
	// Default: Duration.seconds(5)
	//
	QueryInterval awscdk.Duration `field:"optional" json:"queryInterval" yaml:"queryInterval"`
	// AWS Lambda execution role.
	//
	// The role that will be assumed by the AWS Lambda.
	// Must be assumable by the 'lambda.amazonaws.com' service principal.
	// Default: - A default role will be created.
	//
	Role awsiam.IRole `field:"optional" json:"role" yaml:"role"`
	// Security groups to attach to the provider functions.
	//
	// Only used if 'vpc' is supplied.
	// Default: - If `vpc` is not supplied, no security groups are attached. Otherwise, a dedicated security
	// group is created for each function.
	//
	SecurityGroups *[]awsec2.ISecurityGroup `field:"optional" json:"securityGroups" yaml:"securityGroups"`
	// Total timeout for the entire operation.
	//
	// The maximum timeout is 1 hour (yes, it can exceed the AWS Lambda 15 minutes).
	// Default: Duration.minutes(30)
	//
	TotalTimeout awscdk.Duration `field:"optional" json:"totalTimeout" yaml:"totalTimeout"`
	// The vpc to provision the lambda functions in.
	// Default: - functions are not provisioned inside a vpc.
	//
	Vpc awsec2.IVpc `field:"optional" json:"vpc" yaml:"vpc"`
	// Which subnets from the VPC to place the lambda functions in.
	//
	// Only used if 'vpc' is supplied. Note: internet access for Lambdas
	// requires a NAT gateway, so picking Public subnets is not allowed.
	// Default: - the Vpc default strategy if not specified.
	//
	VpcSubnets *awsec2.SubnetSelection `field:"optional" json:"vpcSubnets" yaml:"vpcSubnets"`
	// Defines what execution history events of the waiter state machine are logged and where they are logged.
	// Default: - A default log group will be created if logging for the waiter state machine is enabled.
	//
	WaiterStateMachineLogOptions *LogOptions `field:"optional" json:"waiterStateMachineLogOptions" yaml:"waiterStateMachineLogOptions"`
}

Initialization properties for the `Provider` construct.

Example:

var onEvent function
var isComplete function
var myRole role

myProvider := cr.NewProvider(this, jsii.String("MyProvider"), &ProviderProps{
	OnEventHandler: onEvent,
	IsCompleteHandler: isComplete,
	LogGroup: logs.NewLogGroup(this, jsii.String("MyProviderLogs"), &LogGroupProps{
		Retention: logs.RetentionDays_ONE_DAY,
	}),
	Role: myRole,
	ProviderFunctionName: jsii.String("the-lambda-name"),
})

type SdkCallsPolicyOptions

type SdkCallsPolicyOptions struct {
	// The resources that the calls will have access to.
	//
	// It is best to use specific resource ARN's when possible. However, you can also use `AwsCustomResourcePolicy.ANY_RESOURCE`
	// to allow access to all resources. For example, when `onCreate` is used to create a resource which you don't
	// know the physical name of in advance.
	//
	// Note that will apply to ALL SDK calls.
	Resources *[]*string `field:"required" json:"resources" yaml:"resources"`
}

Options for the auto-generation of policies based on the configured SDK calls.

Example:

getParameter := cr.NewAwsCustomResource(this, jsii.String("GetParameter"), &AwsCustomResourceProps{
	OnUpdate: &AwsSdkCall{
		 // will also be called for a CREATE event
		Service: jsii.String("SSM"),
		Action: jsii.String("GetParameter"),
		Parameters: map[string]interface{}{
			"Name": jsii.String("my-parameter"),
			"WithDecryption": jsii.Boolean(true),
		},
		PhysicalResourceId: cr.PhysicalResourceId_Of(date.now().toString()),
	},
	Policy: cr.AwsCustomResourcePolicy_FromSdkCalls(&SdkCallsPolicyOptions{
		Resources: cr.AwsCustomResourcePolicy_ANY_RESOURCE(),
	}),
})

// Use the value in another construct with
getParameter.GetResponseField(jsii.String("Parameter.Value"))

type WaiterStateMachine added in v2.116.0

type WaiterStateMachine interface {
	constructs.Construct
	// The tree node.
	Node() constructs.Node
	// The ARN of the state machine.
	StateMachineArn() *string
	// Grant the given identity permissions on StartExecution of the state machine.
	GrantStartExecution(identity awsiam.IGrantable) awsiam.Grant
	// Returns a string representation of this construct.
	ToString() *string
}

A very simple StateMachine construct highly customized to the provider framework.

We previously used `CfnResource` instead of `CfnStateMachine` to avoid depending on `aws-stepfunctions` module, but now it is okay.

The state machine continuously calls the isCompleteHandler, until it succeeds or times out. The handler is called `maxAttempts` times with an `interval` duration and a `backoffRate` rate.

Example:

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import cdk "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"

var function_ function
var logGroup logGroup

waiterStateMachine := awscdk.Custom_resources.NewWaiterStateMachine(this, jsii.String("MyWaiterStateMachine"), &WaiterStateMachineProps{
	BackoffRate: jsii.Number(123),
	Interval: cdk.Duration_Minutes(jsii.Number(30)),
	IsCompleteHandler: function_,
	MaxAttempts: jsii.Number(123),
	TimeoutHandler: function_,

	// the properties below are optional
	DisableLogging: jsii.Boolean(false),
	LogOptions: &LogOptions{
		Destination: logGroup,
		IncludeExecutionData: jsii.Boolean(false),
		Level: awscdk.Aws_stepfunctions.LogLevel_OFF,
	},
})

func NewWaiterStateMachine added in v2.116.0

func NewWaiterStateMachine(scope constructs.Construct, id *string, props *WaiterStateMachineProps) WaiterStateMachine

type WaiterStateMachineProps added in v2.116.0

type WaiterStateMachineProps struct {
	// Backoff between attempts.
	BackoffRate *float64 `field:"required" json:"backoffRate" yaml:"backoffRate"`
	// The interval to wait between attempts.
	Interval awscdk.Duration `field:"required" json:"interval" yaml:"interval"`
	// The main handler that notifies if the waiter to decide 'complete' or 'incomplete'.
	IsCompleteHandler awslambda.IFunction `field:"required" json:"isCompleteHandler" yaml:"isCompleteHandler"`
	// Number of attempts.
	MaxAttempts *float64 `field:"required" json:"maxAttempts" yaml:"maxAttempts"`
	// The handler to call if the waiter times out and is incomplete.
	TimeoutHandler awslambda.IFunction `field:"required" json:"timeoutHandler" yaml:"timeoutHandler"`
	// Whether logging for the state machine is disabled.
	// Default: - false.
	//
	DisableLogging *bool `field:"optional" json:"disableLogging" yaml:"disableLogging"`
	// Defines what execution history events are logged and where they are logged.
	// Default: - A default log group will be created if logging is enabled.
	//
	LogOptions *LogOptions `field:"optional" json:"logOptions" yaml:"logOptions"`
}

Initialization properties for the `WaiterStateMachine` construct.

Example:

// The code below shows an example of how to instantiate this type.
// The values are placeholders you should change.
import cdk "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"
import "github.com/aws/aws-cdk-go/awscdk"

var function_ function
var logGroup logGroup

waiterStateMachineProps := &WaiterStateMachineProps{
	BackoffRate: jsii.Number(123),
	Interval: cdk.Duration_Minutes(jsii.Number(30)),
	IsCompleteHandler: function_,
	MaxAttempts: jsii.Number(123),
	TimeoutHandler: function_,

	// the properties below are optional
	DisableLogging: jsii.Boolean(false),
	LogOptions: &LogOptions{
		Destination: logGroup,
		IncludeExecutionData: jsii.Boolean(false),
		Level: awscdk.Aws_stepfunctions.LogLevel_OFF,
	},
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL