Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create random variable in Terraform and pass it to GCE startup script

I want to run a metadata_startup_script when using Terraform to create a GCE instance.

This script is supposed to create a user and assign to this user a random password.

I know that I can create a random string in Terraform with something like:

resource "random_string" "pass" {
  length  = 20
}

And my startup.sh will at some point be like:

echo myuser:${PSSWD} | chpasswd

How can I chain the random_string resource generation with the appropriate script invocation through the metadata_startup_script parameter?

Here is the google_compute_instance resource definition:

resource "google_compute_instance" "coreos-host" {
  name         = "my-vm"
  machine_type = "n1-stantard-2"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
      size = 20
      type = "pd-standard"
    }
  }

  network_interface {
    network = "default"

    access_config {
        network_tier = "STANDARD"
    }
  }

  metadata_startup_script = "${file("./startup.sh")}"

}

where startup.sh includes the above line setting the password non-interactively.

like image 713
pkaramol Avatar asked Oct 23 '19 11:10

pkaramol


1 Answers

If you want to pass a Terraform variable into a templated file then you need to use a template.

In Terraform <0.12 you'll want to use the template_file data source like this:

resource "random_string" "pass" {
  length  = 20
}

data "template_file" "init" {
  template = "${file("./startup.sh")}"
  vars = {
    password = "${random_string.pass.result}"
  }
}

resource "google_compute_instance" "coreos-host" {
  name         = "my-vm"
  machine_type = "n1-stantard-2"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
      size = 20
      type = "pd-standard"
    }
  }

  network_interface {
    network = "default"

    access_config {
        network_tier = "STANDARD"
    }
  }

  metadata_startup_script = "${data.template_file.startup_script.rendered}"
}

and change your startup.sh script to be:

echo myuser:${password} | chpasswd

Note that the template uses ${} for interpolation of variables that Terraform is passing into the script. If you need to use $ anywhere else in your script then you'll need to escape it by using $$ to get a literal $ in your rendered script.

In Terraform 0.12+ there is the new templatefile function which can be used instead of the template_file data source if you'd prefer:

resource "random_string" "pass" {
  length  = 20
}

resource "google_compute_instance" "coreos-host" {
  name         = "my-vm"
  machine_type = "n1-stantard-2"
  zone         = "us-central1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
      size = 20
      type = "pd-standard"
    }
  }

  network_interface {
    network = "default"

    access_config {
        network_tier = "STANDARD"
    }
  }

  metadata_startup_script = templatefile("./startup.sh", {password = random_string.pass.result})
}

As an aside you should also notice the warning on random_string:

This resource does use a cryptographic random number generator.

Historically this resource's intended usage has been ambiguous as the original example used it in a password. For backwards compatibility it will continue to exist. For unique ids please use random_id, for sensitive random values please use random_password.

As such you should instead use the random_password resource:

resource "random_password" "password" {
  length = 16
  special = true
  override_special = "_%@"
}
like image 98
ydaetskcoR Avatar answered Nov 09 '22 11:11

ydaetskcoR