How to use unique resource names with Terraform

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

Author's image
Tamás Sallai
2 mins

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" {
Learn the services needed to build a serverless HTTP-based API on AWS from our free email course .

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.

27 August 2019
In this article