Use templating for terraform manifest.
Templates use go template syntax and must have .tf.tpl extension.
-f defines config file, it is mandatory.
-s defines secrets extensions if set (optional)
$ tree .
.
├── backend.tf
├── service-account.json
├── main.tf
├── modules
│ └── sql
│ ├── main.tf.tpl
│ ├── secrets.tf.production.enc
│ └── variables.tf
├── provider.tf
├── sites.yaml
└── variables.tfRun terraformer with GOOGLE_APPLICATION_CREDENTIALS.
docker run -v ~/.terraform:/root/.terraform -v ~/.terraform.d:/root/.terraform.d -v $(pwd):/app -w /app --rm -e GOOGLE_APPLICATION_CREDENTIALS=/app/service-account.json softonic/terraformer:latest -f sites.yaml -s .production.enc initRun terraformer Use gcloud host credentials.
docker run -v ~/.config:/root/.config -v ~/.terraform:/root/.terraform -v ~/.terraform.d:/root/.terraform.d -v $(pwd):/app -w /app --rm softonic/terraformer:latest -f sites.yaml -s .production.enc initSet alias:
alias terraformer="docker run -v ~/.config:/root/.config -v ~/.terraform:/root/.terraform -v ~/.terraform.d:/root/.terraform.d -v $(pwd):/app -w /app --rm softonic/terraformer:latest"Use aliased command:
terraformer -f sites.yaml -s .production.enc initmain.tf.tpl could look like below:
{{ range (ds "sites").site }}
resource "google_sql_database_instance" "myapp-db-{{ . }}" {
name = "myapp-db"
database_version = "MYSQL_5_7"
region = "europe-west1"
settings {
tier = "db-n1-standard-1"
ip_configuration {
ipv4_enabled = "false"
private_network = "${var.mynetwork}"
}
backup_configuration {
binary_log_enabled = true
enabled = true
}
user_labels {
app = "myapp"
}
}
}
{{ end }}And sites.yaml:
$ cat sites.yaml
site:
- foo
- barAnd then run terraformer:
terraformer -f sites.yamlThe manifest applied would be equivalent of the following:
resource "google_sql_database_instance" "myapp-db-foo" {
name = "myapp-db"
database_version = "MYSQL_5_7"
region = "europe-west1"
settings {
tier = "db-n1-standard-1"
ip_configuration {
ipv4_enabled = "false"
private_network = "${var.mynetwork}"
}
backup_configuration {
binary_log_enabled = true
enabled = true
}
user_labels {
app = "myapp"
}
}
}
resource "google_sql_database_instance" "myapp-db-bar" {
name = "myapp-db"
database_version = "MYSQL_5_7"
region = "europe-west1"
settings {
tier = "db-n1-standard-1"
ip_configuration {
ipv4_enabled = "false"
private_network = "${var.mynetwork}"
}
backup_configuration {
binary_log_enabled = true
enabled = true
}
user_labels {
app = "myapp"
}
}
}main.tf.tpl
{{ range (ds "sites").site }}
resource "google_sql_database_instance" "myapp-db-{{ . }}" {
name = "myapp-db"
database_version = "MYSQL_5_7"
region = "europe-west1"
settings {
tier = "db-n1-standard-1"
ip_configuration {
ipv4_enabled = "false"
private_network = "${var.mynetwork}"
}
backup_configuration {
binary_log_enabled = true
enabled = true
}
user_labels {
app = "myapp"
}
}
}
resource "google_sql_user" "myapp-db-{{ . }}" {
name = "${var.{{ . }}_root_user}"
instance = "${google_sql_database_instance.myapp-db-{{ . }}.name}"
host = "%"
password = "${var.{{ . }}_root_password}"
}
{{ end }}We need to generate an encrypted file. Generate a temporary file: plain.text.tf
variable "foo_root_user" {
default = "fooroot"
}
variable "foo_root_password" {
default = "tooroof"
}
variable "bar_root_user" {
default = "barroot"
}
variable "bar_root_password" {
default = "toorrab"
}Then we need to encrypt it with a well-known extensions, that we will use later (secrets.tf.production.enc):
sops -e plain.text.tf > secrets.tf.production.encThen we need to remove the plain text file:
rm -f plain.text.tfNow we can apply the templating + secrets:
terraformer -f sites.yaml -s .production.encTerraformer must initialize the manifest, or at least it must be initialized with a container with the same parameters, as the directory .terraform contains symbolic links, and it would change depending how it's mounted.
In the case host terraform is already initialized, terraformer would not work. In this case, please delete .terraform directory and initialize with terraformer.