Terraform: How can I pass variables to user_data init script

Viewed 1194

I have been hanging around with this problem for some time now and I can't solve it.

I'm launching an EC2 instance that runs a bash script and installs a few things. At the same time, I am also launching an RDS instance, but I need to be able to pass the value from the RDS endpoint to the EC2 instance to configure the connection.

I'm trying to do this using templatefile, like this

resource "aws_rds_cluster_instance" "cluster_instances" {
  count               = 1
  identifier          = "rds-prod-ddbb-${count.index}"
  cluster_identifier  = aws_rds_cluster.default.id
  instance_class      = "db.r5.large"
  engine              = "aurora"
  engine_version      = "5.6.mysql_aurora.1.22.5"
  publicly_accessible = "true"
}

resource "aws_rds_cluster" "default" {
  cluster_identifier      = "aws-rds-ddbb-cluster"
  availability_zones      = ["us-west-2b"]
  db_subnet_group_name    = "default-vpc-003d3ab296c"
  skip_final_snapshot     = "true"
  backup_retention_period = 30
  vpc_security_group_ids  = [aws_security_group.ddbb.id]
}

data "template_file" "RDSs" {
  template = file("init.sh")
  vars = {
    rds = aws_rds_cluster.default.endpoint
  }
  depends_on = [
    aws_rds_cluster.default,
    aws_rds_cluster_instance.cluster_instances,
  ]
}

resource "aws_instance" "web_01" {
  ami                    = "ami-0477c9562acb09"
  instance_type          = "t2.micro"
  subnet_id              = "subnet-0d0558d99ec3cd3"
  key_name               = "web-01"
  user_data_base64       = base64encode(data.template_file.RDSs.rendered)
  vpc_security_group_ids = [aws_security_group.ddbb.id]
  ebs_block_device {
    device_name = "/dev/sda1"
    volume_type = "gp2"
    volume_size = 20
  }
  tags = {
    Name = "Web01"
  }
  depends_on = [
    aws_rds_cluster.default,
    aws_rds_cluster_instance.cluster_instances,
  ]
}

And then, my init.sh is like this:

#!/bin/bash
echo "rds = $rds" > /var/tmp/rds

But I get nothing in /var/tmp/rds, so it looks like the variable $rds is empty.

Your help will be greatly appreciated.

Ps: I have outputs configured like this:

outputs.tf

output "rds_endpoint" {
  value = aws_rds_cluster.default.endpoint
}

And that is working fine, when the apply is complete, it shows me the value of rds endpoint.

2 Answers

The variable is not a shell variable but a templated variable — so terraform will parse the file, regardless of its type and replace terraform variables in the said file.

Knowing this, $rds is not a terraform variable interpolation, while ${rds} is.

So, your bash script should rather be:

#!/bin/bash
echo "rds = ${rds}" > /var/tmp/rds

Since Terraform 0.12 There is a more elegant way of passing variable to user_data

Instead of using the data "template_file" prefer using the new templatefile function in terraform


locals {
  WEB_SERVER_UNAME   = "your_username"
  WEB_SERVER_PASS    = "your_password"
}

resource "aws_instance" "web_01" {
  ....
  user_data_base64 = base64encode("${templatefile("${path.module}/user_data_script.sh", {
    WEB_SERVER_UNAME   = local.WEB_SERVER_UNAME
    WEB_SERVER_PASS    = local.WEB_SERVER_PASS
  })}")
  ....
}

By using $rds you are refering to variables inside your shell script or env vars, that is the reason why it is displaying nothing.

To use the template variables you need to interpolate in the following way ${variable}

Refer this for further details :- https://www.terraform.io/language/expressions/strings#string-templates

Related