[[linux_wiki:terraform]]

Terraform

General Information

“Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.”

Sites


Checklist

  • AWS Account

Install Terraform

Installing Terraform on Linux.

  • Copy download link
  • On Linux server, wget the link to download (example link)
    wget https://releases.hashicorp.com/terraform/0.11.7/terraform_0.11.7_linux_amd64.zip
  • Unzip single binary, move into /usr/local/bin
    unzip terraform_0.11.7_linux_amd64.zip
     
    mv terraform /usr/local/bin/
  • Verify
    terraform --version

Configure AWS Credentials for Use

  • Login to your AWS account, create access keys for CLI use and download the file.
  • Create an AWS credentials file in your home directory
    vim ~/.aws/credentials
     
    # AWS Credentials
    [default]
    aws_access_key_id = "access-key-id-here"
    aws_secret_access_key = "secret-key-here"
    • The profile name is “default” and can now be referenced in the terraform config files.
  • Lock down permissions
    chmod 600 ~/.aws/credentials

Terraform Example: 2 Tier VPC

Pre-Req: AWS account and access keys setup/configured in the previous section.


Creating a 2-tier VPC (public and private subnets), utilizing 3 availability zones in US-West (Oregon).

This will create the all of the virtual infrastructure to start creating services inside of.

Files can be named anything, as long as it ends in a “.tf”. Terraform will load all files in a directory structure below it that end in that.

Example Structure

├── main.tf      # Terraform root config (does not have to be 'main.tf')
├── outputs.tf   # Output data that can be displayed
├── site         # A local defined module called "site"
│   ├── nat_gateway.tf
│   ├── outputs.tf
│   ├── routes.tf
│   ├── security_groups.tf
│   ├── subnets.tf
│   ├── variables.tf
│   └── vpc.tf
├── terraform.tfstate  # Terrform creates this file to keep track of resource state
├── terraform.tfstate.backup  # And this is just a backup of state
└── variables.tf    # Variables defined here that can be used or passed into modules

Contents of the above config files.

Files in the top level directory. Ordered in a way that is easier to follow.

main.tf
# Title: main.tf
# Description: Main terraform config file. Define provider and load other modules
#              AWS Credentials auto loaded from ~/.aws/credentials
 
## AWS Provider and Region
provider "aws" {
  region = "${var.region}"
  # Name of profile to use from ~/.aws/credentials
  profile = "default"
}
 
## Module: Site Infrastructure Setup
module "site" {
  source = "./site"
  availability_zones = "${var.availability_zones}"
  public_subnet01_cidr = "${var.public_subnet01_cidr}"
  public_subnet02_cidr = "${var.public_subnet02_cidr}"
  public_subnet03_cidr = "${var.public_subnet03_cidr}"
  private_subnet01_cidr = "${var.private_subnet01_cidr}"
  private_subnet02_cidr = "${var.private_subnet02_cidr}"
  private_subnet03_cidr = "${var.private_subnet03_cidr}"
  vpc_cidr = "${var.vpc_cidr}"
}
variables.tf
# Title: variables.tf                                                                                                
# Description: Root defined variables                                                                                
 
####-- Global Variables --####                                                                                       
 
# AWS Region To Use                                                                                                  
variable "region" {                                                                                                  
  default = "us-west-2"                                                                                              
}                                                                                                                    
 
# Availability Zones To Use                                                                                          
variable "availability_zones" {                                                                                      
  type = "list"                                                                                                      
  default = [ "us-west-2a" , "us-west-2b" , "us-west-2c" ]                                                           
}                                                                                                                    
 
####-- VPC Variables --####                                                                                          
 
# VPC Network                                                                                                        
variable "vpc_cidr" {                                                                                                
  description = "CIDR for the whole VPC"                                                                             
  # /21 = 2046 IPs, 10.0.0.1 - 10.0.7.254                                                                            
  default = "10.0.0.0/21"                                                                                            
}                                                                                                                    
 
# Public Subnet 01 (with IGW)                                                                                        
variable "public_subnet01_cidr" {                                                                                    
  description = "CIDR for the Public Subnet"                                                                         
  # /25 = 126 IPs, 10.0.0.1 - 10.0.0.126
  default = "10.0.0.0/25"
}
 
# Public Subnet 02 (with IGW)
variable "public_subnet02_cidr" {
  description = "CIDR for the Public Subnet"
  # /25 = 126 IPs, 10.0.0.129 - 10.0.0.254
  default = "10.0.0.128/25"
}
 
# Public Subnet 03 (with IGW)
variable "public_subnet03_cidr" {
  description = "CIDR for the Public Subnet"
  # /25 = 126 IPs, 10.0.1.1 - 10.0.1.126
  default = "10.0.1.0/25"
}
 
# Private Subnet 01 (no IGW)
variable "private_subnet01_cidr" {
  description = "CIDR for the Private Subnet"
  # /23 = 510 IPs, 10.0.2.1 - 10.0.3.254
  default = "10.0.2.0/23"
}
 
# Private Subnet 02 (no IGW)
variable "private_subnet02_cidr" {
  description = "CIDR for the Private Subnet"
  # /23 = 510 IPs, 10.0.4.1 - 10.0.5.254
  default = "10.0.4.0/23"
}
 
# Private Subnet 03 (no IGW)
variable "private_subnet03_cidr" {
  description = "CIDR for the Private Subnet"
  # /23 = 510 IPs, 10.0.6.1 - 10.0.7.254
  default = "10.0.6.0/23"
}
outputs.tf
 Title: outputs.tf
# Description: Outputs from resources saved as variables
#              If terraform apply is run within this directory, these variables
#              are displayed at the end of the run.
 
# Pull the VPC ID from the site module
output "vpc_id" {
  value = "${module.site.vpc_id}"
}

Files in the site/ module directory. Ordered in a way that is easier to follow.

variables.tf
# Title: site/variables.tf                                                                                           
# Description: Variables for the module 'site'
#              Unset variables are expected to be passed in from the calling parent
 
# Availability Zones: Inherit from main variables
variable "availability_zones" { type = "list" }
 
# VPC CIDR: Inherit from main variables
variable "vpc_cidr" {}
 
# Public Subnets (with IGW): Inherit from main
variable "public_subnet01_cidr" {}
variable "public_subnet02_cidr" {}
variable "public_subnet03_cidr" {}
 
# Private Subnets (no IGW): Inherit from main
variable "private_subnet01_cidr" {}
variable "private_subnet02_cidr" {}
variable "private_subnet03_cidr" {}
vpc.tf
# Title: site/vpc.tf
# Description: Create a VPC and attach an internet gateway
 
####-- VPC --####
 
# VPC: Creation
resource "aws_vpc" "myvpc" {
  cidr_block = "${var.vpc_cidr}"
  enable_dns_hostnames = true
  tags {
    Name = "myvpc"
  }
}
 
# VPC: Internet Gateway
resource "aws_internet_gateway" "myigw" {
  vpc_id =  "${aws_vpc.myvpc.id}"
  tags {
    Name = "myigw"
  }
}
subnets.tf
# Title: site/subnets.tf                                                                                                  
# Description: Create subnets                                                                                        
 
####-- Subnets --####                                                                                                
 
# Public Subnet 01                                                                                                   
resource "aws_subnet" "subnet01-public" {                                                                            
  vpc_id = "${aws_vpc.myvpc.id}"                                                                                     
  cidr_block = "${var.public_subnet01_cidr}"                                                                         
  availability_zone = "${element(var.availability_zones, 0)}"                                                        
  tags {                                                                                                             
    Name = "subnet_public01"                                                                                         
  }
}
 
# Public Subnet 02
resource "aws_subnet" "subnet02-public" {
  vpc_id = "${aws_vpc.myvpc.id}"
  cidr_block = "${var.public_subnet02_cidr}"
  availability_zone = "${element(var.availability_zones, 1)}"                                                       
  tags {
    Name = "subnet_public02"
  }
}
 
# Public Subnet 03
resource "aws_subnet" "subnet03-public" {
  vpc_id = "${aws_vpc.myvpc.id}"
  cidr_block = "${var.public_subnet03_cidr}"
  availability_zone = "${element(var.availability_zones, 2)}"                                                       
  tags {
    Name = "subnet_public03"
  }
}
 
# Private Subnet 01
resource "aws_subnet" "subnet01-private" {
  vpc_id = "${aws_vpc.myvpc.id}"
  cidr_block = "${var.private_subnet01_cidr}"
  availability_zone = "${element(var.availability_zones, 0)}"                                                       
  tags {
    Name = "subnet_private01"
  }
}
 
# Private Subnet 02
resource "aws_subnet" "subnet02-private" {
  vpc_id = "${aws_vpc.myvpc.id}"
  cidr_block = "${var.private_subnet02_cidr}"
  availability_zone = "${element(var.availability_zones, 1)}"                                                       
  tags {
    Name = "subnet_private02"
  }
}
 
# Private Subnet 03
resource "aws_subnet" "subnet03-private" {
  vpc_id = "${aws_vpc.myvpc.id}"
  cidr_block = "${var.private_subnet03_cidr}"
  availability_zone = "${element(var.availability_zones, 2)}"                                                       
  tags {
    Name = "subnet_private03"
  }
}
nat_gateway.tf
# Title: site/nat_gateway.tf
# Description: Create a NAT gateway for private subnets
 
# Note: For true high availabity, you will want:
#       -An EIP and NAT GW per public subnet
#       -Route table per private subnet to route to NAT GW in same AZ
 
# Create the required Elastic IPs to be assigned to the NAT Gateways
resource "aws_eip" "eip_nat01" {
  vpc = true
}
 
resource "aws_eip" "eip_nat02" {
  vpc = true
}
 
resource "aws_eip" "eip_nat03" {
  vpc = true
}
 
# Create the NAT Gateways
resource "aws_nat_gateway" "nat_gw01" {
  subnet_id = "${aws_subnet.subnet01-public.id}"
  allocation_id = "${aws_eip.eip_nat01.id}"
  tags { Name = "nat_gw01" }
 
  # Dependencies: Internet Gateway and EIP
  depends_on = ["aws_internet_gateway.myigw", "aws_eip.eip_nat01"]
}
 
resource "aws_nat_gateway" "nat_gw02" {
  subnet_id = "${aws_subnet.subnet02-public.id}"
  allocation_id = "${aws_eip.eip_nat02.id}"
  tags { Name = "nat_gw02" }
 
  # Dependencies: Internet Gateway and EIP
  depends_on = ["aws_internet_gateway.myigw", "aws_eip.eip_nat02"]
}
 
resource "aws_nat_gateway" "nat_gw03" {
  subnet_id = "${aws_subnet.subnet03-public.id}"
  allocation_id = "${aws_eip.eip_nat03.id}"
  tags { Name = "nat_gw03" }
 
  # Dependencies: Internet Gateway and EIP
  depends_on = ["aws_internet_gateway.myigw", "aws_eip.eip_nat03"]
}
 
# Route to the NAT Gateway provided elsewhere (in private route table)
routes.tf
#Title: site/routes.tf                                                                                                   
# Description: Route tables for subnets                                                                              
 
####-- Routes --####                                                                                                 
 
##-- Public Subnet Routes --##                                                                                       
 
# Public Route Table - Default Route to Internet Gateway                                                             
resource "aws_route_table" "rt_public" {                                                                             
  vpc_id = "${aws_vpc.myvpc.id}"                                                                                     
 
  route {                                                                                                            
    cidr_block = "0.0.0.0/0"                                                                                         
    gateway_id = "${aws_internet_gateway.myigw.id}"                                                                  
  }                                                                                                                  
 
  tags {                                                                                                             
    Name = "rt_public"                                                                                               
  }                                                                                                                  
}                                                                                                                    
 
# Associate Subnet Public 01 with Route Table                                                                        
resource "aws_route_table_association" "rt_assoc_public01" {                                                         
  subnet_id = "${aws_subnet.subnet01-public.id}"                                                                     
  route_table_id = "${aws_route_table.rt_public.id}"                                                                 
}                                                                                                                    
 
# Associate Subnet Public 02 with Route Table                                                                        
resource "aws_route_table_association" "rt_assoc_public02" {                                                         
  subnet_id = "${aws_subnet.subnet02-public.id}"                                                                     
  route_table_id = "${aws_route_table.rt_public.id}"                                                                 
}                                                                                                                    
 
# Associate Subnet Public 03 with Route Table                                                                        
resource "aws_route_table_association" "rt_assoc_public03" {                                                         
  subnet_id = "${aws_subnet.subnet03-public.id}"                                                                     
  route_table_id = "${aws_route_table.rt_public.id}"                                                                 
}
 
##-- Private Subnet Routes --##                                                                                      
 
# Private Route Tables - Default Route to NAT GW in each AZ                                                          
resource "aws_route_table" "rt_private01" {                                                                          
  vpc_id = "${aws_vpc.myvpc.id}"                                                                                     
 
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat_gw01.id}"
  }
 
  tags {
    Name = "rt_private01"
  }
}
 
resource "aws_route_table" "rt_private02" {
  vpc_id = "${aws_vpc.myvpc.id}"
 
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat_gw02.id}"
  }
 
  tags {
    Name = "rt_private02"
  }
}
 
resource "aws_route_table" "rt_private03" {
  vpc_id = "${aws_vpc.myvpc.id}"
 
  route {
    cidr_block = "0.0.0.0/0"
    nat_gateway_id = "${aws_nat_gateway.nat_gw03.id}"
  }
 
  tags {
    Name = "rt_private03"
  }
}
 
# Associate Subnet Private 01 with Route Table
resource "aws_route_table_association" "rt_assoc_private01" {
  subnet_id = "${aws_subnet.subnet01-private.id}"
  route_table_id = "${aws_route_table.rt_private01.id}"
}
 
# Associate Subnet Private 02 with Route Table
resource "aws_route_table_association" "rt_assoc_private02" {                                                       
  subnet_id = "${aws_subnet.subnet02-private.id}"
  route_table_id = "${aws_route_table.rt_private02.id}"
}
 
# Associate Subnet Private 03 with Route Table
resource "aws_route_table_association" "rt_assoc_private03" {                                                       
  subnet_id = "${aws_subnet.subnet03-private.id}"
  route_table_id = "${aws_route_table.rt_private03.id}"
}
security_groups.tf
# Title: site/security_groups.tf                                                                                          
# Description: Security groups for resources in subnets.                                                             
 
####-- Security Groups --####                                                                                        
 
# Create default locked down security groups for private and public subnets                                          
 
# Security Group: Public Subnets                                                                                     
resource "aws_security_group" "sg_public_default" {                                                                  
  name = "sg_public_default"                                                                                         
  description = "Default public facing security group"
  tags = { Name = "sg_public_default" }
  vpc_id = "${aws_vpc.myvpc.id}"
 
  ##-- Ingress/Inbound Rules --##
  # No ingress/inbound rules by default
  #ingress {
  #}
 
  ##-- Egress/Outbound Rules --##
  # Allow all egress/outbound traffic
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
 
# Security Group: Private Subnets
resource "aws_security_group" "sg_private_default" {
  name = "sg_private_default"
  description = "Default private facing security group"
  tags = { Name = "sg_private_default" }
  vpc_id = "${aws_vpc.myvpc.id}"
 
  ##-- Ingress/Inbound Rules --##
  # Allow all ssh traffic from default public security group                                                        
  ingress {
    from_port = 22
    to_port = 22
    protocol = "tcp"
    security_groups = ["${aws_security_group.sg_public_default.id}"]                                                
  }
 
  # Allow all traffic within the private security group
  ingress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    self = "true"
  }
 
  ##-- Egress/Outbound Rules --##
  # Allow all egress/outbound traffic
  egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
outputs.tf
# Title: site/outputs.tf
# Description: Outputs from resources saved as variables
#              Accessible via "${module.site.variable_name}"
 
# Set output variable from resource format                                                                           
# output "variable_name" {
#   value = "${aws_resource.name.attribute}"
# }
 
# Store the VPC ID
output "vpc_id" {
  value = "${aws_vpc.myvpc.id}"
}
 
# Store the Public Subnet ID
output "subnet01_public_id" {
  value = "${aws_subnet.subnet01-public.id}"
}
 
# Store the Public Security Group ID
output "sg_public_default_id" {
  value = "${aws_security_group.sg_public_default.id}"
}

  • linux_wiki/terraform.txt
  • Last modified: 2019/05/26 03:50
  • (external edit)