I wanted to create a terraform EC2 Spot instance on AWS using the terraform module terraform-aws-ec2-instance.
Upon creation, I noticed the EC2 instance was missing the tags I had assigned to it. So I started digging and came up with this MCVE:
provider "aws" {
region = local.region
}
locals {
name = "example-ec2-complete"
region = "us-east-2"
}
module "ec2_instance" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "4.3.0"
name = "spot-instance"
create_spot_instance = true
spot_price = "0.60"
spot_type = "persistent"
ami = "ami-05502a22127df2492"
instance_type = "t2.micro"
subnet_id = element(module.vpc.private_subnets, 0)
tags = {
Name = "Test"
Terraform = "true"
Environment = "dev"
}
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "my-openshift-test-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-2a", "us-east-2b", "us-east-2c"]
private_subnets = ["10.0.1.0/24"]
private_subnet_names = ["my-openshift-private-subnet-one"]
}
resource "local_file" "ec2_instance_id" {
content = "${module.ec2_instance.spot_instance_id}"
filename = "instance_id.txt"
}
You can launch the above example and retrieve the assigned tags with the following bash one-liner (you must launch it 2 times as the instance id isn't immediately loaded by Terraform and it will fail the first time):
terraform init && terraform apply && aws ec2 describe-tags --filters "Name=resource-id,Values=`cat instance_id.txt`"
Upon creation, we can see the instance has no tags:

I tried the oldest and newest versions of the module, to no avail:
#version = "~> 3.0"
#version = "4.3.0"
#version = "2.0"
#version = "2.21.0"
#version = "3.0.0""
I later found out this happens because the tags DO get added, but to the spot Instance Request, as can be shown with terraform show/terraform plan:
$ terraform show
# local_file.ec2_instance_id:
resource "local_file" "ec2_instance_id" {
...
# no tags in the output!
...
}
# module.ec2_instance.aws_spot_instance_request.this[0]:
resource "aws_spot_instance_request" "this" {
...
tags = {
"Environment" = "dev"
"Name" = "Test"
"Terraform" = "true"
}
tags_all = {
"Environment" = "dev"
"Name" = "Test"
"Terraform" = "true"
}
...
I couldn't find any official explanations on this, but, reading from the AWS Documentation, it is said here:
When you tag a Spot Instance request, the instances and volumes that are launched by the Spot Instance request are not automatically tagged. You need to explicitly tag the instances and volumes launched by the Spot Instance request. You can assign a tag to a Spot Instance and volumes during launch, or afterward.
Therefore I assume the reason this cannot be implemented in Terraform is because AWS doesn't support tagging EC2 Spot Instances in an idempotent way. This is also being discussed here and here.
As a workaround, I created the tag manually after getting the instance ID:
resource "aws_ec2_tag" "example" {
#resource_id = aws_vpn_connection.example.transit_gateway_attachment_id
resource_id = module.ec2_instance.spot_instance_id
key = "Name"
value = "Test"
}
The above code can be directly added at the bottom of the original example.
Are there other better Terraform constructs that would allow this given the context? It seems fundamentally wrong to create the tags in a separate place from where the instance is created, as well as being error-prone considering the way Spot Instances are instantiated on AWS.
Thanks!
