Desplegando infraestructura en AWS con Terraform

¿Qué es Terraform?

Terraform es un software de código libre que permite, a partir de un lenguaje de alto nivel, crear, modificar o destruir una infraestructura compleja en alguna plataforma de Cloud Computing, como Amazon Web Services, Microsoft Azure o Google Cloud Platform, entre otras. A este proceso de gestión de recursos mediante código se le denomina IaC (Infrastucture as Code)

Escenario

En primer lugar, veamos el escenario que vamos a desplegar:

Un escenario que contiene la arquitectura de red recomendada por Amazon

Código

A continuación vemos el script de creación dividido en trozos que corresponden con los recursos que pretendemos crear:

Proveedor y credenciales

En primer lugar se especifican el proveedor y las credenciales:

# Proveedor y credenciales

provider "aws" {
  profile    = "default" # Recoge las credenciales del fichero .aws/credentials
  region     = "eu-west-1"
} 

Creación de variables

Las variables, que podríamos rellenar con parámetros del script, y que tienen valores por defecto por si estos no se introducen:

# Variables

variable "vpc-name" {
    description = "El nombre de la vpc a crear"
    type    = string
    default = "mi-vpc"
}

variable "vpc-cidr" {
    description = "La dirección de red de la vpc a crear"
    type    = string
    default = "10.0.0.0/16"
}

variable "igw-name" {
    description = "Nombre del Internet Gateway"
    type    = string
    default = "mi-igw"
}

variable "private-subnet1-name" {
    description = "Nombre de la subred privada 1"
    type    = string
    default = "private-subnet1"
}

variable "private-subnet1-cidr" {
    description = "Rango de direcciones de la subred privada 1"
    type    = string
    default = "10.0.1.0/24"
}

variable "private-subnet2-name" {
    description = "Nombre de la subred privada 2"
    type    = string
    default = "private-subnet2"
}

variable "private-subnet2-cidr" {
    description = "Rango de direcciones de la subred privada 2"
    type    = string
    default = "10.0.2.0/24"
}

variable "public-subnet1-name" {
    description = "Nombre de la subred publica 1"
    type    = string
    default = "public-subnet1"
}

variable "public-subnet1-cidr" {
    description = "Rango de direcciones de la subred pública 1"
    type    = string
    default = "10.0.3.0/24"
}

variable "public-subnet2-name" {
    description = "Nombre de la subred publica 2"
    type    = string
    default = "public-subnet2"
}

variable "public-subnet2-cidr" {
    description = "Rango de direcciones de la subred publica 2"
    type    = string
    default = "10.0.4.0/24"
}

variable "route-table-public-subnet1-name" {
    description = "Nombre de la tabla de rutas para la subred publica"
    type    = string
    default = "route-table-public-subnet1"
}

variable "route-table-public-subnet2-name" {
    description = "Nombre de la tabla de rutas para la subred publica"
    type    = string
    default = "route-table-public-subnet2"
}

variable "eip-name" {
    description = "Nombre de la eip para el nat gateway"
    type    = string
    default = "eip-ngw"
}

variable "ngw-name" {
    description = "Nombre para el nat gateway"
    type    = string
    default = "ngw"
}

Creación de recursos

Creación de la VPC:

# VPC

resource "aws_vpc" "main" { # Se exportan los atributos del recurso, pudiendose utilizar después
  cidr_block = var.vpc-cidr
  tags = {
    Name = var.vpc-name
  }
}

Creación de subredes:

# Subnet privada 1 (eu-west-a)

resource "aws_subnet" "private-subnet1" {
  vpc_id     = "${aws_vpc.main.id}"
  availability_zone = "${data.aws_availability_zones.available.names[0]}"
  cidr_block = var.private-subnet1-cidr

  tags = {
    Name = var.private-subnet1-name
  }
}
# Subnet privada 2 (eu-west-b)

resource "aws_subnet" "private-subnet2" {
  vpc_id     = "${aws_vpc.main.id}"
  availability_zone = "${data.aws_availability_zones.available.names[1]}"
  cidr_block = var.private-subnet2-cidr

  tags = {
    Name = var.private-subnet2-name
  }
}
# Subnet publica 2 (eu-west-b)

resource "aws_subnet" "public-subnet2" {
  vpc_id     = "${aws_vpc.main.id}"
  availability_zone = "${data.aws_availability_zones.available.names[1]}"
  cidr_block = var.public-subnet2-cidr
  map_public_ip_on_launch = true # auto-assing public ip
  tags = {
    Name = var.public-subnet2-name
  }
}
# Subnet publica 1 (eu-west-a)

resource "aws_subnet" "public-subnet1" {
  vpc_id     = "${aws_vpc.main.id}"
  availability_zone = "${data.aws_availability_zones.available.names[0]}"
  cidr_block = var.public-subnet1-cidr
  map_public_ip_on_launch = true # auto-assing public ip
  tags = {
    Name = var.public-subnet1-name
  }
}

Creación del Internet Gateway

# Internet Gateway

resource "aws_internet_gateway" "igw" {
  vpc_id = "${aws_vpc.main.id}" # Id exportado en la creación de la vpc

  tags = {
    Name = var.igw-name
  }
}

Creación de subredes y asociaciones:

# Tabla de rutas para la subred pública 1

resource "aws_route_table" "route-table-public-subnet1" {
  vpc_id = "${aws_vpc.main.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.igw.id}"
  }
  tags = {
    Name = var.route-table-public-subnet1-name
  }
}
resource "aws_route_table_association" "route-table-association-public-subnet1" {
  subnet_id      = "${aws_subnet.public-subnet1.id}"
  route_table_id = "${aws_route_table.route-table-public-subnet1.id}"
}
# Tabla de rutas para la subred pública 2

resource "aws_route_table" "route-table-public-subnet2" {
  vpc_id = "${aws_vpc.main.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.igw.id}"
  }
  tags = {
    Name = var.route-table-public-subnet2-name
  }
}
resource "aws_route_table_association" "route-table-association-public-subnet2" {
  subnet_id      = "${aws_subnet.public-subnet2.id}"
  route_table_id = "${aws_route_table.route-table-public-subnet2.id}"
}
# Tabla de rutas para la subred privada 1 

resource "aws_route_table" "route-table-private-subnet1" {
  vpc_id = "${aws_vpc.main.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_nat_gateway.nat-gw.id}"
  }
  tags = {
    Name = "route-table-private-subnet1"
  }
}
resource "aws_route_table_association" "route-table-association-private-subnet1" {
  subnet_id      = "${aws_subnet.private-subnet1.id}"
  route_table_id = "${aws_route_table.route-table-private-subnet1.id}"
}
# Tabla de rutas para la subred privada 2 

resource "aws_route_table" "route-table-private-subnet2" {
  vpc_id = "${aws_vpc.main.id}"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_nat_gateway.nat-gw.id}"
  }
  tags = {
    Name = "route-table-private-subnet2"
  }
}
resource "aws_route_table_association" "route-table-association-private-subnet2" {
  subnet_id      = "${aws_subnet.private-subnet2.id}"
  route_table_id = "${aws_route_table.route-table-private-subnet2.id}"
}

Creación de la Elastic IP

# Elastic IP para el NAT Gateway

resource "aws_eip" "eip" {
  vpc      = true
  tags = {
    Name = var.eip-name
  }
}

Creación del NAT Gateway

# NAT Gateway

resource "aws_nat_gateway" "nat-gw" {
  allocation_id = "${aws_eip.eip.id}"
  subnet_id     = "${aws_subnet.public-subnet1.id}"

  tags = {
    Name = var.ngw-name
  }
}

Creación de un Security Group

# Security Group

resource "aws_security_group" "allow_http" {
  name        = "allow_http"
  description = "Allow http inbound traffic"
  vpc_id      = "${aws_vpc.main.id}"
  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"]
  }
  tags = {
		Name = "allow-http-sg"
	}
}

Creación de la instancia EC2

# EC2 Webserver

resource "aws_instance" "my-instance" {
	ami = "ami-08d658f84a6d84a80"
	instance_type = "t2.nano"
  security_groups = ["${aws_security_group.allow_http.id}"]
  subnet_id = "${aws_subnet.public-subnet1.id}"
	user_data = "${file("install_apache.sh")}"
	tags = {
		Name = "webserver"
	}
}

Script para el user_data de la instancia:

#! /bin/bash

apt-get update
apt-get install -y apache2
systemctl start apache2
systemctl enable apache2
echo "<h1>Deployed via Terraform</h1>" | sudo tee /var/www/html/index.html

A continuación se muestra el despliegue del entorno con Terraform:

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *