Есть ли способ получить назначенный IP-адрес ресурса aws_lb во время создания aws_lb Terraform?
Как и в Документация AWS — NLB — поиск частных IP-адресов для внесения в белый список, мы можем узнать IP-адрес, связанный с ELB.
Чтобы иметь возможность настроить группу безопасности для белого списка IP-адреса ELB, поскольку балансировщик сетевой нагрузки не может не иметь группы безопасности, как в Балансировщики сетевой нагрузки не имеют групп безопасности.
Считал aws_network_interface но не работает с ошибкой.
Error: no matching network interface found
Также я думаю, что источник данных предполагает, что ресурс уже существует и не может использоваться для ресурса, который будет создан Terraform.





Получите IP-адрес NLB, используя вызов Python/boto3 от внешнего поставщика.
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}"
}
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_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])}"
}
Более элегантное решение с использованием только HCL в 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"
}
}
Источник : https://github.com/terraform-providers/terraform-provider-aws/issues/3007
Надеюсь это поможет.
Это действительно здорово! Мне это очень нравится.
Это высокий класс!
Решение от @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)
}
Просто проверяю, но это не работает, если балансировщик нагрузки создается одновременно с этими источниками данных, верно?