The other day I needed to lookup the public IPs of a NAT gateway, in another AWS account, in Terraform.

There’s three ways you could achieve this:

  • You can look it up dynamically, as I have. This assumes you have access to credentials which are able to query that AWS account.
  • If the other VPC is also managed by Terraform, you could query the state file for this information. You’d need access to the state file, obviously.
  • You could look up (or be given) the IPs and just hardcode them or add them as a variable. NAT gateways are unlikely to change frequently unless the infrastructure is frequently being torn up/down so while manual, it would work.

Each of the steps below corresponds to a block of Terraform code.

  1. Lookup the other VPC, in this came filtering on name vpc.
  2. Lookup all the elastic network interfaces in the other account that are;
    1. In the above VPC,
    2. Have source destination checking disabled (required by NAT Gateways and NAT instances),
    3. Requester-managed, which means it’s a network interface that was created by an AWS service.
  3. Collect data on each of the IPs that we got in the previous step. You’re not ready to use these wherever you need.
  4. As an example, you could use them in an AWS WAF IP set.
# 1
data "aws_vpc" "other_account" {
  provider = aws.other_account

  tags = {
    Name = "vpc"

# 2
data "aws_network_interfaces" "other_account_vpc_ngw_enis" {
  provider = aws.other_account

  filter {
    name   = "vpc-id"
    values = []
  filter {
    name   = "source-dest-check"
    values = ["false"]
  filter {
    name   = "requester-managed"
    values = ["true"]

# 3
data "aws_network_interface" "eni_ids" {
  provider = aws.other_account

  for_each = data.aws_network_interfaces.other_account_vpc_ngw_enis.ids
  id       = each.value

# 4
resource "aws_wafv2_ip_set" "allowlist" {
  name               = "allowlist"
  scope              = "REGIONAL"
  ip_address_version = "IPV4"
  addresses = [for eni in data.aws_network_interface.eni_ids : "${eni.association[0].public_ip}/32"]

It feels a little bit clunky to me at the moment, but it works. 👌