Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform how to get IP address of aws_lb

Question

If there a way to get the assigned IP address of an aws_lb resource at the time aws_lb is created by Terraform?

As in AWS documentation - NLB - To find the private IP addresses to whitelist, we can find out the IP address associated to ELB.

  1. Open the Amazon EC2 console at https://console.aws.amazon.com/ec2/.
  2. In the navigation pane, choose Network Interfaces.
  3. In the search field, type the name of your Network Load Balancer. There is one network interface per load balancer subnet.
  4. On the Details tab for each network interface, copy the address from Primary private IPv4 IP.

Background

To be able to setup security group to white list the ELB IP address as Network Load Balancer cannot not have Security Group as in Network Load Balancers don't have Security Groups.

Considered aws_network_interface but it does not work with an error.

Error: no matching network interface found

Also I think datasource assumes the resource already exists and cannot be used for the resource to be created by Terraform.

like image 393
mon Avatar asked Jun 22 '19 07:06

mon


People also ask

What is Aws_eip?

Resource: aws_eip. Provides an Elastic IP resource. Note: EIP may require IGW to exist prior to association. Use depends_on to set an explicit dependency on the IGW.

What is Aws_lb_target_group?

Data Source: aws_lb_target_group Note: aws_alb_target_group is known as aws_lb_target_group . The functionality is identical. Provides information about a Load Balancer Target Group. This data source can prove useful when a module accepts an LB Target Group as an input variable and needs to know its attributes.

How to add my IP address to a terraform file?

The trick is having a website such as icanhazip.com which retrieve your IP, so set it in your terraform file as data: And whenever you want to place your IP just use data.http.myip.body, example: ingress { from_port = 5432 to_port = 5432 protocol = "tcp" cidr_blocks = ["$ {chomp (data.http.myip.body)}/32"] }

How do I find private IP addresses associated with load balancer interfaces?

Find private IP addresses associated with load balancer elastic network interfaces using the AWS Management Console 1. Open the Amazon Elastic Compute Cloud (Amazon EC2) console. 2. Under Load Balancing, choose Load Balancers from the navigation pane. 3. Select the load balancer that you're finding IP addresses for.

How to get IP from Alb_lb (NLB)?

A way to get the IP address from alb_lb (NLB) so that the white listing IP in Security Group, etc can be possible. Being able to create aws_security_group and set the IP addresses of NLB at the time alb_lb is created.


3 Answers

More elegent solution using only HCL in Terraform :

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"
  }
}

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

Hope this helps.

like image 161
user1297406 Avatar answered Oct 06 '22 18:10

user1297406


Using external provider

Get the NLB IP using Python/boto3 invoking from external provider.

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()

Using aws_network_interfaces datasource

After aws_lb has been created.

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])}"
}
like image 39
mon Avatar answered Oct 06 '22 16:10

mon


The solution from @user1297406 leads to an exeption. data.aws_network_interface.lb is tuple with 2 elements. Correct syntax is:

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)
}
like image 7
awiechert Avatar answered Oct 06 '22 16:10

awiechert