ÍNDICE
1. ¿Qué es Terraform?
2. Prerequisitos
3. ¿Qué vamos a hacer?
4. Pasos
4.1. Crear usuario CLI
Claves de Acceso
4.2. Instalación Software
Instalar AWS CLI
Instalar Terraform
4.3. Código Principal
Proveedor
Creación de la instancia
Conexión desde fuera
Conexión RDP
RDP: Security Groups
RDP: Key pair
Instancia Modificada
Output
Output: IP Pública
Output: Credenciales
5. Extras
5.1. AMI Dinámica
5.2. Credenciales de AWS en archivo
1. ¿Qué es Terraform?
Terraform es una herramienta Open Source que permite generar una infraestructura a través de un lenguaje declarativo. Esto es lo que se llama Infraestructura como código (IaC)
Es decir, permite abstraernos del entorno en que se vaya a implementar dicha estructura, tanto para entornos en la nube (como AWS, Azure, Google Cloud), como entornos locales (como Virtualbox, RouterOS de Mikrotik o Unifi), para centrarnos en la creación de esta.
2. Prerequisitos
Para este lab necesitaremos:
- Una cuenta en AWS que haya sido creada previamente
- Una máquina virtual o PC que con Permisos de Administrador
3. ¿Qué vamos a hacer?
En resumen, las tareas que vamos a hacer en este lab son:
- Crear un usuario programático en AWS
- Instalación de Terraform en un entorno Linux
- Conocer el uso de distintos módulos de Terraform
- Inicializar y aplicar la configuración en una cuenta AWS
4. Pasos
4.1. Crear usuario CLI
Para que Terraform se conecte a nuestra cuenta de AWS, será necesario previamente crear dicho usuario. En este laboratorio crearemos un usuario con permisos de Administrador, que únicamente utilizaremos para uso programático.
Nos conectaremos a nuestra cuenta AWS, y accederemos a la sección IAM -> Users
En dicha sección cliquearemos en Crear usuario
Rellenaremos con el nombre de usuario que nos interese (en nuestro caso utilizaremos el usuario “usercli”, y dejaremos desactivada la opción de acceso a consola, ya que utilizaremos este usuario únicamente para acceso programático.
En Grupos de permisos, deberemos proporcionarle permisos suficientes para crear recursos. En nuestro caso crearemos un grupo nuevo con permisos de Administrador.
Para ello haremos click en “Crear grupo”.
Le pondremos un nombre a dicho grupo (en nuestro caso utilizaremos el nombre “admin”), y en políticas de permisos asociaremos la política “AdministratorAccess”. Haremos click en “Crear grupo de usuario”.
Y en la ventana de Permisos, seleccionamos nuestro nuevo grupo “admin”
Finalmente hacemos click en “Crear Usuario”.
Claves de Acceso
Ya tenemos creado nuestro nuevo usuario. Pero será necesario generar una clave de acceso para poder acceder a este usuario.
Para ello seleccionamos en el menú de IAM -> Users nuestro usuario “usercli”, y accedemos al apartado “Credenciales de seguridad”
Ahora buscaremos la sección “Access keys” y haremos click en “Create access key”.
En el menú que nos aparece, seleccionaremos la opción “Command Line Interface (CLI)”. Esta opción nos permitirá acceder de forma programática.
Y marcamos la opción de seguridad
Finalmente, haremos click en el botón “Create access key”.
En la siguiente sección, nos aparecerá la pareja de keys que necesitaremos posteriormente: “access key” y “secret key”.
4.2. Instalación Software
Instalar AWS CLI
Para poder utilizar AWS en nuestro equipo, será necesario instalar AWS CLI. En nuestro caso, para una distribución Ubuntu, será necesario ejecutar los siguientes comandos:
apt-get install zip curl -y
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Instalar Terraform
Primero será necesario actualizar nuestro sistema e instalar los paquetes necesarios para su instalación (gnupg, curl)
sudo apt-get update && sudo apt-get install -y gnupg software-properties-common
Una vez instalado, procedemos a instalar la key GPG
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
Agregamos el repositorio de Hashicorp y procedemos a descargar la información de paquetes
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
Finalmente instalamos terraform
sudo apt install terraform
4.3. Código Principal
Proveedor
Lo primero que vamos a necesitar va a ser indicarle a Terraform la manera de poder conectarse a AWS.
En nuestro caso, dado que hemos creado un usuario para conectarnos por CLI, será el que utilicemos. Concretamente necesitaremos el “access_key” y el “secret_key” de dicho usuario.
Además de estos datos, será necesario indicar la región en la que vamos a trabajar.
provider "aws" {
region = "eu-west-1"
access_key = "USER_ACCESS_KEY"
secret_key = "USER_SECRET_KEY"
}
Creación de la instancia
Respecto a la instancia de Windows, agregaremos las líneas que consideramos primordiales, y luego iremos agregando las necesarias.
resource "aws_instance" "windows-server" {
ami = “ami-04f19c2d332c17a0c”
instance_type = “t2.micro”
associate_public_ip_address = true
}
ami: Indica la imagen de la distribución que queremos agregar a la instancia. En nuestro ejemplo, el identificador pertenece a un Windows Server 2012 R2.
instance_type: Indica el hardware en la que trabajará dicha instancia. En este ejemplo hemos escogido la instancia “t2.micro” ya que es “free tier” (es decir, gratuito hasta 750 horas de uso durante un año si posees una cuenta nueva)
associate_public_ip_address: Esto permitirá asociar una IP pública a la instancia, para conectarnos desde fuera.
Conexión desde fuera
Con la configuración anterior habremos creado una instancia de Windows 2012 R2, pero no podremos conectarnos. Es por ello que agregaremos algunas opciones más.
Conexión RDP
Aparte de una dirección IP, necesitaremos un protocolo para conectarnos a dicha instancia. En este lab optaremos por conectarnos por RDP (Remote Desktop Protocol).
RDP: Security Groups
Recordamos que los Security Groups son permisos que otorgamos a las instancias para controlar el tráfico entrante y saliente del mismo.
ingress: En nuestro caso, es necesario habilitar el acceso entrante al puerto 3389, que es el puerto habitual del protocolo RDP. En nuestro ejemplo aceptaremos cualquier IP, por lo que en nuestro bloque de cidr usamos cualquier rango “0.0.0.0/0”
egress: Como acceso saliente aceptaremos cualquier protocolo, puerto e IP.
# Security Groups
####################################################
# Define the security group for the Windows server
resource "aws_security_group" "sg-windows" {
name = "windows-sg"
description = "Allow incoming connections"
ingress {
from_port = 3389
to_port = 3389
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow incoming RDP connections"
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
RDP: Key pair
En el caso de instancias Windows, es necesario una pareja de claves (key pair). Esta clave permitirá desencriptar la contraseña de administrador. Una vez desencriptada, podremos utilizarla para poder conectarnos a la instancia.
tls_private_key: Utilizaremos este recurso para generar una clave privada. Definiremos el uso del algoritmo RSA para esta clave
aws_key_pair: En esta sección crearemos el par de claves para controlar el acceso a la instancia. Utilizaremos la clave privada creada previamente para crearla.
# Private Key for Credentials
####################################################
resource "tls_private_key" "instance_key" {
algorithm = "RSA"
}
resource "aws_key_pair" "instance_key_pair" {
key_name = "windows-instance-key"
public_key = tls_private_key.instance_key.public_key_openssh
}
Una vez la instancia se cree, podremos desencriptar la contraseña de Administrador. Para ello, vamos a desencriptarlo bajo código, y almacenarlo en un SSM Parameter Store de AWS.
¿Qué es SSM Parameter Store?
Es una capacidad de AWS System Manager, que proporciona un almacenamiento seguro y jerárquico para la administración de los datos de configuración y de los secretos.
Puede almacenar datos como contraseñas, cadenas de base de datos, ID de Amazon Machine Image (AMI) y códigos de licencia como valores de parámetros. Puede almacenar valores como texto sin formato o como datos cifrados.
El comando principal que permite desencriptar la contraseña es:
rsadecrypt(aws_instance.windows-server.password_data, nonsensitive(tls_private_key.instance_key.private_key_pem))
tls_private_key.instance_key.private_key_pem: Esta es la clave privada creada previamente en formado PEM.
Función nonsensitive(SENSITIVE_TEXT): La clave privada anterior es un elemento sensible, por lo que no nos permitirá utilizarlo. Esta función de Terraform nos permite devolver una copia de dicha clave eliminando la marca de “sensible”.
aws_instance.windows-server.password_data: Una vez se crea la instancia, este argumento apunta a la contraseña encriptada de la misma.
Función rsadecrypt(CIPHERTEXT, PRIVATEKEY): Permite desencriptar un texto cifrado en RSA y lo devuelve en texto plano.
# Store Password
####################################################
resource "aws_ssm_parameter" "windows_ec2" {
depends_on = [aws_instance.windows-server]
name = "/Instances/windows/windows-password"
type = "SecureString"
value = rsadecrypt(aws_instance.windows-server.password_data, nonsensitive(tls_private_key.instance_key.private_key_pem))
}
La mayoría de las veces, Terraform infiere dependencias entre recursos en función de la configuración proporcionada, de modo que los recursos se crean y destruyen en el orden correcto. Esto se realiza de forma automática y recibe el nombre de "dependencias implícitas".
Sin embargo, en ocasiones, Terraform no puede inferir dependencias entre diferentes partes de su infraestructura, y deberá crear una dependencia explícita de forma manual con el argumento depend_on.
Instancia Modificada
Finalmente, modificaremos nuestro recurso de creación de la instancia para que utilice estos recursos extras que hemos agregado.
# Create EC2 Instance
resource "aws_instance" "windows-server" {
# Instance info
ami = “ami-04f19c2d332c17a0c”
instance_type = "t2.micro"
# Public IP
associate_public_ip_address = true
# Instance Credentials
key_name = aws_key_pair.instance_key_pair.key_name
get_password_data = true
# Security Group
vpc_security_group_ids = [aws_security_group.sg-windows.id]
}
Output
Una vez tenemos todos los recursos creados, hay ciertos datos que requeriremos para conectarnos a dicha instancia. Para ello utilizaremos en este ejemplo dos formas distintas para mostrar dicha información
Output: IP Pública
Necesitaremos la IP pública para poder conectarnos. Es por ello que haremos que nos la muestre utilizando el módulo “output”. Esta información la mostrará por pantalla una vez termine de crear la instancia.
# Windows Public IP
output "windows_public_ip" {
value = aws_instance.windows-server.public_ip
}
Output: Credenciales
Dado que hemos almacenado las credenciales en un Parameter Store, vamos a exportar dicha información en un fichero local, en el mismo directorio donde lanzamos la ejecución.
filename: Nombre del fichero destino
content: Lo que va a exportar; en nuestro caso, las credenciales
# Export Credentials to File
resource "local_file" "RDP_key" {
filename = "windows_key.txt"
content = aws_ssm_parameter.windows_ec2.value
}
5. Extras
5.1. AMI Dinámica
En AWS, para poder crear una instancia EC2, es necesario conocer el ID de la imagen que queremos utilizar (o AMI).
Dicha ID varía según la versión de la distribución, región e incluso idioma. Es por ello que sería necesario conocer previamente la identificación exacta de la imagen para poder aplicarla a nuestro código.
Pero Terraform posee un módulo que nos ayudará en esta tarea. El módulo “Data” permite conectarse a la cuenta de AWS, y realizar una búsqueda con los parámetros que concretemos.
En nuestro caso, vamos a indicar que queremos la distribución en español de Windows 2012 R2, y concretaremos que queremos la última versión.
data "aws_ami" "windows-2012-r2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["Windows_Server-2012-R2_RTM-Spanish-64Bit-Base-*"]
}
}
Y sustituiremos en el módulo de creación de la instancia el valor de la AMI por el nuevo valor obtenido de este nuevo módulo “aws_ami”
# Create EC2 Instance
resource "aws_instance" "windows-server" {
# Instance info
ami = data.aws_ami.windows-2012-r2.id
instance_type = "t2.micro"
# Public IP
associate_public_ip_address = true
# Instance Credentials
key_name = aws_key_pair.instance_key_pair.key_name
get_password_data = true
# Security Group
vpc_security_group_ids = [aws_security_group.sg-windows.id]
}
5.2. Credenciales de AWS en archivo
Originalmente habíamos definido el módulo del proveedor con las claves “access key” y “secret key” del usuario “usercli” que creamos en AWS.
De esta forma, las credenciales se encuentran a la vista de código, por lo que en el caso de querer exportarlo, generaríamos un problema de seguridad.
AWS CLI tiene un directorio en el cual poder almacenar credenciales. Por defecto suele estar localizado en “~/.aws/config” en Linux, y “C:\Users\USERNAME\.aws\config” en Windows.
Es por ello que editaremos el archivo (o crearemos el archivo si no se encuentra) , y le asignaremos el perfil “default”.
# nano /home/USER/.aws/config/credentials
[default]
aws_access_key_id = ACCESS_KEY
aws_secret_access_key = SECRET_ACCESS_KEY
Y modificaremos el módulo de proveedor de Terraform de forma que apuntaremos a la ubicación de dichas credenciales
provider "aws" {
region = "eu-west-1"
shared_credentials_files = ["/home/USER/.aws/credentials"]
profile = "default"
}
6. Quiero el código
El código completo lo podrás encontrar en el repositorio:
Código
¿Te ha gustado?
Si te ha gustado y quieres aportar tu granito de arena para que esta comunidad crezca: