Creación de instancias EC2 y reglas de seguridad en AWS con Terraform (5/5)

Instancias EC2 y seguridad de recursos

Tutorial 5 de 5 acerca del uso de Terraform y Ansible para AWS. Tras finalizar el tutorial habrá creado mediante Terraform un VPC en AWS con una instancia EC2 conectadas a una base de datos MariaDB ejecutándose sobre RDS. Posteriormente se usa Ansible para configurar e instalar el software necesario.

Prerequisitos y código fuente:

Creación de un instancias AWS EC2 con Terraform

Las instancias EC2 se definen en terraform.tfvars, algunos valores (ami, vpc_security_group_ids and subnet_id) se obtienen de la salida de otros módulos por lo que su origen se ve en el fichero de definición de cada instancia, en este caso aws_ec2_pro_wp.tf al no poder hacer referencia a variables interpoladas en terraform.tfvars.

    #------------------------
    # WP PRO
    #------------------------

  aws_ec2_pro_pub_wp_01 = {
    name              = "ditwl-ec2-pro-pub-wp01"
    ami               = "" #Uses data.aws_ami.ubuntu1604.id
    instance_type     = "t2.micro" #AWS Free Tier: 750 hours per month of Linux, RHEL, or SLES t2.micro instance usage
    availability_zone = "us-east-1a"
    key_name          = "ditwl_kp_infradmin"
    # vpc_security_group_ids = SEE TF file
    # subnet_id         = SEE TF file
    associate_public_ip_address = true

    root_block_device_size        = 8

    # See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html
    root_block_device_volume_type = "gp2"

    tag_private_name  = "ditwl-ec2-pro-pub-wp-01"
    tag_public_name   = "www"
    tag_app           = "wp"
    tag_app_id        = "wp-01"
    tag_os            = "ubuntu"
    tag_os_id         = "ubuntu-16"
    tags_environment  = "pro"
    tag_cost_center   = "ditwl-permanent"
    tags_volume       = "ditwl-ec2-pro-pub-wp-01-root"

  }

  #------------------------
  # WP PRO Security Group
  #------------------------
  aws_sg_ec2_pro_pub_wp_01 = {
    sec_name        = "ditwl-sg-ec2-pro-pub-01"
    sec_description = "ditwl - WP server access rules - Pub, Env: PRO"
    allow_all_outbound = false
  }

  aws_sr_ec2_pro_pub_wp_01_internet_to_80 = {
    type              = "ingress"
    from_port         = 80
    to_port           = 80
    protocol          = "tcp"
    cidr_blocks       = "0.0.0.0/0"
    description       = "Access from Internet to port 80"
  }

  aws_sr_ec2_pro_pub_wp_01_internet_to_443 = {
    type              = "ingress"
    from_port         = 443
    to_port           = 443
    protocol          = "tcp"
    cidr_blocks       = "0.0.0.0/0"
    description       = "Access from Internet to port 443"
  }

Todas los nombres de las instancias EC2 y sus reglas y grupos de seguridad siguen un patrón de nombrado estándar:

  • Cloud: un prefijo que especifica un nombre único para este cloud y proveedor. En este caso se utiliza ditwl que se obtiene de las iniciales de Demo IT Wonder Lab en minúscula.
  • Recurso: un nombre corto que identifica el tipo de recurso, en este caso usamos:
    • ec2: para instancias EC2
    • sg-ec2: para grupos de seguridad EC2
    • sr-ec2: para reglas de seguridad EC2
  • Entorno: para recursos que no están compartidos en varios entornos, se utiliza un acrónimo del entorno:
    • pro: producción
    • pre: preproducción
    • dev: desarrollo
  • Visibilidad: para recursos que pueden ser públicos o privados, se utilizan 3 letras para indicar su visibilidad:
    • pub: para recursos públicos
    • pri: par recursos privados
  • Nombre/ID: nombre o identificador que describe el uso del recurso o el número de instancia del mismo, por ejemplo para RDS:
    • Número de recursos EC2: El número de recurso, por ejemplo para esta demo será el servidor de WordPress wp número 01 tanto para la zona privada como la pública. En un futuro podríamos tener más de un servidor o varios en cada zona por lo que añadir desde el principio un número permite crecer de forma ordenada.
    • Número de grupo de seguridad de EC2: el número de grupo de seguridad. Al crecer tendremos mas grupos por lo que es conveniente identificarlos y diferenciarlos desde el principio.
    • Descripción del objetivo de la regla: utilizando una descripción que nos indique el objetivo de la regla. Por ejemplo internet_to_443 nos indica que es la regla de acceso desde Internet al puerto 443 de las instancias EC2.

Clave privada Para la instancia EC2

Para tener acceso a la instancia Linux recién creada en AWS se requiere un cliente SSH y la autenticación se realiza con una clave privada y en el caso de Ubuntu con el login “ubuntu”.

La clave privada debe ser registrada en la consola de AWS EC2, puede ser creada mediante un asistente o subida en caso de disponer ya de un para de clave privada y pública.

Creación mediante el asistente:

  1. Visite la consola de AWS
  2. Seleccione la región en la que se creará la instancia EC2 ya que los pares de claves se registran específicamente para cada región
  3. Vaya a EC2
  4. Vaya a la sección red, seguridad pares de claves.
  5. Cree un nuevo par de clave con el nombre ditwl_kp_infradmin. AWS generará un fichero PEM que deberá almacenar en su equipo de forma segura.
  6. Almacene el fichero descargado en ${HOME}/keys/ditwl_kp_infradmin.pem. Será utilizado por Ansible en el siguiente tutorial.

Definición de instancias AWS EC2 con Terraform

Una vez configurados los valores de la instancia en terraform.tfvar, el fichero aws_ec2_pro_wp.tf hace uso de módulos de Terraform para crear los recursos.

El módulo de Terraform /modules/aws/ec2/instance/add se utiliza para crear la instancia EC2. La mayoría de las variables se fijan en terraform.tfvars y el resto son interpolaciones de otros recursos:

  • ami = data.aws_ami.ubuntu1604.id utiliza la salida de la fuente de datos aws_ami, vea búsqueda de AMI y creación de EC2 con Terraform para una explicación.
  • disable_api_termination = var.is_production ? true : false. Utiliza el valor de is_production para prevenir la destrucción de la instancia EC2. Vea Avoiding AWS instance destroy with Terraform para una explicación.
  • vpc_security_group_ids = [module.aws_sec_group_ec2_default.id, module.aws_sg_ec2_pro_pub_wp_01.id] es una lista de grupos de seguridad que tienen acceso a la instancia.
  • register_dns_private = verdad y register_dns_public = verdad se utilizan para indicar si se debe o no registra la instancia en DNS público y privado. Vea AWS Route 53 con Terraform para una explicación.
  # Create WP instance
  module "aws_ec2_pro_pub_wp_01" {
    source            = "./modules/aws/ec2/instance/add"
    name              = var.aws_ec2_pro_pub_wp_01["name"]
    ami               = data.aws_ami.ubuntu1604.id
    instance_type     = var.aws_ec2_pro_pub_wp_01["instance_type"]
    availability_zone = var.aws_ec2_pro_pub_wp_01["availability_zone"]
    key_name          = var.aws_ec2_pro_pub_wp_01["key_name"]
    disable_api_termination = var.is_production ? true : false
    vpc_security_group_ids = [module.aws_sg_ec2_default.id,module.aws_sg_ec2_pro_pub_wp_01.id]
    subnet_id         = module.aws_sn_za_pro_pub_32.id
    associate_public_ip_address = var.aws_ec2_pro_pub_wp_01["associate_public_ip_address"]
    instance_tags     = {}
    tag_private_name  = var.aws_ec2_pro_pub_wp_01["tag_private_name"]
    tag_public_name   = var.aws_ec2_pro_pub_wp_01["tag_public_name"]
    tag_app           = var.aws_ec2_pro_pub_wp_01["tag_app"]
    tag_app_id        = var.aws_ec2_pro_pub_wp_01["tag_app_id"]
    tag_os            = var.aws_ec2_pro_pub_wp_01["tag_os"]
    tag_os_id         = var.aws_ec2_pro_pub_wp_01["tag_os_id"]
    tags_environment  = var.aws_ec2_pro_pub_wp_01["tags_environment"]
    tag_cost_center   = var.aws_ec2_pro_pub_wp_01["tag_cost_center"]

    register_dns_private = true
    route53_private_zone_id = module.aws_route53_public.id

    register_dns_public = true
    route53_public_zone_id = module.aws_route53_public.id

    root_block_device = {
      volume_size           = var.aws_ec2_pro_pub_wp_01["root_block_device_size"]
      volume_type           = var.aws_ec2_pro_pub_wp_01["root_block_device_volume_type"]
      delete_on_termination = var.is_production ? false : true #If production, Do not delete!
    }

    volume_tags       = {
      Name = var.aws_ec2_pro_pub_wp_01["name"]
    }

    ignore_changes = ["ami"]

  }

Seguridad de recursos en AWS con Terraform

La securización de recursos en AWS con Terraform hace uso de 3 módulos:

  • modules/aws/security/group: crea un grupo de seguridad y devuelve el ID para ser utilizado en las asociación de reglas e instancias.
  • modules/aws/security/rule/cidr_blocks: crea reglas de seguridad y las asocia al grupo indicado (mediante el ID). Hace uso de bloques CIDR como origen del tráfico.
  • modules/aws/security/rule/source_group: crea reglas de seguridad y las asocia al grupo indicado (mediante el ID). Hace uso de otro grupo de seguridad para especificar el origen del tráfico. Vea un ejemplo de su uso en la configuración de una instancia RDS.

Buenas prácticas: Grupos de Seguridad en AWS

Cree un número pequeño de grupos de seguridad que puedan ser combinados para obtener la configuración de seguridad deseada.
Recomendamos tener un grupo de seguridad genérico para cada tipo de recurso con todas las reglas comunes y un grupo de seguridad específico para cada recurso con las particularidades.
Todos los recursos deben estar securizados, independientemente de su ubicación ya que una máquina comprometida puede dar acceso a todas las demás.

Grupos de seguridad recomendados:

  • Un grupo genérico para cada tipo de recurso: estos grupos se utilizan para almacenar reglas que aplican a todos los recursos del mismo tipo, por ejemplo el acceso SSH en el caso de instancias EC2 se permite desde un rango de IPs específico o el acceso a una base de datos. Ejemplos:
    • ditwl-sg-rds-mariadb-def: grupo de seguridad para todas las bases de datos de tipo RDS MariaDB. Es específico para MariaDB ya que otras bases de datos tendrán un puerto de administración diferente.
    • ditwl-sg-ec2-def: grupo de seguridad específico para todas las instancias EC2, tendrá una regla que permite el acceso por SSH.
  • Un grupo específico para cada recurso:  Se recomienda un grupo para cada recurso que deberá nombrarse de forma que identifique claramente al recurso asociado. Ejemplos:
    • ditwl-aws-sg-rds-mariadb-pro-pub-01: grupo de seguridad para la instancia RDS MariaDB del entorno PRO en zona PÚBlica número 01.
    • ditwl-sg-ec2-pro-pub-01: grupo de seguridad para la instancia EC2 del entorno PRO en zona PÚBlica número 01.

Evite crear muchos grupos de seguridad y no utilice un rango de IPs (un CIDR) como origen (excepto cuando se refiera a Internet). Es mejor utilizar como fuente a otros grupos, de esa forma el acceso se obtiene por pertenencia y no por tener una IP concreta que puede cambiar habitualmente.

El siguiente diagrama muestra los grupos de seguridad y las reglas que se aplican a cada recursos de AWS.

List of security rules
AWSC Security rules applied to an EC2 and RDS instances

Continúe la demo de Terraform y Ansible para AWS:

Creación de instancias EC2 y reglas de seguridad en AWS con Terraform (5/5)

Leave a Reply

Your email address will not be published.