Terraform con AWS en Español - Parte 2
Tags: aws, terraform, iac, devops
Published: 2023-07-14 04:25:21

Directo a la acción! Nuestra aplicación 3 tier se basará en esta arquitectura mostrada.

La estructura de nuestros archivos en terraform tendrá la siguiente forma:

```
- main.tf
- outputs.tf
- vpc/
  - main.tf
  - variables.tf
  - outputs.tf
- ec2_instances/
  - main.tf
  - variables.tf
  - outputs.tf
- rds/
  - main.tf
  - variables.tf
  - outputs.tf
- alb/
  - main.tf
  - variables.tf
  - outputs.tf
```
módulo principal:

- main.tf

Este es el archivo principal de Terraform. Aquí definimos todos los módulos que necesitamos (VPC, EC2, RDS, ALB) y cómo interactúan entre ellos, es decir, pasamos las salidas de un módulo (como las IDs de las subredes de la VPC) como variables de entrada para otro módulo.

```
module "network" {
  source = "./vpc"
}

module "ec2_instances" {
  source = "./ec2_instances"
  ami = "ami-0c94855ba95c574c8" 
  vpc_id = module.network.vpc_id
  public_subnet_id = module.network.public_subnets[0]
  private_subnet_id = module.network.private_subnets[0]
}

module "rds" {
  source = "./rds"
  db_name = "mydb"
  db_username = "username"
  db_password = "password"
  vpc_id = module.network.vpc_id
  db_subnet_group = module.network.private_subnets
}

module "alb" {
  source = "./alb"
  subnets = module.network.public_subnets
  vpc_id = module.network.vpc_id
}


```

módulos secundarios:

**VPC**

- vpc/main.tf

Este archivo contiene la definición del módulo de la VPC. Incluye la definición de la VPC, las subredes públicas y privadas, el gateway NAT y los grupos de seguridad necesarios.

```
module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  name = "my-vpc"
  cidr = var.vpc_cidr

  azs             = var.azs
  private_subnets = var.private_subnets_cidrs
  public_subnets  = var.public_subnets_cidrs

  enable_nat_gateway = true
  single_nat_gateway = true
  enable_dns_hostnames = true

  tags = {
    "Name" = "main"
    "Environment" = "Test"
  }
}

output "vpc_id" {
  description = "The ID of the VPC"
  value       = module.vpc.vpc_id
}

output "public_subnets" {
  description = "List of IDs of public subnets"
  value       = module.vpc.public_subnets
}

output "private_subnets" {
  description = "List of IDs of private subnets"
  value       = module.vpc.private_subnets
}


```
- vpc/variables.tf

En este archivo se declaran las variables que necesita el módulo de la VPC, como los CIDR de la VPC y las subredes, y las zonas de disponibilidad que se van a utilizar.

```
variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  default     = "10.0.0.0/16"
}

variable "azs" {
  description = "List of Availability Zones to be used"
  default     = ["us-east-1a", "us-east-1b"]
}

variable "private_subnets_cidrs" {
  description = "List of CIDR blocks for private subnets"
  default     = ["10.0.1.0/24", "10.0.2.0/24"]
}

variable "public_subnets_cidrs" {
  description = "List of CIDR blocks for public subnets"
  default     = ["10.0.3.0/24", "10.0.4.0/24"]
}


```
- vpc/outputs.tf

 Este archivo contiene las salidas que nos interesan del módulo VPC, como la ID de la VPC y las IDs de las subredes.

```
output "vpc_id" {
  description = "The ID of the VPC"
  value       = module.vpc.vpc_id
}

output "public_subnets" {
  description = "List of IDs of public subnets"
  value       = module.vpc.public_subnets
}

output "private_subnets" {
  description = "List of IDs of private subnets"
  value       = module.vpc.private_subnets
}

output "web_sg_id" {
  description = "The ID of the security group for the web server"
  value       = aws_security_group.web_sg.id
}

output "app_sg_id" {
  description = "The ID of the security group for the application server"
  value       = aws_security_group.app_sg.id
}

output "rds_sg_id" {
  description = "The ID of the security group for the RDS instance"
  value       = aws_security_group.rds_sg.id
}

output "alb_sg_id" {
  description = "The ID of the security group for the ALB"
  value       = aws_security_group.alb_sg.id
}

output "vpc_cidr_block" {
  description = "The CIDR block of the VPC"
  value       = module.vpc.vpc_cidr_block
}

```
**EC2**
- ec2_instances/main.tf

Este archivo define las instancias EC2 que vamos a utilizar para nuestros servidores web y de aplicaciones, incluyendo los grupos de seguridad asociados.

```
data "aws_ami" "ubuntu" {
  most_recent = true
  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t2.micro"
  subnet_id              = var.public_subnet_id
  vpc_security_group_ids = [aws_security_group.web_sg.id]

  tags = {
    Name = "Web Server"
  }
}

resource "aws_instance" "app" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t2.micro"
  subnet_id              = var.private_subnet_id
  vpc_security_group_ids = [aws_security_group.app_sg.id]

  tags = {
    Name = "App Server"
  }
}

resource "aws_security_group" "web_sg" {
  name        = "web_sg"
  description = "Allow inbound traffic from ALB and outbound to App"
  vpc_id      = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.alb_cidr]
  }

  egress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.app_cidr]
  }
}

resource "aws_security_group" "app_sg" {
  name        = "app_sg"
  description = "Allow inbound traffic from Web and outbound to RDS"
  vpc_id      = var.vpc_id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = [var.web_cidr]
  }

  egress {
    from_port   = 3306
    to_port     = 3306
    protocol    = "tcp"
    cidr_blocks = [var.rds_cidr]
  }
}

output "web_sg_id" {
  description = "Security Group ID for Web Server"
  value       = aws_security_group.web_sg.id
}

output "app_sg_id" {
  description = "Security Group ID for App Server"
  value       = aws_security_group.app_sg.id
}

```
- ec2_instances/variables.tf

Este archivo declara las variables necesarias para crear las instancias EC2 y los grupos de seguridad.

```
variable "vpc_id" {
  description = "The ID of the VPC to use"
}

variable "public_subnet_id" {
  description = "The ID of the public subnet to use"
}

variable "private_subnet_id" {
  description = "The ID of the private subnet to use"
}

variable "alb_cidr" {
  description = "CIDR block for ALB"
  default     = "0.0.0.0/0"
}

variable "app_cidr" {
  description = "CIDR block for App Server"
  default     = "0.0.0.0/0"
}

variable "web_cidr" {
  description = "CIDR block for Web Server"
  default     = "0.0.0.0/0"
}

variable "rds_cidr" {
  description = "CIDR block for RDS"
  default     = "0.0.0.0/0"
}

```
- ec2_instances/outputs.tf

Este archivo contiene las salidas del módulo EC2 que necesitamos, como las IDs de los grupos de seguridad de las instancias EC2.

```
output "web_sg_id" {
  description = "Security Group ID for Web Server"
  value       = aws_security_group.web_sg.id
}

output "app_sg_id" {
  description = "Security Group ID for App Server"
  value       = aws_security_group.app_sg.id
}

```
**RDS**
- rds/main.tf

Este archivo define la base de datos RDS que vamos a utilizar, incluyendo la configuración de almacenamiento y el grupo de seguridad asociado.

```
resource "aws_db_instance" "default" {
  name            = var.db_name
  username        = var.db_username
  password        = var.db_password
  engine          = "mysql"
  engine_version  = "5.7"
  instance_class  = "db.t2.micro"
  allocated_storage = 20
  vpc_security_group_ids = [var.app_sg_id]
  db_subnet_group_name = var.db_subnet_group

  tags = {
    Name = "MyDBInstance"
  }
}


```
- rds/variables.tf

Este archivo declara las variables que necesitamos para crear la instancia de RDS y su grupo de seguridad.
```

variable "db_name" {
  description = "The database name"
}

variable "db_username" {
  description = "Username for the master DB user"
}

variable "db_password" {
  description = "Password for the master DB user"
}

variable "vpc_id" {
  description = "The ID of the VPC to use"
}

variable "db_subnet_group" {
  description = "A list of subnet IDs to associate with the RDS instance"
}

variable "app_sg_id" {
  description = "Security Group ID for App Server"
}



```
**ALB**
- alb/main.tf

Este archivo define el balanceador de carga de aplicación (ALB) que vamos a utilizar, incluyendo la configuración de escucha y el grupo de seguridad asociado.

```
resource "aws_alb" "example" {
  name               = "example-alb"
  subnets            = var.subnets
  security_groups    = [aws_security_group.alb_sg.id]

  tags = {
    Name = "example-alb"
  }
}

resource "aws_alb_target_group" "example" {
  name     = "example"
  port     = 80
  protocol = "HTTP"
  vpc_id   = var.vpc_id
}

resource "aws_alb_listener" "front_end" {
  load_balancer_arn = aws_alb.example.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_alb_target_group.example.arn
  }
}

resource "aws_security_group" "alb_sg" {
  name        = "alb_sg"
  description = "Allow inbound traffic from the internet"
  vpc_id      = var.vpc_id

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


```
- alb/variables.tf

 Este archivo declara las variables que necesitamos para crear el ALB y su grupo de seguridad.

```
variable "subnets" {
  description = "A list of subnet IDs to associate with the ALB"
}

variable "vpc_id" {
  description = "The ID of the VPC to use"
}


```



¡Genial, casi hemos terminado! Ahora que ya tienes todos los archivos listos, es hora de poner en marcha tu infraestructura. En la terminal, navega hasta el directorio donde se encuentran tus archivos de Terraform. Primero, inicializa tu directorio de trabajo con terraform init. Luego, es recomendable comprobar qué cambios se aplicarán con terraform plan. Si todo está bien, es momento de desplegar tu infraestructura con terraform apply. Este comando te pedirá confirmación, solo escribe 'yes' y Terraform se encargará del resto. Ahora tienes tu arquitectura de 3 niveles funcionando en AWS. Con Terraform, realmente es así de fácil. Recuerda, siempre que hagas cambios en tu código, puedes repetir estos pasos para actualizar tu infraestructura. Y si alguna vez necesitas deshacerte de todo, terraform destroy limpiará todo por ti.