How to use unique resource names with Terraform

Naming things is hard, but this time it's because of a different reason

3 mins
I have a lot of challenges when it comes to AWS, but I bet your pain points are entirely different than mine. I'd love to hear what keeps you up at night. It would be great to hear from you by filling out this form. Thanks in advance!

Background

When a name is optional for a resource then, just like CloudFormation, Terraform will generate a random one when you deploy the stack. This makes it easy to deploy these resources and makes sure that you can safely deploy the same module multiple times.

For example, you can safely omit the bucket name:

resource "aws_s3_bucket" "bucket" {
}

The name is different each time the resource is deployed:

aws_s3_bucket.bucket: Creation complete after 1s [id=terraform-20190809095436960500000002]

aws_s3_bucket.bucket: Creation complete after 1s [id=terraform-20190809095501819400000002]

But several resource types require a name to be specified. And, unfortunately, most examples hardcode a value there making the stack less reusable.

Lambda function

In the case of the aws_lambda_function resource type, the function_name is marked as (Required) in the documentation. In this case, you must specify a name, and it’s tempting to put a constant string there:

resource "aws_lambda_function" "lambda" {
	# Don't do this
	function_name = "function"
	#	...
}

But when you deploy the same module again, apply fails:

Error: Error creating Lambda function: ResourceConflictException: Function already exist: function
        status code: 409, request id: 1961e440-7df5-4f6b-93e9-0c41bc4176a4

  on main.tf line 32, in resource "aws_lambda_function" "lambda":
  32: resource "aws_lambda_function" "lambda" {

Random ID

There is a terraform resource called random_id that generates a random value when you first apply the module. Using that, you can generate a different name every time you create a new stack.

resource "random_id" "id" {
	  byte_length = 8
}

resource "aws_lambda_function" "lambda" {
	function_name = "${random_id.id.hex}-function"
	# ...
}

Using the ${random_id.id.hex} value whenever you need to hardcode a string helps avoid the clashing of names.

Deploying the above lambda multiple times is now safe to do:

aws_lambda_function.lambda: Creation complete after 16s [id=e2aac02d233afeab-function]

aws_lambda_function.lambda: Creation complete after 16s [id=94fc006c721bc912-function]

Other resources

The same applies to the AWS Config Rule. Instead of hardcoding a name, use randomness:

resource "aws_config_config_rule" "rule" {
  name = "${random_id.id.hex}-rule"
	# ...

In the case of an SQS Queue, the name is optional. However, if you create a FIFO queue then the name must end with .fifo. In this case, the auto-generated name will result in an error.

# standard queue
resource "aws_sqs_queue" "standard_queueu" {
	# no name attribute
}

# FIFO queue
resource "aws_sqs_queue" "fifo_queue" {
  name = "${random_id.id.hex}-queue.fifo"
  fifo_queue = true
}

Conclusion

Non-unique naming is a particularly insidious problem that usually manifests itself later in the product lifecycle. Seems like everything is working fine, but then you can’t launch a dev environment in the same AWS account because of this. But with a pinch of randomness, you can avoid running into these problems.

Did you know we have a free guide on AWS security basics?

Do you have an AWS account? Of course you do, you've just read an article about AWS. But do you know how to secure it?

As a certified security specialist I'm familiar with most of the security controls AWS offers. I've compiled this guide so you don't have to take a month off to learn all that.

5 quick and easy steps to avoid the rookie mistakes and reduce the risk of costly events down the road.

Download the free guide here:

27 August 2019