【问题标题】:Terraform how to get IP address of aws_lbTerraform如何获取aws_lb的IP地址
【发布时间】:2019-11-04 21:33:42
【问题描述】:

问题

是否有办法在 Terraform 创建 aws_lb 时获取 aws_lb 资源的分配 IP 地址?

AWS documentation - NLB - To find the private IP addresses to whitelist一样,我们可以找到ELB关联的IP地址。

  1. 打开 Amazon EC2 控制台https://console.aws.amazon.com/ec2/
  2. 在导航窗格中,选择网络接口。
  3. 在搜索字段中,输入您的网络负载均衡器的名称。 每个负载平衡器子网有一个网络接口。
  4. 在每个网络接口的详细信息选项卡上,复制地址 主要私有 IPv4 IP

背景

为了能够设置安全组以将 ELB IP 地址列入白名单,因为网络负载均衡器不能没有安全组,如 Network Load Balancers don't have Security Groups

考虑过aws_network_interface,但由于错误而无法使用。

错误:找不到匹配的网络接口

另外我认为数据源假设资源已经存在,不能用于 Terraform 创建的资源。

【问题讨论】:

    标签: terraform amazon-elb terraform-provider-aws


    【解决方案1】:

    在 Terraform 中仅使用 HCL 的更优雅的解决方案:

    data "aws_network_interface" "lb" {
      for_each = var.subnets
    
      filter {
        name   = "description"
        values = ["ELB ${aws_lb.example_lb.arn_suffix}"]
      }
    
      filter {
        name   = "subnet-id"
        values = [each.value]
      }
    }
    
    resource "aws_security_group" "lb_sg" {
      vpc_id = var.vpc_id
    
      ingress {
        from_port   = 0
        to_port     = 0
        protocol    = "tcp"
        cidr_blocks = formatlist("%s/32", [for eni in data.aws_network_interface.lb : eni.private_ip])
        description = "Allow connection from NLB"
      }
    }
    

    来源:https://github.com/terraform-providers/terraform-provider-aws/issues/3007

    希望这会有所帮助。

    【讨论】:

    • 这真是太棒了!我非常喜欢这个。
    • 这是高级别的!
    【解决方案2】:

    使用外部提供商

    使用 Python/boto3 从外部提供程序调用获取 NLB IP。

    nlb_private_ips.tf

    variable "nlb_name" {
    }
    variable "vpc_id" {
    }
    variable "region" {
    }
    
    data "external" "get_nlb_ips" {
      program = ["python", "${path.module}/get_nlb_private_ips.py"]
      query = {
        aws_nlb_name  = "${var.nlb_name}"
        aws_vpc_id    = "${var.vpc_id}"
        aws_region    = "${var.region}"
      }
    }
    
    output "aws_nlb_ip_decoded" {
      value = "${jsondecode(data.external.get_nlb_ips.result.private_ips)}"
    }
    
    output "aws_nlb_ip_encoded" {
      value = "${data.external.get_nlb_ips.result.private_ips}"
    }
    

    get_nlb_private_ips.py

    import boto3
    import json
    import sys
    
    
    def json_serial(obj):
        """JSON serializer for objects not serializable by default json code
            Args:
                obj: object to serialize into JSON
        """
        _serialize = {
            "int": lambda o: int(o),
            "float": lambda o: float(o),
            "decimal": lambda o: float(o) if o % 1 > 0 else int(o),
            "date": lambda o: o.isoformat(),
            "datetime": lambda o: o.isoformat(),
            "str": lambda o: o,
        }
        return _serialize[type(obj).__name__.lower()](obj)
    
    
    def pretty_json(dict):
        """
        Pretty print Python dictionary
        Args:
            dict: Python dictionary
        Returns:
            Pretty JSON
        """
        return json.dumps(dict, indent=2, default=json_serial, sort_keys=True, )
    
    
    def get_nlb_private_ips(data):
        ec2 = boto3.client('ec2', region_name=data['aws_region'])
        response = ec2.describe_network_interfaces(
            Filters=[
                {
                    'Name': 'description',
                    'Values': [
                        "ELB net/{AWS_NLB_NAME}/*".format(
                            AWS_NLB_NAME=data['aws_nlb_name'])
                    ]
                },
                {
                    'Name': 'vpc-id',
                    'Values': [
                        data['aws_vpc_id']
                    ]
                },
                {
                    'Name': 'status',
                    'Values': [
                        "in-use"
                    ]
                },
                {
                    'Name': 'attachment.status',
                    'Values': [
                        "attached"
                    ]
                }
            ]
        )
    
        # print(pretty_json(response))
        interfaces = response['NetworkInterfaces']
    
        # ifs = list(map(lamba index: interfaces[index]['PrivateIpAddresses'], xrange(len(interfaces))))
        # --------------------------------------------------------------------------------
        # Private IP addresses associated to an interface (ENI)
        # Each association has the format:
        #   {
        #     "Association": {
        #       "IpOwnerId": "693054447076",
        #       "PublicDnsName": "ec2-52-88-47-177.us-west-2.compute.amazonaws.com",
        #       "PublicIp": "52.88.47.177"
        #     },
        #     "Primary": true,
        #     "PrivateDnsName": "ip-10-5-1-205.us-west-2.compute.internal",
        #     "PrivateIpAddress": "10.5.1.205"
        #   },
        # --------------------------------------------------------------------------------
        associations = [
            association for interface in interfaces
            for association in interface['PrivateIpAddresses']
        ]
    
        # --------------------------------------------------------------------------------
        # Get IP from each IP association
        # --------------------------------------------------------------------------------
        private_ips = [
            association['PrivateIpAddress'] for association in associations
        ]
    
        return private_ips
    
    
    def load_json():
        data = json.load(sys.stdin)
        return data
    
    
    def main():
        data = load_json()
        """
        print(data['aws_region'])
        print(data['aws_vpc_id'])
        print(data['aws_nlb_name'])
        """
        ips = get_nlb_private_ips(data)
        print(json.dumps({"private_ips": json.dumps(ips)}))
    
    
    if __name__ == '__main__':
        main()
    

    使用 aws_network_interfaces 数据源

    创建 aws_lb 之后。

    data "aws_network_interfaces" "this" {
      filter {
        name = "description"
        values = ["ELB net/${aws_lb.this.name}/*"]
      }
      filter {
        name = "vpc-id"
        values = ["${var.vpc_id}"]
      }
      filter {
        name = "status"
        values = ["in-use"]
      }
      filter {
        name = "attachment.status"
        values = ["attached"]
      }
    }
    
    locals {
      nlb_interface_ids = "${flatten(["${data.aws_network_interfaces.this.ids}"])}"
    }
    
    data "aws_network_interface" "ifs" {
      count = "${length(local.nlb_interface_ids)}"
      id = "${local.nlb_interface_ids[count.index]}"
    }
    
    output "aws_lb_network_interface_ips" {
      value = "${flatten([data.aws_network_interface.ifs.*.private_ips])}"
    }
    

    【讨论】:

    • 只是检查,但如果负载均衡器是在创建这些数据源的同时进行的,那将不起作用,对吧?
    【解决方案3】:

    @user1297406 的解决方案导致异常。 data.aws_network_interface.lb is tuple with 2 elements.正确的语法是:

    data "aws_network_interface" "lb" {
    count = length(var.vpc_private_subnets)
    
      filter {
        name   = "description"
        values = ["ELB ${aws_alb.lb.arn_suffix}"]
      }
      filter {
        name   = "subnet-id"
        values = [var.vpc_private_subnets[count.index]]
      }
    }
    
    
    resource "aws_security_group_rule" "lb_sg" {
      from_port         = 0
      protocol          = "TCP"
      to_port           = 0
      type              = "ingress"
      cidr_blocks = formatlist("%s/32", data.aws_network_interface.lb.*.private_ip)
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-18
      • 2010-12-26
      • 1970-01-01
      • 2014-12-30
      • 2021-01-28
      • 2010-11-04
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多