Terraform Notes
it’s just terraform notes.
1. The Background
There are two ways to manage infrastructure:
- Manually
- Through automation
When I first learned AWS, I created everything using the console. I clicked here and there to create EC2, S3, VPC, and other resources. At that time, it felt easy and normal. For learning, I think using the console helped me understand what each service does.
The problem started when my project became bigger. I had many resources. Some of them depended on each other. For example, an EC2 instance needs a VPC, subnet, security group, and IAM role. If I deleted one thing by mistake, other resources stopped working. Sometimes I even forgot what I created before.
Another problem was when I wanted to create the same setup again. I had to repeat all the steps manually. It took time, and sometimes I missed some settings. The result was not always the same.
So this manual approach can be solved by using Infrastructure as Code (IaC), such as Terraform or CloudFormation. Instead of creating resources one by one from the console, we define everything in code.
In this article, I will write notes about my journey learning Terraform. I will not explain the concepts in very detailed way because this is just for my personal note. I write this so I can come back and read it again if I forget some concepts in the future.
2. IAC Categories
2.1 Infrastrucure Orchestration
Infrastructure Orchestration is used to create and manage infrastructure. It focuses on provisioning resources like servers, networks, and databases.
Example:
- Create 3 EC2 instances with 8 GB RAM and 4 vCPUs
- Allow SSH access only from my IP address
- Create VPC, subnet, and security group
Tools example: Terraform, CloudFormation
2.2 Configuration Management
Configuration Management is used to manage software inside the server. It focuses on installing and configuring applications after the server is created.
Example:
- Install Nginx on EC2
- Configure Nginx to serve a static website
- Install Antivirus version 11.0.0 on all EC2 instances
Tools example: Ansible, Chef, Puppet
3. Authentication and Authorization
- Authentication is the process of verifying who a user is.
- Authorization is the process of verifying what they are allowed to access.
When using Terraform, make sure you have access to AWS (or another cloud provider) and you have permission to create resources. If you only have ReadOnly permission, you cannot create or modify resources. To connect Terraform with AWS, you need credentials. You can use:
- Temporary access key (recommended)
- IAM User access key
- Github Tokens
You can visit these documentation to configure credentials using AWS CLI
4. Providers and Resources
Terraform supports multiple providers such as AWS, Azure, Google Cloud, Kubernetes, Oracle Cloud, and Alibaba Cloud.
4.1 Provider Plugins
When you run terraform init, Terraform will download the provider plugin automatically. The plugin will be saved in the .terraform directory.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
# Constrain to a specific version range
version = "~> 6.7.0"
}
}
}
# AWS Provider with a specific region
provider "aws" {
region = "us-east-1"
}
For production use, you should always used version argument to ensure new version doesn’t break the current version.
4.2 Resources
A resource block is used to create infrastructure.
resource "aws_instance" "web_server1" {
# configuration here
}
Explanation:
aws_instance→ resource typeweb_server1→ local name (identifier)
The local name must be unique in the same project.
5. Terraform Destroy
Use the following command to destroy all resources created by Terraform.
# Destroy all resources
terraform destroy
# Destroy specific resources
terraform destroy -target=<resource_type>.<resource_name>
# Example
terraform destroy -target=aws_instance.web_server1
6. Terraform State File
Terraform state file is a file that stores information about the resources Terraform manages.
The filename is terraform.tfstate.
Terraform uses this file to:
- Track what resources are created
- Know the current state of infrastructure
- Compare real infrastructure with your code
7. Desired and Current State
7.1 Desired State
Desired state is what you define in your .tf files. It is the condition you want your infrastructure to be.
resource "aws_instance" "web_server1" {
instance_type = "t3.micro"
}
Here, your desired state is: You want one EC2 instance with type t3.micro.
7.2 Current State
Current state is the real condition of your infrastructure right now. Terraform gets this information from:
- The terraform.tfstate file
- The real infrastructure in AWS
7.2.1 How it works?
- When you run
terraform plan, Terraform will check the current state of your infrastructure. - Terraform compares:
- Desired state (your code)
- Current state (real infrastructure)
- If they are different, Terraform will show what needs to change. (TF Drift)
- When you run
terraform applyTerraform will make the current state match the desired state.
Notes! Always make sure the current state and desired state are the same. The configuration in AWS Console must match your Terraform script. If they are different and you run terraform apply, Terraform will detect the changes and modify the resources to match your code.
So, in summary:
- Desired state → What you want (tf scripts)
- Current state → What exists now (in AWS Console)
- Terraform → Makes them the same (
terraform apply)
I always fix tf drift when this is happen.
8. Terraform Refresh
terraform refresh is used to update the Terraform state file with the real condition of your infrastructure.
It reads all resources from the cloud provider and updates the terraform.tfstate file.
Important:
- It does NOT change real resources in AWS.
- It only updates the Terraform state file. Sometimes, resources are changed manually in AWS console.
Example:
You change EC2 instance type from t3.micro to t3.small directly in AWS Console.
Now:
- Real infrastructure →
t3.small - Terraform state → still
t3.micro
The state is not accurate anymore. Running terraform refresh will sync the state with the real infrastructure.
It is equal to:
terraform apply -refresh-only -auto-approve
Recommended way:
terraform apply -refresh-only
This will:
- Check real infrastructure
- Show detected changes
- Ask for confirmation before updating state
Simple idea:
- Refresh → Sync state with real infrastructure
- Does not create or delete resources
- Only updates terraform.tfstate and it doesn’t update tf scripts.
9. AWS - Authentication and Configurations
I don’t want to explain too much in this section because the concept is the same as when using AWS CLI.
Before using Terraform with AWS, make sure to check which account you are currently using, run:
aws sts get-caller-identity
10. Attributes
Attributes are the properties of a resource. They can be:
- Required attributes: must be defined in the resource block.
- Optional attributes: can be defined but not required.
Example:
resource "aws_instance" "web_server1" {
instance_type = "t3.micro" # Required attribute
tags = { # Optional attribute
Name = "Web Server 1"
}
}
In the above examples, instance_type is required attribute, and tags is optional attributes.
11. Cross Referencing Resource Attribute
Cross referencing is used to connect one resource to another.
Instead of writing value manually, we take the value from another resource.
Example:
resource "aws_security_group" "web_sg" {
name = "web-sg"
}
resource "aws_instance" "web_server" {
ami = "ami-123456"
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.web_sg.id]
}
Here, the EC2 instance uses the ID from the security group. Terraform knows that EC2 depends on the security group.
12. String Interpolcation
String interpolation is used to insert a value inside a string.
Terraform uses this format:
${resource_type.resource_name.attribute}
Example
tags = {
Name = "web-${aws_instance.web_server.id}"
}
This will create a tag with the EC2 instance ID inside the name. It’s like web-i-0123456789abcdef0.
13. Output Values
Output values are used to show information after terraform apply.
It is useful to see things like public IP, instance ID, etc.
Example:
output "instance_public_ip" {
value = aws_instance.web_server.public_ip
}
After apply, Terraform will show the public IP in the terminal.
Output is useful when you need important information from your infrastructure.
14. Terraform Variables
Terraform variables are used to make your code more flexible.
Instead of hardcoding values, you can use variables.
Example:
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
# Use the variable inside resource:
resource "aws_instance" "web_server" {
ami = "ami-123456"
instance_type = var.instance_type
}
Now we can change the instance type without editing the resource block.
Btw, if you have not defined a value for a variable. Terraform will ask you to input the value in CLI Terminal when run tf plan / apply.
14.1 Declaring Variable Values
There are 4 ways to declare or assign variable values.
14.1.1 Set a default value when defining the variable in variables.tf
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t3.micro"
}
14.1.2 Using .tfvars File
Create a file like terraform.tfvars and inside the file put instance_type = "t3.small". Terraform will automatically read terraform.tfvars.
14.1.3 Using Command Line (-var)
You can pass variable directly when running Terraform.
terraform apply -var="instance_type=t3.small"
14.1.3 Using Environment Variables
You can set environment variable with the format TF_VAR_<variable_name>.
export TF_VAR_instance_type="t3.small"
15. Variable Definiations File (TFVars)
.tfvars file is used to assign values to variables.
Example:
terraform.tfvars
Inside the file:
instance_type = "t3.small"
When you run terraform apply, it will automatically read the values from terraform.tfvars.
We can also use custom file:
terraform apply -var-file="custom.tfvars"
terraform apply -var-file="dev.tfvars"
Notes! If file name is terraform.tfvars -> Terraform will automatically load values from it. If file name is different like prod.tfvars -> We have to explicitly define the file during plan / apply operation.
16. Variable Definition Precedence
Variable definition precedence means the order Terraform uses when multiple variable values are provided.
If the same variable is defined in many places, Terraform will choose the value with the highest priority.
From lowest to highest precedence:
- Default value inside
variableblock - Environment variable (
TF_VAR_name) terraform.tfvarsfile-var-fileflag-varflag (highest priority)
Example
If you have:
- Default →
t3.micro - terraform.tfvars →
t3.small - CLI
-var="instance_type=t3.large"
Terraform will use t3.large because -var has the highest precedence.
17. Data Types
Terraform variables and arguments support different data types. Data types define what kind of value a variable can store.
17.1 String
A string is text.
Example:
variable "instance_type" {
type = string
}
# Value Example
instance_type = "t3.micro"
17.2 Number
A number is a numeric value.
Example:
variable "instance_count" {
type = number
}
# Value Example
instance_count = 3
17.3 Boolean
A boolean is a true or false value.
Example:
variable "enable_monitoring" {
type = bool
}
# Value Example
enable_monitoring = true
17.4 List
A list is an ordered collection of values.
Example:
variable "availability_zones" {
type = list(string)
}
# Value Example
availability_zones = ["us-east-1a", "us-east-1b"]
17.5 Map
A map is a collection of key-value pairs.
Example:
variable "tags" {
type = map(string)
}
# Value Example
tags = {
Name = "Web Server"
Env = "Production"
}
17.6 Null
Null is a special value that represents the absence of a value.
Example:
variable "instance_type" {
type = string
default = null
}
# Value Example
resource "aws_instance" "web" {
instance_type = var.instance_type
}
In this example, if instance_type is not defined, it will be null. Terraform will use the default instance type for the resource.
18. The COUNT Meta-Argument
The count meta-argument is used to create multiple resources from a single resource block.
Instead of writing the same resource many times, we can use count.
Example:
resource "aws_instance" "web_server" {
count = 3
ami = "ami-123456"
instance_type = "t3.micro"
}
This will create 3 EC2 instances.
18.1 Accessing Each Resource
Terraform gives each resource an index number starting from 0.
Example:
aws_instance.web_server[0]
aws_instance.web_server[1]
aws_instance.web_server[2]
18.1 Using count.index
You can use count.index to create different values for each resource.
Example:
resource "aws_instance" "web_server" {
count = 3
ami = "ami-123456"
instance_type = "t3.micro"
tags = {
Name = "web-server-${count.index}"
}
}
Results:
- web-server-0
- web-server-1
- web-server-2
Btw if you’re using count when creating IAM User it will not work since we cannot have multiple IAM User with the exact same name. So, the solution should use count.index.
19. Conditional Expressions
Conditional expressions are used to set a value based on a condition.
Terraform uses a simple if–else style expression.
Format:
condition ? true_value : false_value
- If the condition is
true, Terraform usestrue_value. - If the condition is
false, Terraform usesfalse_value.
Example:
variable "environment" {
type = string
default = "dev"
}
# Use conditional expression
resource "aws_instance" "web_server" {
ami = "ami-123456"
instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"
}
Explanation:
- If environment =
prod→ instance typet3.medium - Otherwise → instance type
t3.micro
19.1 Using Multiple Variables
We can also use multiple variables in a conditional expression.
Example:
variable "environment" {
type = string
}
variable "high_availability" {
type = bool
}
# Use both variables
count = var.environment == "prod" && var.high_availability ? 3 : 1
Explanation:
- If environment is
prodand high availability istrue→ create 3 instances - Otherwise → create 1 instance
20. Terraform Functions
Terraform functions are built-in functions that help us transform or calculate values in our configuration.
We can use functions to manipulate strings, numbers, lists, files, and more.
Example
# Using the upper function to convert a string to uppercase
variable "environment" {
type = string
}
output "env_upper" {
value = upper(var.environment)
}
This will take the value of environment variable and convert it to uppercase.
General Format
function_name(argument1, argument2)
max() Function
locals {
highest_number = max(5, 10, 20)
}
# Terraform will output 30 as the largest number
resource "aws_instance" "example" {
count = max(1, 2, 3)
}
Terraform will create 3 instances because 3 is the largest value.
file() Function
The file() function reads the content of a file from our local system.
It can be used to put the user data or policy.json.
Example we have file user_data.sh:
#!/bin/bash
echo "Hello Terraform"
resource "aws_instance" "web_server" {
ami = "ami-123456"
instance_type = "t3.micro"
user_data = file("user_data.sh")
}
This is useful when we want to pass the user data without including it to the scripts.
21. Local Values
Local values (locals) are used to store temporary values inside a Terraform configuration.
It is used for reusing values. So, instead of repeating the same value many times, you can define it once and use it everywhere.
Here are few example:
locals {
environment = "production"
instance_type = "t3.micro"
instance_name = "web-server"
}
resource "aws_instance" "web_server" {
ami = "ami-123456"
instance_type = local.instance_type
tags = {
Env = local.environment
Name = local.instance_name
}
}
Another Example:
locals {
common_tags = {
Environment = "dev"
Owner = "team-devops"
}
}
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
tags = local.common_tags
}
Data Sources
Data sources are used to get information from existing resources.
Instead of creating a new resource, Terraform reads data from resources that already exist in the cloud.
Example: Read Existing AWS Resource
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*"]
}
}
This will get the most recent Amazon Linux 2 AMI ID from AWS.
To use it in resources:
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
}
Example: Read Local File
Let’s say we have file user_data.sh in our current file system path where the tf scripts is located. We can fetch using data sources:
data "local_file" "user_data" {
filename = "${path.module}/user_data.sh"
}
This will read the content of user_data.sh file and we can use it in our resource.
There are so much list available data source in the provider, like AWS. Visit Terraform documentation for that.
By using the data sources, it solve a problem to use static information such as put hard coded value of AMI ID to the EC2 resource.
Terraform fmt and validate
terraform fmt is used to format our Terraform code.
It will automatically fix spacing, indentation, and layout.
For example, we have code that the format is inconsistent and doesn’t follow terraform standard.
We just have to pass command terraform fmt and the code will be clean and easier to read.
Btw in VS Code, there is an extension terrafom that will automatically format the code if we save the file.
Now, for terraform validate is used to check if our configuration is valid.
It checks syntax and basic errors, but it does not create resources.
We just have to pass command terraform validate before running terraform plan.
Dynamic Block
Dynamic block is used to create repeated nested blocks inside a resource.
It is useful when we want to avoid writing the same block many times.
The reason we use dynamic blocks is that sometimes a resource needs multiple nested blocks, like multiple security group rules.
Instead of writing them one by one, we can use a dynamic block.
Example:
variable "ports" {
default = [80, 443]
}
resource "aws_security_group" "web_sg" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
Explanation
dynamic "ingress"→ create multiple ingress blocksfor_each→ loop over the listingress.value→ current value (port)
This will create:
- One rule for
port 80 - One rule for
port 443
Terraform Replace
terraform replace is used to force recreate a resource.
It tells Terraform to destroy and create the resource again, even if there is no change in the code.
For example, if the EC2 instance has an issue and we want a fresh one:
terraform apply -replace="aws_instance.web_server"
Terraform will destroy the existing instance and create a new one.
When to Use:
- Resource is broken
- We want to recreate without changing code
- Replace old resource with new one
Saving Terraform Plan to File
Terraform allows to save plan file.
terraform plan -out infra.plan
To apply from plan file.
terraform apply infra.plan
Resource Targetting
Resource targeting is used to apply changes to specific resources only.
Instead of running Terraform on all resources, we can focus on one resource.
Format:
terraform apply -target=<resource_type>.<resource_name>
Example:
terraform apply -target=aws_instance.web_server
This will only create or update to aws_instance.web_server and ignore other resources.
We can also destroy specific resource using -target.
terraform destroy -target=aws_instance.web_server
This will only destroy aws_instance.web_server and ignore other resources.
Comments
Comments are used to write notes in our code. Terraform will ignore comments when running.
Single Line Comment
Use # or //.
# This is a single line comment
// This is also a single line comment
Multi Line Comment
Use /* */.
/*
This is a multi line comment
It can span multiple lines
*/
Resource Behavior and Meta-Argument
A resource block means we want a resource to exist with a specific configuration.
How Terraform Applies a Configuration
- Create resrouce that exist in the configuration (scripts) but are not associate with a real infrastructure object in the state
- Destroy resource that exist in the state (console) but no longer exist in the configuration (scripts)
- Update in-place resource if resource can be updated without recreation
- Destroy and re-create resources whose arguments have changed but which cannot be updated in-place due to remote API limitations and requires new resource
There are different meta arguments
lifecycle
lifecycle block is used to control how Terraform handles a resource.
create_before_destroy
Create new resource first, then delete the old one.
lifecycle {
create_before_destroy = true
}
Use case:
- Avoid downtime when replacing a resource.
prevent_destroy
Prevent resource from being deleted.
lifecycle {
prevent_destroy = true
}
If we try to destroy, Terraform will show error.
Use case:
- Protect critical resources from accidental deletion (like database).
ignore_changes
Ignore specific changes in a resource. Sometimes we use to ignore changes in the tags.
lifecycle {
ignore_changes = [tags]
}
Use case:
- Ignore changes that are made outside of Terraform (like manual changes in AWS Console).
replace_triggered_by
Force resource to be replaced when something changes.
lifecycle {
replace_triggered_by = [aws_security_group.web_sg]
}
Use case:
- Force replacement when a related resource changes (like security group).
depends_on
depends_on is used to tell Terraform that one resource depends on another resource.
It ensures Terraform creates resources in the correct order.
Terraform usually detects dependencies automatically.
But sometimes, the dependency is not clear.
In that case, we need to define it manually using depends_on.
resource "aws_security_group" "web_sg" {
name = "web-sg"
}
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
depends_on = [aws_security_group.web_sg]
}
In this example, terraform will create security group first and then create the ec2.
When to Use:
- When dependency is not obvious
- When resource uses indirect dependency
- When Terraform does not detect dependency automatically
count
count is used to create multiple resources from a single resource block.
resource "aws_instance" "web" {
count = 3
ami = "ami-123456"
instance_type = "t3.micro"
}
# Access Each Resource
aws_instance.web[0]
aws_instance.web[1]
aws_instance.web[2]
Terraform will create 3 EC2 instances.
Conditional count
count = var.environment == "prod" ? 3 : 1
- If
prod→ 3 instances - If not → 1 instance
for_each
for_each is used to create multiple resources using a map or set.
It is similar to count, but gives more control and better naming.
resource "aws_instance" "web" {
for_each = {
dev = "t3.micro"
prod = "t3.medium"
}
ami = "ami-123456"
instance_type = each.value
tags = {
Name = each.key
}
}
# Accessing Resource
aws_instance.web["dev"]
aws_instance.web["prod"]
This will create:
devinstance with typet3.microprodinstance with typet3.medium
Difference with count
count→ uses index (0, 1, 2)for_each→ uses key (dev, prod)
provider
provider meta-argument is used to specify which provider configuration a resource should use.
This is useful when we have multiple providers (like different regions or accounts).
provider "aws" {
region = "us-east-1"
}
provider "aws" {
alias = "west"
region = "us-west-2"
}
resource "aws_instance" "web" {
provider = aws.west
ami = "ami-123456"
instance_type = "t3.micro"
}
This will create:
- Default provider →
us-east-1 - This resource → uses
us-west-2
When to Use
- Multiple regions
- Multiple AWS accounts
- Different configurations
Terraform Provisioners
Provisioners are used to run scripts or commands after a resource is created.
They are usually used for setup tasks, like installing software.
local-exec
local-exec runs a command on our local machine (where we run Terraform).
Example:
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
provisioner "local-exec" {
command = "echo Instance created"
}
}
This will print “Instance created” in our terminal after the EC2 instance is created.
remote-exec
remote-exec runs commands inside the resource (like inside EC2).
Example:
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
connection {
type = "ssh"
user = "ec2-user"
private_key = file("key.pem")
host = self.public_ip
}
provisioner "remote-exec" {
inline = [
"sudo yum update -y",
"sudo yum install -y nginx"
]
}
}
This will connect to the EC2 instance via SSH and run the commands to update and install Nginx.
Terraform Modules
Modules are used to organize and re-use code in Terraform.
Instead of writing everything in one file, we can split our code into smaller parts (modules).
Why Use Modules?
- Make code cleaner
- Reuse the same configuration
- Easier to manage large projects
Example Modules
modules/ec2/main.tf
Inside the module:
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
}
To use module in main.tf:
module "ec2_instance" {
source = "./modules/ec2"
}
Modules with Variables
Module:
variable "instance_type" {}
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = var.instance_type
}
Main.tf:
module "ec2_instance" {
source = "./modules/ec2"
instance_type = "t3.micro"
}
This allows us to pass different values to the module when we use it.
Point to Notes
- Module = reusable Terraform code
source= where module is located- We can pass variables into module
Avoid Hardcoded Values in Variables
Avoid writing fixed values directly in the Terraform code.
Hardcoded values make our code less flexible and harder to reuse.
Bad Examples (Hardcoded)
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
}
Good Example (Using Variables)
variable "instance_type" {
default = "t3.micro"
}
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = var.instance_type
}
This way, we can change the instance type without editing the resource block. We can also reuse the same code for different instance types by passing different values to the variable.
Module Outputs
Module outputs are used to return values from a module.
So we can use that value in our main configuration.
Example
Inside module:
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
}
output "instance_id" {
value = aws_instance.web.id
}
Use Output in Main File
module "ec2_instance" {
source = "./modules/ec2"
}
# Accessing the output
output "my_instance_id" {
value = module.ec2_instance.instance_id
}
The flow is like:
- Module creates EC2
- Module returns instance_id
- Main file can use that value
Terraform Backend
Terraform backend is used to store the state file.
By default, Terraform stores state locally (terraform.tfstate).
With backend, we can store it remotely.
Why Use Backend?
- Share state with team
- Keep state safe
- Avoid conflicts
Example: S3 Backend
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
}
}
This will store the state file in an S3 bucket.
Notes! It will be better to have S3 versioning enabled to allow recovery in case of accidental deletions.
Terraform State Management
Terraform state commands are used to manage and inspect the state file.
state list
Show all resources in the state.
terraform state list
state show
Show detailed information about a resource.
terraform state show aws_instance.web
state mv
Move or rename a resource in the state.
terraform state mv aws_instance.old_name aws_instance.new_name
state rm
Remove a resource from the state (does not delete real resource).
terraform state rm aws_instance.web
state pull
Download the current state file.
terraform state pull > terraform.tfstate
state push
Upload a state file manually.
terraform state push terraform.tfstate
state replace-provider
Replace provider in the state.
terraform state replace-provider hashicorp/aws registry.terraform.io/hashicorp/aws
Terraform Import
terraform import is used to bring an existing resource into Terraform state.
This is useful when a resource was created manually (for example in AWS Console) and we want Terraform to manage it.
What Import Does?
- Adds the existing resource into terraform.tfstate
- Lets Terraform track the resource
Example: Importing an EC2 Instance
terraform import aws_instance.web i-0123456789abcdef0
This will import the EC2 instance with ID i-0123456789abcdef0 into Terraform state as aws_instance.web.
Important Notes
- Import does not create a resource, it only adds existing resource to the state.
- After import, we need to write the corresponding resource block in your
.tffiles to match the imported resource. - If the resource block does not match the imported resource, Terraform will show differences in
terraform planand may try to modify or recreate the resource.
There is a way to generate tf scripts, using -generate-config-out. See the documentation for more details.
Sensitive Parameter
Sensitive parameters are used to mark a variable or output as sensitive.
When a value is marked as sensitive, Terraform will not show it in the terminal output or logs.
This is useful for values like:
- Password
- Access key
- Secret key
- Token
Example variable
variable "db_password" {
type = string
sensitive = true
}
Example Output
output "db_password" {
value = var.db_password
sensitive = true
}
When we run terraform apply, the value of db_password will not be shown in the terminal.
Important Note
- Sensitive only hides the value in CLI output.
- The real value may still exist inside the state file.
So we must keep our state file secure.