<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nikhil Zadoo</title>
    <description>The latest articles on DEV Community by Nikhil Zadoo (@nikhilzadoo).</description>
    <link>https://dev.to/nikhilzadoo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F634685%2F5255c2e3-07de-4437-9e30-fc1f1077b824.jpeg</url>
      <title>DEV Community: Nikhil Zadoo</title>
      <link>https://dev.to/nikhilzadoo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikhilzadoo"/>
    <language>en</language>
    <item>
      <title>AWS Custom Resource using CDK `AwsCustomResource` construct</title>
      <dc:creator>Nikhil Zadoo</dc:creator>
      <pubDate>Mon, 24 May 2021 11:23:59 +0000</pubDate>
      <link>https://dev.to/nikhilzadoo/aws-custom-resource-using-cdk-awscustomresource-construct-5emn</link>
      <guid>https://dev.to/nikhilzadoo/aws-custom-resource-using-cdk-awscustomresource-construct-5emn</guid>
      <description>&lt;h1&gt;
  
  
  Prerequisite
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Understanding of AWS CDK (Cloud development kit)&lt;/li&gt;
&lt;li&gt;Understanding of AWS Custom resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  INTRODUCTION
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;All through the blog I will be mentioning terms &lt;strong&gt;custom resource lambda&lt;/strong&gt; and &lt;strong&gt;custom resource&lt;/strong&gt;. Both terms look similar but actually are different. &lt;strong&gt;Custom resource lambda&lt;/strong&gt; refers to the lambda that is responsible for implementing the logic. &lt;strong&gt;Custom resource&lt;/strong&gt; is the resource itself that is created by invoking the custom resource lambda.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this blog I am covering a niche scenario related to AWS custom resources when all your custom resource lambda needs is to call an AWS API. Usual use case of doing so would be when cloudformation does not support a resource and it is only available with an API.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For all other use cases, please refer to my earlier blog &lt;a href="https://nikhil-zadoo.com/custom-resources-with-aws-cdk"&gt;Custom Resources with AWS CDK&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;CDK Construct &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_custom-resources.AwsCustomResource.html"&gt;AwsCustomResource&lt;/a&gt; helps us achieve that. It takes care of creating custom resource lambda and permissions needed under the hood. As a custom resource author, all you need to do is pass the &lt;strong&gt;AWS Service&lt;/strong&gt; and &lt;strong&gt;API action&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why should you use yet another way of creating custom resource?
&lt;/h3&gt;

&lt;p&gt;Although you can achieve the same results using &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_custom-resources.Provider.html"&gt;Provider&lt;/a&gt; cdk construct described in my &lt;a href="https://nikhil-zadoo.com/custom-resources-with-aws-cdk"&gt;previous blog&lt;/a&gt;, the reasons why you might choose this method are:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You will see all these points in action in the example below. So revisit these points again after going through the example for better understanding)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;You do not need to even create a Custom resource lambda explicitly&lt;/li&gt;
&lt;li&gt;You do not need to manage the permissions needed by custom resource lambda anymore. CDK construct takes care of it. Also it follows the least privilege principle by design.&lt;/li&gt;
&lt;li&gt;It seamlessly blends with your CDK code&lt;/li&gt;
&lt;li&gt;CDK interfaces and enums definitions can be leveraged since all you code is part of CDK application and not a separate lambda&lt;/li&gt;
&lt;li&gt;You need lesser lines of code to achieve the same results&lt;/li&gt;
&lt;li&gt;Code readability is better&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  EXAMPLE
&lt;/h3&gt;

&lt;p&gt;Below is an example of a use case not possible to achieve with Cloudformation.&lt;/p&gt;

&lt;p&gt;If you want to create a subscription when the SNS topic and the endpoint are in different regions, it is not possible with Cloudformation at the moment.&lt;/p&gt;

&lt;p&gt;Let us try and create a custom resource for it using CDK construct &lt;strong&gt;AwsCustomResource&lt;/strong&gt;. This construct will be responsible for calling AWS &lt;strong&gt;subscribe&lt;/strong&gt; and &lt;strong&gt;unsubscribe&lt;/strong&gt; API's.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as lambda from '@aws-cdk/aws-lambda';
import * as sns from '@aws-cdk/aws-sns';
import * as cdk from '@aws-cdk/core';
import * as cr from '@aws-cdk/custom-resources';

export class CustomResourceSNS extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    const topicArnInAnotherRegion = '&amp;lt;ARN_TOPIC_IN_DIFFERENT_REGION&amp;gt;';

    // Just a dummy lambda to act as an endpoint for SNS. Don't confuse it as lambda for CDK resource
    const dummyLambdaEndpoint = new lambda.Function(this, 'Function', {
      code: lambda.Code.fromInline('exports.handler = async (event) =&amp;gt; {console.log(event)};'),
      handler: 'index.handler',
      runtime: lambda.Runtime.NODEJS_12_X,
    });

    // Construct that takes care of creating the custom resource
    new cr.AwsCustomResource(this, 'SNSCustomResource', {
      policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
        resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
      }),
      onCreate: {
        action: 'subscribe',
        service: 'SNS',
        physicalResourceId: cr.PhysicalResourceId.fromResponse('SubscriptionArn'),
        region: '&amp;lt;TOPIC_REGION&amp;gt;',
        parameters: {
          Protocol: sns.SubscriptionProtocol.LAMBDA,
          TopicArn: topicArnInAnotherRegion,
          Endpoint: dummyLambdaEndpoint.functionArn,
        },
      },
      onUpdate: {
        action: 'subscribe',
        service: 'SNS',
        physicalResourceId: cr.PhysicalResourceId.fromResponse('SubscriptionArn'),
        region: '&amp;lt;TOPIC_REGION&amp;gt;',
        parameters: {
          Protocol: sns.SubscriptionProtocol.LAMBDA,
          TopicArn: topicArnInAnotherRegion,
          Endpoint: dummyLambdaEndpoint.functionArn,
        },
      },
      onDelete: {
        action: 'unsubscribe',
        service: 'SNS',
        region: '&amp;lt;TOPIC_REGION&amp;gt;',
        parameters: {
          SubscriptionArn: new cr.PhysicalResourceIdReference(), // Passes the physical resource ID set during CREATE/UPDATE
        },
      },
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding the code
&lt;/h3&gt;

&lt;p&gt;You might have already noticed some differences with the &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_custom-resources.Provider.html"&gt;Provider&lt;/a&gt; CDK construct.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_custom-resources.Provider.html"&gt;Provider&lt;/a&gt; CDK construct just like &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html"&gt;Cloudformation custom resources&lt;/a&gt; first creates a custom resource lambda, which you later reference using &lt;strong&gt;serviceToken&lt;/strong&gt; property in your custom resource. The semantics of &lt;strong&gt;AwsCustomResource&lt;/strong&gt; work a little differently. Here everything is done in 1 shot. You do not create a custom resource lambda separately and then reference it in your custom resource. Both the custom resource lambda and custom resource itself are created by the same AwsCustomResource construct.&lt;/p&gt;

&lt;p&gt;As understandable by their names, &lt;strong&gt;onCreate, onUpdate&lt;/strong&gt; and &lt;strong&gt;onDelete&lt;/strong&gt; properties represent the lifecycle events of the custom resource and are invoked when the custom resource is created, updated or deleted respectively.&lt;/p&gt;

&lt;h4&gt;
  
  
  Let us go through the interesting parts in the code one by one:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...
      policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
        resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
      }),
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Property &lt;code&gt;policy&lt;/code&gt; configures the IAM permissions for your custom resource lambda role. Method &lt;code&gt;fromSdkCalls&lt;/code&gt; adds actions configured in &lt;code&gt;onCreate&lt;/code&gt;, &lt;code&gt;onUpdate&lt;/code&gt; and &lt;code&gt;onDelete&lt;/code&gt; properties, to the custom resource lambda IAM policy. Based on the above example, custom resource lambda IAM policy will have &lt;code&gt;sns:subscribe&lt;/code&gt; and &lt;code&gt;sns:unsubscribe&lt;/code&gt; permissions.&lt;/p&gt;

&lt;p&gt;Property &lt;code&gt;resources&lt;/code&gt; controls which resources the custom resource lambda role will be given access to. &lt;code&gt;AwsCustomResourcePolicy.ANY_RESOURCE&lt;/code&gt; will simply pass &lt;code&gt;"*"&lt;/code&gt; wildcard as resource in the custom resource lambda IAM policy. However you should always aim to explicitly pass the resources so as to follow the least privilege principle. In our example we could have used it like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resources: [topicArnInAnotherRegion],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;








&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...
      onCreate: {
        action: 'subscribe',
        service: 'SNS',
        physicalResourceId: cr.PhysicalResourceId.fromResponse('SubscriptionArn'),
        region: '&amp;lt;TOPIC_REGION&amp;gt;',
        parameters: {
          Protocol: sns.SubscriptionProtocol.LAMBDA,
          TopicArn: topicArnInAnotherRegion,
          Endpoint: dummyLambdaEndpoint.functionArn,
        },
      },
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This block is configuring the various parameters that we intend to pass to the  &lt;a href="https://docs.aws.amazon.com/sns/latest/api/API_Subscribe.html"&gt;AWS SUBSCRIBE API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;physicalResourceId: PhysicalResourceId.fromResponse('SubscriptionArn')&lt;/code&gt; This piece of code tells lambda to fetch &lt;code&gt;SubscriptionArn&lt;/code&gt; from the response of sns subscribe api call and set it as physical resource id for the custom resource created.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;onUpdate&lt;/code&gt; block also works similarly.&lt;/p&gt;






&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ...
      onDelete: {
        action: 'unsubscribe',
        service: 'SNS',
        region: '&amp;lt;TOPIC_REGION&amp;gt;',
        parameters: {
          SubscriptionArn: new cr.PhysicalResourceIdReference(),
        },
      },
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the &lt;code&gt;onDelete&lt;/code&gt; block the only interesting part of code is &lt;code&gt;SubscriptionArn: new cr.PhysicalResourceIdReference()&lt;/code&gt;. Class &lt;code&gt;PhysicalResourceIdReference&lt;/code&gt; is responsible here to return the current physical resource id set for the custom resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  CONCLUSION
&lt;/h3&gt;

&lt;p&gt;In conclusion, the aim of the construct &lt;strong&gt;AwsCustomResource&lt;/strong&gt; is to abstract away all the infrastructure parts and let you as a custom resource author just care about the parameters needed to be passed to the underlying AWS API. It creates a lambda for you and also manages the permissions needed by lambda.&lt;/p&gt;

&lt;p&gt;Although as mentioned at the beginning of the article also, this method serves a very specific use case. You might not use it that often. Do check out my other post on &lt;a href="https://nikhil-zadoo.com/custom-resources-with-aws-cdk"&gt;Custom Resources with AWS CDK&lt;/a&gt;. That is how you will most likely be using the custom resources.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>devops</category>
      <category>cloudskills</category>
    </item>
    <item>
      <title>Custom Resources with AWS CDK</title>
      <dc:creator>Nikhil Zadoo</dc:creator>
      <pubDate>Thu, 20 May 2021 11:47:42 +0000</pubDate>
      <link>https://dev.to/nikhilzadoo/custom-resources-with-aws-cdk-56l5</link>
      <guid>https://dev.to/nikhilzadoo/custom-resources-with-aws-cdk-56l5</guid>
      <description>&lt;h1&gt;
  
  
  Prerequisite
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Understanding of AWS CDK (Cloud development kit)&lt;/li&gt;
&lt;li&gt;Understanding of AWS Custom resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Custom resource with lib @aws-cdk/custom-resources
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html"&gt;CDK&lt;/a&gt; provides a library for conveniently writing custom resources.&lt;br&gt;
As a custom resource author how does it make your life any easier?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a custom resource author, &lt;strong&gt;you can focus on the actual logic for the custom resource and let CDK take care of other boilerplate stuff.&lt;/strong&gt; Eg- you do not need to worry about sending the response back to the pre-signed S3 URL. Just return &lt;code&gt;PhysicalResourceId&lt;/code&gt; using the return statement and you are good to go. Consequently it also makes your code easier to read and maintain.&lt;/li&gt;
&lt;li&gt;Doubling down on the point above, in case your Custom resource lambda needs to run for more than the lambda timeout, this cdk construct can also take care of polling and retrying by using an additional handler &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_custom-resources.Provider.html#iscompletehandler"&gt;isComplete&lt;/a&gt;. An example where this might come in handy would be if you are provisioning some service on EC2 which takes 20~30 mins to stabilize (consider that the max time a lambda can run is 15 minutes at the moment)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  How does it do all these things?
&lt;/h3&gt;

&lt;p&gt;As you might have already guessed, the answer is using a wrapper lambda which takes care of the boilerplate stuff, so that you as a custom resource author just concentrate on the logic needed for creating the actual resource.&lt;/p&gt;

&lt;p&gt;Lambda needs to return &lt;code&gt;PhysicalResourceId&lt;/code&gt; and if needed &lt;code&gt;Data&lt;/code&gt;.&lt;br&gt;
Here is an example custom resource lambda which just reads the latest ami-id and returns it after reading from SSM parameter &lt;code&gt;/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2&lt;/code&gt;. This example is written in &lt;code&gt;typescript&lt;/code&gt; but you can easily achieve  the same in the language of your choice (should  be supported by AWS LAMBDA ofcourse).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that this example is just to demonstrate how to use custom resources with CDK. It has no real use case, since you can always directly use this SSM parameter in your CDK app / Cloudformation stack to get the AMI.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { CloudFormationCustomResourceEvent } from 'aws-lambda';
import * as AWS from 'aws-sdk';

export const handler = async (event: CloudFormationCustomResourceEvent) =&amp;gt; {
  const ssm = new AWS.SSM();
  switch (event.RequestType) {
    case 'Update':
    case 'Create': {
      const ami = await ssm.getParameter({
        Name: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2',
      }).promise();
      return {
        PhysicalResourceId: ami.Parameter?.Value,
      };
    }
    case 'Delete': {
      return;
    }
    default: {
      throw new Error('Unknown request type');
    }
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stitching it with CDK
&lt;/h3&gt;

&lt;p&gt;Now that we have a lambda which does the actual job of fetching the AMI ID from the SSM parameter, we will see how to use it inside a CDK application. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';
import * as cr from '@aws-cdk/custom-resources';

export class CustomResourceWithCDK extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: cdk.StackProps) {
    super(scope, id, props);

    // Points to the lambda we saw above
    const customResourceLambda = new lambda.Function(this, 'CRLambda', {
      code: lambda.Code.fromAsset(`${__dirname}/&amp;lt;LOCAL_PATH_TO_LAMBDA&amp;gt;`),
      handler: 'index.handler',
      runtime: lambda.Runtime.NODEJS_12_X,
    });

    // Allow lambda to read SSM parameter
    const ssmPolicy = new iam.PolicyStatement({
      effect: iam.Effect.ALLOW,
      actions: ['ssm:*'],
      resources: ['arn:aws:ssm:eu-west-1::parameter/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'],
    });
    customResourceLambda.addToRolePolicy(ssmPolicy);

    // Create a custom resource provider which wraps around the lambda above
    const customResourceProvider = new cr.Provider(this, 'CRProvider', {
      onEventHandler: customResourceLambda,
    });

    // Create a new custom resource consumer
    new cdk.CustomResource(this, 'CustomResourceAMIConsume', {
      serviceToken: customResourceProvider.serviceToken,
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding this CDK code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const customResourceLambda = new lambda.Function(
    ...
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part deploys the actual lambda responsible for the Custom resource logic (The first lambda example we saw in this example)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const customResourceProvider = new cr.Provider(
    ...
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This part is responsible for creating a wrapper around your lambda. This wrapper takes care of sending the response back to s3 Pre signed URL in case of SUCCESS/Failure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new cdk.CustomResource(
    ...
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this part we are just consuming the Custom resource created above.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is an even easier way of writing custom resources with CDK if the custom resource just needs to call an AWS API call. I have covered it under &lt;a href="https://nikhil-zadoo.com/aws-custom-resource-using-cdk-awscustomresource-construct"&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>cloudskills</category>
      <category>devops</category>
      <category>cdk</category>
    </item>
  </channel>
</rss>
