Multi-Cloud with Terraform – Any infra, anywhere provision

This post is about provisioning Amazon Web Services EC2 instances using Terraform IaaS, we can create reproducible infrastructure for Dev, UAT, SIT, and Production environments using automation of Terraform scripts. Terraform allows you to split your configuration into as many files as you wish.

We can execute these same scripts against multiple clouds providers, Microsoft Azure, Amazon Web Services, GCP etc. Terraform as infrastructure as code tool, makes this task simple and easy to perform. We can use Terraform to use Infrastructure as Code to provision and manage any cloud, infrastructure, or service.

Terraform infrastructure is configured and provision using language, HCL – HashiCorp Configuration Language. Below are the most commonly used commands by HCL infra provisioning.

CommandsPurpose
INITInitialize the working directory
PLANTo execute the plan for the resources managed by .tf files
APPLYBuild or changes the infrastructure as code which is defined
VERSIONPrints of the Terraform versions
DESTROYDestroy the infrastructure managed by Terraform
VALIDATEValidate the terraform files against the targetted schema
GRAPHOutputs the visual graph of Terraform resources.

There can be multiple reason for the client to go for Multi-Cloud approach:-

  • Cost Considerations,
  • Vendor diversity,
  • Vendor leverage,
  • Desire to use unique services,
  • Need for a particular region [Low latency],

Prerequisites

Once you download terraform binaries, please ensure to have environment variables setup. I have set up my variables, considering I have placed binary in the C folder. Run a version check on the command prompt in the below screenshot.

Implementation – Demo for AWS provisioning

To keep the length of the post limited, since most of the code is very similar. I will limit this demo to AWS. The similar approach can be adopted for Azure. Terraform has separate providers for Microsoft Azure and they can be used to configure infrastructure in Microsoft Azure using the Azure Resource Manager API’s.

More info here – https://www.terraform.io/docs/providers/azurerm/index.html

This configuration provisions infrastructure on Amazon Web Service. I will post the .tf file below for AWS which needed to be executed using AWS access keys and secret access keys.

I have added Azure Terraform plugin, as a Visual Studio Code plugin for IntelliSense but you can use any other tool for the same.

Note – AWS Access Key and AWS Secret Access Key should be configured on the host running this Terraform configuration.

export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Below is the code required to provision for AWS provider:-

provider “aws” {
region = “eu-west-1”
}

module “aws_vpc” {
source = “terraform-aws-modules/vpc/aws”
version = “1.5.1”
name = “${var.configuration_name}-vpc”
cidr = “10.0.0.0/16”
enable_dns_hostnames = true
enable_dns_support = true
azs = [“eu-west-1a”, “eu-west-1b”, “eu-west-1c”]
public_subnets = [“10.0.101.0/24”, “10.0.102.0/24”, “10.0.103.0/24”]
}

module “aws_asg” {
source = “terraform-aws-modules/autoscaling/aws”
version = “2.0.0”
name = “${var.configuration_name}-asg”
image_id = “${data.aws_ami.amazon_linux.id}”
instance_type = “t2.nano”
security_groups = [“${aws_security_group.sg.id}”]
user_data = “${data.template_file.web_server_aws.rendered}”
load_balancers = [“${module.aws_elb.this_elb_id}”]

root_block_device = [
{
volume_size = “8”
volume_type = “gp2”
},
]

vpc_zone_identifier = “${module.aws_vpc.public_subnets}”

health_check_type = “EC2”
min_size = 3
max_size = 3
desired_capacity = 3
wait_for_capacity_timeout = 0
}

module “aws_elb” {
source = “terraform-aws-modules/elb/aws”
version = “1.4.1”
name = “elb”
subnets = [“${module.aws_vpc.public_subnets}”]
security_groups = [“${aws_security_group.sg.id}”]
internal = false

listener = [
{
instance_port = “80”
instance_protocol = “HTTP”
lb_port = “80”
lb_protocol = “HTTP”
},
]

health_check = [
{
target = “HTTP:80/”
interval = 30
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
},
]
}

resource “aws_security_group” “sg” {
name = “${var.configuration_name}-sg”
description = “security group for ${var.configuration_name}”
vpc_id = “${module.aws_vpc.vpc_id}”

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

egress {
from_port = 0
to_port = 65535
protocol = “udp”
cidr_blocks = [“0.0.0.0/0”]
}

egress {
from_port = 0
to_port = 65535
protocol = “tcp”
cidr_blocks = [“0.0.0.0/0”]
}
}

data “aws_ami” “amazon_linux” {
most_recent = true

filter {
name = “name”
values = [“amzn-ami-hvm-*-x86_64-gp2”]
}

filter {
name = “owner-alias”
values = [“amazon”]
}
}

data “template_file” “web_server_aws” {
template = “${file(“${path.module}/web-server.tpl”)}”

vars {
cloud = “aws”
}
}

data “aws_availability_zones” “available” {
state = “available”
}

Commands to be executed for Terraform.

  1. Initialise Terraform :terraform init
  2. Execute a plan :terraform plan -out=1.tfplan
  3. Execute an Apply :terraform apply 1.tfplan
  4. Destroy if you are done with the task in hand and you no longer need the resources.

Upcoming Demo – Azure provisioning

This is pending for another post, I will put this as demo with screenshots in a separate post.