How to use unique resource names with Terraform
Naming things is hard, but this time it's because of a different reason
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.