Feb 12 2022

Recurso Compartido de Terraform con el Ejemplo: Claves SSH

Published by at 8:36 under Devops,Terraform

Terraform automatiza la creación de infraestructura en el cloud, comúnmente conocida como infraestructura como código. Necesitamos crear una máquina virtual, que debe contener las claves SSH de 3 administradores. El objetivo será hacer que este recurso compartido de Terraform sea reutilizable por otros módulos. Este ejemplo en Cloud IBM se basa en el plugin de IBM para Terraform, pero el método sigue siendo válido para otros proveedores de cloud, por supuesto.
No puse la creación de la VPC, subredes y grupos de seguridad para ganar legibilidad.

Recurso Compartido de Terraform


Recursos en un solo módulo

Comencemos por crear los archivos ssh.tf que contienen el código que crea las claves del administrador y vm.tf el código de creación del servidor en el mismo directorio. Las claves se dan como parámetros a la máquina virtual.

resource "ibm_is_ssh_key" "user1_sshkey" {
  name       = "user1"
  public_key = "ssh-rsa AAAAB3[...]k+XR=="
}

resource "ibm_is_ssh_key" "user2_sshkey" {
  name       = "user2"
  public_key = "ssh-rsa AAAAB3[...]Zo9R=="
}

resource "ibm_is_ssh_key" "user3_sshkey" {
  name       = "user3"
  public_key = "ssh-rsa AAAAB3[...]67GqV="
}
resource "ibm_is_instance" "server1" {
  name    = "server1"
  image   = var.image
  profile = var.profile
  vpc  = ibm_is_vpc.vpc.id
  zone = var.zone1

  primary_network_interface {
    subnet          = ibm_is_subnet.subnet1.id
    security_groups = [ibm_is_vpc.vpc.default_security_group]
  }

  keys = [
    ibm_is_ssh_key.user1_sshkey.id,
    ibm_is_ssh_key.user2_sshkey.id,
    ibm_is_ssh_key.user3_sshkey.id
  ]
}


El código es simple pero tiene un problema importante:
Las claves SSH no son reutilizables en otro módulo de Terraform. Si copiamos/pegamos este código para crear una segunda VM, un error indicará que las claves ya existen. Además, agregar una clave requiere modificar los 2 archivos de Terraform.


Recursos comunes de Terraform

Por lo tanto, es necesario crear las claves SSH en un módulo Terraform independiente y hacerlas accesibles desde los otros módulos. Esto se puede lograr exportando los id de las claves utilizando los valores output. Los outputs permiten que las variables estén disponibles en la línea de comandos o en otros módulos de Terraform para su reutilización.
Muevamos la declaración de las claves a un nuevo directorio de Terraform al que agregamos una salida output ssh_keys que devuelve una matriz de sus ID, ya que esto es lo que las máquinas virtuales esperan como parámetro.

resource "ibm_is_ssh_key" "user1_sshkey" {
  name       = "user1"
  public_key = "ssh-rsa AAAAB3[...]k+XR=="
}

resource "ibm_is_ssh_key" "user2_sshkey" {
  name       = "user2"
  public_key = "ssh-rsa AAAAB3[...]Zo9R=="
}

resource "ibm_is_ssh_key" "user3_sshkey" {
  name       = "user3"
  public_key = "ssh-rsa AAAAB3[...]67GqV="
}

output "ssh_keys" {
  value = [
    ibm_is_ssh_key.user1_sshkey.id,
    ibm_is_ssh_key.user2_sshkey.id,
    ibm_is_ssh_key.user3_sshkey.id
  ]
}


Después de ejecutar terraform apply, podemos mostrar los valores de salida con terraform output:

$ terraform output
ssh_keys = [
  "r010-3e98b94b-9518-4e11-9ac4-a014120344dc",
  "r010-b271dce5-4744-48c3-9001-a620e99563d9",
  "r010-9358c6ab-0eed-4de7-a4a0-4ba20b2c04c9",
]


Es exactamente lo que queríamos. Todo lo que queda es recuperar el contenido de la salida en forma de data lookup para usarlo en el módulo VM.

data "terraform_remote_state" "ssh_keys" {
  backend = "local"
  config = {
    path = "../ssh_keys/terraform.tfstate"
  }
}

resource "ibm_is_instance" "server1" {
  name    = "server1"
  image   = var.image
  profile = var.profile

  primary_network_interface {
    subnet          = ibm_is_subnet.subnet1.id
    security_groups = [ibm_is_vpc.vpc.default_security_group]
  }

  vpc  = ibm_is_vpc.vpc.id
  zone = var.zone1
  keys = data.terraform_remote_state.ssh_keys.outputs.ssh_keys
}


Es mucho mejor, podemos administrar las claves SSH independientemente de otros módulos de Terraform y reutilizarlas a voluntad. El path del data lookup es la ruta relativa al directorio que contiene el archivo ssh.tf.


Variables de Lista

No está mal pero podríamos hacer más elegante la creación de recursos compartidos (aquí las claves SSH).
De hecho, agregar una nueva clave se realiza en 2 lugares: crear un recurso de Terraform y agregarlo a los valores devueltos en la salida. Lo cual es restrictivo y genera errores.De hecho, agregar una nueva clave se realiza en 2 lugares: crear un recurso de Terraform y agregarlo a los valores devueltos en la salida. Lo cual es restrictivo y puede generar errores.
Además, sigue siendo bastante difícil de leer y sería más claro separar valores y código.

Para eso almacenaremos las claves en una tabla de tipo map en un archivo terraform.tfvars, que se cargará automáticamente.

ssh_keys = {
  "user1" = "ssh-rsa AAAAB3[...]k+XR=="
  "user2" = "ssh-rsa AAAAB3[...]Zo9R=="
  "user3" = "ssh-rsa AAAAB3[...]67GqV="
}


En ssh.tf, luego recorreremos esta matriz de clave/valor para crear los recursos y exportarlos en el output.

# Définition du tableau
variable "ssh_keys" {
  type = map(string)
}

resource "ibm_is_ssh_key" "keys" {
  for_each = var.ssh_keys
  name = each.key
  public_key = each.value
}

output "ssh_keys" {
  value = values(ibm_is_ssh_key.keys)[*].id
}


Recuperar valores es un poco complejo. Empecé generando valores de output (ibm_is_ssh_key.keys) para analizar la estructura y así recuperar los id.

Al final, un nuevo recurso compartido (una clave SSH en nuestro caso) se realiza simplemente agregándolo a una matriz, en un archivo que contiene solo variables. En un lugar. Cualquiera puede hacer esto sin siquiera leer o entender el código.


No responses yet

Comments RSS

Leave a Reply