Terraform : AWS : Terraform on AWS | Section 4: Terraform Input Variables and Datasources

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 25. Step-01: Introduction to Variables Section

From the terraform perspective . we are going to learn the following on the left and from AWS perspective

  •  We are going to dynamically get the latest AMI id from AWS, using data source terraform concept and then create the EC2 Instance . In addition to that we are also going to associate an existing Key pair to for whatever is present in our EC2 key Pairs to our EC2 instance when it is creating .



Earlier we manually configured the NSG - Network security group. here we are going to create two resources called VPC-SSH , VPC-Web,  so that can be used to access the EC2 instance .

So using ssh you should be able to access the EC2 instance and using VPC Web security will be used to access the web server.

We also need to understand why are we creating two security groups here . This is for demonstrating how we can pass on the list of items using two security groups or else we could have had two security rules in one security group. 

 

We are practically going to implement 

  • We will get the latest ami id dynamically  from aws using Terraform Datasources concept and then create the EC2 Instance . 
  • In addition to that we are going to associate the  existing Key pair whatever is present in our environment to our EC2 Instance when it is getting created  and
  • We will create two security groups VPC-SSH , VPC-Web  so those can be used to access the EC2 Instance , So using SSH you will be able to login into the terminal of the EC2 instance . And using the VPC- Web you will be able to access the web server .

25. Step-01: Introduction to Variables Section


As part of this section we are going to focus on Input Variables and Output Values.

Lets move and understand about Input Variables


Input variable serve as parameter for a terraform module allowing aspects of the module to be customized without altering the modules own source code. And allowing modules to be shared with different configurations. Input variable is the similar to any other programming language .

You can pass the input in 10 different ways to terraform

There are 10 different concepts that we need to learn when we define the input variable for Terraform .

https://github.com/stacksimplify/terraform-on-aws-ec2/tree/main/04-Terraform-Variables-and-Datasources

Step-00: Pre-requisite Note

  • Create a terraform-key in AWS EC2 Key pairs which we will reference in our EC2 Instance

Primarily we are going to define three input variables .

  1. Learn about Terraform Input Variable basics
  • AWS Region
  • Instance Type
  • Key Name

26. Step-02: Input Variables Introduction

We can pass input variables to Terraform in 10 different ways , which means there are 10 different concepts that you need to master while we discuss input variables in terraform .

 

 

Scenario 1 : Whenever you run terraform apply  -- it will be prompted for a variable

Scenario 2 : or -var aurgument for your terraform apply , you can provide the value

Scenario3: Defining the environmental variables TF_var_name -- we will be able to pass the variables

Scenario4 : In addition to that we can define the variables in terraform.tfvars

Scenarios5 : Any <name >.tfvars with CLI arguments with -var-file

Scenarios6 : auto.tfvars file 

So there are multiple ways you can play with input variables. Others are mentioned in the terrform certification GitHub link .

27. Step-03: Implement Input Variables


for setting the variable as sensitive information . Sensitive = true . If you are defining a password here you can define true / false to define sensitive here.

 In Addition to that you have something called Validation .

under validation you can define some validation rules. For instance

  • My ami id must be this.
  • My region must be us-east-1 region must be in this format

Go to c1.version.tf

 

provider "aws" {
  region = "ap-south-1"
  profile = "default"
}

 you remove the hard coded value.

type var.<variable_name> from the c1.variable.tf file

 


 After the variable changed


28. Step-04: Create Security Group Resources

 Now we are going to define c3-ec2securitygroups.tf

 You can easily look for the resource code that you are looking for , for instance type 

aws security group terraform on google

Takes you to this site https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group

  •  Ingress is nothing but the inbound rule
  •  egress means outbound rule

 

resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = aws_vpc.main.id

  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [aws_vpc.main.cidr_block]
    ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "allow_tls"
  }
}

 

The above content was edited to our requirement

vpc_id      = aws_vpc.main.id

we are using our default VPC so we do not want to provide a vpc id

if you do not specify any vpc id then it uses the default vpc 

In terraform whereever you find a square bracket , it is a list item

cidr_blocks      = [aws_vpc.main.cidr_block]

 currently we want to open the port from internet

 changed to 

    cidr_blocks      = [0.0.0.0/0]

 added description

egress {
    description      = "Allow all Ip and all ports"
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
 

 

We are going to create one for Web Traffic also . So lets copy this and paste it. We are defining two ingress rules.

This completes the creation of security groups .

29. Step-05: Create AMI Datasource Resource

Create c4--ami-datasource.tf 

This will dynamically get the ami source id.

google aws ami datasource terraform

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami

data "aws_ami" "example" {
  executable_users = ["self"]
  most_recent      = true
  name_regex       = "^myami-\\d{3}"
  owners           = ["self"]

  filter {
    name   = "name"
    values = ["myami-*"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

This will dynamically get the ami source id. 

go to launch EC2 instance and get the ami id -- go to images and search for the ami id choose "public" from drop down

 


 


 search the public IMages to enter the below

  filter {
    name   = "name"
    values = ["myami-*"]

  filter {
    name   = "name"
    values = ["amzn2-ami-kernel-5.10-hvm-2.0.20220316.0-x86_64-gp2-*"]
  }

 Modify the above

  filter {
    name   = "name"
    values = ["amzn2-ami-kernel-5.10-hvm-*-gp2"]
  }

 

We will add one more filter to tell the terraform to pickup up which bit of VM .

 

Prefer 64-bit (x86)

These informations are picked from this page


This completes the creation of datasource resource in terraform to get the latest Amazon linux ami id





30. Step-06: Create EC2 Instance Resource


use the datasource.tf to enter the ami = "argument" above





 32. Step-08: Execute Terraform Commands and Clean-Up

 

 PS C:\Users\sreejith_b\Desktop\AWS_SPACE> terraform apply

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.ec2_instance will be created
  + resource "aws_instance" "ec2_instance" {
      + ami                                  = "ami-04893cdb768d0f9ee"
      + 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_termination              = (known after apply)
      + ebs_optimized                        = (known after apply)
      + get_password_data                    = false
      + host_id                              = (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                             = "terraform-key"
      + 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" = "Gorilla"
        }
      + tags_all                             = {
          + "Name" = "Gorilla"
        }
      + tenancy                              = (known after apply)
      + user_data                            = "d6194f48053da708f6aeb8edf069363ca9625c3d"   
      + user_data_base64                     = (known after apply)
      + user_data_replace_on_change          = false
      + vpc_security_group_ids               = (known after apply)

      + capacity_reservation_specification {
          + capacity_reservation_preference = (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id = (known after apply)
            }
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + enclave_options {
          + enabled = (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      + metadata_options {
          + http_endpoint               = (known after apply)
          + http_put_response_hop_limit = (known after apply)
          + http_tokens                 = (known after apply)
          + instance_metadata_tags      = (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_interface_id  = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # aws_security_group.vpc-ssh will be created
  + resource "aws_security_group" "vpc-ssh" {
      + arn                    = (known after apply)
      + description            = "Dev VPC SSH"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow all Ip and all ports"
              + from_port        = 0
              + ipv6_cidr_blocks = [
                  + "::/0",
                ]
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow port no 22"
              + from_port        = 22
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 22
            },
        ]
      + name                   = "vpc-ssh"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "vpc-ssh"
        }
      + tags_all               = {
          + "Name" = "vpc-ssh"
        }
      + vpc_id                 = (known after apply)
    }

  # aws_security_group.vpc-web will be created
  + resource "aws_security_group" "vpc-web" {
      + arn                    = (known after apply)
      + description            = "Dev VPC WEB"
      + egress                 = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow all Ip and all ports"
              + from_port        = 0
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "-1"
              + security_groups  = []
              + self             = false
              + to_port          = 0
            },
        ]
      + id                     = (known after apply)
      + ingress                = [
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow port no 443"
              + from_port        = 443
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 443
            },
          + {
              + cidr_blocks      = [
                  + "0.0.0.0/0",
                ]
              + description      = "Allow port no 80"
              + from_port        = 80
              + ipv6_cidr_blocks = []
              + prefix_list_ids  = []
              + protocol         = "tcp"
              + security_groups  = []
              + self             = false
              + to_port          = 80
            },
        ]
      + name                   = "vpc-web"
      + name_prefix            = (known after apply)
      + owner_id               = (known after apply)
      + revoke_rules_on_delete = false
      + tags                   = {
          + "Name" = "vpc-web"
        }
      + tags_all               = {
          + "Name" = "vpc-web"
        }
      + vpc_id                 = (known after apply)
    }

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

Changes to Outputs:
  + instance_publicdns = (known after apply)
  + instance_publicip  = (known after apply)

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

aws_security_group.vpc-ssh: Creating...
aws_security_group.vpc-web: Creating...
aws_security_group.vpc-ssh: Creation complete after 1s [id=sg-005ab4a6013b8d975]
aws_security_group.vpc-web: Creation complete after 2s [id=sg-0e3b5e0b563c835fe]
aws_instance.ec2_instance: Creating...
aws_instance.ec2_instance: Still creating... [10s elapsed]
aws_instance.ec2_instance: Still creating... [20s elapsed]
aws_instance.ec2_instance: Still creating... [30s elapsed]
aws_instance.ec2_instance: Creation complete after 31s [id=i-03c75b7b52d82b1da]

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

Outputs:

instance_publicdns = "ec2-13-126-145-69.ap-south-1.compute.amazonaws.com"
instance_publicip = "13.126.145.69"
PS C:\Users\sreejith_b\Desktop\AWS_SPACE>



All the codes

 1. app1-install.sh

#! /bin/bash
# Instance Identity Metadata Reference - https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
sudo yum update -y
sudo yum install -y httpd
sudo systemctl enable httpd
sudo service httpd start  
sudo echo '<h1>Welcome to StackSimplify - APP-1</h1>' | sudo tee /var/www/html/index.html
sudo mkdir /var/www/html/app1
sudo echo '<!DOCTYPE html> <html> <body style="background-color:rgb(250, 210, 210);"> <h1>Welcome to Stack Simplify - APP-1</h1> <p>Terraform Demo</p> <p>Application Version: V1</p> </body></html>' | sudo tee /var/www/html/app1/index.html
sudo curl http://169.254.169.254/latest/dynamic/instance-identity/document -o /var/www/html/app1/metadata.html

 

 2. c1-version.tf

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "4.8.0"
    }
  }
}

#provider block
provider "aws" {
  region = var.aws_region
  profile = "default"
}


 

 3. c2.variables.tf

#AWS Region
variable "aws_region" {
    description = "Region in which AWS resource to be created"
    type = string
    default = "ap-south-1"
 
}

#AWS EC2 Instance type
variable "instance_type" {
    description = "EC2 Instance Type"
    type = string
    default = "t2.micro"
 
}

#AWS EC2 Instance Key Pair
variable "instance_keypair" {
     description = "AWS EC2 Key pair that needs to be associate with EC2"
     type = string
     default = "terraform-key"

 
}


4. c3.ec2securitygroup.tf

resource "aws_security_group" "vpc-ssh" {
  name        = "vpc-ssh"
  description = "Dev VPC SSH"

  ingress {
    description      = "Allow port no 22"
    from_port        = 22
    to_port          = 22
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  egress {
    description      = "Allow all Ip and all ports"
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = "vpc-ssh"
  }
}

# Next one
resource "aws_security_group" "vpc-web" {
  name        = "vpc-web"
  description = "Dev VPC WEB"

  ingress {
    description      = "Allow port no 80"
    from_port        = 80
    to_port          = 80
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  ingress {
    description      = "Allow port no 443"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  egress {
    description      = "Allow all Ip and all ports"
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
  }

  tags = {
    Name = "vpc-web"
  }
}


5. c4.ami-datasource.tf

data "aws_ami" "amzlinux2" {
  most_recent      = true
  owners           = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-kernel-5.10-hvm-*-gp2"]
  }

  filter {
    name   = "root-device-type"
    values = ["ebs"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

 filter {
    name   = "architecture"
    values = ["x86_64"]
  }

}


6. c5-ec2instance.tf

resource "aws_instance" "ec2_instance" {
  ami = data.aws_ami.amzlinux2.id
  instance_type = var.instance_type
  user_data = file("${path.module}/app1-install.sh")
  key_name = var.instance_keypair
  vpc_security_group_ids = [ aws_security_group.vpc-ssh.id , aws_security_group.vpc-web.id ]
  tags = {
    "Name" = "Gorilla"
  }
}


7. c6.outputs.tf

# EC2 instance Public IP
output "instance_publicip" {
    description = "EC2 instance Public IP"
    value = aws_instance.ec2_instance.public_ip
}
# EC2 instance Public DNS
output "instance_publicdns" {
    description = "EC2 instace public DNS"
    value = aws_instance.ec2_instance.public_dns
}


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

Outputs:

instance_publicdns = "ec2-13-126-145-69.ap-south-1.compute.amazonaws.com"
instance_publicip = "13.126.145.69"






 

Comments

Popular posts from this blog

Terraform : AWS : Terraform on AWS with SRE & IaC DevOps | Section 2 : Terraform basics

Terraform VPC - on AWS : Three tier architecture design