1

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]
}
ashishmohite
  • 1,120
  • 6
  • 14

2 Answers2

1

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.

Raj
  • 11
  • 2
  • newb question: Should I assume that your terraform code somewhere explicitly created aws_vpc_endpoint.transfer (in the '## Data Section' of your example)? If not (for example, if you just created a transfer service in the basic way, how do you get access to this data? What is this concept called, so I can read about it? – Jason Michael Apr 04 '22 at 20:54
-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.

Martin Atkins
  • 62,420
  • 8
  • 120
  • 138
  • The problem is I'm using NLB for exposing the SFTP server to outside network with IP whitelisting. aws.amazon.com/sftp/faqs "Q: Can I filter incoming traffic to access my SFTP server’s VPC endpoint?". So, I can't remove NLB in this context – ashishmohite Sep 12 '19 at 05:54