Como crear VPC, EFS y EC2 usando Terraform

Hello World 🙂

En el mundo de la infraestructura en la nube, la automatización y la gestión eficiente de recursos son fundamentales. En esta entrada, exploraremos cómo crear una infraestructura robusta y escalable en AWS utilizando Terraform. Nos centraremos en la combinación de tres servicios clave: Virtual Private Cloud (VPC), Elastic File System (EFS) y Elastic Compute Cloud (EC2).

La VPC proporciona un entorno virtual aislado en la nube, sobre la misma crearemos nuestro diferentes recursos, mientras que EFS ofrece almacenamiento de archivos compartido altamente disponible y escalable. Por otro lado, EC2 son las instancias de servidores virtuales en donde vamos a montar el EFS generado.

A lo largo de esta guía, utilizaremos Terraform, una herramienta de infraestructura como código (IaC) que nos permite definir y gestionar nuestra infraestructura de manera declarativa. Siguiendo los pasos detallados, podrás crear fácilmente esta infraestructura básica en AWS de manera eficiente y reproducible.

¡Prepárate para adentrarte en el mundo de la automatización de infraestructura con Terraform!

Requisitos:

Esta va a hacer la estructura de nuestro proyecto;

1- Primero necesitamos exporta nuestras credenciales de AWS;

  • export AWS_ACCESS_KEY_ID="XXXXXXXXXX"
    export AWS_SECRET_ACCESS_KEY="XXXXXXXXXX"

2- Crear el fichero 0-provider.tf, definiremos el proveedor y la región que utilizaremos en este proyecto. Estos proveedores son esenciales, ya que permiten a Terraform interactuar con los distintos servicios de infraestructura en la nube necesarios para desplegar los recursos correctamente.

  • provider "aws" {
      region = "us-west-1"
    }

3- Crear el fichero 1-vpc-module.tf, definiremos todo lo necesario para generar nuestra VPC, que servirá como la base de la infraestructura del proyecto. Aquí, definiremos subredes y demás componentes claves que permitirán una red segura y eficiente para los recursos que desplegaremos más adelante.

  • module "vpc" {
      source  = "terraform-aws-modules/vpc/aws"
      name = "main-module"
      cidr = "10.0.0.0/16"
      azs             = ["us-west-1a", "us-west-1b"]
      private_subnets = ["10.0.0.0/19", "10.0.32.0/19"]
      public_subnets  = ["10.0.64.0/19", "10.0.96.0/19"]
      enable_dns_hostnames = true
      enable_dns_support   = true
      enable_nat_gateway     = true
      single_nat_gateway     = true
      one_nat_gateway_per_az = false
      public_subnet_tags = {
        "Name"                       = "public-subnet"
        "kubernetes.io/role/elb"     = 1
        "kubernetes.io/cluster/demo" = "owned"
      }
      private_subnet_tags = {
        "Name"                       = "private-subnet"
        "kubernetes.io/role/internal-elb" = 1
        "kubernetes.io/cluster/demo"      = "owned"
      }
    }

4- Crear el fichero 2-efs.tf, definiremos todo lo necesario para generar el EFS;

  • resource "aws_efs_file_system" "eks" {
      creation_token = "demo"
      performance_mode = "generalPurpose"
      throughput_mode  = "bursting"
      encrypted        = true
      tags = {
        Name = "demo"
      }
    }
    resource "aws_efs_mount_target" "zone" {
      for_each = { for idx, subnet in module.vpc.private_subnets : idx => subnet }
      file_system_id  = aws_efs_file_system.eks.id
      subnet_id       = each.value
      security_groups = [aws_security_group.efs.id]
    }

5- Crear el fichero 3-security.tf, definiremos todo lo necesario para generar 2 Security Group, uno para las instancias de EC2 y otro para el EFS. Este archivo nos permitirá establecer las reglas de acceso y seguridad adecuadas para cada recurso, garantizando una comunicación segura y restringida.

  • SG para las instancias de EC2.
    • resource "aws_security_group" "ec2" {
        name        = "ec2-sg"
        description = "Allow efs outbound traffic"
        vpc_id = module.vpc.vpc_id
        egress {
          from_port       = 0
          to_port         = 0
          protocol        = "-1"
          cidr_blocks     = ["0.0.0.0/0"]
        }
        tags = {
          Name = "ec2-sg"
        }
      }
  • SG para el EFS, permitiendo que se conecten a las instancias EC2.
    • resource "aws_security_group" "efs" {
         name = "efs-sg"
         description= "Allow inbound efs traffic from ec2"
         vpc_id = module.vpc.vpc_id
         ingress {
           security_groups = [aws_security_group.ec2.id]
           from_port = 2049
           to_port = 2049
           protocol = "tcp"
         }    
         egress {
           security_groups = [aws_security_group.ec2.id]
           from_port = 0
           to_port = 0
           protocol = "-1"
         }
         tags = {
          Name = "efs-sg"
        }
       }

6- Crear el fichero 4-ec2.tf, definiremos todo lo necesario para generar 2 instancias EC2.

  • resource "aws_instance" "testinstance" {
        count = 2
        ami = "ami-05af0694d2e8e6df3" # Revisar siempre antes de ejecutar
        instance_type = "t2.micro"
        iam_instance_profile = "${aws_iam_instance_profile.poc_profile.name}"
        subnet_id = module.vpc.public_subnets[0]
        associate_public_ip_address= true
        vpc_security_group_ids = [aws_security_group.ec2.id]
        key_name="demo-efs"
        tags= {
            Name = "demo-efs"
        }
    }

7- Crear el fichero 5-iam.tf, definiremos todo lo necesario para generar un Role, adjuntarle algunas Policys a ese rol y generar un Instance Profile que será adjuntando a la instancia, de esta forma podemos conectarnos a la instancia usando el SSM.

  • Definimos el Role.
    • resource "aws_iam_role" "poc_role" {
        name = "poc_role"
        assume_role_policy = <<EOF
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Action": "sts:AssumeRole",
            "Principal": {
              "Service": "ec2.amazonaws.com"
            },
            "Effect": "Allow",
            "Sid": ""
          }
        ]
      }
      EOF
        tags = {
            tag-key = "tag-value"
        }
      }
  • Adjuntamos un par de Policys.
    • resource "aws_iam_policy_attachment" "attach_amazon_ssm_full_access-poc_role" {
        name       = "attach-amazon-ssm-full-access-poc_role"
        roles      = [aws_iam_role.poc_role.name]
        policy_arn = "arn:aws:iam::aws:policy/AmazonSSMFullAccess"
      }
      resource "aws_iam_policy_attachment" "attach_amazon_ec2_role_for_ssm-poc_role" {
        name       = "attach-amazon-ec2-role-for-ssm-poc_role"
        roles      = [aws_iam_role.poc_role.name]
        policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
      }
  • Creamos un Instance Profile.
    • resource "aws_iam_instance_profile" "poc_profile" {
        name = "poc_profile"
        role = "${aws_iam_role.poc_role.name}"
      }

Después de crear todos estos ficheros ya estamos en condiciones de ejecutar terraform;

  • terraform init
  • terraform plan
  • terraform apply

Después que todos los recursos estén creados necesitamos conectarnos a nuestras instancias EC2 y montar el EFS;

  • Ir al EFS en la consola de AWS para ver opciones de montaje.
  • Conectarnos a la instancia EC2 usando el SSM.
  • Así es como luce cuando estamos dentro de la instancia.
  • Una vez dentro de la instancia debemos ejecutar los siguientes comandos.
    • yum install amazon-efs-utils -y

    • mkdir /opt/efs && cd /opt/
  • Montar el EFS en la instancia y chequearlo.
  • Repetir el mismo proceso para la otra instancia. Una vez completado, crear un archivo o carpeta desde cualquiera de las 2 instancias; podrá ser visto y editado desde ambas instancias.

Eliminar todos los recursos creados, es un paso muy importante porque si no vas a incurrir en más gastos y es algo que no te va a gustar mucho 🙂

Conclusiones

Hemos construido una infraestructura pequeña pero robusta y altamente escalable. Una de las principales ventajas de utilizar EFS es la capacidad de tener múltiples instancias compartiendo el mismo almacenamiento de manera eficiente. Esta característica nos permite escalar fácilmente, ya que podemos agregar o quitar instancias según sea necesario sin preocuparnos por la gestión del almacenamiento. Además, al aprovechar el ‘Instance Profile’ y las políticas asociadas al Rol, hemos fortalecido la seguridad de nuestras instancias. Esta estrategia nos ha permitido evitar el acceso por SSH directamente a las instancias, optando en su lugar por el uso del System Manager. Esta medida no solo simplifica la gestión y administración de nuestras instancias, sino que también reduce significativamente la exposición a posibles amenazas externas.

¡Nos vemos en la próxima entrada!

Nota: Todo el código lo pueden encontrar en el siguiente repositorio

Deja una respuesta

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

IT

Artículo anterior

Filebeat vs Fluentd vs FluentBit