<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Phu Hoang</title>
    <description>The latest articles on Forem by Phu Hoang (@posibble).</description>
    <link>https://forem.com/posibble</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2579967%2Fa483120c-9617-420e-970f-73195a7368e8.png</url>
      <title>Forem: Phu Hoang</title>
      <link>https://forem.com/posibble</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/posibble"/>
    <language>en</language>
    <item>
      <title>Amazon EKS From The Ground Up - Part 2: Worker Nodes with AWS Managed Nodes</title>
      <dc:creator>Phu Hoang</dc:creator>
      <pubDate>Sat, 10 Jan 2026 08:03:00 +0000</pubDate>
      <link>https://forem.com/posibble/amazon-eks-from-the-ground-up-part-2-worker-nodes-in-aws-managed-nodes-way-en-1lhh</link>
      <guid>https://forem.com/posibble/amazon-eks-from-the-ground-up-part-2-worker-nodes-in-aws-managed-nodes-way-en-1lhh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://dev.to/posibble/amazon-eks-from-the-ground-up-part-1-control-plane-infrastructure-47pf"&gt;&lt;strong&gt;Part 1&lt;/strong&gt;&lt;/a&gt;, we successfully finished building the EKS &lt;strong&gt;Control Plane&lt;/strong&gt;, we set up the VPC, Subnets, NAT Gateway, the Kubernetes API Server, and configured &lt;code&gt;kubectl&lt;/code&gt; connectivity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC, Subnets, NAT&lt;/li&gt;
&lt;li&gt;Kubernetes API Server&lt;/li&gt;
&lt;li&gt;An IAM role with enough permissions for the Control Plane&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; already connected to the cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you’ll see… &lt;strong&gt;nothing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That’s the real state of the cluster we created: it has a &lt;strong&gt;brain (Control Plane)&lt;/strong&gt;, but no &lt;strong&gt;hands and feet (Worker Nodes)&lt;/strong&gt;. Without compute capacity, the Kubernetes Scheduler can only stare at Pods stuck in the &lt;code&gt;Pending&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;In this Part 2, we’ll “grow limbs” for your EKS cluster by deploying Worker Nodes using &lt;strong&gt;AWS Managed Nodes&lt;/strong&gt; - the most practical middle ground between production readiness and operational effort.&lt;/p&gt;

&lt;p&gt;This post won’t stop at “click and it works.” We’ll also explore what AWS quietly builds for you in a Managed Node Group, and contrast it with the &lt;strong&gt;Self-managed&lt;/strong&gt; way so you understand the fundamentals and can debug with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  📝A Quick Primer on Worker Nodes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is a Worker Node, really?
&lt;/h3&gt;

&lt;p&gt;In the most accurate - and simplest - definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Worker Node is an EC2 instance configured to run Kubernetes workloads (Pods).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At minimum, every worker node runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubelet&lt;/code&gt; — the agent that talks to the Kubernetes API Server&lt;/li&gt;
&lt;li&gt;a container runtime — typically &lt;code&gt;containerd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kube-proxy&lt;/code&gt; — manages service/network rules&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS VPC CNI&lt;/strong&gt; — the plugin that allocates Pod IPs from your VPC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Following production best practices, EKS worker nodes usually live inside &lt;strong&gt;private subnets&lt;/strong&gt; without public IPs. That significantly reduces exposure: workloads are not directly reachable from the Internet, and outbound connectivity is handled through a &lt;strong&gt;NAT Gateway&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Worker Node Deployment Models
&lt;/h3&gt;

&lt;p&gt;AWS offers three main ways to run compute for EKS, each with a different balance of control, operational cost, and “serverless-ness”:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Managed Nodes&lt;/th&gt;
&lt;th&gt;Self-managed Nodes&lt;/th&gt;
&lt;th&gt;AWS Fargate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;EC2 Instances (partly managed by AWS)&lt;/td&gt;
&lt;td&gt;EC2 Instances (fully managed by you)&lt;/td&gt;
&lt;td&gt;Serverless (no nodes to manage)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational cost (OpEx)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Billing&lt;/td&gt;
&lt;td&gt;Per EC2 instance&lt;/td&gt;
&lt;td&gt;Per EC2 instance&lt;/td&gt;
&lt;td&gt;Per Pod (CPU/Mem)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fargate hides almost everything—including the “node layer.” That’s convenient, but if your goal is to understand EKS fundamentals, the interesting engineering happens in Managed Nodes vs Self-managed Nodes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;Managed Nodes (Managed Node Group)&lt;/th&gt;
&lt;th&gt;Self-managed Nodes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node creation&lt;/td&gt;
&lt;td&gt;EKS Console or CLI command creates a Node Group&lt;/td&gt;
&lt;td&gt;EC2 Launch Template + ASG +  User Data (bootstrap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASG management&lt;/td&gt;
&lt;td&gt;AWS manages the Auto Scaling Group lifecycle&lt;/td&gt;
&lt;td&gt;You manage the ASG entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cluster Join&lt;/td&gt;
&lt;td&gt;AWS automatically handles the wiring and credentials for join&lt;/td&gt;
&lt;td&gt;You must provide user data calling &lt;code&gt;/etc/eks/bootstrap.sh&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node auth mapping (IAM→ RBAC)&lt;/td&gt;
&lt;td&gt;AWS typically maps the Node Role automatically&lt;/td&gt;
&lt;td&gt;You must manually update &lt;code&gt;aws-auth&lt;/code&gt; to map the Node Role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upgrades/Updates&lt;/td&gt;
&lt;td&gt;Built-in, managed rolling update workflows&lt;/td&gt;
&lt;td&gt;You design and manage &lt;code&gt;drain&lt;/code&gt; / &lt;code&gt;replace&lt;/code&gt; strategies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug level&lt;/td&gt;
&lt;td&gt;Fewer common traps, higher abstraction&lt;/td&gt;
&lt;td&gt;More control, but more responsibility for low-level configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What AWS does for you in a Managed Node Group
&lt;/h3&gt;

&lt;p&gt;When you click &lt;strong&gt;Create Node Group&lt;/strong&gt;, AWS typically handles a long checklist that Self-managed nodes would require you to build manually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creates an &lt;strong&gt;Auto Scaling Group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Picks an &lt;strong&gt;EKS-Optimized AMI&lt;/strong&gt; compatible with your cluster version&lt;/li&gt;
&lt;li&gt;Creates/manages a &lt;strong&gt;Launch Template&lt;/strong&gt; (or uses one you provide)&lt;/li&gt;
&lt;li&gt;Attaches an &lt;strong&gt;IAM Instance Profile&lt;/strong&gt; using your Node IAM Role&lt;/li&gt;
&lt;li&gt;Injects the bootstrap configuration so nodes can join the cluster&lt;/li&gt;
&lt;li&gt;Automates the node registration path&lt;/li&gt;
&lt;li&gt;Provides a &lt;strong&gt;rolling update workflow&lt;/strong&gt; for node group upgrades&lt;/li&gt;
&lt;li&gt;Typically handles node role mapping into the cluster auth mechanism&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Recommendation: Use Managed Nodes for most production setups to reduce operational overhead. Choose Self-managed only when you have very specific requirements (custom OS hardening, special bootstrap, deep control of the node lifecycle).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Cluster IAM Role vs Node IAM Role
&lt;/h3&gt;

&lt;p&gt;This is one of the most common points of confusion, so let’s make it crystal clear.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cluster IAM Role
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Used by the &lt;strong&gt;EKS Control Plane&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Allows the Control Plane to manage ENIs and interact with your VPC resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This role is &lt;strong&gt;not&lt;/strong&gt; meant for workloads.&lt;/p&gt;

&lt;h4&gt;
  
  
  Node IAM Role
&lt;/h4&gt;

&lt;p&gt;Worker nodes need a Node IAM Role to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join the cluster&lt;/li&gt;
&lt;li&gt;Allow the VPC CNI to attach ENIs and allocate Pod IPs&lt;/li&gt;
&lt;li&gt;Pull images from ECR&lt;/li&gt;
&lt;li&gt;Access other required AWS APIs (later: secrets, parameters, logs, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your worker nodes won’t become &lt;code&gt;Ready&lt;/code&gt; without (at least) these managed policies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Policy&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEKSWorkerNodePolicy.html" rel="noopener noreferrer"&gt;&lt;code&gt;AmazonEKSWorkerNodePolicy&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Join cluster, talk to the API Server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEKS_CNI_Policy.html" rel="noopener noreferrer"&gt;&lt;code&gt;AmazonEKS_CNI_Policy&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Attach ENIs, allocate Pod IPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEC2ContainerRegistryReadOnly.html" rel="noopener noreferrer"&gt;&lt;code&gt;AmazonEC2ContainerRegistryReadOnly&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Pull images from ECR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  AWS IAM &amp;amp; Kubernetes Authentication
&lt;/h3&gt;

&lt;p&gt;Access to an EKS cluster is a combination of two layers: &lt;strong&gt;AWS IAM&lt;/strong&gt; &amp;amp; &lt;strong&gt;Kubernetes RBAC&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  IAM = Authentication
&lt;/h4&gt;

&lt;p&gt;IAM answers: &lt;strong&gt;“Who are you?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a principal (an EC2 node or a human user) calls the Kubernetes API Server, EKS uses IAM authentication to verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which IAM principal (Role/User) the request comes from&lt;/li&gt;
&lt;li&gt;Whether the request has a valid SigV4 signature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ This is why worker nodes must have a proper Node IAM Role attached.&lt;/p&gt;

&lt;h4&gt;
  
  
  Kubernetes RBAC = Authorization
&lt;/h4&gt;

&lt;p&gt;RBAC answers: &lt;strong&gt;“What are you allowed to do?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even if IAM authentication succeeds, the API call can still fail with &lt;code&gt;Forbidden&lt;/code&gt; if RBAC doesn’t grant the required permissions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bridging the two worlds: mapping IAM → Kubernetes identity
&lt;/h4&gt;

&lt;p&gt;After IAM authentication, EKS maps IAM identity into Kubernetes users/groups so RBAC can evaluate permissions. Two common mechanisms exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;aws-auth ConfigMap&lt;/strong&gt; (classic, still widely used), example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mapRoles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;- rolearn: arn:aws:iam::&amp;lt;account-id&amp;gt;:role/EKSNodeRole&lt;/span&gt;
    &lt;span class="s"&gt;username: system:node:{{EC2PrivateDNSName}}&lt;/span&gt;
    &lt;span class="s"&gt;groups:&lt;/span&gt;
      &lt;span class="s"&gt;- system:bootstrappers&lt;/span&gt;
      &lt;span class="s"&gt;- system:nodes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;EKS Access Entries / Access Policies&lt;/strong&gt; (newer Console-based approach)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Nodes&lt;/strong&gt; must be mapped into groups like &lt;code&gt;system:bootstrappers&lt;/code&gt; and &lt;code&gt;system:nodes&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Humans/admins&lt;/strong&gt; are commonly mapped to &lt;code&gt;system:masters&lt;/code&gt; or granted an equivalent Access Policy&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hands-on Time
&lt;/h2&gt;

&lt;p&gt;The AWS architecture after completing the steps below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15xyqwg5xsilfrfuvwve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F15xyqwg5xsilfrfuvwve.png" alt="part_2_aws_architecture.png" width="800" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 0 — Preparation
&lt;/h3&gt;

&lt;p&gt;Make sure all resources from Part 1 are created correctly and your cluster is &lt;code&gt;ACTIVE&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Create the IAM Role for Worker Nodes
&lt;/h3&gt;

&lt;p&gt;Open the AWS Console:&lt;/p&gt;

&lt;p&gt;→ Go to &lt;strong&gt;IAM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Choose &lt;strong&gt;Roles&lt;/strong&gt; → &lt;strong&gt;Create role&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Configure &lt;strong&gt;Trusted entity&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trusted entity type: &lt;strong&gt;AWS service&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Service or use case: &lt;strong&gt;EC2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use case: &lt;strong&gt;EC2&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb75z1neletp23m4ijeox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb75z1neletp23m4ijeox.png" alt="part_2_IAM_Role_create_step_1.png" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Click &lt;strong&gt;Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Attach policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AmazonEKSWorkerNodePolicy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AmazonEKS_CNI_Policy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AmazonEC2ContainerRegistryReadOnly&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Role name: &lt;code&gt;EKSNodeRole&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Create role&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5exsoblbo20litvd46o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5exsoblbo20litvd46o.png" alt="part_2_IAM_Role_create_step_3.png" width="800" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Create a Managed Node Group
&lt;/h3&gt;

&lt;p&gt;→ Open the &lt;strong&gt;EKS&lt;/strong&gt; service&lt;/p&gt;

&lt;p&gt;→ Select cluster &lt;code&gt;demo-eks-cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Go to &lt;strong&gt;Compute&lt;/strong&gt; → &lt;strong&gt;Add node group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb50cnftd7fl7zey42p26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb50cnftd7fl7zey42p26.png" alt="part_2_eks_compute_add.png" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure node group
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;eks-mng-general&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Node IAM role: &lt;code&gt;EKSNodeRole&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffnxs5h7hi41lweoptn2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffnxs5h7hi41lweoptn2.png" alt="part_2_eks_add_node_group_step_1.png" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure compute &amp;amp; scaling
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;AMI type: &lt;strong&gt;EKS optimized&lt;/strong&gt; (Amazon Linux / Bottlerocket)&lt;/li&gt;
&lt;li&gt;Capacity type: &lt;strong&gt;On-Demand&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Instance type: &lt;code&gt;t3.medium&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Disk size: 20 GiB&lt;/li&gt;
&lt;li&gt;Scaling:

&lt;ul&gt;
&lt;li&gt;Desired: 2&lt;/li&gt;
&lt;li&gt;Min: 1&lt;/li&gt;
&lt;li&gt;Max: 3&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;→ Keep other settings as default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftisi3i2bmwqaa8mdrldb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftisi3i2bmwqaa8mdrldb.png" alt="part_2_eks_add_node_group_step_2.png" width="800" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Configure networking
&lt;/h4&gt;

&lt;p&gt;Select &lt;strong&gt;only the two private subnets&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is critical: subnet selection here determines where your worker nodes live. Private subnets are ideal for production worker nodes because they don’t expose instances to the Internet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq0cz5fonl5iyn8rtzk5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxq0cz5fonl5iyn8rtzk5.png" alt="part_2_eks_add_node_group_step_3.png" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Next&lt;/strong&gt; → &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Wait until the node group status becomes &lt;strong&gt;Active&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wf3fbu839xqmrmygf8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8wf3fbu839xqmrmygf8p.png" alt="part_2_eks_node_group_active.png" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 - Join the Cluster - AWS handles it
&lt;/h3&gt;

&lt;p&gt;You don’t need to manually configure bootstrap steps for a Managed Node Group - but understanding the join flow is what makes you effective at troubleshooting.&lt;/p&gt;

&lt;h4&gt;
  
  
  3.1 Node join flow
&lt;/h4&gt;

&lt;p&gt;When you create a Managed Node Group, AWS launches EC2 worker nodes. Each instance gets an &lt;strong&gt;Instance Profile&lt;/strong&gt; containing your &lt;strong&gt;Node IAM Role&lt;/strong&gt; (&lt;code&gt;EKSNodeRole&lt;/code&gt;). The join flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The EC2 instance boots using an EKS-Optimized AMI&lt;/li&gt;
&lt;li&gt;Bootstrap config provides &lt;code&gt;kubelet&lt;/code&gt; with:

&lt;ul&gt;
&lt;li&gt;cluster name&lt;/li&gt;
&lt;li&gt;API endpoint&lt;/li&gt;
&lt;li&gt;cluster CA certificate&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubelet&lt;/code&gt; calls the Kubernetes API Server to register the node&lt;/li&gt;
&lt;li&gt;EKS performs &lt;strong&gt;IAM authentication&lt;/strong&gt; and identifies the IAM Role from the instance profile&lt;/li&gt;
&lt;li&gt;EKS maps IAM identity → Kubernetes identity via &lt;strong&gt;aws-auth / Access Entries&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;If mapping is valid (node is in &lt;code&gt;system:nodes&lt;/code&gt;), the node becomes &lt;strong&gt;Ready&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short: nodes don’t “join by Kubernetes magic.” They join because:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;IAM authentication proves identity + Kubernetes group mapping allows the node role to function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3.2 What Managed Node Group eliminates compared to Self-managed
&lt;/h4&gt;

&lt;p&gt;With Self-managed nodes, you must build the join path yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Launch Template (AMI, instance profile, user data)&lt;/li&gt;
&lt;li&gt;Ensure bootstrap via &lt;code&gt;/etc/eks/bootstrap.sh &amp;lt;cluster-name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create ASG and subnet placement&lt;/li&gt;
&lt;li&gt;Manually update &lt;code&gt;aws-auth&lt;/code&gt; to map the node role into:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;system:bootstrappers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;system:nodes&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Managed Node Groups remove most of this plumbing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Verify
&lt;/h3&gt;

&lt;p&gt;This is the moment your EKS cluster finally starts to feel alive.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1 Verify with kubectl
&lt;/h4&gt;

&lt;p&gt;→ Open a terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes &lt;span class="nt"&gt;-o&lt;/span&gt; wide
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;→ Then check system pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; kube-system

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You should see &lt;strong&gt;two nodes&lt;/strong&gt; (based on desired size), in &lt;code&gt;Ready&lt;/code&gt; state&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;coredns&lt;/code&gt;, &lt;code&gt;metrics-server&lt;/code&gt;, and &lt;code&gt;kube-proxy&lt;/code&gt; should transition to &lt;code&gt;Running&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwhce8dpvqhww2p50aqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgwhce8dpvqhww2p50aqz.png" alt="part_2_verify_kubectl.png" width="800" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4.2 What AWS resources were created behind the scenes?
&lt;/h4&gt;

&lt;p&gt;Now let’s satisfy curiosity and confirm what AWS created inside your account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(1) Auto Scaling Group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Open EKS Service &lt;/p&gt;

&lt;p&gt;→ Select EKS cluster &lt;code&gt;demo-eks-cluster&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Compute&lt;/strong&gt; tab&lt;/p&gt;

&lt;p&gt;→ Select node group &lt;code&gt;eks-mng-general&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe64k3fdjwlq4pvl97zo3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe64k3fdjwlq4pvl97zo3.png" alt="part_2_verify_node_group.png" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ In &lt;strong&gt;Details&lt;/strong&gt;, click the &lt;strong&gt;Auto Scaling Group&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o3hxqrn62muwta1o2mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o3hxqrn62muwta1o2mw.png" alt="part_2_verify_asg.png" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the ASG page, you’ll find:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desired / Min / Max configuration&lt;/li&gt;
&lt;li&gt;EC2 instances in &lt;code&gt;InService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Launch Template reference&lt;/li&gt;
&lt;li&gt;Security Groups&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o7ivyljqg2wwcb4scrt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1o7ivyljqg2wwcb4scrt.png" alt="part_2_verify_asg_detail.png" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2) Launch Template&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From the ASG page:&lt;/p&gt;

&lt;p&gt;→ Click the &lt;strong&gt;Launch template&lt;/strong&gt; link.&lt;/p&gt;

&lt;p&gt;You’ll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AMI ID&lt;/li&gt;
&lt;li&gt;Instance type&lt;/li&gt;
&lt;li&gt;Security groups attached&lt;/li&gt;
&lt;li&gt;User data/bootstrap wiring (partly hidden, but it’s there)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu20mcj1umutg04usank5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu20mcj1umutg04usank5.png" alt="part_2_verify_launch_template.png" width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(3) Security Group for worker nodes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From the ASG details page&lt;/p&gt;

&lt;p&gt;→ Click the &lt;strong&gt;Security group IDs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Review inbound/outbound rules applied to worker nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Node group is Active, but &lt;code&gt;kubectl get nodes&lt;/code&gt; shows nothing
&lt;/h3&gt;

&lt;p&gt;Likely causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The node group is using the wrong IAM role (not &lt;code&gt;EKSNodeRole&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Node IAM role is missing required policies&lt;/li&gt;
&lt;li&gt;Wrong subnet selection or private subnet route tables are incorrect&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2) Instances keep launching and terminating in the ASG
&lt;/h3&gt;

&lt;p&gt;Likely causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instance type capacity shortage → try a more common type (&lt;code&gt;t3.large&lt;/code&gt;, &lt;code&gt;m5.large&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Subnet/AZ constraints → expand to more AZs/subnets&lt;/li&gt;
&lt;li&gt;EC2 quota limits → request quota increase&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3) Pods stuck in &lt;code&gt;Pending&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Likely causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Insufficient node resources (CPU/memory) → choose a larger instance type&lt;/li&gt;
&lt;li&gt;Taints/labels preventing scheduling → remove taints or adjust selectors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4) &lt;code&gt;ImagePullBackOff&lt;/code&gt; / &lt;code&gt;ErrImagePull&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Likely causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Private subnets have no NAT gateway, or routes are wrong&lt;/li&gt;
&lt;li&gt;DNS resolution is broken → check VPC settings (&lt;strong&gt;DNS resolution&lt;/strong&gt; and &lt;strong&gt;DNS hostnames&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In Part 2, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added production-style worker nodes (private subnets) so workloads finally have somewhere to run&lt;/li&gt;
&lt;li&gt;Clearly separated Cluster Role vs Node Role&lt;/li&gt;
&lt;li&gt;Covered the IAM → Kubernetes authentication story&lt;/li&gt;
&lt;li&gt;Explored what a Managed Node Group creates behind the scenes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, in &lt;strong&gt;Part 3&lt;/strong&gt;, we’ll go deeper into EKS networking: VPC CNI, ENIs, Pod IP allocation, and traffic flow debugging.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>eks</category>
      <category>devops</category>
    </item>
    <item>
      <title>Amazon EKS From The Ground Up - Part 1: Control Plane &amp; Infrastructure</title>
      <dc:creator>Phu Hoang</dc:creator>
      <pubDate>Thu, 25 Dec 2025 10:25:30 +0000</pubDate>
      <link>https://forem.com/posibble/amazon-eks-from-the-ground-up-part-1-control-plane-infrastructure-47pf</link>
      <guid>https://forem.com/posibble/amazon-eks-from-the-ground-up-part-1-control-plane-infrastructure-47pf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a DevOps engineer, the ability to provision and manage Kubernetes clusters efficiently is essential. Amazon EKS (Elastic Kubernetes Service) makes this significantly easier—you can create an EKS cluster with just a single command or a few clicks in the AWS Console.&lt;/p&gt;

&lt;p&gt;While you’re sipping your coffee, however, &lt;strong&gt;a lot is happening behind the scenes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article is the first part of a deep-dive series that breaks down those behind-the-scenes actions. We will examine the components that make up an Amazon EKS cluster, focusing specifically on the &lt;strong&gt;Infrastructure layer&lt;/strong&gt; and &lt;strong&gt;IAM &amp;amp; Security&lt;/strong&gt;, which form the foundation of everything that comes later.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Brief Concept of EKS
&lt;/h2&gt;

&lt;p&gt;Amazon EKS is a managed Kubernetes service that allows you to run Kubernetes without having to operate the Control Plane yourself.&lt;/p&gt;

&lt;p&gt;In simple terms, EKS handles the two most difficult aspects of running Kubernetes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Setting up and managing the Control Plane&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Control Plane is the “brain” of Kubernetes. It consists of the API server, the etcd database (which stores cluster state), the scheduler, and the controller manager. AWS ensures that this Control Plane is highly available, secure, and continuously patched.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deep integration with AWS services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;EKS tightly integrates Kubernetes with core AWS services such as VPC networking, IAM-based security, and Elastic Load Balancing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Building the Foundation – Infrastructure First
&lt;/h2&gt;

&lt;p&gt;A very common misconception among newcomers is the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EKS = Kubernetes, and AWS handles everything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In reality, EKS is split into two distinct responsibility domains:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component Partition&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Management Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS-managed (Control Plane)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;API Server, etcd, Scheduler, Controller Manager&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;AWS&lt;/strong&gt; (not configurable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Your AWS Account (Data Plane &amp;amp; Networking)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VPC, Subnets, Security Groups, IAM Roles, EC2 Worker Nodes or Fargate Pods&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;You&lt;/strong&gt; (must be designed and maintained)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this reason, the remainder of this article focuses on &lt;strong&gt;the infrastructure that you are responsible for&lt;/strong&gt;, before the EKS Control Plane is even created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoq6sdk57gxjrbuop5dp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoq6sdk57gxjrbuop5dp.png" alt="part_1_architecture" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0 – Preparing the Tools
&lt;/h2&gt;

&lt;p&gt;Before creating the EKS cluster, ensure you have the following ready:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with access to the AWS Console&lt;/li&gt;
&lt;li&gt;AWS CLI installed and configured&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; installed&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Although this article is console-first, we will use the CLI to verify and explain what happens under the hood.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 – Preparing the VPC
&lt;/h2&gt;

&lt;p&gt;The EKS Control Plane itself does &lt;strong&gt;not&lt;/strong&gt; run inside your VPC. However, you still need a VPC for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EC2 worker nodes&lt;/li&gt;
&lt;li&gt;Pod IP address allocation&lt;/li&gt;
&lt;li&gt;Security groups to control traffic&lt;/li&gt;
&lt;li&gt;Internet or NAT access for outbound communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: &lt;strong&gt;without a properly designed VPC, EKS cannot function.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1. Actions in the AWS Console
&lt;/h3&gt;

&lt;p&gt;→ Open the &lt;strong&gt;Amazon VPC&lt;/strong&gt; service&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Create VPC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Choose &lt;strong&gt;VPC and more&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recommended Configuration (Practice / Production-Ready Baseline)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;eks-demo-vpc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IPv4 CIDR&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10.0.0.0/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Availability Zones&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;High availability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Public subnets&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Used for NAT Gateways and public load balancers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private subnets&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Where worker nodes will run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NAT Gateway&lt;/td&gt;
&lt;td&gt;1 per AZ&lt;/td&gt;
&lt;td&gt;Required for outbound access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS Hostnames&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Enabled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Required for nodes to resolve the API server&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xwh5t807c2s2zk3ml1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xwh5t807c2s2zk3ml1p.png" alt="image.png" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 – Adding Tags to Subnets
&lt;/h2&gt;

&lt;p&gt;Amazon EKS does &lt;strong&gt;not&lt;/strong&gt; automatically infer which subnets it should use. Many EKS features—especially the AWS Load Balancer Controller—depend entirely on &lt;strong&gt;subnet tags&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1. Required Tags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cluster discovery tag&lt;/strong&gt; (required on &lt;strong&gt;all&lt;/strong&gt; subnets):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubernetes.io/cluster/demo-eks-cluster = shared
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Public load balancer subnets&lt;/strong&gt; (public subnets only):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubernetes.io/role/elb=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Internal load balancer subnets&lt;/strong&gt; (private subnets only):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubernetes.io/role/internal-elb =1
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Incorrect or missing tags are one of the most common causes of load balancer failures in EKS.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2. Actions in the AWS Console
&lt;/h3&gt;

&lt;p&gt;→ Open &lt;strong&gt;VPC → Subnets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Locate subnets named &lt;code&gt;eks-demo-subnet-*&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Select &lt;code&gt;eks-demo-subnet-public1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Open the &lt;strong&gt;Tags&lt;/strong&gt; tab → &lt;strong&gt;Manage tags&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem8reh809q22sledevkr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fem8reh809q22sledevkr.png" alt="image.png" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Add tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubernetes.io/cluster/demo-eks-cluster = shared&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubernetes.io/role/elb = 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Save&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldrizcuxko86xl9yguug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldrizcuxko86xl9yguug.png" alt="image.png" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat for &lt;code&gt;eks-demo-subnet-public2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7pr5x4430cshv3ayn2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv7pr5x4430cshv3ayn2l.png" alt="image.png" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For each private subnets, add tags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubernetes.io/cluster/demo-eks-cluster = shared&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubernetes.io/role/internal-elb = 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ge22vljm6npfaaj5ru4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ge22vljm6npfaaj5ru4.png" alt="image.png" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb7qvrpeypa2qt5p6g1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb7qvrpeypa2qt5p6g1r.png" alt="image.png" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 - Add a dedicated Security Group for the EKS Cluster
&lt;/h2&gt;

&lt;p&gt;In this step, we’ll create a &lt;strong&gt;separate Security Group&lt;/strong&gt; for the EKS cluster. The goal is to establish a clean security boundary early (even if you’re still in the “control plane only” stage).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inbound:&lt;/strong&gt; allow internal traffic within the same Security Group so EKS-related components that share this SG can communicate with each other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound:&lt;/strong&gt; allow outbound traffic so the cluster and its components can reach required endpoints (e.g., AWS APIs, image registries, etc.).&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This is a learning/bootstrapping-friendly baseline. In production, you typically tighten inbound/outbound rules based on actual traffic requirements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3.1. Actions in the AWS Console
&lt;/h3&gt;

&lt;p&gt;→ Open &lt;strong&gt;VPC&lt;/strong&gt; service&lt;/p&gt;

&lt;p&gt;→ Go to &lt;strong&gt;Security Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Configure the Security Group&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security group name:&lt;/strong&gt; &lt;code&gt;eks-cluster-sg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC:&lt;/strong&gt; &lt;code&gt;eks-demo-vpc&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→  Add (or keep) this outbound rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port range&lt;/th&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;All traffic&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;0.0.0.0/0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fno8hk6ia1raa029xs6ef.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fno8hk6ia1raa029xs6ef.png" alt="image.png" width="800" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Then click &lt;strong&gt;Create security group&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now we’ll allow “intra-SG” traffic:&lt;/p&gt;

&lt;p&gt;→ Select the Security Group &lt;strong&gt;&lt;code&gt;eks-cluster-sg&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Open the &lt;strong&gt;Inbound rules&lt;/strong&gt; tab → click &lt;strong&gt;Edit inbound rules&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Add a new rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port range&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;All traffic&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Custom → &lt;strong&gt;Security group&lt;/strong&gt;: &lt;code&gt;eks-cluster-sg&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;→ Save the rule.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe41jkdfnu9qucb4m9oph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe41jkdfnu9qucb4m9oph.png" alt=" " width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 – Creating the IAM Role for the EKS Control Plane
&lt;/h2&gt;

&lt;p&gt;Although AWS manages the Control Plane, it still needs permissions to interact with resources in &lt;strong&gt;your AWS account&lt;/strong&gt;, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating and managing ENIs&lt;/li&gt;
&lt;li&gt;Attaching security groups&lt;/li&gt;
&lt;li&gt;Communicating with VPC resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is achieved through an &lt;strong&gt;IAM Role&lt;/strong&gt; that the EKS service assumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1. Actions in the AWS Console
&lt;/h3&gt;

&lt;p&gt;→ Open &lt;strong&gt;IAM → Roles&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Create role&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vib2v17i6kl7t79h7dp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vib2v17i6kl7t79h7dp.png" alt="image.png" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Trusted entity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Type: &lt;strong&gt;AWS service&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Service: &lt;strong&gt;EKS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use case: &lt;strong&gt;EKS – Cluster&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkxgzwo9gcj3irhwrz8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmkxgzwo9gcj3irhwrz8l.png" alt="image.png" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Continue to permissions&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AmazonEKSClusterPolicy&lt;/code&gt; is attached automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fcc6y77da2mhypo8l5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1fcc6y77da2mhypo8l5u.png" alt="image.png" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;→ Name the role: &lt;code&gt;EKSClusterRole&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Create the role&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx9jfc34iqzkx8s6ix25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxx9jfc34iqzkx8s6ix25.png" alt="image.png" width="800" height="777"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2. Trust Policy Explanation
&lt;/h3&gt;

&lt;p&gt;The role’s trust policy contains the following statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"eks.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRole"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Allow the EKS service to assume this role and call AWS APIs using the permissions defined in &lt;code&gt;AmazonEKSClusterPolicy&lt;/code&gt;.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Granting only this policy follows the &lt;strong&gt;Principle of Least Privilege&lt;/strong&gt; and is sufficient for the Control Plane to operate correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 – Creating the EKS Cluster
&lt;/h2&gt;

&lt;p&gt;With the infrastructure and IAM role in place, we can now create the Control Plane.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1. Actions in the AWS Console
&lt;/h3&gt;

&lt;p&gt;→ Open &lt;strong&gt;Amazon EKS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Click &lt;strong&gt;Create cluster&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Choose &lt;strong&gt;Custom configuration&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Disable &lt;strong&gt;EKS Auto Mode&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Cluster Configuration step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Name: &lt;code&gt;demo-eks-cluster&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ IAM role: &lt;code&gt;EKSClusterRole&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Kubernetes version: &lt;strong&gt;1.34&lt;/strong&gt; (latest stable at the time of writing)&lt;/p&gt;

&lt;p&gt;→ Leave other settings as default&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv822piuad9q9gvug45s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsv822piuad9q9gvug45s.png" alt="image.png" width="800" height="770"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Networking Configuration step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ VPC: &lt;code&gt;eks-demo-vpc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Subnets: &lt;strong&gt;select all 4 subnets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Security group: &lt;code&gt;eks-cluster-sg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;→ Endpoint access: &lt;strong&gt;Public and Private&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Public + Private access allows management from your local machine while ensuring worker nodes communicate internally within the VPC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpca0ju29s7wyacazqve7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpca0ju29s7wyacazqve7.png" alt="image.png" width="800" height="885"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Logging Configuration step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Enable the following logs (recommended):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API server&lt;/li&gt;
&lt;li&gt;Audit&lt;/li&gt;
&lt;li&gt;Authenticator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq5j0e5cy64evi4bjp1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frq5j0e5cy64evi4bjp1b.png" alt="image.png" width="800" height="716"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In Add-ons Configuration step:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ Keep the AWS-recommended defaults:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kube-proxy&lt;/li&gt;
&lt;li&gt;Amazon VPC CNI&lt;/li&gt;
&lt;li&gt;Node monitoring agent&lt;/li&gt;
&lt;li&gt;CoreDNS&lt;/li&gt;
&lt;li&gt;Amazon EKS Pod Identity Agent&lt;/li&gt;
&lt;li&gt;External DNS&lt;/li&gt;
&lt;li&gt;Metrics Server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;→ Click &lt;strong&gt;Create&lt;/strong&gt; and wait for the cluster status to become &lt;strong&gt;Healthy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylqf3k88a8ce0dgiylzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylqf3k88a8ce0dgiylzd.png" alt="image.png" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Behind the scenes, this is equivalent to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks create-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; demo-eks-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-arn&lt;/span&gt; arn:aws:iam::&amp;lt;account-id&amp;gt;:role/EKSClusterRole &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--resources-vpc-config&lt;/span&gt; &lt;span class="nv"&gt;subnetIds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;subnet-public1&amp;gt;,&amp;lt;subnet-public2&amp;gt;,&amp;lt;subnet-private1&amp;gt;,&amp;lt;subnet-private2&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which do you prefer AWS Console or AWS CLI? 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 – Connecting and Verifying the Cluster
&lt;/h2&gt;

&lt;p&gt;Once the cluster is &lt;strong&gt;ACTIVE&lt;/strong&gt;, connect to it from your local machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  6.1 Fetching the kubeconfig
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws eks update-kubeconfig &lt;span class="nt"&gt;--name&lt;/span&gt; demo-eks-cluster &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieves the API endpoint&lt;/li&gt;
&lt;li&gt;Updates &lt;code&gt;~/.kube/config&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Configures authentication using your current IAM identity&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  6.2 Verifying the Cluster
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl cluster-info
kubectl get namespaces
kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Expected Results
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cluster-info&lt;/code&gt;: API server is reachable&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get namespaces&lt;/code&gt;: default namespaces are listed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get nodes&lt;/code&gt;: &lt;strong&gt;no nodes returned&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is expected.&lt;/p&gt;

&lt;p&gt;The Control Plane is ready, but &lt;strong&gt;no worker nodes exist yet&lt;/strong&gt;, so Kubernetes has no compute capacity to schedule Pods. Core system Pods such as CoreDNS remain in the &lt;code&gt;Pending&lt;/code&gt; state.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cd3qvkbxgcrgirl1769.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cd3qvkbxgcrgirl1769.png" alt="image.png" width="800" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this first part of the series, we built the foundation of an Amazon EKS cluster from the ground up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designed a production-ready VPC with properly tagged subnets&lt;/li&gt;
&lt;li&gt;Created an IAM role for the EKS Control Plane&lt;/li&gt;
&lt;li&gt;Provisioned the EKS Control Plane with secure endpoint access&lt;/li&gt;
&lt;li&gt;Verified connectivity while intentionally stopping before worker nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, we have built the &lt;strong&gt;brain&lt;/strong&gt; of Kubernetes.&lt;/p&gt;

&lt;p&gt;It is powered on, networked, and authorized—but it is still waiting for its “hands”.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>eks</category>
    </item>
  </channel>
</rss>
