Importing existing AWS resources using AWS CDK

viniciuskneves

Vinicius Kiatkoski Neves

Posted on February 21, 2022

Importing existing AWS resources using AWS CDK

Cover photo from Gavin Allanwood on Unsplash.

I like infrastructure and I advocate AWS CDK for one reason: it allows us to use Typescript (or other languages) which is less of a blocker for new contributors in frontend. It is verbose but it does a lot of the weight lifting for you and is extremely flexible as well.

I've always been curious about the following situation: most companies start setting up their infrastructure through AWS Console. At some point Infrastructure as Code is introduced. How do we close the gap between them? Shall we code everything from scratch?

For a while (end of 2019) we can import existing AWS resources into a CloudFormation Stack. The blog post from AWS does a good job explaining how it works. There is another blog post that explains how to do it with AWS CDK.

My goal here is to make it visual and with code examples. If you follow the steps from both blog posts you are good to go but I found myself confused with some names in between and decided to summarize it for myself (as I'm pretty sure I won't remember how to do it next time) and maybe help you as well.

I'm assuming that you're familiar with AWS CDK and also with CloudFormation. If not, don't hesitate to ask questions and I can try to answer them or guide you to other resources.

AWS CDK output

AWS CDK "simply" translates some code we write into a CloudFormation template in this case, a .json file by the end. It is this file that is used by AWS CloudFormation to setup our infrastructure.

The output from AWS CDK can be found inside the cdk.out/ folder. The CloudFormation template from your stack is in the file MyStackName.template.json.

AWS CDK creates this file whenever we run synth or deploy (which runs synth beforehand). The main difference is that deploy uploads this file to AWS CloudFormation, while synth "only" creates it.

Importing existing AWS resources

I will manually create a bucket in my account and run a small example (the steps are similar for more resources but it takes more time). I called it viniciuskneves-aws-cdk-real-bucket and you can see it in the image below:

Created S3 Bucket

In order to import an existing resource to our stack, we first need to create the stack. We can create a stack with a dummy resource as follows:



import { RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Bucket } from "aws-cdk-lib/aws-s3";

export class AwsCdkTypescriptStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const DummyBucket = new Bucket(this, "DummyBucket", {
      removalPolicy: RemovalPolicy.DESTROY, // Easier to remove later
    });
  }
}



Enter fullscreen mode Exit fullscreen mode

The bucket removal policy was set to delete as this bucket will be deleted later and it is not our real bucket, which will be imported later on.

Now we can run deploy and, after deploying our Stack, we should be able to see it in AWS CloudFormation console:

Created CloudFormation Stack

Following the instructions from AWS, we need to create a template with the resource we would like to import in this case, a S3 bucket. We can rely on AWS CDK to do the job for us. To create a S3 bucket, we need the following piece of code:



import { RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Bucket } from "aws-cdk-lib/aws-s3";

export class AwsCdkTypescriptStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const DummyBucket = new Bucket(this, "DummyBucket", {
      removalPolicy: RemovalPolicy.DESTROY,
    });
    const RealBucket = new Bucket(this, "RealBucket", {
      removalPolicy: RemovalPolicy.RETAIN, // Recommended in order to avoid data loss
    });
  }
}



Enter fullscreen mode Exit fullscreen mode

Now we can run synth to obtain our CloudFormation template. This template contains a bucket but it is not yet deployed, we will use it to manually import the resource through the AWS console.

We can go to our stack in AWS CloudFormation console, click Stack Actions and Import resources into stack:

Import resources into AWS CloudFormation stack

There we select the file created by synth in the step above (cdk.out/MyStackName.template.json):

Select template file from synth

This step tells CloudFormation which new template to use.
The next step is how to link the CloudFormation template with an existing resource. AWS S3 uses the bucket name for linking, so we need to input the bucket name (from the bucket created earlier) here:

Identify S3 bucket resource in CloudFormation

In the last step you will see the applied changes and our imported bucket will be there:

Changes applied to CloudFormation stack after import resource

After a while (in our example it happens almost immediately as we're talking about a single resource) you will find the resource imported in your stack:

CloudFormation events importing resource
List of all S3 resources from CloudFormation template

Now we can try to run deploy again and we will get a message that no changes have been found in the stack, which means success to us:

AWS CDK deploy no changes

From now on we can make changes in the stack and it will be applied as expected, as if the resource had been created by us, in AWS CDK, since the beginning:



const RealBucket = new Bucket(this, "RealBucket", {
  websiteIndexDocument: "index.html",
  removalPolicy: RemovalPolicy.RETAIN,
});


Enter fullscreen mode Exit fullscreen mode

After deploying, we've:

Static web hosting enabled for bucket

We can finally remove the DummyBucket and as it had a destroy policy, the bucket will be removed as expected (no need to manually delete it):



import { RemovalPolicy, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Bucket } from "aws-cdk-lib/aws-s3";

export class AwsCdkTypescriptStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const RealBucket = new Bucket(this, "RealBucket", {
      websiteIndexDocument: "index.html",
      removalPolicy: RemovalPolicy.RETAIN,
    });
  }
}


Enter fullscreen mode Exit fullscreen mode

After deploying, we've:

Resources list with only one bucket

Importing resources that don't follow defaults

Our example above followed a clean approach: the real bucket had no extra configuration, it was the default, the same setup from a bucket created from AWS CDK without any configuration.

What would happen if the bucket had, for example, static webhosting setup?

It will allow us to import the resource as we did in the example above. One curiosity: the defaults, from AWS CDK, won't override already set configuration.

If we deploy the stack, it won't disable static webhosting, for example. The only way to disable it (overwrite it), is to enable it through CDK, deploy, and then remove it from CDK and deploy again.

Even if you run cdk diff you won't get this as a diff as it will compare the output of synth with the template that has been uploaded to CloudFormation. Stack drift won't highlight it as well which is weird.

It is a good approach as it won't magically overwrite everything that has been working. It could be tricky though if you don't know that a resource had been imported and some defaults don't apply to it.

What would happen if the template had some setup, like static webhosting, when importing an existing resource?

It is the opposite of the situation above. The resource we create in AWS CDK to be imported has some setup and is not the default resource.

There are two cases:

  1. Imported resource and template have the same setup (static webhosting enabled): no problem. The resource is imported and changes made in CDK will apply once you deploy.
  2. Imported resource and template have a different setup (static webhosting enabled in template): the difference won't be applied but drift will warn you that there is a difference.

Drift from imported resource


I hope it helps you, as it helped me, to visualize the process described in both blog posts mentioned in the introduction. I also went a bit further to explore drifts in the CloudFormation stack but it is a bit weird (check the examples above).

If you've further insights/questions, feel free to drop them in the comments!

💖 💪 🙅 🚩
viniciuskneves
Vinicius Kiatkoski Neves

Posted on February 21, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related