Infrastructure as Code with Terraform [Part 2]
Providers
Providers allow Terraform to interact with cloud providers, SaaS providers, and other APIs.
Some providers require you to configure them with endpoint URLs, cloud regions, or other settings before Terraform can use them. As we're building Infrastructure on the AWS cloud, we'll be using "aws" as the provider.
Create a new provider.tf file in Visual Studio Code editor and add below Terraform code.
We are stating 4 things in the below code which we'll be mentioning in the variable file:
provider as aws
AWS account access key
AWS account secret access key
AWS region
provider "aws" {
access_key = "${var.AWS_ACCESS_KEY}"
secret_key = "${var.AWS_SECRET_ACCESS_KEY}"
region = "${var.AWS_REGION}"
}
IAM user
To create infrastructure on the AWS cloud, you will require permission to do.
For practice's sake and getting started with Terraform, I'll suggest you create an IAM user with Administrator access in the AWS account in which you want your infrastructure to be created. Once the IAM user is created, please save your Access key and Secret access key in a secure place.
If you're new to the IAM service in AWS, please check the below blog on how to create an IAM user in AWS with Admin access.
https://medium.com/@nwoyesamuelc/creating-an-iam-user-on-aws-32a8de4d5d9d
Variables
Variables are fundamental constructs in every programming language because they are inherently useful in building dynamic programs. We use variables to store temporary values so that they can assist programming logic in simple as well as complex programs.
Create new vars.tf file and define the below variables.
variable AWS_ACCESS_KEY {}
variable AWS_SECRET_ACCESS_KEY {}
variable AWS_REGION {
default = "us-east-1"
}
Where to store your Access keys?
(Use any one approach)
There are multiple ways to store the AWS Access keys
Let's look one by one:
Pass them as environment variables
This is a safer way to add credentials. Pass the values of access key and secret key as environment variables. The only overhead would be of adding them again with a new session/terminal.
export AWS_ACCESS_KEY="anaccesskey"
export AWS_SECRET_ACCESS_KEY="asecretkey"
Using AWS profile
This is a better approach in comparison to the above-mentioned approach. We can configure aws credentials in our local. Make sure aws cli is installed on your machine before you configure this and provide your access key and other details as required.
sudo apt install awscli
aws configure
AWS Access Key ID:
AWS Secret Access Key :
Default region name:
Default output format:
The above information will be stored in ~/.aws/credentials file. Add this path to the shared_credentials_file section in your aws provider block.
provider "aws" {
shared_credentials_file = ~/.aws/credentials"
region = var.aws_region
}
Storing credentials in terraform.tfvars file
(we're using this method here)
This is an easy way to get started and I'll recommend you use this as a starter.
Create a new file called terraform.tfvars and add your credentials as below:
AWS_ACCESS_KEY = "your-access-key"
AWS_SECRET_ACCESS_KEY = "your-secret-access-key"
Points to note:
The file terraform.tfvars should only live on your local computer and never be checked into source control.
It is very important that terraform.tfvars is placed in your .gitignore file.
Create .gitignore file and add the terraform.tfvars file with its path in it so that git doesn't track and store this file. We should always keep our credentials safe.
Create your first EC2 instance in AWS
Create a new file instance.tf and with the below-mentioned code we'll create our first EC2 instance. Note that every region has a different AMI ID. The AMI ID's keeps on changing so make sure you use the latest AMI ID from the AWS console.
resource "aws_instance" "myec2" {
ami = "ami-830c94e3"
instance_type = "t2.micro"
tags
{
Name = "First-terraform-instance"
}
}
Resources
Use resource
blocks to define components of your infrastructure. A resource might be a physical or virtual component such as an EC2 instance, or it can be a logical resource such as a Heroku application.
Resource blocks have two strings before the block: the resource type and the resource name. In this example, the resource type is aws_instance
and the name is myec2
. The prefix of the type maps to the name of the provider. In the example configuration, Terraform manages the aws_instance
resource with the aws
provider. Together, the resource type and resource name form a unique ID for the resource. For example, the ID for your EC2 instance is aws_instance.myec2
.
Resource blocks contain arguments that you use to configure the resource. Arguments can include things like machine sizes, disk image names, or VPC IDs. For our EC2 instance, the example configuration sets the AMI ID to an Ubuntu image, and the instance type to t2.micro
, which qualifies for AWS' free tier. It also sets a tag to give the instance a name.
Running the Terraform code
Init – This is where you initialize your code to download the requirements mentioned in your code.
Plan – This is where you review changes and choose whether to simply accept them.
Apply – This is where you accept changes and apply them against real infrastructure.
Destroy – This is where to destroy all your created infrastructure.
Steps to execute Terraform code:
- terraform init
> terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v4.52.0
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
- terraform plan
> terraform plan
Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "myec2" {
+ ami = "ami-830c94e3"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ disable_api_stop = (known after apply)
+ disable_api_termination = (known after apply)
+ ebs_optimized = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ host_resource_group_arn = (known after apply)
+ iam_instance_profile = (known after apply)
+ id = (known after apply)
+ instance_initiated_shutdown_behavior = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ monitoring = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ placement_partition_number = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ secondary_private_ips = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "First-terraform-instance"
}
- terraform apply
> terraform apply
(...)
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "example" {
+ ami = "ami-830c94e3"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
(...)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
Clean up the environment
If you want to destroy all Terraform environments and resources, ensure that you're in the Terraform module/directory that you used to create the EC2 instance and run "terraform destroy".
Cool! We have now created our EC2 instance with Terraform in AWS. You can create many more resources with Terraform as per your requirements. We'll be learning a lot more concepts in the next [Part 3 ].
Stay Tuned, thanks!
Today's top 3 books to read
"Your habits shape your identity, and your identity shapes your habits."
― James Clear, Atomic Habits
Aaqib Ahmad
DevOps Engineer