Digital Age Experts, LLC

Extending CloudFormation Using Custom Resources

With the breakneck pace at which Amazon launches new services and features, it’s frequent that our inner DevOps wants to leap into action and introduce it into our CloudFormations. Often, this is not an issue, as AWS normally will roll out corresponding Cloud Formation (CFN) resource types at the same time. However, that is not always the case – like for Aurora Serverless back in April 2018. Custom resources fill the gap left when 1) AWS doesn’t release a CFN needed resource type or 2) you have particular logic that needs to be executed within a CFN.

CloudFormation Custom Resources offers the ability to create any custom type your heart desires. Custom Resources has been available since Nov 2013, but even though it has been out that long, it is surprising how often people don’t know about it.

Custom Resources come in two variations – Service or Lambda-backed.  Service-based resources are essentially any AWS  services the can receive input and that you can reference via an ARN. It is very common to use SQS and SNS as a custom resource provider, but it is possible to use other services (though they are less common).  Lambda-backed uses Lambda, duh, and has become the go-to backend for Custom Resources. It so versatile and straightforward it is used most often.

For a moment pretend we live in a world where CloudFormation doesn’t allow you to create S3 buckets. I know that would be a true nightmare. In this world, we need to enable CloudFormation to create a bucket – what are we to do?! Let’s use Lambda to call the S3 API via Custom Resources.

Below you will see an in-line Lambda resource being created in a CloudFormation (to keep this example simple). The Lambda function, when called, will create a specific S3 bucket. Moreover, it will delete that bucket if the CloudFormation stack is removed. This example uses the cfn-response library to make interacting with CloudFormation from Lambda easier.

AWSTemplateFormatVersion: 2010-09-09
Resources:
  CreateS3BucketFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.handler
      Role: arn:aws:iam::<aws account number></account>:role/LambdaS3ExecRole
      Code:
        ZipFile: !Sub |
            var AWS = require('aws-sdk');
            var s3 = new AWS.S3();
            var response = require('cfn-response');
            var responseData = {};

            exports.handler = function(event, context) {
            var params = {
            Bucket: 'demo-bucketname-monkey'
            };
            
            #Respond to a CFN Delete Call
            if (event.RequestType == 'Delete') {
            s3.deleteBucket(params, function(err, data) {
            if (err) {
                console.log(err);
            }
            else {
                console.log(data);
            }
            });
            response.send(event, context, response.SUCCESS);
            return;
            }
            #Call S3 to create a bucket
            s3.createBucket(params, function(err, data) {
            if (err) {
            responseData = { 'status': 'Error' };
            console.log("CreateBucket");
            console.log(err);
            response.send(event, context, response.FAILED, responseData);
            
            }
            else {
            responseData = { 'status': 'Success' };
            console.log(err);
            console.log(responseData);
            response.send(event, context, response.SUCCESS, responseData);
            
            }
            });
            }
      Runtime: nodejs4.3
  S3Function: 
   Type: Custom::CallLambdaBackend
   Properties:
    ServiceToken: !GetAtt CreateS3BucketFunction.Arn
Outputs:
   Results:
    Description: Create S3 Result
    Value: !GetAtt S3Function.status

Other useful scenarios Custom Resources makes possible:

  • Business logic can be processed before creating a resource. Say a resource is only needed if a series of conditions stored in some random corporate database exists.
  • Enforce password or other types of validity checks on inputted parameters beyond standard regex patterns.

Keep CFN Custom Resources in mind when there are new resources or features available that don’t have corresponding CFN resource types yet or when you need to trigger rather elaborate procedures as part of your DevOps.  This was only one example; you could have Lambda do anything your hearts desires from this point.

By Gabriel Alix

Leave a Reply

Close Menu