Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions examples/pod-identity/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ module "eks" {
endpoint_public_access = true

# So the Terraform runner can create kubernetes_namespace, kubernetes_service_account, kubernetes_deployment
enable_cluster_creator_admin_permissions = true
access_entries = var.access_entries
access_entries = var.access_entries

# Required when using Pod Identity: enable eks-pod-identity-agent addon
addons = {
Expand Down
2 changes: 1 addition & 1 deletion examples/pod-identity/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ variable "aws_region" {
variable "cluster_name" {
description = "Name of the EKS cluster"
type = string
default = "eks-pod-identity-example"
default = "cltest"
}

variable "cluster_version" {
Expand Down
123 changes: 123 additions & 0 deletions examples/private-endpoint/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions examples/private-endpoint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Private API endpoint example

This example creates an EKS cluster with **private API only** (`endpoint_public_access = false`): VPC, EKS, and VPC interface endpoints for the EKS AWS API (PrivateLink). Route 53 and custom DNS are not included; use your own DNS or the default EKS endpoint hostname from a network that can reach the private endpoint.

## Private endpoint

The cluster has no public API endpoint. Terraform and Helm in this example use `module.eks.cluster_endpoint`; they must run from a network that can reach the private API (e.g. VPN into the VPC).

## EKS API PrivateLink (interface endpoints)

The example enables the VPC module’s **EKS API** and **EKS Auth** interface endpoints (`enable_eks_endpoint = true`, `enable_eks_auth_endpoint = true`) per [Access Amazon EKS using AWS PrivateLink](https://docs.aws.amazon.com/eks/latest/userguide/vpc-interface-endpoints.html). Those endpoints allow **EKS API actions** (Terraform, AWS CLI, SDK) from inside the VPC without internet. They **do not** provide access to the **Kubernetes API** (kubectl); kubectl uses the cluster endpoint. Private DNS is enabled in the VPC so `eks.<region>.amazonaws.com` resolves via the endpoint. [AWS PrivateLink pricing](https://aws.amazon.com/privatelink/pricing/) applies. To omit the EKS Auth endpoint, set `enable_eks_auth_endpoint = false` in the VPC module call.

## How to connect (private-only)

Prerequisites: a path into the VPC (e.g. VPN) and DNS so the cluster API hostname resolves to the **private** endpoint IP (e.g. VPC DNS when on VPN, or your own private zone).

### 1. Get kubeconfig

From a machine that can reach the private API (e.g. laptop on VPN):

```bash
aws eks update-kubeconfig --region <region> --name <cluster_name>
```

### 2. Use the default API server or your own DNS

- **Default hostname**: If your DNS (e.g. VPC Resolver when on VPN) resolves the EKS endpoint hostname to the private IP, use the kubeconfig as-is. TLS works because the certificate matches `*.eks.<region>.amazonaws.com`.
- **Custom hostname**: If you use a custom FQDN for the API (your own DNS), set the cluster `server` in `~/.kube/config` to `https://<your-fqdn>` and add `insecure-skip-tls-verify: true` for that cluster (the EKS cert does not match custom names).

Then run `kubectl get nodes` (with AWS credentials if needed, e.g. `aws-vault exec dev -- kubectl get nodes`) to confirm API access.

## Usage

- Run `terraform init`, `terraform plan`, `terraform apply`.
- Connect from a network that can reach the private endpoint (e.g. VPN). Use `cluster_endpoint` or `cluster_endpoint_hostname` outputs if needed.
117 changes: 117 additions & 0 deletions examples/private-endpoint/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
terraform {
required_version = ">= 1.6.0"

required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 6.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.30"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.13"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}

provider "aws" {
region = var.aws_region
}

provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = module.eks.cluster_ca_certificate
token = module.eks.cluster_auth_token
}

provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = module.eks.cluster_ca_certificate
token = module.eks.cluster_auth_token
}
}

module "vpc" {
source = "cloudbuildlab/vpc/aws"

vpc_name = var.cluster_name
vpc_cidr = "10.0.0.0/16"
availability_zones = ["${var.aws_region}a", "${var.aws_region}b"]

public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.101.0/24", "10.0.102.0/24"]

create_igw = true
nat_gateway_type = "single"

enable_eks_tags = true
eks_cluster_name = var.cluster_name
enable_eks_endpoint = true
enable_eks_auth_endpoint = true

tags = var.tags
}

module "eks" {
source = "../../"

name = var.cluster_name
kubernetes_version = var.cluster_version
vpc_id = module.vpc.vpc_id
subnet_ids = concat(module.vpc.public_subnet_ids, module.vpc.private_subnet_ids)

endpoint_public_access = false

access_entries = var.access_entries

addons = {
coredns = {
addon_version = "v1.13.2-eksbuild.1"
}
kube-proxy = {
addon_version = "v1.35.0-eksbuild.2"
}
vpc-cni = {
before_compute = true
addon_version = "v1.21.1-eksbuild.3"
configuration_values = jsonencode({
enableNetworkPolicy = "true"
nodeAgent = {
enablePolicyEventLogs = "true"
}
})
}
}

eks_managed_node_groups = {
one = {
name = "node-group-1"
ami_type = "AL2023_x86_64_STANDARD"
instance_types = ["t3a.small"]

min_size = 1
max_size = 2
desired_size = 1

metadata_options = {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
}
}
}

cloudwatch_log_group_force_destroy = true

depends_on = [
module.vpc
]
}
26 changes: 26 additions & 0 deletions examples/private-endpoint/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# VPC Outputs
output "vpc_id" {
description = "ID of the VPC"
value = module.vpc.vpc_id
}

# EKS Cluster Outputs
output "cluster_name" {
description = "Name of the EKS cluster"
value = module.eks.cluster_name
}

output "cluster_endpoint" {
description = "Endpoint for EKS control plane"
value = module.eks.cluster_endpoint
}

output "cluster_endpoint_hostname" {
description = "EKS API hostname (no scheme) for kubeconfig or custom DNS"
value = replace(module.eks.cluster_endpoint, "https://", "")
}

output "cluster_version" {
description = "Kubernetes version of the EKS cluster"
value = module.eks.cluster_version
}
45 changes: 45 additions & 0 deletions examples/private-endpoint/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
variable "aws_region" {
description = "AWS region for resources"
type = string
default = "ap-southeast-2"
}

variable "cluster_name" {
description = "Name of the EKS cluster"
type = string
default = "cltest"
}

variable "cluster_version" {
description = "Kubernetes version for the EKS cluster"
type = string
default = "1.35"
}

variable "access_entries" {
description = "Map of access entries to add to the cluster"
type = map(object({
kubernetes_groups = optional(list(string))
principal_arn = string
type = optional(string, "STANDARD")
user_name = optional(string)
tags = optional(map(string), {})
policy_associations = optional(map(object({
policy_arn = string
access_scope = object({
namespaces = optional(list(string))
type = string
})
})), {})
}))
default = {}
}

variable "tags" {
description = "Map of tags to apply to all resources"
type = map(string)
default = {
Environment = "dev"
ManagedBy = "terraform"
}
}