Skip to content

[terraform-aws] Support bring-your-own VPC and private EKS API endpoint - #1767

Open
timothy-cloudopsguy wants to merge 4 commits into
interuss:masterfrom
CAL-Analytics:BYOVPC
Open

timothy-cloudopsguy wants to merge 4 commits into
interuss:masterfrom
CAL-Analytics:BYOVPC

Conversation

@timothy-cloudopsguy

@timothy-cloudopsguy timothy-cloudopsguy commented Oct 8, 2026 •

Copy link
Copy Markdown

Summary

Adds an option to deploy the DSS EKS cluster into an existing VPC with the application and Kubernetes control plane running on private subnets. By default nothing changes: existing deployments keep the Terraform-managed VPC and public endpoint.

When using private subnets, the application running on Kubernetes is still accessible via the NLB/ALB, it just points internally. The Kubernetes cluster and api endpoints are not accessible outside of the private subnets.

⚠️ Network access requirement

With use_public_subnets = false, the EKS API server is only reachable from inside the VPC. Terraform runs kubectl, Helm and Tanka against the cluster, so the machine running Terraform must either:

  • be connected to the VPC's private subnets over a VPN, or
  • be an EC2 instance (or CI runner) inside the VPC, or in a peered or Transit Gateway-attached network.

Otherwise the cluster is created and then the first Kubernetes or Helm step fails with the API endpoint unreachable (dial tcp …: i/o timeout). The control-plane security group allows the VPC's CIDR range. If you connect from a different range (for example a VPN client pool or a peered VPC), add an ingress rule for it.

New variables (terraform-aws-dss)

Variable Default Purpose
vpc_id "" Existing VPC to deploy into. If blank, a new VPC is created as before.
private_subnet_ids [] At least 2 subnets (in different AZs) for the EKS cluster and nodes.
public_subnet_ids [] At least 1 subnet for the internet-facing NLBs.
use_public_subnets true Turns the EKS public API endpoint on or off. The private endpoint is always on.

Defined in utils/definitions/ and generated into variables.gen.tf / TFVARS.gen.md.

Changes

  • VPC resources are optional: the VPC, subnets, internet gateway and routes are only created when vpc_id is blank. moved {} blocks keep existing state addresses working.
  • Subnet tags: subnets you bring are tagged for the AWS Load Balancer Controller. Private subnets get role/internal-elb, public subnets get role/elb, and both get kubernetes.io/cluster/<name>=shared.
  • Load balancer subnets: NLBs are placed in the new metadata.public_subnet (Terraform output → terraform-commons-dss → Tanka). It falls back to subnet, so existing Tanka setups are unaffected.
  • Control-plane security group: now attached to the EKS cluster. Ingress allows 0.0.0.0/0 when the endpoint is public, or the VPC's CIDR range when it's private.
  • Preconditions: the plan stops with a clear error for settings that can't work:
    • a new VPC combined with a private-only endpoint (nothing could reach it);
    • your own VPC without enough subnets.

Upgrade impact (existing deployments, default settings)

No VPC or subnet resources are replaced. Expect these in-place changes:

  • eks-controlplane security group attached to the cluster's vpc_config, plus a new ingress rule
  • endpoint_private_access: false → true

Example (terraform.tfvars)

use_public_subnets = false
vpc_id             = "vpc-0123…"
private_subnet_ids = ["subnet-aaa…", "subnet-bbb…"]
public_subnet_ids  = ["subnet-ccc…", "subnet-ddd…"]
Testing
- terraform fmt -check and terraform validate (modules/terraform-aws-dss)
- tk eval deploy/services/tanka/examples/minimum
- terraform plan on an existing deployment with default settings: only the in-place changes listed above
- Fresh deploy with your own VPC and a private endpoint from an EC2 instance inside the VPC
- Fresh deploy with your own VPC and a private endpoint over a VPN
- NLBs provision in the public subnets and are reachable from outside

@linux-foundation-easycla

linux-foundation-easycla Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: timothy-cloudopsguy / name: Timothy Welch (0783e19, 2fb103b)

@timothy-cloudopsguy
timothy-cloudopsguy marked this pull request as draft October 10, 2026 14:03
@timothy-cloudopsguy
timothy-cloudopsguy marked this pull request as ready for review October 19, 2026 15:33

@the-glu the-glu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the PR, first partial review

'service.beta.kubernetes.io/aws-load-balancer-scheme': 'internet-facing',
'service.beta.kubernetes.io/aws-load-balancer-eip-allocations': std.join(',', ipNames),
'service.beta.kubernetes.io/aws-load-balancer-subnets': metadata.subnet,
'service.beta.kubernetes.io/aws-load-balancer-subnets': metadata.public_subnet,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The same change need to be done for helm as well to put LB in correct subnets no?

public_access_cidrs = [
"0.0.0.0/0"
]
subnet_ids = local.vpc_id == "" ? aws_subnet.dss[*].id : var.private_subnet_ids

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I tried a fresh deployment with old config and it's failling

│ Error: Not enough list items
│ 
│   with module.terraform-aws-kubernetes.aws_eks_cluster.kubernetes_cluster,
│   on ../../dependencies/terraform-aws-kubernetes/cluster.tf line 6, in resource "aws_eks_cluster" "kubernetes_cluster":
│    6:     subnet_ids              = local.vpc_id == "" ? aws_subnet.dss[*].id : var.private_subnet_ids
│ 
│ Attribute vpc_config.0.subnet_ids requires 1 item minimum, but config has only 0 declared.

I think that because local.vpc_id cannot be empty and therefor always try to use private_subnet_ids - it should be var.local_vpc no?

description = var.use_public_subnets ? "Allow traffic from the internet" : "Allow traffic from the VPC"
type = "ingress"
from_port = 0
to_port = 65535

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why open everything where as only port 443 is needed for the API ? I do have the feeling that too large.

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.

to be fair, the security group as it is today is only created and never attached to anything, so it's doing no better or worse? :-) But I agree, scope it down to the minimum is best. I guess I wasn't sure what that minimum was since it was not attached and used before.

}

resource "aws_security_group_rule" "eks-controlplane-ingress" {
description = var.use_public_subnets ? "Allow traffic from the internet" : "Allow traffic from the VPC"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In public mode, why is that needed? It's handeled by public_access_cidrs no?

# This is the subnet where Kubernetes workload will be running.
data "aws_subnet" "main_subnet" {
id = aws_subnet.dss[0].id
# If a VPC ID is provided, we need to retrieve the subnets from the existing VPC, and add the tags to the existing subnets

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This will change subnet that are not managed by the chart - shouldn't it be done externally to avoid multiple source of management for those?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants