DEV Community

Honey Kiran
Honey Kiran

Posted on Originally published at honeykiran.substack.com on

OpsBites: Your ‘Private' EKS Cluster Still Bills Like a Public One

Hero image

The requirement arrives in one sentence, usually from security: “The cluster must not be reachable from the internet.”

Fine. Sensible, even. You turn off the public API endpoint, put the nodes in private subnets, and let the engineers in over the VPN. That part of private EKS works exactly as advertised, and AWS documents it well.

Then somebody — usually finance, usually a month later — asks what “private” costs. And the room goes quiet, because the honest answer is: privacy on AWS is not a setting. It’s a subscription.

Privacy on AWS is not a setting. It’s a subscription.

A thread on r/devops this week asked the classic version of the question: we run EKS inside a corporate environment, our network is on-premise, how do we connect to a private cluster? The connectivity answer is the easy half. Here’s the half that shows up on the invoice.

What ‘private’ changes — and what it doesn’t

With the public endpoint disabled, kubectl from the office reaches the API server privately, over VPN or Direct Connect. Nodes live in subnets with no route to the internet. Good. That’s the security posture everyone wanted.

But your cluster still talks to AWS all day long. Nodes register with EC2. Pods pull images from ECR. The autoscaler asks STS for tokens. Logs flow to CloudWatch. Load balancers get created. On a public cluster, those calls stroll out through the internet gateway and nobody thinks about them. In a private subnet there is no stroll. Every single one of those calls needs a private path you provision — a VPC endpoint — or it doesn’t happen at all.

AWS’s own doc for private EKS clusters lists the endpoints a limited-internet cluster needs. Count them with me: EC2, ECR api, ECR dkr, S3, Elastic Load Balancing, CloudWatch Logs, STS, EKS, EKS Auth, the OIDC endpoint, and Route 53. Eleven friends. Most of them are interface endpoints, and interface endpoints have a price list.

Diagram D1

The math nobody does in the design meeting

PrivateLink pricing, US regions: an interface endpoint costs $0.01 per hour, for every AZ you put it in , plus $0.01 per GB of data processed. Sounds like nothing. Now do the multiplication everyone skips.

Line itemThe mathStanding cost / month8 interface endpoints × 3 AZs8 × 3 × $0.01/hr≈ $175EKS control plane$0.10/hr≈ $733 NAT gateways (yes, still)3 × $0.045/hr, before data≈ $991 Application Load Balancer$0.0225/hr, before LCU≈ $16S3 gateway endpointgateway type — free$0 Total, before any data moves≈ $363

Diagram D2

Three details in that table deserve a stare:

The S3 endpoint is free — because it’s a gateway endpoint, not an interface one. No hourly charge, no per-GB charge. It’s the only free seat in the house, and it carries the heaviest traffic in the building, because ECR stores image layers in S3. Take it on day one, every time.

You still pay for NAT. Private doesn’t mean nothing ever leaves: package mirrors, external APIs, vendor webhooks. Whatever egress remains rides NAT gateways at $0.045/hr each plus $0.045 per GB — and a partial hour bills as a full one. One per AZ, because a single shared NAT is a cross-AZ fee machine and a quiet single point of failure.

ALB is cheap; NLB is cheaper; neither is free. $0.0225 an hour for either, with LCU charges on top — $0.008 per LCU-hour on the ALB, $0.006 on the NLB. Small numbers, permanent numbers.

Then the data starts moving

The hourly meter is the rent. The per-GB meter is the toll — and it punishes the lazy route. One terabyte of image pulls through a NAT gateway costs about $45 in processing fees alone. The same terabyte through endpoints costs about $10 — and because image layers actually stream out of S3, most of that weight rides the free gateway endpoint anyway. Endpoints in every AZ also keep the traffic local; let an endpoint live in one AZ while your nodes sit in another and you’ll meet cross-AZ transfer charges, the toll booth nobody remembers building.

Diagram D3

The honest middle

None of this argues against going private. Compliance is real, auditors are realer, and “the Kubernetes API was on the internet” is a sentence nobody wants in an incident report. The bite is narrower:

  • Price the privacy in the design doc , not in the first invoice review. $363 a month standing is nothing to a platform budget — unless nobody budgeted it, in which case it’s a surprise, and surprises are what actually get clusters decommissioned.

  • Codify the endpoints in Terraform from day one. Endpoints added later, by hand, during an outage, are how you end up with three of eleven and a mystery.

  • Dev clusters don’t need the full cathedral. Fewer AZs, a shared-endpoint strategy, a smaller footprint — the meter multiplies by AZs, so spend the multiplication where it matters.

Three traps that make it worse

  • Endpoints in one AZ only. Cheaper on the hourly line — until every node in the other two AZs routes its calls across, and the cross-AZ toll quietly eats the saving. It also builds a dependency nobody drew: one AZ hiccup away from pods that can’t pull images.

  • Forgetting the S3 gateway endpoint. Miss this one free line and ECR layer pulls — the fattest traffic in the cluster — detour through NAT at $0.045 a gigabyte. It’s the most expensive free thing you’ll ever forget to click.

  • Cathedral spec on dev clusters. Three AZs, eleven endpoints, full ceremony, for a cluster three people use to test Helm charts. The meter multiplies by AZs whether the cluster is production or a hobby with a pipeline.

Private was never going to be free. It just sends the bill in a shape the design meeting didn’t draw: every endpoint, times every AZ, forever. Draw it anyway — the architecture diagram and the invoice are the same picture, and you’re better off seeing it first.

Disclaimer

  • This post describes my personal experience with my own systems and accounts, in my own words. It is a first-person account of what I observed and what I do in my own work — not a statement of any company’s intentions, policies, or internal decisions. Where I do not know something, the post says so.

  • I am not affiliated with, endorsed by, or speaking for any company, product, or vendor named in this post. All product and company names are trademarks of their respective owners and are mentioned only to describe the experience accurately.

  • Any error messages, documentation excerpts, or figures quoted here are reproduced from my own records or from the public sources linked in the post, believed accurate at the time of writing. Product behavior changes over time; verify against current official documentation before relying on any detail.

  • Nothing in this post is professional, financial, legal, or security advice for your specific situation. Examples are illustrative — validate in your own environment before running anything in production.

  • Corrections are welcome. If any company named here publishes an official statement, or if any detail is wrong, I will update this post and note the correction. The goal is an accurate public record, not a verdict.


Examples in this post are illustrative unless marked as documented patterns. Pricing figures are the providers’ published US list prices and vary by region — verify against the current pricing pages before budgeting.

© 2026 Honey Kiran

Tags: Kubernetes · Amazon EKS · AWS · VPC · DevOps

Top comments (0)