用語
SG: セキュリティグループ
SGR: セキュリティグループルール
注意
terraform apply
実行時のエラーに対するトラブルシューティングという内容ですが、後述するように、そもそも、terraform state mv
コマンドを適切に事前に実行すれば、回避できるエラーです。
私は、tfmigrate を使っているので、terraform state mv
コマンドをコードに起こして確認してから実行しています。
目的
- SGR(セキュリティグループルール) を改名して、
terraform apply
を実施したときに起きることがあるエラーのトラブルシューティングの方法を知る。
※ 後で説明するが、エラーが起きないときもある。
│ Error: [WARN] A duplicate Security Group rule was found on (sg-XXXXXXXXXXXXXXX). This may be
- SGR(セキュリティグループルール)の削除と作成のタイミングを知る。
- 事前に上記エラーを回避する方法を知る。
結論
- 上記エラーが起きたら、もう一度
terraform apply
をやれば成功する。- ※ただ、そもそも、
terraform apply
を実施してこのエラーを起こす前に、terraform state mv
コマンドやtfmigrate apply
コマンド(tfmigrate のインストール必須)を実施しよう。
- ※ただ、そもそも、
- SGR(セキュリティグループルール)の削除と作成のタイミングは、かなり適当で、上記の
terraform apply
はエラーになったりならなかったりする。 - リソースの改名や置き換えの時は、
state
コマンドを使ってからterraform apply
を実施するべきなので、terraform apply
実施前に必ず検討しよう。
説明
エラーを見てみる
モジュール内のSGRを sgr_ingress
から sgr_ingress_renamed
に改名した。
resource "aws_security_group_rule" "sgr_ingress_renamed" {
type = "ingress"
from_port = var.port
to_port = var.port
protocol = "tcp"
cidr_blocks = var.cidr_blocks_ingress
security_group_id = aws_security_group.normal.id
timeouts {
create = "1m"
}
}
resource "aws_security_group_rule" "sgr_egress" {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.normal.id
timeouts {
create = "1m"
}
}
resource "aws_security_group" "normal" {
name = var.name
vpc_id = var.vpc_id
timeouts {
create = "1m"
delete = "1m"
}
}
module "allow_http" {
source = "./modules/security_group"
name = "AllowHTTP_2"
vpc_id = aws_vpc.tf_my_vpc.id
port = 80
cidr_blocks_ingress = ["0.0.0.0/0"]
}
module "allow_https" {
source = "./modules/security_group"
name = "AllowHTTPS_2"
vpc_id = aws_vpc.tf_my_vpc.id
port = 443
cidr_blocks_ingress = ["0.0.0.0/0"]
}
module "allow_ssh" {
source = "./modules/security_group"
name = "AllowSSH_2"
vpc_id = aws_vpc.tf_my_vpc.id
port = 22
cidr_blocks_ingress = ["0.0.0.0/0"]
}
そして、terraform apply
を実施すると、下記のエラーが出るときがある。 ※ この記事の趣旨でもあるが、場合によってはエラーは出ない。
Plan: 3 to add, 0 to change, 3 to destroy.
module.allow_https.aws_security_group_rule.sgr_ingress: Destroying... [id=sgrule-XXXXXXXXXX]
module.allow_http.aws_security_group_rule.sgr_ingress: Destroying... [id=sgrule-XXXXXXXXXX]
module.allow_ssh.aws_security_group_rule.sgr_ingress: Destroying... [id=sgrule-XXXXXXXXXX]
module.allow_https.aws_security_group_rule.sgr_ingress_renamed: Creating...
module.allow_http.aws_security_group_rule.sgr_ingress_renamed: Creating...
module.allow_ssh.aws_security_group_rule.sgr_ingress_renamed: Creating...
module.allow_http.aws_security_group_rule.sgr_ingress: Destruction complete after 0s
module.allow_ssh.aws_security_group_rule.sgr_ingress: Destruction complete after 0s
module.allow_https.aws_security_group_rule.sgr_ingress: Destruction complete after 1s
module.allow_http.aws_security_group_rule.sgr_ingress_renamed: Creation complete after 1s [id=sgrule-XXXXXXXXXX]
module.allow_ssh.aws_security_group_rule.sgr_ingress_renamed: Creation complete after 2s [id=sgrule-XXXXXXXXXX]
╷
│ Error: [WARN] A duplicate Security Group rule was found on (sg-XXXXXXXXXXXXXXX). This may be
│ a side effect of a now-fixed Terraform issue causing two security groups with
│ identical attributes but different source_security_group_ids to overwrite each
│ other in the state. See https://github.com/hashicorp/terraform/pull/2376 for more
│ information and instructions for recovery. Error: operation error EC2: AuthorizeSecurityGroupIngress, https response error StatusCode: 400, RequestID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, api error InvalidPermission.Duplicate: the specified rule "peer: 0.0.0.0/0, TCP, from port: 443, to port: 443, ALLOW" already exists
│
│ with module.allow_https.aws_security_group_rule.sgr_ingress_renamed,
│ on modules/security_group/aws_security_group_rule.tf line 1, in resource "aws_security_group_rule" "sgr_ingress_renamed":
│ 1: resource "aws_security_group_rule" "sgr_ingress_renamed" {
│
╵
Error: Process completed with exit code 1.
下記の部分に注目してほしい。
module.allow_http.aws_security_group_rule.sgr_ingress
とmodule.allow_ssh.aws_security_group_rule.sgr_ingress
は、無事に破壊されて、リネームされた上で再作成されている。
一方、module.allow_https.aws_security_group_rule.sgr_ingress
はしっかり破壊されているものの、リネームしたSGRの再作成に失敗している。
module.allow_http.aws_security_group_rule.sgr_ingress: Destruction complete after 0s
module.allow_ssh.aws_security_group_rule.sgr_ingress: Destruction complete after 0s
module.allow_https.aws_security_group_rule.sgr_ingress: Destruction complete after 1s
module.allow_http.aws_security_group_rule.sgr_ingress_renamed: Creation complete after 1s [id=sgrule-XXXXXXXXXX]
module.allow_ssh.aws_security_group_rule.sgr_ingress_renamed: Creation complete after 2s [id=sgrule-XXXXXXXXXX]
╷
│ Error: [WARN] A duplicate Security Group rule was found on (sg-XXXXXXXXXXXXXXX). This may b
エラーの原因
エラーの原因は、リネーム前のSGR(module.allow_https.aws_security_group_rule.sgr_ingress
)が破壊されるタイミングと、リネーム後のSGR(module.allow_https.aws_security_group_rule.sgr_ingress_renamed
)が作成されようとしているタイミングが近すぎて、リネーム後のSGRを作成しようとした時に、リネーム前のSGRがまだ破壊されていないと判断されてしまったことである。
リネーム前のSGRとリネーム後のSGRは、名前が違うだけで内容が全く同じなので、同じSGの中に共存できないのである。なので、リネーム後のSGRの内容を少し変更すれば、このようなエラーは起きないはずである(たぶん)。
エラーが起きるときと起きないときがある
何回か実験してみたら、まったくエラーがでないときもあれば、上記とは違って、module.allow_http.aws_security_group_rule.sgr_ingress
を改名したSGRの作成がエラーになるときもあった。
トラブルシューティング
状況としては、リネーム前のSGRの削除に成功して、リネーム後のSGRの作成に失敗しているので、terraform apply
を再度実行すれば解決する。
そもそもこのようなエラーを起こさないために
terraform state mv
コマンドや tfmigrate apply
コマンド(tfmigrate のインストール必須)を実施してから、terraform apply
を実施しよう。
ちなみに、tfmigrate
を使う場合、下記のようなマイグレーションファイルを用意して、tfmigrate apply
を実施することになる。
migration "state" "20241019212900_rename_sgr_ingress_to_sgr_ingress_renamed" {
actions = [
"mv module.allow_http.aws_security_group_rule.sgr_ingress module.allow_http.aws_security_group_rule.sgr_ingress_renamed",
"mv module.allow_https.aws_security_group_rule.sgr_ingress module.allow_https.aws_security_group_rule.sgr_ingress_renamed",
"mv module.allow_ssh.aws_security_group_rule.sgr_ingress module.allow_ssh.aws_security_group_rule.sgr_ingress_renamed"
]
}