## Task 43 The Nautilus DevOps team has been tasked with preparing the infrastructure for a new Kubernetes-based application that will be deployed using Amazon EKS. The team is in the process of setting up an EKS cluster that meets their internal security and scalability standards. They require that the cluster be provisioned using the latest stable Kubernetes version to take advantage of new features and security improvements. To minimize external exposure, the EKS cluster endpoint must be kept private. Additionally, the cluster needs to use the default VPC with availability zones a, b, and c to ensure high availability across different physical locations. Your task is to create an EKS cluster named nautilus-eks, with Custom configuration, use IAM role for the cluster named eksClusterRole. Additionally, ensure that EKS Auto Mode is disabled and that the cluster endpoint access is set to private. Finally, verify that the EKS cluster is successfully created with the correct configuration and is ready for workloads. ### Solution # EKS Private Cluster Task (nautilus-eks) Version pinned: **latest EKS Kubernetes version is 1.36** (`1.36-eks-3` platform version, released June 2, 2026; EKS actively supports 1.36, 1.35, 1.34, 1.33). So `--kubernetes-version 1.36` — swap to 1.35 if the grader's env lags, but 1.36 is "latest stable." The concepts that matter for EKS: the cluster control plane needs an **IAM role it assumes** (trust principal `eks.amazonaws.com`, managed policy `AmazonEKSClusterPolicy`); the control plane spans **subnets in the AZs you pass** (task wants a/b/c for HA); and **"EKS Auto Mode disabled"** is an explicit flag now (Auto Mode is the newer AWS-manages-compute option — disabling it means classic control-plane-only). "Private endpoint" flips the API server's reachability so it's only reachable from inside the VPC. Run on `aws-client`. ## Phase 1 — Cluster IAM role ```bash REGION=us-east-1 cat > /tmp/eks-trust.json << 'EOF' {"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"eks.amazonaws.com"},"Action":"sts:AssumeRole"}]} EOF aws iam create-role --role-name eksClusterRole \ --assume-role-policy-document file:///tmp/eks-trust.json 2>/dev/null || true aws iam attach-role-policy --role-name eksClusterRole \ --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy ROLE_ARN=$(aws iam get-role --role-name eksClusterRole --query 'Role.Arn' --output text) ``` Trust principal is **`eks.amazonaws.com`** (the control-plane service, not `eks-tasks` or `ec2`). `AmazonEKSClusterPolicy` is the single managed policy the control plane needs to manage AWS resources on your behalf (ENIs, load balancers, etc.). ## Phase 2 — Gather default VPC subnets in AZs a, b, c ```bash VPC_ID=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true \ --region $REGION --query 'Vpcs[0].VpcId' --output text) # One subnet per AZ for us-east-1a/b/c SUBNET_A=$(aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$VPC_ID" "Name=availability-zone,Values=${REGION}a" \ --region $REGION --query 'Subnets[0].SubnetId' --output text) SUBNET_B=$(aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$VPC_ID" "Name=availability-zone,Values=${REGION}b" \ --region $REGION --query 'Subnets[0].SubnetId' --output text) SUBNET_C=$(aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$VPC_ID" "Name=availability-zone,Values=${REGION}c" \ --region $REGION --query 'Subnets[0].SubnetId' --output text) echo "subnets: $SUBNET_A $SUBNET_B $SUBNET_C" ``` EKS requires subnets in **at least two** AZs; the task asks for three (a/b/c) for higher availability. Explicitly filtering by AZ guarantees you land one subnet in each of the three, rather than accidentally grabbing two in the same AZ. ## Phase 3 — Create the cluster (private endpoint, Auto Mode off) ```bash aws eks create-cluster \ --name nautilus-eks \ --kubernetes-version 1.36 \ --role-arn "$ROLE_ARN" \ --resources-vpc-config "subnetIds=$SUBNET_A,$SUBNET_B,$SUBNET_C,endpointPublicAccess=false,endpointPrivateAccess=true" \ --compute-config enabled=false \ --kubernetes-network-config '{"elasticLoadBalancing":{"enabled":false}}' \ --storage-config '{"blockStorage":{"enabled":false}}' \ --access-config authenticationMode=API_AND_CONFIG_MAP \ --region $REGION # EKS control plane provisioning is SLOW (~10-15 min). Wait it out. # aws eks wait cluster-active --name nautilus-eks --region $REGION STATUS="" until [ "$STATUS" = "ACTIVE" ]; do STATUS=$(aws eks describe-cluster --name nautilus-eks --region $REGION \ --query 'cluster.status' --output text) echo "nautilus-eks: $STATUS" [ "$STATUS" = "ACTIVE" ] || sleep 30 done ``` The requirement-to-flag mapping — the important ones: - **`endpointPublicAccess=false,endpointPrivateAccess=true`** = the "private endpoint" requirement. This is the crux: the API server becomes reachable *only* from within the VPC, not the internet. Note the implication — you can no longer `kubectl` from outside the VPC after this; you'd need a bastion/VPN inside the VPC. That's the intended security posture. - **`--compute-config enabled=false`** + **`elasticLoadBalancing.enabled=false`** + **`blockStorage.enabled=false`** = **EKS Auto Mode disabled.** Auto Mode is the newer bundle where EKS auto-manages compute, load balancing, and storage; all three sub-toggles being `false` is what "Auto Mode disabled / Custom configuration" means. Setting `compute enabled=true` would flip Auto Mode on — the opposite of the task. - **`--kubernetes-version 1.36`** = latest stable. - **`--role-arn`** = the `eksClusterRole` from Phase 1. - **`--resources-vpc-config subnetIds=...`** = the three AZ subnets for HA. ## Verify ```bash aws eks describe-cluster --name nautilus-eks --region $REGION \ --query 'cluster.{Name:name,Status:status,Version:version,Role:roleArn, PublicAccess:resourcesVpcConfig.endpointPublicAccess, PrivateAccess:resourcesVpcConfig.endpointPrivateAccess, Subnets:resourcesVpcConfig.subnetIds}' ``` Want: `Status: ACTIVE`, `Version: 1.36`, `Role` ending in `eksClusterRole`, `PublicAccess: false`, `PrivateAccess: true`, and three subnet IDs. `ACTIVE` with those endpoint flags is the task's success condition — cluster up, private-only, correct role and version. ## Notes / gotchas - **Provisioning is the slowest wait in the whole AWS set** — EKS control plane takes ~10-15 minutes to go `CREATING → ACTIVE`. The `wait cluster-active` waiter (polls every 30s, generous timeout) covers it; don't submit while `CREATING`. - **Private-only endpoint means no external kubectl.** Once `endpointPublicAccess=false`, you can't reach the API server from `aws-client` unless `aws-client` is inside the VPC. That's expected for this task (it only asks the cluster be created + private + ACTIVE, not that you run workloads through it). - **Auto Mode flag names can drift** across CLI versions. If `--compute-config`/`--storage-config` are rejected by an older CLI, the console "Custom configuration" path with Auto Mode toggled off is the equivalent; or update the CLI. The intent is: compute/LB/storage auto-management all OFF. - **No node group here.** The task is control-plane only — it doesn't ask for worker nodes. A functioning cluster for workloads would need a managed node group or Fargate profile added after, but that's beyond this task's scope.