Home > Net >  cloud-init with terraform cannot loop users
cloud-init with terraform cannot loop users

Time:02-01

So I have the following Terraform code: `

I have the following templatefile:

#cloud-config
users:
  %{ for user in user_list ~}
  - name: ${user.username}
    gecos: ${user.username}
    ssh-authorized-keys:
      - ${user.ssh_public_key}
    lock_passwd: true
    groups: sudo
    shell: /bin/bash
  %{ endfor } 
packages:
    jp

The following Terraform code:

...
output "users" {
  value = [for k in local.external_users : k.username]
}

data "template_cloudinit_config" "config" {
  gzip          = true
  base64_encode = true
  part {
    filename     = "cloud-init.cfg"
    content_type = "text/cloud-config"
    content = templatefile("${path.module}/templates/userdataloop.yaml", {
      user_list = local.external_users
    })
  }
…
resource "azurerm_virtual_machine" "jphostvm" {
...
os_profile {
    computer_name  = "${var.environment}-jp-${format("d", count.index   1)}"
    admin_username = "deploy"
    custom_data    = data.template_cloudinit_config.config.rendered
  }

and finally the following users (declared in a different tf file): `

locals {
  external_users = [
    {
      username       = "ian"
      ssh_public_key = data.vault_generic_secret.ian.data["key"]
    },
    {
      username       = "fred"
      ssh_public_key = data.vault_generic_secret.fred.data["key"]
    },
    {
      username       = "ken"
      ssh_public_key = data.vault_generic_secret.ken.data["key"]
    }
  ]
}

I simply cannot get more than one user to be created. Note the output loop displays all the usernames. Passing single user as follows works perfectly:

data "template_cloudinit_config" "config" {
  gzip          = true
  base64_encode = true
  part {
    filename     = "cloud-init.cfg"
    content_type = "text/cloud-config"
    content = templatefile("${path.module}/templates/userdataloop.yaml", {
      username       = "fred"
      ssh_public_key = data.vault_generic_secret.fred.data["key"]
    })
  }

and using the following template:

#cloud-config
users:
  - default
  - name: ${username}
    gecos: ${username}
    ssh-authorized-keys:
      - ${ssh_public_key}
    lock_passwd: true
    groups: sudo
    shell: /bin/bash
}

Can anyone help with this? I just can't figure out what is wrong and the code is failing silently so no error message to point me. It's a debian image the code uses for the vm. Thanks.

CodePudding user response:

When configuring a system with cloud-init, any errors during processing will be written into the cloud-init logs inside your virtual machine's filesystem. Where exactly you'd find those logs will depend on how your AMI is configured, but the default location is /var/log/cloud-init.log.


You've shown two different templates in your question, one of which contains a for directive while the other contains only interpolation.

Both of these are not following the advice in Generating JSON or YAML from a template, so it's possible that your attempt to generate YAML by string concatenation is producing something that isn't valid YAML syntax or doesn't have the meaning you intended.

The following template uses yamlencode instead, to guarantee that the result will always be valid YAML syntax:

#cloud-config
${yamlencode({
  users = [
    for user in user_list : {
      name                = user.username
      gecos               = user.username
      ssh_authorized_keys = [user.ssh_public_key]
      lock_passwd         = true
      groups              = "sudo"
      shell               = "/bin/bash"
    }
  ]
  packages = [
    "jp",
  ]
})}

I also changed your ssh-authorized-keys key to be ssh_authorized_keys instead, because that seems to be the name used in the relevant cloud-config example.

If you use a template like the above so that the result is guaranteed to be valid YAML syntax and it still doesn't work then that suggests that there's something wrong with the data represented by the YAML rather than the syntax of the YAML. In that case you'll need to refer to the cloud-init log in your virtual machine to see what happened when it tried to interpret your cloud-config data structure.

  • Related