I want to make AWS SDK calls from my AWS Cloud Development Kit (AWS CDK) project using the AwsSdkCall interface.
Short description
You can use AWS Software Development Kit (AWS SDK) calls for stack deployment scenarios such as:
- Retrieve configurations while a stack is being created and updated dynamically.
- Retrieve attributes of resources that aren't supported in return values of the resources in AWS CloudFormation.
- Make small patches or configuration changes that aren't supported by AWS CloudFormation.
You can trigger AWS SDK calls on different CloudFormation stack operation events such as Create, Delete, or Update. You don't need to set up access and tools for your deployment pipeline to make AWS SDK calls. The AWS SDK runtime is set up completely by AWS Cloud Development Kit (AWS CDK). Also, you can customize and limit the access for the AWS Lambda function behind the custom resource.
Resolution
Note: The following examples in this resolution use Python. Make sure to use commands specific to the programming language that you're using.
To make an AWS SDK call using AwsSdkCall, you must declare three basic parameters:
- Service - This is the AWS service that you intend to call. Values are case-sensitive.
- Action - This is the API/action call that you intend to make. This usually follows a camel-case pattern. Values are case-sensitive.
- Parameters - These are the optional parameters that you pass while making the API/action call. You can declare parameters as a variable and then pass them to the interface resembling a JSON object for API payload. For more information, see AWS SDK for JavaScript.
1. Retrieve an Amazon Machine Image ID from AWS Systems Manager Agent:
Note: In the following example import custom_resources as cr and aws_cdk as cdk.
get_ami_id = cr.AwsCustomResource(self, "GetAMIId",
on_create=cr.AwsSdkCall(
service="SSM",
action="getParameter",
parameters={
"Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-kernel-5.10-hvm-x86_64-gp2"
},
physical_resource_id=cr.PhysicalResourceId.of('get-ami-id')),
policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
resources=cr.AwsCustomResourcePolicy.ANY_RESOURCE
))
cdk.CfnOutput(self, 'ImageId', value=get_ami_id.get_response_field('Parameter.Value'))
Note: You can reference the response of the API call with the get_response_field parameter.
2. Encrypt the Lambda log group using a custom KMS key:
Note: In the following example, from aws_cdk import aws_lambda as lambda_, custom_resources as cr, and aws_kms as kms.
encryption_key = kms.Key(self, 'Key')
encryption_key.grant_encrypt_decrypt(
iam.ServicePrincipal('logs.amazonaws.com'))
fn = lambda_.Function(self, "MyFunction",
runtime=lambda_.Runtime.NODEJS_16_X,
handler="index.handler",
code=lambda_.Code.from_inline("hello world"))
associate_kms_key = cr.AwsCustomResource(self, "AssociateKmsKey",
on_create=cr.AwsSdkCall(
service="CloudWatchLogs",
action="associateKmsKey",
parameters={
"kmsKeyId": encryption_key.key_arn,
"logGroupName": fn.log_group.log_group_name
},
physical_resource_id=cr.PhysicalResourceId.of("associate-kms-key")),
policy=cr.AwsCustomResourcePolicy.from_sdk_calls(
resources=cr.AwsCustomResourcePolicy.ANY_RESOURCE
)
)
Note: You can use the property policy to grant permissions to the Lambda function behind the custom resource to make API calls. If you use from_sdk_calls(), then each API call is translated into the corresponding AWS Identity and Access Management (IAM) permissions. If the correct permissions aren't added after synthesis, then you can manually add the permissions using from_statements().
Example:
policy=cr.AwsCustomResourcePolicy.from_statements(
statements=[iam.PolicyStatement(actions=[
'dynamodb:DescribeTable', 'dynamodb:ListTables'],
resources=['*'],
)]
)