EKS private cluster endpoints are the only way to securely expose your EKS API server to your VPC, preventing public internet access.

Let’s see this in action. Imagine you have a freshly created EKS cluster, and you want to ensure its API endpoint is only accessible from within your VPC.

First, let’s get the details of an existing EKS cluster. If you don’t have one, you can create a new one with private access enabled.

aws eks describe-cluster --name my-eks-cluster --query "cluster.resourcesVpcConfig.endpointPublicAccess"

If this returns false, you’ve already got a private endpoint. If it returns true, your API server is currently accessible from the public internet, and you’ll want to change that.

To create a new EKS cluster with a private endpoint, you’d use the eksctl command like this:

eksctl create cluster \
  --name my-private-cluster \
  --region us-west-2 \
  --version 1.29 \
  --vpc-private-subnets subnet-0123456789abcdef0,subnet-0fedcba9876543210 \
  --vpc-public-subnets "" \
  --enable-private-endpoint \
  --associate-iam-oidc-provider

The key here is --enable-private-endpoint. This tells EKS to not provision a public IP for the API server. You also need to provide --vpc-private-subnets and explicitly leave --vpc-public-subnets empty or omit it to ensure only private subnets are used for the cluster’s control plane ENIs.

Once your cluster is set up with a private endpoint, you’ll need to configure your kubectl to access it. This involves updating your kubeconfig file. If you’re running kubectl from an EC2 instance within the same VPC (or a peered VPC), you can use the private endpoint address.

First, get the cluster details to find the private endpoint:

aws eks describe-cluster --name my-private-cluster --query "cluster.resourcesVpcConfig.endpointPrivateAccess"

This will give you the private endpoint URL. Now, you need to ensure your kubectl context points to this private endpoint. If you’re using aws eks update-kubeconfig, it should automatically pick up the private endpoint if your IAM credentials have permissions to access it from your current network location.

aws eks update-kubeconfig --name my-private-cluster --region us-west-2

If you manually edit your kubeconfig, you’ll find a server entry like this:

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <CA_DATA>
    server: https://<PRIVATE_ENDPOINT_URL>:443
  name: my-private-cluster

The server field should contain the private endpoint URL.

The primary benefit of a private endpoint is enhanced security. By default, EKS API servers are publicly accessible. This means anyone with the cluster endpoint can attempt to connect to your control plane. With a private endpoint, access is restricted to IP addresses within your VPC. This is crucial for compliance and for protecting your cluster from unauthorized access attempts originating from the public internet.

To manage access to your private endpoint, you’ll leverage VPC network access controls. This includes Security Groups associated with the cluster’s control plane ENIs and Network Access Control Lists (NACLs) on your subnets. For example, you might have a security group allowing inbound traffic on port 443 from specific security groups (e.g., the security group of your EC2 bastion host or worker nodes).

# Example Security Group rule for the cluster's control plane ENI
# (This would be managed by EKS, but you'd ensure your worker nodes/bastion SG
# has inbound 443 access to the cluster's SG)

If you need to access a private cluster endpoint from outside your VPC (e.g., from your on-premises network or your local machine), you’ll need to establish a VPN connection or use AWS Direct Connect. You would then configure your local machine’s DNS or /etc/hosts file to resolve the cluster endpoint to the private IP address reachable through your VPN or Direct Connect. Alternatively, you can use a bastion host within the VPC.

The most surprising aspect is that even with a private endpoint enabled, EKS still creates a public DNS entry for the cluster endpoint. However, this public DNS entry will resolve to an IP address that is only routable within your VPC. This can be a point of confusion if you’re expecting the public DNS name to simply disappear. The actual accessibility is determined by the underlying IP address and your VPC’s routing configuration.

This setup is essential for a zero-trust network architecture within AWS. By isolating your control plane, you significantly reduce the attack surface.

The next challenge you’ll encounter is reliably accessing this private endpoint from your CI/CD pipelines, which often run outside your VPC.

Want structured learning?

Take the full Eks course →