Terraform


Terraform is an infrastucture orchestration tool

Download from HashiCorp

For Linux

unzip the file

copy the file to /usr/local/bin

test by entering terraform in the bash terminal window which should return a series of commands without errors

some of the commands to be used are


terraform init
terraform plan
terraform apply
terraform destroy

Tagging

locals {

common_tags = {

Billing = "${var.tag_billing}"

CreatedBy = "Terraform"

CustomerFacing = "${var.tag_customer_facing}"
    
Environment = "${var.tag_environment}"

}

}

then, when I want to tag a resource, I can do something like this:

tags = "${merge(

local.common_tags,

map(

"Name", "myservice-${lower(var.environment_tag)}-vpc"

 )

 )}"

that will add all the common tags, plus any additional specific tags, such as “Name” in this case

example.tf file which sets up an instance in a vpc and a subnet in a region after access key and secret key are provided


provider "aws" {
  access_key = ""
  secret_key = ""
  region     = "us-east-1"
}

resource "aws_instance" "example" {
  ami           = "ami-0c6b1d09930fac512"
  instance_type = "t2.nano"
  subnet_id = "${aws_subnet.us-east-1a-public.id}"
}


resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
}

resource "aws_subnet" "us-east-1a-public" {
  vpc_id = "${aws_vpc.example.id}"
  cidr_block = "10.0.1.0/25"
  availability_zone = "us-east-1a"
}

To access your instance:

create key pair and download pem file

chmod 400 awstest.pem

Connect to your instance using its Public DNS:

ec2xxxx.compute-1.amazonaws.com

Example:

ssh -i “awstest.pem” ec2-user@ec2xxxx.compute-1.amazonaws.com ### To make instance publicly accessible

get VPC ID

get Subnet ID

create IGW

Create EIP

associate EIP with instance

Goto existing route table and associated vpc id it will have a local route now add a IGW as below create route table to 0.0.0.0/0 and use IGW

example2.tf

provider "aws" {
  access_key = ""
  secret_key = ""
  region     = "us-east-1"
}

data "template_file" "Web_Server_Userdata" {
    template = "${file("userdata_web_servers.sh")}"
}   
resource "aws_instance" "example" {
  ami           = "ami-0c6b1d09930fac512"
  instance_type = "t2.nano"
  subnet_id = "${aws_subnet.us-east-1a-public.id}"
  private_ip = "10.0.0.12"
  tags {
        Name = "testserver"
    }
#security_groups = ["${aws_security_group.example.name}"]
  vpc_security_group_ids = ["${aws_security_group.example.id}"]
  key_name        = "awstest"
  user_data = "${data.template_file.Web_Server_Userdata.rendered}"
  
}

resource "aws_eip" "example" {
  vpc = true

  instance                  = "${aws_instance.foo.id}"
  associate_with_private_ip = "10.0.0.12"
  depends_on                = ["aws_internet_gateway.gw"]
}

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
 
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.default.id}"
}


resource "aws_subnet" "us-east-1a-public" {
  vpc_id = "${aws_vpc.example.id}"
  cidr_block = "10.0.1.0/25"
  availability_zone = "us-east-1a"
   depends_on = ["aws_internet_gateway.gw"]
}

#resource "tls_private_key" "example" {
#  algorithm = "RSA"
#  rsa_bits  = 4096
#}

#resource "aws_key_pair" "generated_key" {
#  key_name   = "example_key_pair"
#  public_key = "${tls_private_key.example.public_key_openssh}"
#}

resource "aws_security_group" "example" 
{
  name = "sg_2280"
 
  vpc_id = "${aws_vpc.example.id}"
  description = "grant ssh,http"

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

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

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

}
EXAMPLE3.tf
provider "aws" {
  access_key = ""
  secret_key = ""
  region     = "us-east-1"
}

data "template_file" "Web_Server_Userdata" {
    template = "${file("userdata_web_servers.sh")}"
}   
resource "aws_instance" "example" {
  ami           = "ami-0c6b1d09930fac512"
  instance_type = "t2.nano"
  subnet_id = "${aws_subnet.us-east-1a-public.id}"
  private_ip = "10.0.1.12"
  tags {
        Name = "testserver"
    }
#security_groups = ["${aws_security_group.example.name}"]
  vpc_security_group_ids = ["${aws_security_group.example.id}"]
  key_name        = "awstest"
  user_data = "${data.template_file.Web_Server_Userdata.rendered}"
  
}

resource "aws_eip" "example" {
  vpc = true

  instance                  = "${aws_instance.example.id}"
  associate_with_private_ip = "10.0.1.12"
  depends_on                = ["aws_internet_gateway.gw"]
}

resource "aws_vpc" "example" {
  cidr_block = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support = true
 
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.example.id}"
  tags {
        Name = "example_ig"
    }
}

# specify default route
resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.example.id}"

route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

tags {
    Name = "aws_route_table"
  }
}




resource "aws_subnet" "us-east-1a-public" {
  vpc_id = "${aws_vpc.example.id}"
  cidr_block = "10.0.1.0/25"
  availability_zone = "us-east-1a"
   depends_on = ["aws_internet_gateway.gw"]
}

resource "aws_route_table_association" "a" {
 subnet_id      = "${aws_subnet.us-east-1a-public.id}"
 route_table_id = "${aws_route_table.r.id}"
}


resource "aws_security_group" "example" 
{
  name = "sg_2280"
 
  vpc_id = "${aws_vpc.example.id}"
  description = "grant ssh,http"

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

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

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

}

Terraform Remote Backend Storage for storing state files for team collaboration,add below in your tf file

terraform {
backend "s3" {
encrypt="true"
bucket="terraformstate"
dynamodb_table = "terraform-state-lock-dynamo"
key="terraform/dev/terraform_dev.tfstate"
region="us-east-1"
}
}

bucket – the name of the S3 bucket in your account

key – the name of .tfstate file in my example I am keeping the file under terraform/dev/ folders inside my bucket

region – region of your s3 bucket

create a dynamodb table for locking the state file

resource "aws_dynamodb_table" "dynamodb-terraform-state-lock" {
  name = "terraform-state-lock-dynamo"
  hash_key = "LockID"
  read_capacity = 20
  write_capacity = 20
 
  attribute {
    name = "LockID"
    type = "S"
  }
 
  tags {
    Name = "DynamoDB Terraform State Lock Table"
  }
}

A webserver example

resource "aws_security_group" "web_server" {
  name_prefix = "web_server"
  description = "Allow HTTP, HTTPS and SSH from anywhere"
  vpc_id      = "${module.vpc_us-east-1.vpc_id}"

  tags {
    Name    = "web_server"
    http    = "yes"
    https   = "yes"
    ssh     = "yes"
    self    = "yes"
    out_pub = "yes"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server-allow-all-from-self" {
  type              = "ingress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  self              = true
  security_group_id = "${aws_security_group.web_server.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server-allow-ssh-from-all" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = "${aws_security_group.web_server.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server-allow-http-from-all" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = "${aws_security_group.web_server.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server-allow-https-from-all" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = "${aws_security_group.web_server.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server-allow-all-out" {
  type              = "egress"
  cidr_blocks       = ["0.0.0.0/0"]
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  security_group_id = "${aws_security_group.web_server.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group" "web_server_data" {
  name_prefix = "web_server"
  description = "Allow HTTP, HTTPS and SSH from anywhere"
  vpc_id      = "${module.vpc_us-east-1.vpc_id}"

  tags {
    Name = "web_server_data"
    nfs  = "yes"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group_rule" "web_server_data-allow-all-from-web-server" {
  type                     = "ingress"
  from_port                = 0
  to_port                  = 0
  protocol                 = "-1"
  source_security_group_id = "${aws_security_group.web_server.id}"
  security_group_id        = "${aws_security_group.web_server_data.id}"

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_efs_file_system" "web_server_data" {
  tags {
    Name = "web_server_data"
    role = "web_server_data"
  }

  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_efs_mount_target" "web_server_data" {
  count           = "${length(var.public_subnets["us-east-1"])}"
  file_system_id  = "${aws_efs_file_system.web_server_data.id}"
  subnet_id       = "${element(module.vpc_us-east-1.public_subnets, count.index)}"
  security_groups = ["${aws_security_group.web_server_data.id}"]

  lifecycle {
    create_before_destroy = true
  }
}


resource "template_file" "web_server-cloud-config" {
  count    = "${length(var.public_subnets["us-east-1"])}"
  template = "${file("${path.module}/templates/web_server-cloud-config.yml")}"

  vars {
    web_server_data_dns_name = "${element(aws_efs_mount_target.web_server_data.*.dns_name, count.index)}"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_instance" "web_server" {
  count                  = 1
  ami                    = "${data.aws_ami.coreos-stable.id}"
  instance_type          = "t2.micro"
  vpc_security_group_ids = ["${aws_security_group.web_server.id}"]
  subnet_id              = "${element(module.vpc_us-east-1.public_subnets, count.index)}"
  user_data              = "${element(template_file.web_server-cloud-config.*.rendered, count.index)}"

  tags {
    Name = "web_server-${count.index}"
    role = "web_server"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_elb" "web_server" {
  name            = "web-server"
  subnets         = ["${module.vpc_us-east-1.public_subnets}"]
  security_groups = ["${aws_security_group.web_server.id}"]

  listener {
    instance_port     = "80"
    instance_protocol = "tcp"
    lb_port           = "80"
    lb_protocol       = "tcp"
  }

  listener {
    instance_port     = "443"
    instance_protocol = "tcp"
    lb_port           = "443"
    lb_protocol       = "tcp"
  }

  instances                   = ["${aws_instance.web_server.*.id}"]
  cross_zone_load_balancing   = true
  idle_timeout                = "400"
  connection_draining         = true
  connection_draining_timeout = "400"

  tags {
    Name = "web_server"
    role = "lb"
  }
}

These writings represent my own personal views alone.
Licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.