如何在Terraform中为安全组入站规则引用EC2实例IP(cidr_block)
问题描述
我需要允许我的IP地址和另一台EC2实例(Kibana)的IP地址访问Elasticsearch节点,因此要将Kibana实例的公网IP配置到Elasticsearch安全组的cidr_block中。我尝试了多种配置方式,但均未成功:
# cidr_blocks = "${aws_instance.name.public_ip}" # cidr_blocks = ["${formatlist("%v/32", aws_instance.name.public_ip)}"] # cidr_blocks = [aws_instance.name.public_ip,"32"] # cidr_blocks = ["${aws_instance.kibana.public_ip}/32"] # cidr_blocks = join("/",[aws_instance.kibana.public_ip,"32"]) # cidr_blocks = ["${aws_instance.kibana.public_ip}/32"]
相关资源配置代码
Elasticsearch安全组
resource "aws_security_group" "elasticsearch_sg" { vpc_id = aws_vpc.elastic_vpc.id ingress { description = "允许我的IP访问SSH" cidr_blocks = [var.access_ip] # 我的IP from_port = 22 protocol = "tcp" to_port = 22 } ingress { description = "允许Elasticsearch集群内部访问" # cidr_blocks = "${aws_instance.kibana.public_ip}" # cidr_blocks = [aws_instance.kibana.public_ip,"32"] # cidr_blocks = ["${aws_instance.kibana.public_ip}/32"] from_port = 9200 protocol = "tcp" to_port = 9300 self = true } egress { description = "允许所有出站流量" cidr_blocks = [ "0.0.0.0/0" ] from_port = 0 protocol = "-1" to_port = 0 } tags={ Name="elasticsearch_sg" } }
启动Elasticsearch的null_resource
resource "null_resource" "start_es" { depends_on = [ null_resource.move_elasticsearch_file ] count = 3 connection { type = "ssh" user = "ec2-user" private_key = "${tls_private_key.pk.private_key_pem}" host= aws_instance.elastic_nodes[count.index].public_ip } provisioner "remote-exec" { inline = [ "sudo yum update -y", "sudo rpm -i https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.5.1-x86_64.rpm", "sudo systemctl daemon-reload", "sudo systemctl enable elasticsearch.service", # "sudo sed -i 's@-Xms1g@-Xms${aws_instance.elastic_nodes[count.index].root_block_device[0].volume_size/2}g@g' /etc/elasticsearch/jvm.options", # "sudo sed -i 's@-Xmx1g@-Xmx${aws_instance.elastic_nodes[count.index].root_block_device[0].volume_size/2}g@g' /etc/elasticsearch/jvm.options", "sudo rm /etc/elasticsearch/elasticsearch.yml", "sudo cp elasticsearch.yml /etc/elasticsearch/", "sudo systemctl start elasticsearch.service" ] } }
Kibana实例配置
resource "aws_instance" "kibana" { depends_on = [ null_resource.start_es ] ami = "ami-04d29b6f966df1537" instance_type = "t2.medium" iam_instance_profile = "${aws_iam_instance_profile.test_profile.name}" subnet_id = aws_subnet.elastic_subnet[var.az_name[0]].id vpc_security_group_ids = [aws_security_group.kibana_sg.id] key_name = aws_key_pair.kp.key_name associate_public_ip_address = true tags = { Name = "kibana" } }
Elasticsearch节点实例配置
resource "aws_instance" "elastic_nodes" { count = 3 ami = "ami-04d29b6f966df1537" instance_type = "t2.medium" iam_instance_profile = "${aws_iam_instance_profile.test_profile.name}" subnet_id = aws_subnet.elastic_subnet[var.az_name[count.index]].id vpc_security_group_ids = [aws_security_group.elasticsearch_sg.id] key_name = aws_key_pair.kp.key_name associate_public_ip_address = true tags = { Name = "elasticsearch_${count.index}" } }
传输Elasticsearch配置文件的null_resource
resource "null_resource" "move_elasticsearch_file" { depends_on = [aws_instance.elastic_nodes] count = 3 connection { type = "ssh" user = "ec2-user" private_key = "${tls_private_key.pk.private_key_pem}" host= aws_instance.elastic_nodes[count.index].public_ip } provisioner "file" { # content = data.template_file.init_elasticsearch[count.index].rendered content = templatefile("./templates/elasticsearch_config.tpl", { cluster_name = "cluster1" node_name = "node_${count.index}" node = aws_instance.elastic_nodes[count.index].private_ip node1 = aws_instance.elastic_nodes[0].private_ip node2 = aws_instance.elastic_nodes[1].private_ip node3 = aws_instance.elastic_nodes[2].private_ip }) destination = "elasticsearch.yml" } }
问题原因及解决方法
核心问题是依赖顺序循环:
- Elasticsearch安全组需要Kibana实例的公网IP,但Kibana实例依赖
start_es资源 start_es依赖传输配置文件的move_elasticsearch_file,后者又依赖Elasticsearch节点实例- Elasticsearch节点实例又引用了Elasticsearch安全组,导致Terraform在创建安全组时,Kibana实例还未生成,无法获取其公网IP
另外,你尝试的配置中,["${aws_instance.kibana.public_ip}/32"]是正确的语法,但依赖顺序错误导致无法生效。
推荐两种解决方式:
- 用安全组引用替代公网IP(更安全可靠):直接在Elasticsearch安全组的 ingress 规则中引用Kibana的安全组,无需依赖公网IP:
ingress { description = "允许Kibana访问Elasticsearch" security_groups = [aws_security_group.kibana_sg.id] from_port = 9200 protocol = "tcp" to_port = 9300 }
- 调整依赖顺序:如果必须使用公网IP,需要让Kibana实例在Elasticsearch安全组之前创建,同时修改Elasticsearch节点实例的安全组引用逻辑(比如先使用临时安全组,后续再更新),但这种方式步骤繁琐,不如安全组引用简洁。
内容的提问来源于stack exchange,提问作者Temo Hatna
相关产品推荐
相关产品推荐

