Skip to content
Welcome To Charanjit Cheema Blog

Welcome To Charanjit Cheema Blog

An Open Source and Cloud Blog

Menu
  • Home
  • About Me!
  • Way to my Technical Blog
  • Contact me
  • Privacy Policy
Menu

How to Bring and Manage Manually Created AWS Resources Under Terraform Management

Posted on January 31, 2025January 31, 2025 by Charanjit Singh

Imagine a scenario where you might prefer to provision the resources manually in Cloud because it’s quick and easy. Maybe you needed a Cloud resource such as security group in a hurry, or someone on the team just created it without thinking about Terraform. Fast forward a few weeks, and now you’ve ended with a mix up of manual and Terraform-managed resources, which can quickly become disorganized.

Now question arises in such condition how do we manage those resources which were not provisioned via Terraform? Answer is Simple: we bring those manually created resources under Terraform’s control without destroying and recreating them.

Why Bother Managing Existing Resources with Terraform?

Managing Cloud resources manually seems fine at first, but the moment you need to make changes (or debug an issue), things get annoying:

  • No tracking – You don’t know who changed what and when.
  • Inconsistencies creep in – One server has port 22 open, another doesn’t. Now you’re scratching your head.
  • Scaling issue – Imagine recreating the same thing across multiple environments manually. A Big Nightmare!

Terraform fixes all of this by treating infrastructure as code. But what about the resources we already created manually? That’s where importing comes in.

Note: In this guide, I have used AWS as an example cloud platform to demonstrate the process. Always take a backup of your Terraform state before importing. I have also included AWS CLI commands to retrieve resource information from AWS. Therefore, I recommend reading the official AWS CLI guide to learn how to install and configure AWS CLI on your system.

 

Procedure to Import Manually Created Resources Under Terraform’s Control

In the following steps, I will guide you through the process of bringing manually created resources under Terraform’s management without recreating them.

Step 1: Find the Resource in AWS

Let’s say we have a security group name RDSSecurityGroup that we created manually to allow access to RDS instance. First, we need to grab its ID. If you don’t remember the name, just list all security groups through AWS CLI command:

aws ec2 describe-security-groups

If you do remember the name, filter it like this:

aws ec2 describe-security-groups –filters “Name=group-name,Values=my-security-group”

 

This will spit out a bunch of details as below, but the most important thing is the Security Group ID (sg-xxxxxxxx). Hold on to that:

PS C:\Users> aws ec2 describe-security-groups –filters “Name=group-name,Values=RDSSecurityGroup”

{

“SecurityGroups”: [

{

“GroupId”: “sg-*************”,

“IpPermissionsEgress”: [

{

“IpProtocol”: “-1”,

“UserIdGroupPairs”: [],

“IpRanges”: [

{

“CidrIp”: “XXX.XXX.XXX.XXX/XX”

}

],

“Ipv6Ranges”: [],

“PrefixListIds”: []

}

],

“VpcId”: “vpc-********”,

“SecurityGroupArn”: “arn:aws:ec2:ap-south-1:************:security-group/sg-*************”,

“OwnerId”: “************”,

“GroupName”: “RDSSecurityGroup”,

“Description”: “RDS instance Access Security Group”,

“IpPermissions”: [

{

“IpProtocol”: “tcp”,

“FromPort”: 3306,

“ToPort”: 3306,

“UserIdGroupPairs”: [],

“IpRanges”: [

{

“CidrIp”: “XXX.XXX.XXX.XXX/XX”

}

],

“Ipv6Ranges”: [],

“PrefixListIds”: []

}

]

}

]

}

 

 

PS C:\Users>

 

Note: You can also get the same resource details as below from the AWS web console, but I find AWS CLI much more convenient:

Step 2: Write Terraform Code for It
Now, we need to define this security group in Terraform. Here’s a simple example:

provider “aws” {

region = ” ap-south-1″  # Change this to your region

}

 

resource “aws_security_group” “existing_sg” {

name        = “RDSSecurityGroup”

description = “This security group was created manually, but now we’re managing it with Terraform.”

vpc_id      = “vpc-xxxxxxxx”  # Replace with your actual VPC ID

 

ingress {

from_port   = 3306

to_port     = 3306

protocol    = “tcp”

cidr_blocks = [“192.168.0.254/32”]  # Replace with your desired IP address

}

}

Now, here’s the thing Terraform doesn’t know this resource already exists in AWS. If we run terraform apply right now, it’ll try to create a new one, which we don’t want. So, we need to import the existing security group into Terraform’s state.

Step 3: Import the Resource
First, make sure Terraform is set up:

terraform init

Then, import the security group using its ID:

terraform import aws_security_group.existing_sg sg-xxxxxxxx

 

Voila! Terraform now knows this security group exists and will manage it going forward. Check out the terraform show command below, which displays the imported RDS Security Group information fetched from the state file:

 

Updating the Configuration of Imported Resources through Terraform

In the previous procedure, we successfully imported the RDS Security Group under Terraform control. Now, what if we want to update the configuration of this imported security group through Terraform? In that case, we need to make changes in the same Terraform configuration file and run the following command:

terraform plan

If it shows any differences and everything looks good, apply the changes using the command below. For example, I am updating the description of the RDS Security Group:

terraform apply

 

PS C:\Users\charanjit\terraform_import_aws_resource> terraform apply –auto-approve

aws_security_group.existing_sg: Refreshing state… [id=sg-**************]

 

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:

-/+ destroy and then create replacement

 

Terraform will perform the following actions:

 

# aws_security_group.existing_sg must be replaced

-/+ resource “aws_security_group” “existing_sg” {

~ arn                    = “arn:aws:ec2:ap-south-1:***********:security-group/sg-**********” -> (known after apply)

~ description            = “RDS instance Access Security Group” -> “This security group was created manually but now we are managing it with Terraform.” # forces replacement

~ egress                 = [

– {

– cidr_blocks      = [

– “0.0.0.0/0”,

]

– from_port        = 0

– ipv6_cidr_blocks = []

– prefix_list_ids  = []

– protocol         = “-1”

– security_groups  = []

– self             = false

– to_port          = 0

# (1 unchanged attribute hidden)

},

] -> (known after apply)

~ id                     = “sg-*****************” -> (known after apply)

# Warning: this attribute value will be marked as sensitive and will not

# display in UI output after applying this change. The value is unchanged.

~ ingress                = (sensitive value)

name                   = “RDSSecurityGroup”

+ name_prefix            = (known after apply)

~ owner_id               = “************” -> (known after apply)

+ revoke_rules_on_delete = false

– tags                   = {} -> null

~ tags_all               = {} -> (known after apply)

# Warning: this attribute value will be marked as sensitive and will not

# display in UI output after applying this change. The value is unchanged.

~ vpc_id                 = (sensitive value)

}

 

Plan: 1 to add, 0 to change, 1 to destroy.

aws_security_group.existing_sg: Destroying… [id=sg-*****************]

aws_security_group.existing_sg: Destruction complete after 1s

aws_security_group.existing_sg: Creating…

aws_security_group.existing_sg: Creation complete after 2s [id=sg-*****************]

 

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

 

PS C:\Users\charanjit\terraform_import_aws_resource>

 

And that’s it! Your security group is now updated through Terraform. You can also check from the AWS Console, as shown in the screenshot below, to see that the RDS Security Group description has been updated:

 

What About Other AWS Resources?

This procedure works for a lot of things: EC2 instances, S3 buckets, IAM roles, RDS databases, load balancers, you name it. The process is pretty much the same:

  1. Find the resource ID using AWS CLI or AWS Console.
  2. Write the Terraform code for it.
  3. Import it into Terraform state.
  4. Run terraform plan and terraform apply if a configuration update is required.

 

Wrap Up!

If you or your team have manually created AWS resources, now’s the time to bring them under Terraform’s management. It might feel like a hassle at first, but trust me, it’ll save you so much time down the road. No more wondering who changed what, no more manual mistakes, just clean, version-controlled infrastructure that’s compliant with DevSecOps processes.

You can check my Below GitHub link in which you can see how I have written code as per real-world examples:
https://github.com/cjcheema/terraform_import_aws_resource

Hope this helps! If you liked my blog, feel free to leave a comment and share it with your network.

 

Loading

  • Author
  • Recent Posts
Charanjit Singh
Follow him
Charanjit Singh
Charanjit is currently working as a Cloud Architect at Mphasis, with 18 years of experience in IT infrastructure projects, implementation, and support. While his main role is as a DevOps engineer, he holds a Cloud Architect position and has strong skills in cloud technologies and automation. His expertise includes Terraform, AWS, Azure DevOps, Azure Cloud, VMware, and Linux systems.

Charanjit is passionate about automating tasks and improving processes. He uses tools like Terraform and Azure DevOps to build and manage cloud infrastructure and streamline deployment. He also enjoys using Shell scripts and Ansible playbooks to make systems run more efficiently.

In his free time, Charanjit enjoys learning about new technologies and sharing his knowledge through his blog. When he’s not working, he likes listening to music, having a cup of coffee, and relaxing in nature.

You can connect with Charanjit on Twitter, Facebook, LinkedIn, or email him at charanjit.cheema@cjcheema.com.
Charanjit Singh
Follow him
Latest posts by Charanjit Singh (see all)
  • How to Deploy Docker Containers with NGINX on AWS EC2 Using Ansible and GitHub Actions - April 26, 2025
  • No More DynamoDB! Use Native S3 locking for Terraform State - February 7, 2025
  • How to Bring and Manage Manually Created AWS Resources Under Terraform Management - January 31, 2025

Like this:

Like Loading...

Related

Leave a ReplyCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Tags

AWS Cloud Computing Dockers Networking Open Networking OpenSource RHEL-CentOS SDN Server Hardware SLES tcpdump Ubuntu WSL

Follow me @

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 2 other subscribers

Recent Posts

  • How to Deploy Docker Containers with NGINX on AWS EC2 Using Ansible and GitHub Actions
  • No More DynamoDB! Use Native S3 locking for Terraform State
  • How to Bring and Manage Manually Created AWS Resources Under Terraform Management
  • Iterating Cloud Resource Provisioning Using Terraform Count and For_Each Meta-Arguments
  • Terraform and Ansible Collaboration for AWS Cloud Deployment

Recent Comments

  1. Charanjit Singh on Terraform and Ansible Collaboration for AWS Cloud Deployment
  2. christinatodd2020aeaa798563 on Terraform and Ansible Collaboration for AWS Cloud Deployment
  3. Charanjit Singh on How to Set password policy in CentOS or RHEL system
  4. SAURABH on How to recover or rebuild initramfs in CentOS 7 Linux
  5. Sangita on How to Set password policy in CentOS or RHEL system

Archives

  • April 2025
  • February 2025
  • January 2025
  • August 2024
  • July 2024
  • June 2024
  • January 2024
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • September 2022
  • August 2022
  • July 2020
  • May 2020
  • February 2020
  • November 2019
  • June 2019
  • May 2019
  • March 2019
  • February 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • June 2018
  • May 2018
  • April 2018

Categories

  • Automation
  • Cloud Computing
  • Coding
  • CyberSecurity
  • Networking
  • OpenSource
  • RHEL-CentOS
  • Server Hardware
  • SLES
  • Technical Blog
  • Ubuntu
  • WSL

Blog Stats

  • 18,353 hits
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy
  • Home
  • About Me!
  • Way to my Technical Blog
  • Contact me
  • Privacy Policy
© 2025 Welcome To Charanjit Cheema Blog | Powered by Superbs Personal Blog theme
 

Loading Comments...
 

    %d