Context
Hello, facing an interesting issue for basic use-case
- Created a Security Group in AWS using module code referenced below.
- No issues there and the resource creation + deletion works as expected.
- If I modify anything referenced in the input code (in main.tf where module is being used), TF does catch those changes in TF Plan.
- But if I modify anything in AWS for same resource (in this case adding / modifying ingress rule), TF does NOT catch those changes for some reason.
Terraform Version
v1.0.4
Terraform Configuration Files
Security Group Module:
main.tf
// Create security groups
resource "aws_security_group" "ease_security_group" {
for_each = var.security_group
name = each.key
vpc_id = var.ease_vpc_id
tags = {
Name = each.key
}
}
// Add ingress rules to all security groups
locals {
ingress_rules = merge([
for sg_key, sg in var.security_group : {
for rule in sg["ingress"] :
"${sg_key}-${rule["description"]}-${rule["protocol"]}-${rule["from_port"]}-${rule["to_port"]}}" => {
type = "ingress"
security_group_id = "${aws_security_group.ease_security_group[sg_key].id}"
from_port = rule["from_port"]
to_port = rule["to_port"]
protocol = rule["protocol"]
cidr_blocks = rule["cidr_blocks"]
description = rule["description"]
}
}
]...)
}
resource "aws_security_group_rule" "ease_security_group_ingress_rules" {
for_each = local.ingress_rules
type = "ingress"
security_group_id = each.value.security_group_id
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
description = each.value.description
depends_on = [aws_security_group.ease_security_group]
}
// Add egress rules to all security groups
locals {
egress_rules = merge([
for sg_key, sg in var.security_group : {
for rule in sg["egress"] :
"${sg_key}-${rule["description"]}" => {
type = "egress"
security_group_id = "${aws_security_group.ease_security_group[sg_key].id}"
from_port = rule["from_port"]
to_port = rule["to_port"]
protocol = rule["protocol"]
cidr_blocks = rule["cidr_blocks"]
description = rule["description"]
}
}
]...)
}
resource "aws_security_group_rule" "ease_security_group_egress_rules" {
for_each = local.egress_rules
type = "egress"
security_group_id = each.value.security_group_id
from_port = each.value.from_port
to_port = each.value.to_port
protocol = each.value.protocol
cidr_blocks = each.value.cidr_blocks
description = each.value.description
depends_on = [aws_security_group.ease_security_group]
}
variables.tf
// Define security groups
variable "security_group" {
default = {}
}
// Define VPC ID
variable "ease_vpc_id" {
default = ""
}
Using the module:
main.tf
module "securitygroups" {
source = "modules/securitygroups"
vpc_id = "${module.network.out_vpc_id}"
security_group = {
"redis" = {
ingress = {
rule_1 = {
description = "Allow Redis",
from_port = 6379,
to_port = 6379,
protocol = "tcp",
cidr_blocks = [var.vpc_cidr]
},
rule_2 = {
description = "from eng vpn",
from_port = 6379,
to_port = 6379,
protocol = "tcp",
cidr_blocks = ["172.16.0.0/16"]
},
},
egress = {
rule_1 = {
description = "Allow ALL traffic",
from_port = 0,
to_port = 0,
protocol = -1,
cidr_blocks = ["0.0.0.0/0"]
}
}
}
}
}
Debug Output
NOTE:
- Initially there were no manual changes for this SG, so TF Plan was showing right state which is no new changes.
- Then to test, I added a 3rd ingress test rule with dummy values 1 as port and 1.1.1.1/32 as CIDR.
- Next TF Plan still shows as no new changes, would expect TF Plan to destroy that 3rd ingress for that SG being under TF state.
- TF Plan from point 3 which shows no new changes
terraform plan -target=module.securitygroups
module.network.aws_vpc.ease_vpc: Refreshing state... [id=vpc-0f48a7ba42d0f92a2]
module.securitygroups.aws_security_group.ease_security_group["ENG VPN GENERAL"]: Refreshing state... [id=sg-0f9bca78b2aceffb4]
module.securitygroups.aws_security_group.ease_security_group["ease-redis"]: Refreshing state... [id=sg-0f44d46877f814d6b]
module.securitygroups.aws_security_group.ease_security_group["ENG VPN PROD"]: Refreshing state... [id=sg-052d665f8c31dd150]
module.securitygroups.aws_security_group_rule.ease_security_group_egress_rules["ENG VPN GENERAL-Allow ALL traffic"]: Refreshing state... [id=sgrule-1431550098]
module.securitygroups.aws_security_group_rule.ease_security_group_egress_rules["ENG VPN PROD-Allow ALL traffic"]: Refreshing state... [id=sgrule-1039961651]
module.securitygroups.aws_security_group_rule.ease_security_group_egress_rules["ease-redis-Allow ALL traffic"]: Refreshing state... [id=sgrule-3887475553]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-main account eng vpn-1--1--1}"]: Refreshing state... [id=sgrule-1577332433]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN GENERAL-Allow PostgreSQL-tcp-5432-5432}"]: Refreshing state... [id=sgrule-3534773046]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-Allow SSH-tcp-22-22}"]: Refreshing state... [id=sgrule-4112345915]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ease-redis-Allow Redis-tcp-6379-6379}"]: Refreshing state... [id=sgrule-2847224619]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN GENERAL-local-tcp-5432-5432}"]: Refreshing state... [id=sgrule-105634581]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ease-redis-from eng vpn-tcp-6379-6379}"]: Refreshing state... [id=sgrule-327071861]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-Allow HTTP-tcp-80-80}"]: Refreshing state... [id=sgrule-161870213]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-Allow RDP-tcp-3389-3389}"]: Refreshing state... [id=sgrule-3254739701]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-opentelemetry-tcp-4317-4317}"]: Refreshing state... [id=sgrule-802725468]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-Allow Redshift-tcp-5439-5439}"]: Refreshing state... [id=sgrule-1483419703]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ENG VPN PROD-Allow PostgreSQL-tcp-5432-5432}"]: Refreshing state... [id=sgrule-4104625858]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are
needed.
This is how terraform state looks:
module.securitygroups.aws_security_group.ease_security_group["ease-redis"]
module.securitygroups.aws_security_group_rule.ease_security_group_egress_rules["ease-redis-Allow ALL traffic"]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ease-redis-Allow Redis-tcp-6379-6379}"]
module.securitygroups.aws_security_group_rule.ease_security_group_ingress_rules["ease-redis-from eng vpn-tcp-6379-6379}"]
Expected Behavior
TF Plan to destroy 3rd ingress rule.
Actual Behavior
TF Plan shows no new changes.
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are
needed.
Steps to Reproduce
- Terraform apply to create a SG resource using module.
- Manually modify ingress or egress rule.
- Terraform plan which should ideally show that it plans to destroy manual changes made in step 2.
Additional Context
No custom configuration is set apart from what’s shown here.