Infraestructura como Código

Infrastructure as Code (IaC) es el paradigma con el que gestionamos infraestructuras (redes, máquinas virtuales, equilibradores de carga, etc) a partir de un modelo descriptivo. De esta forma, al igual que un mismo código fuente genera el mismo binario, en un modelo IaC, un modelo descriptivo generará el mismo entorno cada vez que se aplica.

Sin IaC, los equipos deben mantener la configuración de los entornos de forma manual e individual. Con IaC se asegura una implementación de entornos con la misma configuración, independientemente del estado inicial del éste, configurando un objetivo existente o descartando el objetivo existente y recreando un entorno nuevo. Si necesitamos hacer modificaciones sobre la infraestructura, se edita el código fuente asociado y no el destino.

Infrastructure as Code permite a los equipos de DevOps probar aplicaciones en entornos similares a los de producción aprovisionando entornos de prueba de manera confiable y bajo demanda. IaC ofrece entornos estables y a escala de forma ágil, evitando configuraciones manuales y reforzando la coherencia al representar el estado deseado de sus entornos mediante código. Las implementaciones de infraestructura con IaC son repetibles y evitan problemas de tiempo de ejecución causados por cambios en la configuración o dependencias faltantes.

iac arquitectura

Terraform como solución IaC

Terraform es una solución para infraestructura como código desarrollado por HashiCorp. Permite a los usuarios definir y configurar la infraestructura de un centro de datos en un lenguaje de alto nivel, generando un plan de ejecución para desplegar la infraestructura en cualquier proveedor de nube como AWS, Azure, IBM Cloud, etc. La infraestructura se define utilizando la sintaxis de configuración de HashiCorp denominada HashiCorp Configuration Language (HCL), que facilita la codificación de una infraestructura dependiendo de nuestras necesidades, los servicios que tengamos que prestar y con una gran variedad de proveedores donde depositar nuestra infraestructura.

La solución a todos estos problemas pasaría por disponer de una herramienta que nos permita modelar nuestra infraestructura como código, pero que sea agnóstica al entorno cloud donde se ejecute.

Encontramos soluciones como CloudFormation de AWS o Heat de Openstack o Azure ARM en Azure, pero estas herramientas están ligadas al cloud donde se desea desplegar. En este sentido, Terraform nos permite codificar nuestra infraestructura atendiendo a las necesidades del servicio, ofreciendo un amplio abanico de proveedores para el despliegue de la infraestructura.

Caso de uso de IaC con Terraform

A continuación, se desarrolla con Terraform una Infraestructura consistente en una máquina virtual para desplegar en azure.

Instalación de Terraform

Para comenzar, descargamos Terraform del siguiente link: https://www.terraform.io/downloads.html. Para el caso de Windows, Terraform está compuesto de un único ejecutable (terraform.exe), que podremos descargar en cualquier carpeta incluida en la variable PATH del sistema.

Una vez descargado, podemos comprobar su funcionamiento desde powershell:

Power shell iac

Autenticación en Azure con Terraform

Para posibilitar la integración de Terraform con Azure, es necesaria la creación de un Service Principal en Azure Active Directory, al que después daremos privilegios de ‘Contributor’ en la subscripción sobre la que vamos a desplegar.

 
 
 
 
$subscriptionId = ‘xxxx-xxxxx-xxxxx’
$sp = az ad sp create-for-rbac –role=“Contributor” –scopes=“/subscriptions/$subscriptionId -n srvcpral-terraform | ConvertFrom-Json

Configuración de Terraform para acceso a Azure

Una vez creado el Service Principal con alguno de los métodos descritos anteriormente, hemos de configurar Terraform para el acceso a Azure, haciendo uso de dicho Service Principal con el uso de la definición de las siguientes variables:

 
 
 
 
$ServicePrincipal = Get-AzADServicePrincipal -DisplayName srvcpral-terraform
 
## ServicePrincipalNames : {<<>>}
## ApplicationId : <<>>
## ObjectType : ServicePrincipal
## DisplayName : srvcpral-terraform
## Id : <<>>
## Type :
$ENV:ARM_SUBSCRIPTION_ID = “<<Indicar Subscription_ID>>”
$ENV:ARM_CLIENT_ID = $ServicePrincipal.ApplicationId
$ENV:ARM_CLIENT_SECRET = “<<Indicar Secret o Password del Service Principal>>”
$ENV:ARM_TENANT_ID = “<<Tenant ID asociado al Service Principal>>”

Creación del código de infraestructura

Para el despliegue de la infraestructura, creamos el archivo main.tf que contendrá la configuración para construir la máquina virtual de Azure con Terraform.

En nuestro caso, se van a crear los siguientes elementos para la puesta en marcha de la máquina virtual:

  • Grupo de Recursos: RG_terraformTesting
# Creación del grupo de Recursos RG_terraformTesting
resource “azurerm_resource_group” “RG_terraformTesting” {
name = “RG_terraformTesting”
location = “northeurope”
 
tags = {
environment = “Terraform Demo”
}
}
  • Virtual network: VNET_terraformTesting
# Create virtual network
resource “azurerm_virtual_network” “VNET_terraformTesting” {
name = “VNET_terraformTesting”
address_space = [“10.0.0.0/16”]
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
tags = {
environment = “Terraform Demo”
}
}
  • Segmento de red incluido en la virtual network VNET_terraformTesting
# Create subnet
resource “azurerm_subnet” “SubNET1_terraformTesting” {
name = “SubNET1_terraformTesting”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
virtual_network_name = azurerm_virtual_network.VNET_terraformTesting.name
address_prefix = “10.0.2.0/24”
}
  • IP para acceso público
# Create public IPs
resource “azurerm_public_ip” “PublicIP_terraformTesting” {
name = “PublicIP_terraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
allocation_method = “Dynamic”
 
tags = {
environment = “Terraform Demo”
}
}
  • Reglas de seguridad para acceso por RDP (TCP Port 3389)
# Create Network Security Group and rule
resource “azurerm_network_security_group” “NSG_terraformTesting” {
name = “NSG_terraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
security_rule {
name = “RDP”
priority = 1001
direction = “Inbound”
access = “Allow”
protocol = “Tcp”
source_port_range = “*”
destination_port_range = “3389”
source_address_prefix = “*”
destination_address_prefix = “*”
}
 
tags = {
environment = “Terraform Demo”
}
}
  • NIC para servidor virtual
# Create network interface
resource “azurerm_network_interface” “NIC_TerraformTesting” {
name = “NIC_TerraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
ip_configuration {
name = “NICConfig_TerraformTesting”
subnet_id = azurerm_subnet.SubNET1_terraformTesting.id
private_ip_address_allocation = “Dynamic”
public_ip_address_id = azurerm_public_ip.PublicIP_terraformTesting.id
}
 
tags = {
environment = “Terraform Demo”
}
}
 
# Connect the security group to the network interface
resource “azurerm_network_interface_security_group_association” “NISGA_TerraformTesting” {
network_interface_id = azurerm_network_interface.NIC_TerraformTesting.id
network_security_group_id = azurerm_network_security_group.NSG_terraformTesting.id
}
  • Creación de la máquina virtual TFWVMServer
resource “azurerm_windows_virtual_machine” “WindowsVMTerraformTesting” {
name = “WindowsVM”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
location = azurerm_resource_group.RG_terraformTesting.location
size = “Standard_F2”
computer_name = “TFWVMServer”
admin_username = “adminuser”
admin_password = “P@$$w0rd1234!”
network_interface_ids = [
azurerm_network_interface.NIC_TerraformTesting.id,
]
 
os_disk {
caching = “ReadWrite”
storage_account_type = “Standard_LRS”
}
 
source_image_reference {
publisher = “MicrosoftWindowsServer”
offer = “WindowsServer”
sku = “2016-Datacenter”
version = “latest”
}
}

El contenido completo de main.tf para el ejemplo propuesto, se lista a continuación:

 
 
 
 
# Configure the Microsoft Azure Provider
provider “azurerm” {
# The “feature” block is required for AzureRM provider 2.x.
# If you’re using version 1.x, the “features” block is not allowed.
version = “=2.5.0”
features {}
}
 
# Create a resource group if it doesn’t exist
resource “azurerm_resource_group” “RG_terraformTesting” {
name = “RG_terraformTesting”
location = “northeurope”
 
tags = {
environment = “Terraform Demo”
}
}
 
# Create virtual network
resource “azurerm_virtual_network” “VNET_terraformTesting” {
name = “VNET_terraformTesting”
address_space = [“10.0.0.0/16”]
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
tags = {
environment = “Terraform Demo”
}
}
 
# Create subnet
resource “azurerm_subnet” “SubNET1_terraformTesting” {
name = “SubNET1_terraformTesting”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
virtual_network_name = azurerm_virtual_network.VNET_terraformTesting.name
address_prefix = “10.0.2.0/24”
}
 
# Create public IPs
resource “azurerm_public_ip” “PublicIP_terraformTesting” {
name = “PublicIP_terraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
allocation_method = “Dynamic”
 
tags = {
environment = “Terraform Demo”
}
}
 
# Create Network Security Group and rule
resource “azurerm_network_security_group” “NSG_terraformTesting” {
name = “NSG_terraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
security_rule {
name = “RDP”
priority = 1001
direction = “Inbound”
access = “Allow”
protocol = “Tcp”
source_port_range = “*”
destination_port_range = “3389”
source_address_prefix = “*”
destination_address_prefix = “*”
}
 
tags = {
environment = “Terraform Demo”
}
}
 
# Create network interface
resource “azurerm_network_interface” “NIC_TerraformTesting” {
name = “NIC_TerraformTesting”
location = “northeurope”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
 
ip_configuration {
name = “NICConfig_TerraformTesting”
subnet_id = azurerm_subnet.SubNET1_terraformTesting.id
private_ip_address_allocation = “Dynamic”
public_ip_address_id = azurerm_public_ip.PublicIP_terraformTesting.id
}
 
tags = {
environment = “Terraform Demo”
}
}
 
# Connect the security group to the network interface
resource “azurerm_network_interface_security_group_association” “NISGA_TerraformTesting” {
network_interface_id = azurerm_network_interface.NIC_TerraformTesting.id
network_security_group_id = azurerm_network_security_group.NSG_terraformTesting.id
}
 
resource “azurerm_windows_virtual_machine” “WindowsVMTerraformTesting” {
name = “WindowsVM”
resource_group_name = azurerm_resource_group.RG_terraformTesting.name
location = azurerm_resource_group.RG_terraformTesting.location
size = “Standard_F2”
computer_name = “TFWVMServer”
admin_username = “adminuser”
admin_password = “P@$$w0rd1234!”
network_interface_ids = [
azurerm_network_interface.NIC_TerraformTesting.id,
]
 
os_disk {
caching = “ReadWrite”
storage_account_type = “Standard_LRS”
}
 
source_image_reference {
publisher = “MicrosoftWindowsServer”
offer = “WindowsServer”
sku = “2016-Datacenter”
version = “latest”
}
}

Despliegue de la infraestructura con Terraform

Una vez disponemos del código que generará la infraestructura, solo queda desplegarla:

 
 
 
 
$ServicePrincipal = Get-AzADServicePrincipal -DisplayName srvcpral-terraform
 
## ServicePrincipalNames : …
## ApplicationId : …
## ObjectType : …
## DisplayName : …
## Id : …
## Type : …
 
$ENV:ARM_SUBSCRIPTION_ID = “<<id de subscripción en la que se va a desplegar>>”
$ENV:ARM_CLIENT_ID = $ServicePrincipal.ApplicationId
$ENV:ARM_CLIENT_SECRET = “<<Password definido en el secret del Service Principal>>”
$ENV:ARM_TENANT_ID = “<<Tenant del Service Principal>>”
 
terraform.exe init
terraform.exe plan
terraform.exe apply
0 Shares:
Deja una respuesta

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

You May Also Like