CloudFormation can import existing AWS resources into a stack, but it doesn’t magically discover them; you have to tell it exactly what you want to import and how it should represent them.

Let’s see this in action. Suppose you have a VPC that you didn’t create with CloudFormation, and you want to bring it under management.

First, you need the VPC’s ID. You can get this from the AWS console or using the AWS CLI:

aws ec2 describe-vpcs --filters "Name=tag:Name,Values=my-existing-vpc" --query "Vpcs[*].VpcId" --output text

This might return vpc-0123456789abcdef0.

Now, you need to create a CloudFormation template that describes this VPC. You can do this manually or by "exporting" the existing resource’s properties. For a VPC, the template might look like this:

Resources:
  MyExistingVpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: my-existing-vpc

The crucial part here is that the CidrBlock, EnableDnsSupport, EnableDnsHostnames, and Tags must exactly match the properties of the existing VPC. If they don’t, CloudFormation won’t be able to import it.

Once you have this template, you initiate the import process using the AWS CLI:

aws cloudformation import-existing-stack \
  --stack-name my-imported-stack \
  --template-body file://vpc-template.yaml \
  --logical-resource-id MyExistingVpc \
  --physical-resource-id vpc-0123456789abcdef0

This command tells CloudFormation to:

  • Create a new stack named my-imported-stack.
  • Use the vpc-template.yaml to define the resources.
  • Specifically target the resource named MyExistingVpc within that template.
  • Associate this logical resource with the physical AWS resource identified by vpc-0123456789abcdef0.

After running this, CloudFormation will attempt to import the VPC. If successful, the VPC will now be managed by my-imported-stack. Any subsequent updates to this VPC must go through CloudFormation.

The system’s surprising truth is that "importing" isn’t a discovery mechanism; it’s a declaration. You’re telling CloudFormation, "This resource already exists and its properties are exactly what I’m describing in this template. Please acknowledge its existence and start managing it." If your description deviates from reality, the import fails because CloudFormation can’t reconcile your template with the actual state of the resource. This is why getting the properties precisely right is paramount.

The mental model here is that CloudFormation is essentially performing a "drift detection" check before it takes ownership. It compares your template’s declared properties against the actual properties of the physical resource. If they match, it registers the resource as managed. If they don’t, it flags an error, preventing the import and thus avoiding a potential conflict where CloudFormation might try to "update" a resource to a state it’s already in, or worse, to a state that breaks its existing functionality.

This process is particularly powerful when you’re migrating existing infrastructure to a codified state. You can gradually bring resources under CloudFormation management without needing to recreate them. For instance, you might have a production RDS instance that was manually provisioned. You can create a CloudFormation template describing that instance, specify its DBInstanceIdentifier as the physical resource ID, and import it. From that point on, any changes to the RDS instance’s configuration (like scaling storage or modifying parameters) would be done through updates to the CloudFormation stack.

You’ll often find that importing resources with complex dependencies requires you to import those dependencies first. For example, if you’re importing an EC2 instance, you’ll likely need to import its associated VPC, subnets, security groups, and potentially IAM roles before you can successfully import the instance itself. CloudFormation needs to see the entire lineage of managed resources to correctly associate them.

The next challenge you’ll face is understanding how CloudFormation handles drift detection on imported resources.

Want structured learning?

Take the full Cloudformation course →