Invalid value for "vars" parameter: vars map does not contain key error

Hi, while trying terraform for ec2, I’m hitting an errror of

Invalid value for “vars” parameter: vars map does not contain key
“BOUNDARY_NAME_SUFFIX”, referenced at ./userdata_controller.sh:40,36-56.

However, I defined the variable BOUNDARY_NAME_SUFFIX inside my userdata script, but having this kind of error. Any help? (I can workaround the issue by changing the BOUNDARY_NAME_SUFFIX in the userdata script to conf_name_suffix, but just want to know why. Is it related to the EOF I’m using ?

resource "aws_key_pair" "boundary" {
  key_name   = "boundary-test"
  public_key = file(var.pub_ssh_key_path)

  tags = merge(local.common_tags, {
    Name = "boundary-${terraform.workspace}-key-pair"
  })
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "controller" {
  count                       = var.num_controllers
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t3.micro"
  iam_instance_profile        = aws_iam_instance_profile.boundary.name
  subnet_id                   = data.terraform_remote_state.network.outputs.tokyo_vpc_main.private_subnet_ids[count.index]
  key_name                    = aws_key_pair.boundary.key_name
  vpc_security_group_ids      = [aws_security_group.controller.id]
  associate_public_ip_address = true

  user_data = base64encode(templatefile(
    "${path.module}/userdata_controller.sh", {
      conf_tls_private_key        = tls_private_key.boundary.private_key_pem
      conf_tls_self_signed_cert   = tls_self_signed_cert.boundary.cert_pem
      conf_tls_key_path           = var.tls_key_path
      conf_tls_cert_path          = var.tls_cert_path
      conf_tls_disabled           = var.tls_disabled     
      conf_name_suffix            = count.index
      conf_db_endpoint            = aws_db_instance.boundary.endpoint
      conf_kms_type               = var.kms_type
      conf_kms_worker_auth_key_id = aws_kms_key.worker_auth.id
      conf_kms_recovery_key_id    = aws_kms_key.recovery.id
      conf_kms_root_key_id        = aws_kms_key.root.id
    }
  ))

  tags = merge(local.common_tags, {
    Name = "boundary-${terraform.workspace}-controller-instance"
  })
}

resource "aws_security_group" "controller" {
  vpc_id = data.terraform_remote_state.network.outputs.tokyo_vpc_main.vpc_id

  tags = merge(local.common_tags, {
    Name = "boundary-${terraform.workspace}-controller-sg"
  })
}

resource "aws_security_group_rule" "allow_ssh_controller" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.controller.id
}

resource "aws_security_group_rule" "allow_9200_controller" {
  type              = "ingress"
  from_port         = 9200
  to_port           = 9200
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.controller.id
}

resource "aws_security_group_rule" "allow_9201_controller" {
  type              = "ingress"
  from_port         = 9201
  to_port           = 9201
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.controller.id
}

resource "aws_security_group_rule" "allow_egress_controller" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.controller.id
}

resource "aws_security_group" "worker" {
  vpc_id = data.terraform_remote_state.network.outputs.tokyo_vpc_main.vpc_id

  tags = merge(local.common_tags, {
    Name = "boundary-${terraform.workspace}-worker-sg"
  })
}

resource "aws_security_group_rule" "allow_ssh_worker" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.worker.id
}

resource "aws_security_group_rule" "allow_web_worker" {
  type              = "ingress"
  from_port         = 8000
  to_port           = 8000
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.worker.id
}

resource "aws_security_group_rule" "allow_9202_worker" {
  type              = "ingress"
  from_port         = 9202
  to_port           = 9202
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.worker.id
}

resource "aws_security_group_rule" "allow_egress_worker" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.worker.id
}

# Example resource for connecting to through boundary over SSH
resource "aws_instance" "target" {
  count                  = var.num_targets
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = "t3.micro"
  subnet_id              = data.terraform_remote_state.network.outputs.tokyo_vpc_main.private_subnet_ids[count.index]
  key_name               = aws_key_pair.boundary.key_name
  vpc_security_group_ids = [aws_security_group.worker.id]

  tags = merge(local.common_tags, {
    Name = "boundary-${terraform.workspace}-target-instance"
  })
}

The userdata_controller.sh is as below.

#!/bin/bash

apt update -y
apt install -y \
  unzip

# Values from Terraform
BOUNDARY_TLS_PRIVATE_KEY=${conf_tls_private_key}
BOUNDARY_TLS_SELF_SIGNED_CERT=${conf_tls_self_signed_cert}
BOUNDARY_TLS_KEY_PATH=${conf_tls_private_key}
BOUNDARY_TLS_CERT_PATH=${conf_tls_self_signed_cert}
BOUNDARY_TLS_DISABLED=${conf_tls_disabled}
BOUNDARY_KMS_TYPE=${conf_kms_type}
BOUNDARY_KMS_WORKER_AUTH_KEY_ID=${conf_kms_worker_auth_key_id}
BOUNDARY_KMS_RECOVERY_KEY_ID=${conf_kms_recovery_key_id}
BOUNDARY_KMS_ROOT_KEY_ID=${conf_kms_root_key_id}

BOUNDARY_NAME_SUFFIX=${conf_name_suffix}
BOUNDARY_DB_ENDPOINT=${conf_db_endpoint}
BOUNDARY_PRIVATE_IP=$(curl http://169.254.169.254/latest/meta-data/local-ipv4)

sudo mkdir -p /etc/pki/tls/boundary
echo '$BOUNDARY_TLS_PRIVATE_KEY' | sudo tee $BOUNDARY_TLS_KEY_PATH
echo '$BOUNDARY_TLS_SELF_SIGNED_CERT' | sudo tee $BOUNDARY_TLS_CERT_PATH

curl https://releases.hashicorp.com/boundary/0.1.2/boundary_0.1.2_darwin_amd64.zip --output ~/boundary.zip
unzip boundary.zip
sudo mv ~/boundary /usr/local/bin/boundary
sudo chmod 0755 /usr/local/bin/boundary

cat <<EOF > ~/boundary-controller.hcl
disable_mlock = true

telemetry { 
  prometheus_retention_time = "24h"
  disable_hostname          = true
}

controller {
  name        = "demo-controller-${BOUNDARY_NAME_SUFFIX}"
  description = "A controller for a demo!"

  database {
    url = "postgresql://boundary:boundarydemo@${BOUNDARY_DB_ENDPOINT}/boundary"
  }
}

listener "tcp" {
  address                           = "${BOUNDARY_PRIVATE_IP}:9200"
	purpose                           = "api"
%{ if tls_disabled == true }
	tls_disable                       = true
%{ else }
  tls_disable   = false
  tls_cert_file = "${BOUNDARY_TLS_CERT_PATH}"  
  tls_key_file  = "${BOUNDARY_TLS_KEY_PATH}"
%{ endif }
	# proxy_protocol_behavior         = "allow_authorized"
	# proxy_protocol_authorized_addrs = "127.0.0.1"
	cors_enabled                      = true
	cors_allowed_origins              = ["*"]
}

listener "tcp" {
  address                           = "${BOUNDARY_PRIVATE_IP}:9201"
	purpose                           = "cluster"
%{ if tls_disabled == true }
	tls_disable                       = true
%{ else }
  tls_disable   = false
  tls_cert_file = "${BOUNDARY_TLS_CERT_PATH}"  
  tls_key_file  = "${BOUNDARY_TLS_KEY_PATH}"
%{ endif }
	# proxy_protocol_behavior         = "allow_authorized"
	# proxy_protocol_authorized_addrs = "127.0.0.1"
}

%{ if kms_type == "aws" }
kms "awskms" {
	purpose    = "root"
	key_id     = "global_root"
  kms_key_id = "${BOUNDARY_KMS_ROOT_KEY_ID}"
}

kms "awskms" {
	purpose    = "worker-auth"
	key_id     = "global_worker_auth"
  kms_key_id = "${BOUNDARY_KMS_WORKER_AUTH_KEY_ID}"
}

kms "awskms" {
	purpose    = "recovery"
	key_id     = "global_recovery"
  kms_key_id = "${BOUNDARY_KMS_RECOVERY_KEY_ID}"
}
%{ else }
kms "aead" {
	purpose   = "root"
	aead_type = "aes-gcm"
	key       = "sP1fnF5Xz85RrXyELHFeZg9Ad2qt4Z4bgNHVGtD6ung="
	key_id    = "global_root"
}

kms "aead" {
	purpose   = "worker-auth"
	aead_type = "aes-gcm"
	key       = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
	key_id    = "global_worker-auth"
}

kms "aead" {
	purpose   = "recovery"
	aead_type = "aes-gcm"
	key       = "8fZBjCUfN0TzjEGLQldGY4+iE9AkOvCfjh7+p0GtRBQ="
	key_id    = "global_recovery"
}
%{ endif }
EOF

sudo mv ~/boundary-controller.hcl /etc/boundary-controller.hcl

TYPE=controller
NAME=boundary

sudo cat << EOF > /etc/systemd/system/${NAME}-${TYPE}.service
[Unit]
Description=${NAME} ${TYPE}
[Service]
ExecStart=/usr/local/bin/${NAME} server -config /etc/${NAME}-${TYPE}.hcl
User=boundary
Group=boundary
LimitMEMLOCK=infinity
Capabilities=CAP_IPC_LOCK+ep
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
[Install]
WantedBy=multi-user.target
EOF

# Add the boundary system user and group to ensure we have a no-login
# user capable of owning and running Boundary
sudo adduser --system --group boundary || true
sudo chown boundary:boundary /etc/${NAME}-${TYPE}.hcl
sudo chown boundary:boundary /usr/local/bin/boundary

# Make sure to initialize the DB before starting the service. This will result in
# a database already initizalized warning if another controller or worker has done this 
# already, making it a lazy, best effort initialization
if [ "${TYPE}" = "controller" ]; then
  sudo /usr/local/bin/boundary database init -skip-auth-method-creation -skip-host-resources-creation -skip-scopes-creation -skip-target-creation -config /etc/${NAME}-${TYPE}.hcl || true
fi

sudo chmod 664 /etc/systemd/system/${NAME}-${TYPE}.service
sudo systemctl daemon-reload
sudo systemctl enable ${NAME}-${TYPE}
sudo systemctl start ${NAME}-${TYPE}