Guía del comando sed
Ejecutar Charts de Helm con helmfile

Herramientas para Terraform

Herramientas para terraform

Terraform es una herramienta esencial para la Infraestructura como Código (IaC) y para un SRE. Al igual que muchos proyectos de código abierto, la comunidad crea y comparte muchas herramientas para hacerlo más potente.

A veces hay demasiadas herramientas, comandos y plugins alrededor de un proyecto y puede ser saturador. Es por eso que aquí, voy a presentar algunas herramientas Terraform útiles para el uso diario. Algunos de los atributos adicionales que buscamos son:

  • Cambiar entre diferentes versiones de Terraform.
  • Detectar errores y mejorar el código.
  • Generar automáticamente la documentación del código.
  • Detectar posibles problemas de seguridad en el código.
  • Estimar el coste en la nube de los cambios.

Buenas prácticas en Terraform

Terraform console

El Terraform Console es probablemente una de las herramientas más pasadas por alto en el arsenal. Esto es sorprendente porque es nativo de Terraform y está empaquetado dentro del binario.

El comando `terraform console` proporciona una consola interactiva que se puede utilizar para probar y evaluar cualquier expresión de Terraform que desee usar en su código. En lugar de experimentar interminablemente, escribir salidas incómodas y golpear su cabeza contra el escritorio, la consola de Terraform le permite probar expresiones complicadas antes de ejecutar su código.

Echemos un vistazo rápido a un ejemplo:

$ terraform console

Terraform console version 0.15.1

> 10 + 20

30

> "hola, mundo"

"hola, mundo"

> length("hola, mundo")

12

> substr("hola, mundo", 0, 5)

"hola"

> exit

Como se puede ver, es útil para experimentar con expresiones antes de agregarlas a su código. También puede evaluar variables y manipular cualquier otra cosa en el estado que necesite.

Un detalle a tener en cuenta es que la configuración debe poder aprobar un plan antes de que el comando `terraform console` funcione. Asegúrese de comentar cualquier problema que esté tratando de resolver antes de ingresar a la consola para solucionarlo.

TFSwitch

Terraform es una herramienta que evoluciona rápidamente y cambia de versiones. Necesitas descargar e instalar la versión correcta desde la web de HashiCorp. Para cada versión diferente, necesitas el binario asociado. Cuando tienes varios proyectos de Terraform con diferentes versiones, puede volverse muy pesado administrarlos.

TFSwitch es una herramienta de línea de comandos que resuelve este problema. Te permite seleccionar la versión de Terraform con la que deseas trabajar e instalarla automáticamente.

Instalación en Linux

curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/release/install.sh | bash

Inicio rápido

TFSwitch

«Selecciona la versión de Terraform que deseas usar con el menú desplegable» desde https://tfswitch.warrensbox.com/

[1]: Escribe «tfswitch» y presiona «Enter» en tu terminal

[2]: Selecciona la versión de Terraform que deseas usar con las flechas arriba y abajo.

[3]: Presiona «Enter» para seleccionar la versión de Terraform.

También puedes proporcionar la versión de Terraform en la línea de comandos:
«Proporciona la versión de Terraform en la línea de comandos» desde https://tfswitch.warrensbox.com/

tfswitch

 

TFLint

Los errores de sintaxis a veces no son fáciles de entender al ejecutar código. Los linters proporcionan información crucial para acelerar la depuración y ahorrar tiempo de desarrollo. También puedes integrarlos en el pipeline de CI/CD para implementar mejoras continuas.

Terraform se basa en el HCL (HashiCorp Language), un lenguaje que describe el estado de tu infraestructura. TFLint es un plugin linter que admite Terraform y su lenguaje. Además de la revisión de código, también es un marco con características ampliables mediante otros plugins.

Esto es lo que TFLint puede hacer por tu proyecto de IaC:

  • Encontrar posibles errores para los principales proveedores de nube: AWS/Azure/GCP.
  • Advertir sobre sintaxis deprecada y declaraciones no utilizadas.
  • Aplicar las mejores prácticas y convenciones de nomenclatura.

Instalación en Linux

curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash

Inicio rápido

Por defecto, TFLint inspecciona los archivos en el directorio actual. Puedes cambiar este comportamiento con las opciones que encontrarás en argumentos en –help:

Usage:
  tflint [OPTIONS] [FILE or DIR...]Application Options:
  -v, --version                                           Print TFLint version
      --init                                              Install plugins
      --langserver                                        Start language server
  -f, --format=[default|json|checkstyle|junit|compact]    Output format
                                                          (default: default)
  -c, --config=FILE                                       Config file name
                                                          (default: .tflint.hcl)
      --ignore-module=SOURCE                              Ignore module sources
      --enable-rule=RULE_NAME                             Enable rules from the
                                                          command line
      --disable-rule=RULE_NAME                            Disable rules from
                                                          the command line
      --only=RULE_NAME                                    Enable only this
                                                          rule, disabling all
                                                          other defaults. Can
                                                          be specified multiple
                                                          times
      --enable-plugin=PLUGIN_NAME                         Enable plugins from
                                                          the command line
      --var-file=FILE                                     Terraform variable
                                                          file name
      --var='foo=bar'                                     Set a Terraform
                                                          variable
      --module                                            Inspect modules
      --force                                             Return zero exit
                                                          status even if issues
                                                          found
      --no-color                                          Disable colorized
                                                          output
      --loglevel=[trace|debug|info|warn|error]            Change the loglevelHelp Options:
  -h, --help                                              Show this help message

También se puede pasar un archivo de configuración a TFLint según esta prioridad:

  • Directorio actual (./.tflint.hcl)
  • Directorio de inicio (~/.tflint.hcl)

En el .tflint.hcl , se puede realizar las siguientes acciones:

  • Definir la configuración de TFLint
  • Declarar los plugins a utilizar
  • Activar/Desactivar reglas TFLint específicas

Un ejemplo de archivo de configuración TFLint:

config {
  plugin_dir = "~/.tflint.d/plugins"

  module = true
  force = false
  disabled_by_default = false

  ignore_module = {
    "terraform-aws-modules/vpc/aws"            = true
    "terraform-aws-modules/security-group/aws" = true
  }

  varfile = ["example1.tfvars", "example2.tfvars"]
  variables = ["foo=bar", "bar=[\"baz\"]"]
}plugin "aws" {
  enabled = true
  version = "0.12.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}rule "aws_instance_invalid_type" {
  enabled = false
}

Para ejecutar un simple lint:

tflint

Si no obtiene el comportamiento esperado, se puede ver los registros detallados con el modo depuración:

TFLINT_LOG=debug tflint

Utilizar plugins para proveedores de nube

Utilizando proveedores de AWS, Azure o GCP, se puede utilizar el plugin correspondiente:

El código siguiente muestra el uso del plugin de AWS:

plugin "aws" {
  enabled = true
  version = "0.12.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

El siguiente comando instala los plugins:

tflint --init

Terraform no valida las cuestiones específicas del proveedor. Aquí hay un ejemplo con el siguiente archivo de configuración:

resource "aws_instance" "foo" {
  ami           = "ami-0ff8a91507f77f867"
  instance_type = "t1.2xlarge" # invalid type!
}

El t1.2xlarge es un tipo de instancia no válido. Se producirá un error al ejecutar «terraform apply». Pero los comandos «terraform validate» y «terraform plan» no muestran ningún error. Se trata de un problema específico del proveedor de AWS y no de la sintaxis de Terraform. El plugin TFLint ayuda a detectar este error antes de la aplicación del código:

TFLint

Terraform-docs

Documentar el código es un punto importante para el trabajo en equipo y la reutilización. Terraform-docs es una utilidad rápida para generar documentos de módulos Terraform en varios formatos de salida.

Instalación en Linux

curl -Lo ./terraform-docs.tar.gz https://github.com/terraform-docs/terraform-docs/releases/download/v0.16.0/terraform-docs-v0.16.0-$(uname)-amd64.tar.gz

tar -xzf terraform-docs.tar.gz

chmod +x terraform-docs

mv terraform-docs /usr/local/terraform-docs

Inicio rápido

La creación de módulos Terraform implica el uso de entradas, salidas, recursos y, eventualmente, fuentes de datos. El siguiente fragmento de Terraform crea una instancia AWS EC2 a partir de una AMI (Amazon Machine Image). Aunque todo está en un archivo, se puede considerar como un módulo:

terraform {
  required_version = ">= 1.0.0"
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}variable "aws_region" {
  description = "The AWS region where to deploy the EC2 instance."
  type        = string
  default     = "us-east-1"
}variable "tags" {
  description = "The tags to associate to the EC2 instance."
  type        = map(string)
  default     = {}
}provider "aws" {
  region = var.aws_region
}data "aws_ami" "ubuntu" {
  most_recent = truefilter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }owners = ["099720109477"]
}resource "aws_instance" "default" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t2.micro"tags   = merge({
    Name = "my-ec2-instance"
  }, var.tags)
}output "arn" {
  description = "EC2 instance ARN."
  value       = aws_instance.default.arn
}

La siguiente línea de comandos generará la documentación de Terraform en markdown y la almacenará en un archivo README:

terraform-docs markdown table --output-file README.md .

En el archivo README, encontramos los diferentes elementos utilizados por el módulo y enlazamos con la documentación oficial de cada uno de ellos:

<!-- BEGIN_TF_DOCS -->

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 3.74.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [aws_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
| [aws_ami.ubuntu](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | The AWS region where to deploy the EC2 instance. | `string` | `"us-east-1"` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | The tags to associate to the EC2 instance. | `map(string)` | `{}` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_arn"></a> [arn](#output\_arn) | EC2 instance ARN. |
<!-- END_TF_DOCS -->

Terrascan

Aunque el nombre «Terrascan» lleva a uno a creer que es específico de Terraform, en realidad funciona para muchos proveedores de IaC. Terraform, Kubernetes, Ansible, Cloudformation y más son compatibles con Terrascan gracias a su conjunto extenso de políticas preescritas. Por supuesto, también puedes escribir tus propias políticas para casos de uso personalizados.

Terrascan se integra con varias herramientas de CI/CD y es extremadamente flexible al diseñar tus canalizaciones.

Aquí tienes un ejemplo básico de uso de Terrascan:

$ terrascan scan -t aws

results:

violations:

- rule_name: scanOnPushDisabled

description: Unscanned images may contain vulnerabilities

rule_id: AWS.ECR.DataSecurity.High.0578

severity: MEDIUM

category: Data Security

resource_name: scanOnPushDisabled

resource_type: aws_ecr_repository

file: ecr.tf

line: 1

count:

low: 0

medium: 1

high: 0

total: 1

Checkov

Checkov es una herramienta de análisis estático de código para escanear archivos de infraestructura como código, incluyendo Terraform. Busca errores de configuración que puedan provocar problemas de seguridad o de cumplimiento de normativas. Dispone de 750 políticas predefinidas para buscar problemas comunes de desconfiguración.

Instalación

pip install checkov

Inicio rápido

Tomaremos el código de de la anterior parte de terraform-docs. Generaremos el plan Terraform y lo analizaremos con Checkov:

terraform init 

terraform plan -out tf.plan 

terraform show -json tf.plan  > tf.json  

checkov -f tf.json
       _               _
   ___| |__   ___  ___| | _______   __
  / __| '_ \ / _ \/ __| |/ / _ \ \ / /
 | (__| | | |  __/ (__|   < (_) \ V / 
  \___|_| |_|\___|\___|_|\_\___/ \_/
By bridgecrew.io | version: 2.0.528 Update available 2.0.528 -> 2.0.829
Run pip3 install -U checkov to updatecloudformation scan results:Passed checks: 0, Failed checks: 0, Skipped checks: 0, Parsing errors: 1Error parsing file tf.json
terraform_plan scan results:Passed checks: 2, Failed checks: 4, Skipped checks: 0Check: CKV_AWS_88: "EC2 instance should not have public IP."
 PASSED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/public_12Check: CKV_AWS_46: "Ensure no hard-coded secrets exist in EC2 user data"
 PASSED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/bc_aws_secrets_1Check: CKV_AWS_79: "Ensure Instance Metadata Service Version 1 is not enabled"
 FAILED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/bc_aws_general_31Check: CKV_AWS_126: "Ensure that detailed monitoring is enabled for EC2 instances"
 FAILED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/ensure-that-detailed-monitoring-is-enabled-for-ec2-instancesCheck: CKV_AWS_135: "Ensure that EC2 is EBS optimized"
 FAILED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/ensure-that-ec2-is-ebs-optimizedCheck: CKV_AWS_8: "Ensure all data stored in the Launch configuration EBS is securely encrypted"
 FAILED for resource: aws_instance.default
 File: /tf.json:0-0
 Guide: https://docs.bridgecrew.io/docs/general_13

Un ejemplo de cómo usar Checkov para escanear vulnerabilidades de IaC:

from lark import Token
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories

class S3PCIPrivateACL(BaseResourceCheck):

    def __init__(self):
        name = "Ensure PCI Scope buckets has private ACL (enable public ACL for non-pci buckets)"
        id = "CKV_AWS_999"
        supported_resources = ['aws_s3_bucket']
        categories = [CheckCategories.BACKUP_AND_RECOVERY]
        guideline = "Follow the link to get more info https://docs.bridgecrew.io/docs"
        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, guideline=guideline)

    def scan_resource_conf(self, conf):
        if 'tags' in conf.keys():
            environment_tag = Token("IDENTIFIER", "Scope")
            if environment_tag in conf['tags'][0].keys():
                if conf['tags'][0][environment_tag] == "PCI":
                    if 'acl' in conf.keys():
                        acl_block = conf['acl']
                        if acl_block in [["public-read"], ["public-read-write"], ["website"]]:
                            return CheckResult.FAILED
        return CheckResult.PASSED

check = S3PCIPrivateACL()

Infracost: Estimación de costos en la nube desde tu código

Los cambios realizados por Terraform pueden alterar el estado de los recursos alojados por un proveedor de servicios en la nube. Dependiendo de esto, los costos pueden variar. Es importante tener en cuenta esta dimensión al escribir código de Infraestructura como Código (IaC) y esta herramienta para Terraform es una gran ayuda.

Infracost muestra estimaciones de costos en la nube para proyectos de infraestructura como código, como Terraform. Ayuda a ver rápidamente un desglose de costos y comparar diferentes opciones de antemano.

Instalación en Linux

/usr/local/bin

curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh

Inicio rápido

Registra Infracost con tu dirección de correo electrónico para recibir una clave API:

infracost register

Ahora tu clave API se encuentra en:

$HOME/.config/infracost/credentials.yml

Puedes usar Infracost para obtener el desglose completo de costos mensuales:

infracost breakdown --path ...
Detected Terraform directory at .
  ✔ Checking for cached plan... not found
  ✔ Running terraform plan
  ✔ Running terraform show
  ✔ Extracting only cost-related params from terraform
  ✔ Retrieving cloud prices to calculate costsProject: .Name                                                 Monthly Qty  Unit   Monthly Costaws_instance.default
 ├─ Instance usage (Linux/UNIX, on-demand, t2.micro)          730  hours         $8.47
 └─ root_block_device
    └─ Storage (general purpose SSD, gp2)                       8  GB            $0.80OVERALL TOTAL                                                                   $9.27
──────────────────────────────────
1 cloud resource was detected, rerun with --show-skipped to see details:
∙ 1 was estimated, 1 includes usage-based costs, see https://infracost.io/usage-file

También puedes detectar el cambio en el coste mensual debido a un cambio de código:

Detected Terraform directory at .
  ✔ Checking for cached plan... change detected
  ✔ Running terraform plan
  ✔ Running terraform show
  ✔ Extracting only cost-related params from terraform
  ✔ Retrieving cloud prices to calculate costsProject: .~ aws_instance.default
  +$21.90 ($9.27 → $31.17)~ Instance usage (Linux/UNIX, on-demand, t2.micro → t3.medium)
      +$21.90 ($8.47 → $30.37)Monthly cost change for .
Amount:  +$21.90 ($9.27 → $31.17)
Percent: +236%──────────────────────────────────
Key: ~ changed, + added, - removed1 cloud resource was detected, rerun with --show-skipped to see details:
∙ 1 was estimated, 1 includes usage-based costs, see https://infracost.io/usage-fileAdd cost estimates to your pull requests: https://infracost.io/cicd

También se puede generar un informe HTML:

infracost breakdown --path . --format html > report.html 
Detected Terraform directory at .
  ✔ Checking for cached plan... found
  ✔ Extracting only cost-related params from terraform
  ✔ Retrieving cloud prices to calculate costs

Captura de pantalla que muestra un informe HTML generado por Infracost para Terraform

Más apuntes

Invítame a un café con bitcoins:
1QESjZDPxWtZ9sj3v5tvgfFn3ks13AxWVZ

Bitcoins para café
También puedes invitarme a algo para mojar...

Deja una respuesta

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

Rellena este campo
Rellena este campo
Por favor, introduce una dirección de correo electrónico válida.
Tienes que aprobar los términos para continuar