Skip to content

feat: GatewayLoadBalancer supported with subnet_ids#1288

Open
codyrat wants to merge 3 commits intoterraform-aws-modules:masterfrom
codyrat:feature/add-gwlb-to-vpc-endpoints
Open

feat: GatewayLoadBalancer supported with subnet_ids#1288
codyrat wants to merge 3 commits intoterraform-aws-modules:masterfrom
codyrat:feature/add-gwlb-to-vpc-endpoints

Conversation

@codyrat
Copy link
Copy Markdown

@codyrat codyrat commented Mar 11, 2026

Description

feat: Allow subnet_ids to be passed for GatewayLoadBalancer endpoint type

The subnet_ids argument on aws_vpc_endpoint is valid for both Interface and GatewayLoadBalancer endpoint types, but the module currently only passes subnet_ids when service_type is Interface.

This PR updates the modules/vpc-endpoints/main.tf to include GatewayLoadBalancer in the list of types that receive subnet_ids:

# Before:
subnet_ids = try(each.value.service_type, "Interface") == "Interface" ? distinct(concat(var.subnet_ids, lookup(each.value, "subnet_ids", []))) : null

# After:
subnet_ids = contains(["Interface", "GatewayLoadBalancer"], try(each.value.service_type, "Interface")) ? distinct(concat(try(each.value.service_type, "Interface") == "Interface" ? var.subnet_ids : [], lookup(each.value, "subnet_ids", []))) : null

Key behavior:

  • Interface endpoints: unchanged — var.subnet_ids (module-level default) is concatenated with per-endpoint subnet_ids
  • GatewayLoadBalancer endpoints: now receive per-endpoint subnet_ids (module-level var.subnet_ids is excluded since GWLB endpoints are AZ-specific and should not inherit the shared default)
  • Gateway endpoints: unchanged — subnet_ids remains null

Motivation and Context

GatewayLoadBalancer VPC endpoints must be associated with a subnet in order to function. The AWS provider's aws_vpc_endpoint resource accepts subnet_ids for this type, but the module's conditional logic is silently setting subnet_ids = null. This caused GWLB endpoints to be created with no subnet attachment.

This is problematic for centralized inspection architectures where GWLB endpoints are created per-AZ in spoke VPCs and each endpoint must be placed in a specific subnet.

Breaking Changes

No breaking changes. The only behavioral difference is that GatewayLoadBalancer endpoints now correctly receive their per-endpoint subnet_ids. Existing configurations that do not use GatewayLoadBalancer endpoints are completely unaffected. Existing GatewayLoadBalancer endpoints that did not specify subnet_ids will continue to receive null (via lookup(each.value, "subnet_ids", [])).

How Has This Been Tested?

  • I have updated at least one of the examples/* to demonstrate and validate my change(s)
  • I have tested and validated these changes using one or more of the provided examples/* projects

Tested by deploying GWLB endpoints in a live AWS environment using this module with the following endpoint configuration:

endpoints = {
  "gwlb-cac1-1a" = {
    service_name = "com.amazonaws.vpce.ca-central-1.vpce-svc-..."
    service_type = "GatewayLoadBalancer"
    subnet_ids   = ["subnet-abc123"]
  }
  "gwlb-cac1-1b" = {
    service_name = "com.amazonaws.vpce.ca-central-1.vpce-svc-..."
    service_type = "GatewayLoadBalancer"
    subnet_ids   = ["subnet-def456"]
  }
}

Before the fix, the endpoints were created but with no subnet association. After the fix, each endpoint is correctly associated with its specified subnet.

  • I have executed pre-commit run -a on my pull request

Michael Dupuis added 2 commits March 11, 2026 17:51
…e with subnet_ids

A vpc-endpoint with type Interface is able to be associated with subnet_ids but GatewayLoadBalancer type is ignored.
auto_accept = try(each.value.auto_accept, null)

security_group_ids = try(each.value.service_type, "Interface") == "Interface" ? length(distinct(concat(local.security_group_ids, lookup(each.value, "security_group_ids", [])))) > 0 ? distinct(concat(local.security_group_ids, lookup(each.value, "security_group_ids", []))) : null : null
subnet_ids = try(each.value.service_type, "Interface") == "Interface" ? distinct(concat(var.subnet_ids, lookup(each.value, "subnet_ids", []))) : null
Copy link
Copy Markdown
Member

@bryantbiggs bryantbiggs Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can simply be:

Suggested change
subnet_ids = try(each.value.service_type, "Interface") == "Interface" ? distinct(concat(var.subnet_ids, lookup(each.value, "subnet_ids", []))) : null
subnet_ids = try(each.value.service_type, "Interface") != "Gateway" ? distinct(concat(var.subnet_ids, lookup(each.value, "subnet_ids", []))) : null

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this commit to the PR.

@github-actions
Copy link
Copy Markdown

This PR has been automatically marked as stale because it has been open 30 days
with no activity. Remove stale label or comment or this PR will be closed in 10 days

@github-actions github-actions bot added the stale label Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants