I have an ec2 instance defined in terraform along with some security rules.
These are the security rules:
resource "aws_security_group" "ec2_web" {
name = "${var.project_name}_${var.env}_ec2_web"
description = "ec2 instances that serve to the load balancer"
vpc_id = aws_vpc.main.id
}
resource "aws_security_group_rule" "ec2_web_http" {
type = "egress"
from_port = 80
to_port = 80
protocol = "tcp"
# cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.ec2_web.id
source_security_group_id = aws_security_group.elb.id
}
resource "aws_security_group_rule" "ec2_web_ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
I’m trying to simply add another security rule:
resource "aws_security_group_rule" "ec2_web_ssh_test" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${var.ip_address}/32"]
security_group_id = aws_security_group.ec2_web.id
}
And terraform wants to completely replace the security group, and that cascades into completely replacing the ec2 instance.
I’m modifying the .tf file and then running:
terraform apply
EDIT:
The security group itself seems completely unrelated. When I do "plan", I get the output:
# aws_instance.ec2 must be replaced
-/+ resource "aws_instance" "ec2" {
...
~ security_groups = [ # forces replacement
+ "sg-0befd5d21eee052ad",
]
The ec2 instance is created with:
resource "aws_instance" "ec2" {
ami = "ami-0b5eea76982371e91"
instance_type = "t3.small"
key_name = "${var.project_name}"
depends_on = [aws_internet_gateway.main]
user_data = <<EOF
#!/bin/bash
sudo amazon-linux-extras install -y php8.1 mariadb10.5
sudo yum install -y httpd mariadb php8.1 php8.1-cli
sudo systemctl start httpd
sudo systemctl enable httpd
echo 'yup' | sudo tee /var/www/html/index.html
echo '<?php echo phpinfo();' | sudo tee /var/www/html/phpinfo.php
EOF
tags = {
Name = "${var.project_name}_${var.env}_ec2"
}
root_block_device {
volume_size = 8 # GB
volume_type = "gp3"
}
security_groups = [aws_security_group.ec2_web.id]
# vpc_security_group_ids = [aws_security_group.main.id]
subnet_id = aws_subnet.main1.id
}
If I comment out
# security_groups = [aws_security_group.bake.name]
I do not get any errors.
3
Answers
Before apply please run
terraform apply -refresh-only
then your main problem is you can not define same rule with different terraform id.When you apply new changes for
ec2_web_ssh_test
AWS will complain aboutThen you will get this error from AWS api
With Terraform it compares the current state of your configuration with the new state which will contain the new rule you are adding. Here current state is not same as the desired state with new rule you are adding.
Hence with two different states, Terraform is trying to destroy the EC2 instances and trying to build new instances with newly added rules state.
This can be avoided with using
terraform import
command that will import the existing resources to your terraform state and then make changes to it.This happens because
security_groups
can only be used EC2-Classic (legacy instances) and a default VPC. For everything else you must usevpc_security_group_ids
.In your cause you are using custom VPC called
main
, thus you must be usingvpc_security_group_ids
, notsecurity_groups
.