You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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"
  }
}
问题原因及解决方法

核心问题是依赖顺序循环:

  1. Elasticsearch安全组需要Kibana实例的公网IP,但Kibana实例依赖start_es资源
  2. start_es依赖传输配置文件的move_elasticsearch_file,后者又依赖Elasticsearch节点实例
  3. Elasticsearch节点实例又引用了Elasticsearch安全组,导致Terraform在创建安全组时,Kibana实例还未生成,无法获取其公网IP

另外,你尝试的配置中,["${aws_instance.kibana.public_ip}/32"]是正确的语法,但依赖顺序错误导致无法生效。

推荐两种解决方式:

  1. 用安全组引用替代公网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
}
  1. 调整依赖顺序:如果必须使用公网IP,需要让Kibana实例在Elasticsearch安全组之前创建,同时修改Elasticsearch节点实例的安全组引用逻辑(比如先使用临时安全组,后续再更新),但这种方式步骤繁琐,不如安全组引用简洁。

内容的提问来源于stack exchange,提问作者Temo Hatna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:50:40