'terraform get subnet integration ips from vpc endpoint subnets tab
The flow is like
1.vpc-->vpc_endpoint(com.amazonaws.us-east-1.transfer.server) --> [subnet_1, subnet_2]
2.net --> nlb --> targetgroups --> [subnet_ip_1, subnet_ip_2]
I am creating a NLB with target groups pointing to VPC endpoint created for 'AWS transfers for sftp' com.amazonaws.us-east-1.transfer.server but terraform doesn't return the ips of the subnets that are integrated with VPC endpoint
So, currently i'm manually copying the ips from subnets tab under vpc endpoint. But, I want to automate this complete process using terraform
Any help would be appreciated
resource "aws_eip" "nlb" {
count = length(var.public_subnet_ids)
vpc = true
}
resource "aws_lb" "network" {
name = "${var.service_name}-${var.env}-nlb"
load_balancer_type = "network"
dynamic subnet_mapping {
for_each = [for i in range(length(module.vpc.public_subnet_ids)) : {
subnet_id = var.public_subnet_ids[i]
allocation_id = aws_eip.nlb[i].id
}]
content {
subnet_id = subnet_mapping.value.subnet_id
allocation_id = subnet_mapping.value.allocation_id
}
}
}
resource "aws_lb_target_group" "target-group" {
name = "${var.service_name}-${var.env}-nlb-target-group"
port = 22
protocol = "TCP"
target_type = "ip"
vpc_id = var.vpc_id
}
// TODO need to add vpc endpoint subnet ip addresses manually to nlb target group as terraform doesn't export the subnet ip addresses
//resource "aws_lb_target_group_attachment" "vpc-endpoint" {
// count = length(var.public_subnet_ids)
// target_group_arn = aws_lb_target_group.target-group.arn
// target_id = this needs ip of subnets intgerated with vpc endpoint
// port = 22
//}
resource "aws_vpc_endpoint" "transfer" {
vpc_id = var.vpc_id
service_name = "com.amazonaws.${var.aws_region}.transfer.server"
vpc_endpoint_type = "Interface"
subnet_ids = var.public_subnet_ids
private_dns_enabled = true
}
resource "aws_transfer_server" "sftp" {
identity_provider_type = "API_GATEWAY"
endpoint_type = "VPC_ENDPOINT"
endpoint_details {
vpc_endpoint_id = aws_vpc_endpoint.transfer.id
}
url = aws_api_gateway_deployment.deploy.invoke_url
invocation_role = aws_iam_role.transfer-identity-provider-role.arn
logging_role = aws_iam_role.transfer-logging-role.arn
depends_on = [aws_vpc_endpoint.transfer]
}
Solution 1:[1]
From the docs it seems like VPC endpoints have hostnames rather than static IP addresses, which often means that the hostname might refer to multiple IP addresses or may change over time. Therefore what you want to do here may not be possible, or at least might not remain reliable over time as things change.
With that said, you may be able to obtain the IP addresses that correspond with those hostnames at the time Terraform runs using the dns provider, as long as those hostnames are available immediately:
resource "aws_vpc_endpoint" "transfer" {
vpc_id = var.vpc_id
service_name = "com.amazonaws.${var.aws_region}.transfer.server"
vpc_endpoint_type = "Interface"
subnet_ids = var.public_subnet_ids
private_dns_enabled = true
}
data "dns_a_record_set" "endpoints" {
# dns_a_record_set.endpoints is a map from hostname to an object containing "addrs"
for_each = { for e in aws_vpc_endpoint.transfer.dns_entry : e.dns_name => e }
host = each.key
}
locals {
# Flatten the IP addresses down into a single set.
endpoint_ip_addrs = toset(flatten(dns_a_record_set.endpoints[*].addrs))
}
resource "aws_lb_target_group_attachment" "vpc-endpoint" {
for_each = local.endpoint_ip_addrs
target_group_arn = aws_lb_target_group.target-group.arn
target_id = each.value
port = 22
}
Unfortunately I expect that the hostnames in aws_vpc_endpoint's dns_entry attribute will be known only after apply, and thus they are not good keys to use for for_each. If that's true then the above will produce the error saying that the for_each value is inappropriate unless you gradually apply this using -target.
The design of aws_vpc_endpoint doesn't seem to lend itself well to what you are trying to do here because it doesn't provide any explicit indication of which of the hostnames belongs to which subnet, and thus there's not enough information available to construct a mapping or set value that would have keys that are known in the configuration. Might be worth considering the alternative approach of removing the load balancer from the equation altogether and instead just using the DNS hostnames provided by aws_vpc_endpoint, since that seems to be the intended usage given how the resource type is designed.
Solution 2:[2]
try something like this:
## Data Section
data "aws_network_interface" "eni_0" {
id = "${aws_vpc_endpoint.transfer.network_interface.ids {0}"
}
data "aws_network_interface" "eni_1" {
id = "${aws_vpc_endpoint.transfer.network_interface.ids {1}"
}
## Resource Section
resource "aws_alb_target_group_attachment" "tg_att_0" {
target_group_arn = "$aws_lb_target_group.group.arn}"
target_id = "${data.aws_network_interface.eni_0.private_ips[0]}"
port = 22
}
resource "aws_alb_target_group_attachment" "tg_att_1" {
target_group_arn = "$aws_lb_target_group.group.arn}"
target_id = "${data.aws_network_interface.eni_1.private_ips[0]}"
port = 22
}
This does work but didn't have time to optimize the code yet... It will allow you to attach the NLB to the VPC endpoint internal address.
Good luck.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Martin Atkins |
| Solution 2 | Raj |
