<?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: POTHURAJU JAYAKRISHNA YADAV</title>
    <description>The latest articles on Forem by POTHURAJU JAYAKRISHNA YADAV (@jayakrishnayadav24).</description>
    <link>https://forem.com/jayakrishnayadav24</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%2F1212088%2F58079d8b-2311-41ef-9bff-1e92f5938836.jpg</url>
      <title>Forem: POTHURAJU JAYAKRISHNA YADAV</title>
      <link>https://forem.com/jayakrishnayadav24</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jayakrishnayadav24"/>
    <language>en</language>
    <item>
      <title>Terraform Modular EKS + Istio — Part 5</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 27 Mar 2026 02:49:35 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/-terraform-modular-eks-istio-part-5-38k7</link>
      <guid>https://forem.com/jayakrishnayadav24/-terraform-modular-eks-istio-part-5-38k7</guid>
      <description>&lt;h2&gt;
  
  
  CSI Drivers (How Storage Actually Works in EKS)
&lt;/h2&gt;

&lt;p&gt;So far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC → network&lt;/li&gt;
&lt;li&gt;IAM → permissions&lt;/li&gt;
&lt;li&gt;EKS → control plane&lt;/li&gt;
&lt;li&gt;Nodes → compute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now comes the part many people ignore:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Storage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Without this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pods can’t persist data&lt;/li&gt;
&lt;li&gt;Databases won’t work&lt;/li&gt;
&lt;li&gt;Logs disappear on restart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This module installs &lt;strong&gt;CSI drivers&lt;/strong&gt;, which allow Kubernetes to use AWS storage.&lt;/p&gt;




&lt;h1&gt;
  
  
  📂 Module Files
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/csi-driver/
├── main.tf
├── variables.tf
└── outputs.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📄 variables.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM role ARN for EBS CSI driver"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"s3_csi_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IAM role ARN for S3 CSI driver"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"node_group_dependency"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Node group dependency to ensure nodes exist first"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 What these inputs mean
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cluster_name&lt;/code&gt; → where to install addons&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ebs_csi_role_arn&lt;/code&gt; → IAM role for EBS driver&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s3_csi_role_arn&lt;/code&gt; → IAM role for S3 driver&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node_group_dependency&lt;/code&gt; → ensures nodes exist first&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ⚠️ Important insight
&lt;/h3&gt;

&lt;p&gt;This module depends on:&lt;/p&gt;

&lt;p&gt;👉 IAM (for IRSA roles)&lt;br&gt;
👉 Node groups (for scheduling pods)&lt;/p&gt;


&lt;h1&gt;
  
  
  📄 main.tf
&lt;/h1&gt;


&lt;h2&gt;
  
  
  1. EBS CSI Driver
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_addon"&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
  &lt;span class="nx"&gt;addon_name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-ebs-csi-driver"&lt;/span&gt;
  &lt;span class="nx"&gt;service_account_role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ebs_csi_role_arn&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_group_dependency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧠 What this does
&lt;/h2&gt;

&lt;p&gt;Installs:&lt;/p&gt;

&lt;p&gt;👉 AWS EBS CSI Driver inside cluster&lt;/p&gt;


&lt;h3&gt;
  
  
  What is CSI?
&lt;/h3&gt;

&lt;p&gt;CSI = &lt;strong&gt;Container Storage Interface&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;👉 It allows Kubernetes to talk to AWS storage.&lt;/p&gt;


&lt;h3&gt;
  
  
  What EBS CSI enables
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create EBS volumes&lt;/li&gt;
&lt;li&gt;Attach volumes to pods&lt;/li&gt;
&lt;li&gt;Persist data&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Important line
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;service_account_role_arn&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ebs_csi_role_arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 This is IRSA&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Pod gets IAM role&lt;/li&gt;
&lt;li&gt;Pod can call AWS APIs&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  Without this
&lt;/h3&gt;

&lt;p&gt;❌ Pod cannot create volumes&lt;br&gt;
❌ PVC fails&lt;/p&gt;


&lt;h2&gt;
  
  
  2. S3 CSI Driver
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_addon"&lt;/span&gt; &lt;span class="s2"&gt;"s3_csi"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
  &lt;span class="nx"&gt;addon_name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"aws-mountpoint-s3-csi-driver"&lt;/span&gt;
  &lt;span class="nx"&gt;service_account_role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_csi_role_arn&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_group_dependency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧠 What this does
&lt;/h2&gt;

&lt;p&gt;Installs:&lt;/p&gt;

&lt;p&gt;👉 S3 CSI driver&lt;/p&gt;


&lt;h3&gt;
  
  
  What it enables
&lt;/h3&gt;

&lt;p&gt;Mount S3 bucket as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pod → S3 bucket (like filesystem)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Use cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;shared storage&lt;/li&gt;
&lt;li&gt;backups&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Dependency Handling
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_group_dependency&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why this is critical
&lt;/h3&gt;

&lt;p&gt;CSI driver runs as pods.&lt;/p&gt;

&lt;p&gt;👉 Pods need nodes&lt;/p&gt;

&lt;p&gt;So order must be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes → CSI Driver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Without this
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Addon installs&lt;/li&gt;
&lt;li&gt;But pods fail to schedule&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📄 outputs.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi_addon_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"EBS CSI addon ID"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_addon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ebs_csi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"s3_csi_addon_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"S3 CSI addon ID"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_addon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3_csi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Why outputs matter
&lt;/h2&gt;

&lt;p&gt;Used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tracking addon deployment&lt;/li&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;dependencies in future modules&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🔥 What You Actually Built
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes Pod
      │
      │
CSI Driver
      │
      │
AWS Storage (EBS / S3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Real Issues People Face
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Missing IRSA → access denied&lt;/li&gt;
&lt;li&gt;No node dependency → pods fail&lt;/li&gt;
&lt;li&gt;Wrong role → volume attach fails&lt;/li&gt;
&lt;li&gt;Forgetting CSI → PVC stuck in pending&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes doesn’t manage storage directly&lt;/li&gt;
&lt;li&gt;CSI drivers connect Kubernetes to AWS&lt;/li&gt;
&lt;li&gt;IRSA is required for secure access&lt;/li&gt;
&lt;li&gt;EBS = block storage&lt;/li&gt;
&lt;li&gt;S3 = object storage&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Next
&lt;/h1&gt;

&lt;p&gt;In Part 6:&lt;/p&gt;

&lt;p&gt;👉 AWS Load Balancer Controller&lt;br&gt;
👉 How ALB actually integrates with Kubernetes&lt;br&gt;
👉 Why &lt;code&gt;target-type: ip&lt;/code&gt; matters&lt;/p&gt;




&lt;p&gt;At this point, your cluster can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run workloads&lt;/li&gt;
&lt;li&gt;persist data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we move to traffic layer.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>csi</category>
    </item>
    <item>
      <title>Terraform Modular EKS + Istio — Part 4</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 27 Mar 2026 02:47:10 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/-terraform-modular-eks-istio-part-4-3p8h</link>
      <guid>https://forem.com/jayakrishnayadav24/-terraform-modular-eks-istio-part-4-3p8h</guid>
      <description>&lt;h2&gt;
  
  
  EKS Node Groups (Where Your Cluster Actually Gets Compute)
&lt;/h2&gt;

&lt;p&gt;In the previous part, we created the EKS control plane.&lt;/p&gt;

&lt;p&gt;At that point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes API exists&lt;/li&gt;
&lt;li&gt;Cluster is reachable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But:&lt;/p&gt;

&lt;p&gt;👉 There are &lt;strong&gt;no machines to run workloads&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s where &lt;strong&gt;Node Groups&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;This module creates the actual EC2 instances that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;join the cluster&lt;/li&gt;
&lt;li&gt;run pods&lt;/li&gt;
&lt;li&gt;execute your applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📂 Module Files
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/eks-nodes/
├── main.tf
├── variables.tf
└── outputs.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📄 variables.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"node_group_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS node group"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"node_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ARN of the EKS node group IAM role"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of subnet IDs"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"instance_types"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of instance types"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"t3.large"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"desired_size"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Desired number of nodes"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"max_size"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Maximum number of nodes"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"min_size"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Minimum number of nodes"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"max_unavailable"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Maximum number of nodes unavailable during update"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"labels"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Key-value map of Kubernetes labels"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 What these variables control
&lt;/h2&gt;

&lt;p&gt;This module is completely configurable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cluster → which EKS cluster to join&lt;/li&gt;
&lt;li&gt;instance_types → what machines to use&lt;/li&gt;
&lt;li&gt;scaling → how many nodes&lt;/li&gt;
&lt;li&gt;labels → Kubernetes scheduling&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Example thinking
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dev → small nodes (t3.medium)
prod → bigger nodes (m5.large)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Same code, different behavior.&lt;/p&gt;




&lt;h1&gt;
  
  
  📄 main.tf
&lt;/h1&gt;




&lt;h2&gt;
  
  
  1. Node Group Resource
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_node_group"&lt;/span&gt; &lt;span class="s2"&gt;"nodes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
  &lt;span class="nx"&gt;node_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_group_name&lt;/span&gt;
  &lt;span class="nx"&gt;node_role_arn&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_role_arn&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_ids&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What this does
&lt;/h3&gt;

&lt;p&gt;Creates:&lt;/p&gt;

&lt;p&gt;👉 EC2 instances managed by EKS&lt;/p&gt;

&lt;p&gt;These instances:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;automatically join the cluster&lt;/li&gt;
&lt;li&gt;register as Kubernetes nodes&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Important inputs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cluster_name&lt;/code&gt; → which cluster to join&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;node_role_arn&lt;/code&gt; → permissions for nodes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;subnet_ids&lt;/code&gt; → where nodes are created&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Subnet choice
&lt;/h3&gt;

&lt;p&gt;You are passing:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;private subnets&lt;/strong&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;nodes do NOT have public IP&lt;/li&gt;
&lt;li&gt;more secure&lt;/li&gt;
&lt;li&gt;traffic goes through NAT&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Instance Types
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;instance_types&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_types&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What this controls
&lt;/h3&gt;

&lt;p&gt;Defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU&lt;/li&gt;
&lt;li&gt;Memory&lt;/li&gt;
&lt;li&gt;cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t3.large → 2 vCPU, 8GB RAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Scaling Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;scaling_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;desired_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;desired_size&lt;/span&gt;
  &lt;span class="nx"&gt;max_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max_size&lt;/span&gt;
  &lt;span class="nx"&gt;min_size&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min_size&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Meaning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;desired_size → current running nodes&lt;/li&gt;
&lt;li&gt;min_size → minimum nodes&lt;/li&gt;
&lt;li&gt;max_size → maximum nodes&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;min = 1
desired = 2
max = 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Cluster can scale between 1–5 nodes&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Update Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;update_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;max_unavailable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max_unavailable&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;p&gt;Controls rolling updates.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;max_unavailable = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Only 1 node can be down during update&lt;/p&gt;




&lt;h3&gt;
  
  
  Why important
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;prevents downtime&lt;/li&gt;
&lt;li&gt;controls deployment safety&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Labels
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;labels&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;labels&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What labels do
&lt;/h3&gt;

&lt;p&gt;Labels are used by Kubernetes for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scheduling&lt;/li&gt;
&lt;li&gt;targeting workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env = dev
type = backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;👉 Later you can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Dependency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;node_role_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why this is needed
&lt;/h3&gt;

&lt;p&gt;Even though role is passed:&lt;/p&gt;

&lt;p&gt;Terraform might not always guarantee order.&lt;/p&gt;

&lt;p&gt;So this ensures:&lt;/p&gt;

&lt;p&gt;👉 IAM role exists before node creation&lt;/p&gt;




&lt;h1&gt;
  
  
  📄 outputs.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"node_group_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Amazon Resource Name (ARN) of the EKS Node Group"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_node_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"node_group_status"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Status of the EKS Node Group"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_node_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Why outputs matter
&lt;/h2&gt;

&lt;p&gt;These outputs help in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;li&gt;integration with other modules&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🔥 What You Actually Built
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EKS Control Plane
        │
        │
Managed Node Group (EC2 Instances)
        │
        │
Kubernetes Pods run here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Real Issues People Face
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Wrong subnet → nodes can’t join&lt;/li&gt;
&lt;li&gt;Missing IAM role → node creation fails&lt;/li&gt;
&lt;li&gt;No NAT → nodes can’t pull images&lt;/li&gt;
&lt;li&gt;Too small instance → pods crash&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Node group = actual compute layer&lt;/li&gt;
&lt;li&gt;Control plane alone is useless without nodes&lt;/li&gt;
&lt;li&gt;Scaling config controls capacity&lt;/li&gt;
&lt;li&gt;Labels help in workload placement&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Next
&lt;/h1&gt;

&lt;p&gt;In Part 5:&lt;/p&gt;

&lt;p&gt;👉 Addons + CSI Driver&lt;br&gt;
👉 How storage works in EKS&lt;br&gt;
👉 Why IRSA becomes critical&lt;/p&gt;




&lt;p&gt;At this point, your cluster is alive — now we make it usable.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>eks</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Terraform Modular EKS + Istio — Part 3</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 27 Mar 2026 02:45:23 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-3-4n9e</link>
      <guid>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-3-4n9e</guid>
      <description>&lt;h2&gt;
  
  
  EKS Cluster Module (What Actually Creates Kubernetes)
&lt;/h2&gt;

&lt;p&gt;After setting up VPC and IAM, the next step is creating the actual Kubernetes control plane using Amazon EKS.&lt;/p&gt;

&lt;p&gt;This module is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating the EKS cluster&lt;/li&gt;
&lt;li&gt;Configuring networking&lt;/li&gt;
&lt;li&gt;Enabling authentication&lt;/li&gt;
&lt;li&gt;Setting up OIDC (required for IRSA)&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📂 Module Files
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/eks-cluster/
├── main.tf
├── variables.tf
└── outputs.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📄 variables.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_version"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Kubernetes version"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1.29"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ARN of the EKS cluster IAM role"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"private_subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of private subnet IDs"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"public_subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"List of public subnet IDs"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 What this module expects
&lt;/h2&gt;

&lt;p&gt;This module doesn’t create everything itself. It depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC module → for subnets&lt;/li&gt;
&lt;li&gt;IAM module → for cluster role&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inputs tell it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what to name the cluster&lt;/li&gt;
&lt;li&gt;which version to run&lt;/li&gt;
&lt;li&gt;where to place it&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📄 main.tf
&lt;/h1&gt;

&lt;p&gt;This is where the actual EKS cluster is created.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. EKS Cluster Resource
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eks_cluster"&lt;/span&gt; &lt;span class="s2"&gt;"cluster"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
  &lt;span class="nx"&gt;version&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_version&lt;/span&gt;
  &lt;span class="nx"&gt;role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_role_arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this does
&lt;/h3&gt;

&lt;p&gt;This creates the &lt;strong&gt;EKS control plane&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Important point:&lt;/p&gt;

&lt;p&gt;👉 You are NOT creating master nodes&lt;br&gt;
👉 AWS manages them for you&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Networking Configuration
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;vpc_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why both private and public subnets?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Private subnets → worker nodes&lt;/li&gt;
&lt;li&gt;Public subnets → load balancers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only pass private:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALB/NLB creation can fail later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only pass public:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not secure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Passing both is correct production setup.&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Access Configuration (Very Important)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;access_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;authentication_mode&lt;/span&gt;                         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"API_AND_CONFIG_MAP"&lt;/span&gt;
  &lt;span class="nx"&gt;bootstrap_cluster_creator_admin_permissions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this solves
&lt;/h3&gt;

&lt;p&gt;Newer EKS versions changed authentication behavior.&lt;/p&gt;

&lt;p&gt;This block ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API-based authentication is enabled&lt;/li&gt;
&lt;li&gt;IAM + aws-auth both work&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  This line is critical
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;bootstrap_cluster_creator_admin_permissions&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Gives admin access to the creator&lt;/p&gt;

&lt;p&gt;Without this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cluster gets created&lt;/li&gt;
&lt;li&gt;but you cannot access it&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  4. Dependency Handling
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_role_arn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why needed?
&lt;/h3&gt;

&lt;p&gt;Even though role ARN is passed:&lt;/p&gt;

&lt;p&gt;Terraform may not always detect dependency properly.&lt;/p&gt;

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

&lt;p&gt;👉 IAM role exists before cluster creation&lt;/p&gt;


&lt;h1&gt;
  
  
  🔥 OIDC Setup (Core Concept)
&lt;/h1&gt;

&lt;p&gt;This is the most important part of this module.&lt;/p&gt;


&lt;h2&gt;
  
  
  5. Fetch TLS Certificate
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"tls_certificate"&lt;/span&gt; &lt;span class="s2"&gt;"cluster"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;issuer&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is happening?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EKS creates an OIDC endpoint&lt;/li&gt;
&lt;li&gt;This block fetches its certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Used for:&lt;br&gt;
👉 Trust verification in IAM&lt;/p&gt;


&lt;h2&gt;
  
  
  6. Create OIDC Provider
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_openid_connect_provider"&lt;/span&gt; &lt;span class="s2"&gt;"cluster"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client_id_list&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sts.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;thumbprint_list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tls_certificate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;certificates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;sha1_fingerprint&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;issuer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What this actually does
&lt;/h3&gt;

&lt;p&gt;This creates a bridge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kubernetes → IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why this is required
&lt;/h3&gt;

&lt;p&gt;Without OIDC:&lt;/p&gt;

&lt;p&gt;❌ Pods cannot assume IAM roles&lt;br&gt;
❌ IRSA will not work&lt;/p&gt;


&lt;h3&gt;
  
  
  Thumbprint
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;thumbprint_list&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Ensures secure trust between AWS and OIDC provider&lt;/p&gt;


&lt;h1&gt;
  
  
  📄 outputs.tf
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_endpoint"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_security_group_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;cluster_security_group_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"cluster_certificate_authority_data"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;certificate_authority&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"oidc_provider_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_openid_connect_provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"oidc_provider"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;aws_eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"https://"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧠 Why these outputs matter
&lt;/h2&gt;

&lt;p&gt;These values are used by other modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes provider → uses endpoint + certificate&lt;/li&gt;
&lt;li&gt;IAM module → uses OIDC provider&lt;/li&gt;
&lt;li&gt;Node module → uses cluster name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_endpoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔥 What You Actually Built
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Managed Control Plane
        │
        │
OIDC Provider (for IAM integration)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Real Issues People Face
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;No OIDC → IRSA breaks&lt;/li&gt;
&lt;li&gt;Wrong subnets → cluster unstable&lt;/li&gt;
&lt;li&gt;Missing access_config → login issues&lt;/li&gt;
&lt;li&gt;Wrong IAM role → cluster creation fails&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster = control plane only&lt;/li&gt;
&lt;li&gt;AWS manages master nodes&lt;/li&gt;
&lt;li&gt;OIDC is required for IAM integration&lt;/li&gt;
&lt;li&gt;Outputs connect modules together&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Next Step
&lt;/h1&gt;

&lt;p&gt;Next module:&lt;/p&gt;

&lt;p&gt;👉 Node Groups (actual compute layer)&lt;br&gt;
👉 How EC2 instances join the cluster&lt;br&gt;
👉 Scaling and updates&lt;/p&gt;




&lt;p&gt;This module is where Kubernetes actually starts — but without nodes, it’s still empty.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>eks</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Terraform Modular EKS + Istio — Part 2</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 27 Mar 2026 02:40:48 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-2-abi</link>
      <guid>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-2-abi</guid>
      <description>&lt;h2&gt;
  
  
  IAM Module (IRSA, OIDC, and Why This Controls Everything)
&lt;/h2&gt;

&lt;p&gt;In the previous part, we built the VPC.&lt;/p&gt;

&lt;p&gt;Now we move to something that causes the most confusion in EKS setups:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;IAM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is not just “permissions”.&lt;/p&gt;

&lt;p&gt;This module controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how EKS works&lt;/li&gt;
&lt;li&gt;how nodes behave&lt;/li&gt;
&lt;li&gt;how pods access AWS services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this is wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALB won’t work&lt;/li&gt;
&lt;li&gt;CSI drivers fail&lt;/li&gt;
&lt;li&gt;Pods can’t access AWS&lt;/li&gt;
&lt;li&gt;Debugging becomes painful&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📂 Module Files
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/iam/
├── main.tf
├── variables.tf
└── outputs.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📄 variables.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"oidc_provider_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ARN of the OIDC provider"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"oidc_provider"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"OIDC provider URL"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 What these inputs mean
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cluster_name&lt;/code&gt;&lt;br&gt;
→ used to name roles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;oidc_provider_arn&lt;/code&gt;&lt;br&gt;
→ comes from EKS module&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;oidc_provider&lt;/code&gt;&lt;br&gt;
→ used for IRSA condition matching&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Important:&lt;/p&gt;

&lt;p&gt;This module &lt;strong&gt;depends on EKS&lt;/strong&gt;&lt;br&gt;
Because OIDC is created inside the EKS module.&lt;/p&gt;


&lt;h1&gt;
  
  
  📄 main.tf (Core IAM Logic)
&lt;/h1&gt;


&lt;h1&gt;
  
  
  1. EKS Cluster Role
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-cluster-role"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&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="nx"&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="nx"&gt;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&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="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧠 What this actually does
&lt;/h2&gt;

&lt;p&gt;This role is used by:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;EKS Control Plane (managed by AWS)&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Key line
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks.amazonaws.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“EKS service is allowed to assume this role”&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Attach Policy
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"&lt;/span&gt;
  &lt;span class="nx"&gt;role&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this policy?
&lt;/h3&gt;

&lt;p&gt;This allows EKS to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;manage nodes&lt;/li&gt;
&lt;li&gt;communicate with AWS&lt;/li&gt;
&lt;li&gt;create resources&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  2. Node Group Role
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"eks_nodes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-node-group-role"&lt;/span&gt;

  &lt;span class="nx"&gt;assume_role_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&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="nx"&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="nx"&gt;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ec2.amazonaws.com"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🧠 What this role is for
&lt;/h2&gt;

&lt;p&gt;👉 Used by &lt;strong&gt;EC2 instances (worker nodes)&lt;/strong&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  Key line
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ec2.amazonaws.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EC2 instances can assume this role&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  3. Node Policies
&lt;/h1&gt;

&lt;p&gt;Now we attach multiple policies.&lt;/p&gt;


&lt;h2&gt;
  
  
  a. Worker Node Policy
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"eks_worker_node_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Allows nodes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;join cluster&lt;/li&gt;
&lt;li&gt;communicate with control plane&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  b. CNI Policy
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"eks_cni_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 This is very important&lt;/p&gt;

&lt;p&gt;Allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pod networking&lt;/li&gt;
&lt;li&gt;ENI management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Without this:&lt;br&gt;
Pods won’t get IPs&lt;/p&gt;


&lt;h2&gt;
  
  
  c. ECR Access
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"eks_container_registry_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Allows nodes to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pull Docker images&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  d. SSM Access
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"eks_ssm_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSM access&lt;/li&gt;
&lt;li&gt;no need for SSH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 This is production best practice&lt;/p&gt;


&lt;h1&gt;
  
  
  4. EBS CSI Driver Role (🔥 Most Important Part)
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role"&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi_driver"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-ebs-csi-driver-role"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is NOT for nodes.&lt;/p&gt;

&lt;p&gt;This is for:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Kubernetes Pod (EBS CSI controller)&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  🔥 This is IRSA (Core Concept)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;Action&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 This is different from EC2 roles&lt;/p&gt;

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

&lt;p&gt;👉 Pods → assume IAM role&lt;/p&gt;


&lt;h2&gt;
  
  
  🔥 OIDC Trust
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Federated&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oidc_provider_arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 This links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster&lt;/li&gt;
&lt;li&gt;IAM&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🔥 Condition (VERY IMPORTANT)
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oidc_provider&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:sub"&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"system:serviceaccount:kube-system:ebs-csi-controller-sa"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;ONLY this service account can assume the role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kube-system / ebs-csi-controller-sa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;p&gt;👉 This is &lt;strong&gt;fine-grained security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;❌ giving full access to nodes&lt;/p&gt;

&lt;p&gt;You do:&lt;/p&gt;

&lt;p&gt;✅ give access only to specific pod&lt;/p&gt;




&lt;h2&gt;
  
  
  Attach Policy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_iam_role_policy_attachment"&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;policy_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  What this enables
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create volumes&lt;/li&gt;
&lt;li&gt;Attach volumes&lt;/li&gt;
&lt;li&gt;Manage storage&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📄 outputs.tf
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"eks_nodes_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"ebs_csi_driver_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_iam_role&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ebs_csi_driver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 Why outputs matter
&lt;/h2&gt;

&lt;p&gt;These are used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS module&lt;/li&gt;
&lt;li&gt;Node module&lt;/li&gt;
&lt;li&gt;CSI module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;cluster_role_arn&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster_role_arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This creates dependency automatically.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔥 Real Architecture (What You Built)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EKS Control Plane → uses cluster role

EC2 Nodes → use node role

Pods (CSI) → use IRSA role (OIDC)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Real Mistakes People Make
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Giving full IAM to nodes (bad security)&lt;/li&gt;
&lt;li&gt;Not using IRSA&lt;/li&gt;
&lt;li&gt;Wrong OIDC condition → role not assumed&lt;/li&gt;
&lt;li&gt;Forgetting CNI policy → pods fail&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;IAM is not optional — it defines system behavior&lt;/li&gt;
&lt;li&gt;Nodes and pods should have separate roles&lt;/li&gt;
&lt;li&gt;IRSA is the correct way to give AWS access to pods&lt;/li&gt;
&lt;li&gt;OIDC is what connects Kubernetes to IAM&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Next
&lt;/h1&gt;

&lt;p&gt;In Part 3:&lt;/p&gt;

&lt;p&gt;👉 EKS Cluster Module&lt;br&gt;
👉 How control plane is created&lt;br&gt;
👉 What OIDC actually does internally&lt;/p&gt;




&lt;p&gt;If you understand this module, you understand how AWS + Kubernetes actually connect behind the scenes.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iam</category>
      <category>terraform</category>
      <category>istio</category>
    </item>
    <item>
      <title>Terraform Modular EKS + Istio — Part 1</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 27 Mar 2026 02:37:41 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-1-2j14</link>
      <guid>https://forem.com/jayakrishnayadav24/terraform-modular-eks-istio-part-1-2j14</guid>
      <description>&lt;h2&gt;
  
  
  VPC Module (Complete Code + Real Explanation)
&lt;/h2&gt;

&lt;p&gt;Before touching EKS, Istio, or routing — everything depends on one thing:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Your network&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the VPC is wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nodes won’t join&lt;/li&gt;
&lt;li&gt;ALB won’t work&lt;/li&gt;
&lt;li&gt;Pods won’t get IPs&lt;/li&gt;
&lt;li&gt;Routing will fail in weird ways&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So in this part, I’ll walk through the &lt;strong&gt;entire VPC module from my setup&lt;/strong&gt;, using the exact code — and explain what each part is doing and why it exists.&lt;/p&gt;




&lt;h1&gt;
  
  
  📂 Module Files
&lt;/h1&gt;

&lt;p&gt;This module consists of 3 files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modules/vpc/
├── main.tf
├── variables.tf
└── outputs.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📄 variables.tf
&lt;/h1&gt;

&lt;p&gt;This file defines what inputs the module expects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"vpc_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the VPC"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"vpc_cidr"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CIDR block for VPC"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"availability_zones"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Availability zones"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"private_subnet_cidrs"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CIDR blocks for private subnets"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"public_subnet_cidrs"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CIDR blocks for public subnets"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Name of the EKS cluster"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧠 What this means
&lt;/h2&gt;

&lt;p&gt;This module is &lt;strong&gt;not hardcoded&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Everything is controlled from outside:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CIDR ranges&lt;/li&gt;
&lt;li&gt;AZs&lt;/li&gt;
&lt;li&gt;Subnet layout&lt;/li&gt;
&lt;li&gt;Cluster name&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 That’s what makes it reusable across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dev&lt;/li&gt;
&lt;li&gt;staging&lt;/li&gt;
&lt;li&gt;prod&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📄 main.tf (Core Logic)
&lt;/h1&gt;

&lt;p&gt;This is where actual infrastructure is created.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. VPC
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_cidr&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_support&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;enable_dns_hostnames&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cidr_block&lt;/code&gt; → defines network size&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;enable_dns_support&lt;/code&gt; → required for internal communication&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;enable_dns_hostnames&lt;/code&gt; → required for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS&lt;/li&gt;
&lt;li&gt;ALB&lt;/li&gt;
&lt;li&gt;service discovery&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;👉 If DNS is off, things break silently.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Private Subnets (EKS Nodes)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"private_subnets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability_zones&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What’s happening
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;count&lt;/code&gt; creates multiple subnets&lt;/li&gt;
&lt;li&gt;Each subnet is tied to an AZ&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  🔥 Important Tags
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Name&lt;/span&gt;                              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-private-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability_zones&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="s2"&gt;"kubernetes.io/role/internal-elb"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
  &lt;span class="s2"&gt;"kubernetes.io/cluster/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"owned"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why these tags matter
&lt;/h3&gt;

&lt;p&gt;These are &lt;strong&gt;not optional&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;internal-elb&lt;/code&gt;&lt;br&gt;
→ used by AWS to place &lt;strong&gt;internal load balancers&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;cluster tag&lt;/code&gt;&lt;br&gt;
→ required for EKS to discover subnets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 Missing this = ALB or services fail later&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Public Subnets (ALB Layer)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"public_subnets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;                   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zone&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability_zones&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;map_public_ip_on_launch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key difference
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;map_public_ip_on_launch&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Instances here get public IPs&lt;/p&gt;




&lt;h3&gt;
  
  
  Tag Difference
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="s2"&gt;"kubernetes.io/role/elb"&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This tells AWS:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Use this subnet for internet-facing load balancers”&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Internet Gateway
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_internet_gateway"&lt;/span&gt; &lt;span class="s2"&gt;"igw"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-igw"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Purpose
&lt;/h3&gt;

&lt;p&gt;Allows:&lt;/p&gt;

&lt;p&gt;👉 Public subnet → Internet&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Elastic IP (for NAT)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_eip"&lt;/span&gt; &lt;span class="s2"&gt;"nat"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;domain&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-nat-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;depends_on&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;igw&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why EIP?
&lt;/h3&gt;

&lt;p&gt;NAT Gateway needs a &lt;strong&gt;public IP&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. NAT Gateway (Critical)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_nat_gateway"&lt;/span&gt; &lt;span class="s2"&gt;"nat"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;allocation_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_eip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What it does
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private Subnet → NAT → Internet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Nodes can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pull Docker images&lt;/li&gt;
&lt;li&gt;access APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BUT:&lt;/p&gt;

&lt;p&gt;👉 They don’t get public IP (secure)&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Private Route Table
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table"&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_block&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;
    &lt;span class="nx"&gt;nat_gateway_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_nat_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Meaning
&lt;/h3&gt;

&lt;p&gt;All outbound traffic → NAT&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Public Route Table
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table"&lt;/span&gt; &lt;span class="s2"&gt;"public"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;route&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;
    &lt;span class="nx"&gt;gateway_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_internet_gateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;igw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Meaning
&lt;/h3&gt;

&lt;p&gt;Public subnet → direct internet&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Route Table Associations
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table_association"&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_route_table_association"&lt;/span&gt; &lt;span class="s2"&gt;"public"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;route_table_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_route_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why needed
&lt;/h3&gt;

&lt;p&gt;👉 Subnets don’t automatically get routing&lt;/p&gt;

&lt;p&gt;You must attach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;subnet → route table&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  📄 outputs.tf
&lt;/h1&gt;

&lt;p&gt;This file exposes values for other modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"vpc_id"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ID of the VPC"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"private_subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IDs of the private subnets"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnets&lt;/span&gt;&lt;span class="p"&gt;[*].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"public_subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"IDs of the public subnets"&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnets&lt;/span&gt;&lt;span class="p"&gt;[*].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why outputs matter
&lt;/h2&gt;

&lt;p&gt;These are used by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EKS cluster&lt;/li&gt;
&lt;li&gt;Node groups&lt;/li&gt;
&lt;li&gt;ALB controller&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="k"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This creates dependency automatically.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 Final Architecture
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internet
   │
Internet Gateway
   │
Public Subnets (ALB)
   │
NAT Gateway
   │
Private Subnets (EKS Nodes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Real Things That Break in Production
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Missing subnet tags → ALB won’t create&lt;/li&gt;
&lt;li&gt;No NAT → nodes can’t pull images&lt;/li&gt;
&lt;li&gt;Wrong AZ mapping → cluster unstable&lt;/li&gt;
&lt;li&gt;Public nodes → security issue&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;VPC is the foundation of everything&lt;/li&gt;
&lt;li&gt;Subnet tagging is critical for EKS&lt;/li&gt;
&lt;li&gt;NAT enables private nodes&lt;/li&gt;
&lt;li&gt;Outputs drive Terraform dependencies&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Next
&lt;/h1&gt;

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

&lt;p&gt;👉 IAM Module — IRSA explained properly&lt;br&gt;
👉 How pods assume AWS roles&lt;br&gt;
👉 Why OIDC is required&lt;/p&gt;




&lt;p&gt;If you're building EKS in production, this part is not optional — this is where most issues actually start.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>vpc</category>
    </item>
    <item>
      <title>🔍 Terraform Modular EKS + Istio — The Part Nobody Explains</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Thu, 26 Mar 2026 12:17:09 +0000</pubDate>
      <link>https://forem.com/aws-builders/-terraform-modular-eks-istio-the-part-nobody-explains-2mk3</link>
      <guid>https://forem.com/aws-builders/-terraform-modular-eks-istio-the-part-nobody-explains-2mk3</guid>
      <description>&lt;p&gt;When I first modularized my Terraform for EKS, everything looked clean…&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%2Fwuvfxll9li71wl31nr1a.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%2Fwuvfxll9li71wl31nr1a.png" alt=" " width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Until it didn’t work.&lt;/p&gt;

&lt;p&gt;Modules were correct.&lt;br&gt;
Code was clean.&lt;br&gt;
Folder structure looked “perfect”.&lt;/p&gt;

&lt;p&gt;But Terraform was behaving in ways I didn’t expect.&lt;/p&gt;

&lt;p&gt;Resources were creating in weird order.&lt;br&gt;
Dependencies felt invisible.&lt;br&gt;
And debugging became painful.&lt;/p&gt;

&lt;p&gt;That’s when I realized:&lt;/p&gt;

&lt;p&gt;👉 Understanding Terraform syntax is easy&lt;br&gt;
👉 Understanding how Terraform &lt;em&gt;thinks&lt;/em&gt; is the real game&lt;/p&gt;

&lt;p&gt;This blog is about that shift.&lt;/p&gt;


&lt;h1&gt;
  
  
  🧠 The Biggest Misconception
&lt;/h1&gt;

&lt;p&gt;Initially, I thought Terraform runs like a script:&lt;/p&gt;

&lt;p&gt;Step 1 → Step 2 → Step 3&lt;/p&gt;

&lt;p&gt;But that assumption is completely wrong.&lt;/p&gt;

&lt;p&gt;Terraform doesn’t execute line by line.&lt;/p&gt;

&lt;p&gt;👉 It builds a &lt;strong&gt;dependency graph first&lt;/strong&gt;, and only then decides what to create and in what order.&lt;/p&gt;

&lt;p&gt;Once this clicked, everything started making sense.&lt;/p&gt;


&lt;h1&gt;
  
  
  🧩 My Project Structure (Real Setup)
&lt;/h1&gt;

&lt;p&gt;Here’s how I organized everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;modularized/
├── eks/                      # Root module (entry point)
│   ├── main.tf
│   ├── variables.tf
│   ├── providers.tf
│   └── backend.tf
├── modules/
│   ├── vpc/
│   ├── iam/
│   ├── eks-cluster/
│   ├── eks-nodes/
│   ├── aws-load-balancer-controller/
│   ├── istio-base/
│   ├── istiod/
│   ├── istio-gateway/
│   └── istio-manifests/
└── environments/
    ├── dev/
    │   ├── terraform.tfvars
    │   └── backend.hcl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At a glance, this looks like just folders.&lt;/p&gt;

&lt;p&gt;But in reality:&lt;/p&gt;

&lt;p&gt;👉 This is a &lt;strong&gt;system design mapped into code&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🔗 The Real Role of &lt;code&gt;main.tf&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Think of &lt;code&gt;main.tf&lt;/code&gt; not as a file…&lt;/p&gt;

&lt;p&gt;👉 But as an &lt;strong&gt;orchestrator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It doesn’t “do” things directly.&lt;br&gt;
It &lt;strong&gt;connects modules together using data&lt;/strong&gt;.&lt;/p&gt;


&lt;h1&gt;
  
  
  🔹 Step 1: VPC — The Foundation
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../modules/vpc"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_name&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_cidr&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_cidr&lt;/span&gt;
  &lt;span class="nx"&gt;availability_zones&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;availability_zones&lt;/span&gt;
  &lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_cidrs&lt;/span&gt;
  &lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_cidrs&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This module creates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VPC&lt;/li&gt;
&lt;li&gt;Public &amp;amp; private subnets&lt;/li&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the important part is not creation…&lt;/p&gt;

&lt;p&gt;👉 It’s what it &lt;strong&gt;exports&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"private_subnet_ids"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private&lt;/span&gt;&lt;span class="p"&gt;[*].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🧠 First Realization
&lt;/h1&gt;

&lt;p&gt;Terraform modules don’t “talk” directly.&lt;/p&gt;

&lt;p&gt;They communicate through:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Outputs → Inputs&lt;/strong&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🔹 Step 2: IAM — Identity Layer
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"iam"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../modules/iam"&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Cluster role&lt;/li&gt;
&lt;li&gt;Node role&lt;/li&gt;
&lt;li&gt;IRSA roles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And exposes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"eks_nodes_role_arn"&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔗 Step 3: EKS Cluster — Where Things Clicked
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks_cluster"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../modules/eks-cluster"&lt;/span&gt;

  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_name&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_version&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_version&lt;/span&gt;
  &lt;span class="nx"&gt;cluster_role_arn&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster_role_arn&lt;/span&gt;
  &lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;
  &lt;span class="nx"&gt;public_subnet_ids&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_subnet_ids&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line changed everything for me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster_role_arn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This is not just a reference&lt;br&gt;
👉 This is a &lt;strong&gt;dependency signal&lt;/strong&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  💥 The Aha Moment
&lt;/h1&gt;

&lt;p&gt;I didn’t define any order like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Create IAM first”&lt;/li&gt;
&lt;li&gt;“Then VPC”&lt;/li&gt;
&lt;li&gt;“Then EKS”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet Terraform &lt;em&gt;automatically&lt;/em&gt; knew.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because:&lt;/p&gt;

&lt;p&gt;👉 Dependencies define execution order&lt;/p&gt;


&lt;h1&gt;
  
  
  🔹 Step 4: Node Groups — Implicit Dependency
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"eks_nodes"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"../modules/eks-nodes"&lt;/span&gt;

  &lt;span class="nx"&gt;cluster_name&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cluster_id&lt;/span&gt;
  &lt;span class="nx"&gt;node_role_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eks_nodes_role_arn&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_ids&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_subnet_ids&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now Terraform understands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nodes depend on cluster&lt;/li&gt;
&lt;li&gt;Cluster depends on IAM + VPC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So it builds a graph like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VPC → IAM → EKS → Nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without you ever writing that flow.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚠️ Mistake I Made (Important)
&lt;/h1&gt;

&lt;p&gt;At one point, I hardcoded subnet IDs inside my EKS module.&lt;/p&gt;

&lt;p&gt;It worked… initially.&lt;/p&gt;

&lt;p&gt;But the moment I tried another environment — everything broke.&lt;/p&gt;

&lt;p&gt;That’s when I understood:&lt;/p&gt;

&lt;p&gt;👉 Hardcoding breaks modular design&lt;br&gt;
👉 Outputs make modules reusable&lt;/p&gt;


&lt;h1&gt;
  
  
  ⚙️ Variables — The Real Power
&lt;/h1&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Values come from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="c1"&gt;# environments/dev/terraform.tfvars&lt;/span&gt;

&lt;span class="nx"&gt;cluster_name&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"dev-cluster"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Same code&lt;br&gt;
👉 Different environments&lt;/p&gt;

&lt;p&gt;No duplication.&lt;/p&gt;


&lt;h1&gt;
  
  
  🧠 What Terraform Actually Does
&lt;/h1&gt;

&lt;p&gt;When 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;terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform does NOT just “run code”.&lt;/p&gt;

&lt;p&gt;It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads variables&lt;/li&gt;
&lt;li&gt;Resolves all references&lt;/li&gt;
&lt;li&gt;Builds dependency graph&lt;/li&gt;
&lt;li&gt;Plans execution order&lt;/li&gt;
&lt;li&gt;Applies resources&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  🔐 Backend — Silent but Critical
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;backend&lt;/span&gt; &lt;span class="s2"&gt;"s3"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-tf-state"&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eks/dev/terraform.tfstate"&lt;/span&gt;
    &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Remote state&lt;/li&gt;
&lt;li&gt;Team collaboration&lt;/li&gt;
&lt;li&gt;State locking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, things get messy fast.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 Final Shift in Thinking
&lt;/h1&gt;

&lt;p&gt;At the beginning, Terraform felt like:&lt;/p&gt;

&lt;p&gt;👉 “Writing infrastructure scripts”&lt;/p&gt;

&lt;p&gt;Now it feels like:&lt;/p&gt;

&lt;p&gt;👉 “Designing systems using data flow”&lt;/p&gt;

&lt;p&gt;That shift changes everything.&lt;/p&gt;




&lt;h1&gt;
  
  
  💡 Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main.tf&lt;/code&gt; is not execution — it’s orchestration&lt;/li&gt;
&lt;li&gt;Outputs are how modules communicate&lt;/li&gt;
&lt;li&gt;Dependencies are inferred, not written&lt;/li&gt;
&lt;li&gt;Variables make environments scalable&lt;/li&gt;
&lt;li&gt;Terraform is a graph engine, not a script runner&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🔗 Repo
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/jayakrishnayadav24/istio-ip-based-routing" rel="noopener noreferrer"&gt;https://github.com/jayakrishnayadav24/istio-ip-based-routing&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  🚀 Final Thought
&lt;/h1&gt;

&lt;p&gt;Once you stop thinking in terms of files…&lt;/p&gt;

&lt;p&gt;And start thinking in terms of &lt;strong&gt;data flowing between modules&lt;/strong&gt;…&lt;/p&gt;

&lt;p&gt;Terraform stops being just infrastructure code.&lt;/p&gt;

&lt;p&gt;👉 It becomes a system design tool.&lt;/p&gt;




&lt;p&gt;If this helped you understand Terraform at a deeper level:&lt;/p&gt;

&lt;p&gt;⭐ Star the repo&lt;br&gt;
🔁 Share with others&lt;br&gt;
💬 Let me know what confused you — I’ll write about it next&lt;/p&gt;

&lt;p&gt;Happy building 🚀&lt;/p&gt;

</description>
      <category>aws</category>
      <category>terraform</category>
      <category>istio</category>
    </item>
    <item>
      <title>🚀 Creating an EC2 Instance Using Python requests (Without boto3)</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Tue, 24 Mar 2026 04:36:51 +0000</pubDate>
      <link>https://forem.com/aws-builders/creating-an-ec2-instance-using-python-requests-without-boto3-1m5n</link>
      <guid>https://forem.com/aws-builders/creating-an-ec2-instance-using-python-requests-without-boto3-1m5n</guid>
      <description>&lt;p&gt;Most developers use &lt;code&gt;boto3&lt;/code&gt; to interact with AWS.&lt;/p&gt;

&lt;p&gt;But have you ever wondered…&lt;/p&gt;

&lt;p&gt;👉 What actually happens behind the scenes?&lt;br&gt;
👉 How does AWS authenticate your API requests?&lt;/p&gt;

&lt;p&gt;I always used boto3 without thinking much about it — until I tried calling AWS APIs directly.&lt;/p&gt;

&lt;p&gt;In this blog, we’ll go one level deeper and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔥 Create an EC2 instance using raw HTTP requests with AWS Signature Version 4 (SigV4)&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h1&gt;
  
  
  🧠 boto3 is Just a Wrapper
&lt;/h1&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_instances&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behind the scenes, boto3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Builds an HTTP request&lt;/li&gt;
&lt;li&gt;Signs it using AWS Signature Version 4&lt;/li&gt;
&lt;li&gt;Sends it to AWS APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blog, we’ll do all of that manually.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚙️ What We’re Building
&lt;/h1&gt;

&lt;p&gt;We’ll create a Python script that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses &lt;code&gt;requests&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Implements AWS SigV4 authentication&lt;/li&gt;
&lt;li&gt;Launches a real EC2 instance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No SDK. No shortcuts.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔄 High-Level Flow
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → Canonical Request → String to Sign → Signature → AWS API → Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔐 Understanding AWS Signature Version 4 (SigV4)
&lt;/h1&gt;

&lt;p&gt;AWS secures every API request using SigV4. It ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication (who you are)&lt;/li&gt;
&lt;li&gt;Integrity (request not tampered)&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  💻 Full Working Code
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt;

&lt;span class="c1"&gt;# 🔐 AWS credentials
&lt;/span&gt;&lt;span class="n"&gt;ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ap-south-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SERVICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ec2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ec2.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.amazonaws.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# 📦 EC2 parameters
&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RunInstances&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ImageId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ami-0f5ee92e2d63afc18&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;InstanceType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t2.micro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MinCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MaxCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2016-11-15&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# 🕒 Time
&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;amz_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%Y%m%dT%H%M%SZ&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;date_stamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%Y%m%d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Step 1: Canonical Query String
&lt;/span&gt;&lt;span class="n"&gt;canonical_querystring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Step 2: Canonical Request
&lt;/span&gt;&lt;span class="n"&gt;canonical_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;x-amz-date:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amz_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;signed_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host;x-amz-date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;payload_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;canonical_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;canonical_querystring&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;canonical_headers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signed_headers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payload_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Step 3: String to Sign
&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS4-HMAC-SHA256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;credential_scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;date_stamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;SERVICE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/aws4_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;string_to_sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amz_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;credential_scope&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canonical_request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Step 4: Signing Key
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;k_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;date_stamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_signing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aws4_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;k_signing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;string_to_sign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Step 5: Headers
&lt;/span&gt;&lt;span class="n"&gt;authorization_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; Credential=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ACCESS_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;credential_scope&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SignedHeaders=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signed_headers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Signature=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-amz-date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amz_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;authorization_header&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# 🔹 Final request
&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;canonical_querystring&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;👉 Calling:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Status Code:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Response:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔍 Breaking Down the Code (with Snippets)
&lt;/h1&gt;

&lt;p&gt;Let’s understand what’s happening step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔐 1. AWS Credentials &amp;amp; Config
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ACCESS_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SECRET_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ap-south-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;SERVICE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ec2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ec2.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.amazonaws.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Defines credentials + region + service endpoint.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 2. EC2 Parameters
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RunInstances&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ImageId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ami-0f5ee92e2d63afc18&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;InstanceType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t2.micro&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MinCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MaxCount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2016-11-15&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This is the actual API request payload.&lt;/p&gt;




&lt;h2&gt;
  
  
  🕒 3. Timestamp
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;utcnow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;amz_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%Y%m%dT%H%M%SZ&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Required for AWS request validation.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔹 4. Canonical Query String
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;canonical_querystring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Sort + encode parameters&lt;br&gt;
👉 Critical step (most common failure point)&lt;/p&gt;


&lt;h2&gt;
  
  
  🔹 5. Canonical Request
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;canonical_request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;canonical_querystring&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;canonical_headers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;signed_headers&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payload_hash&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Exact request AWS validates internally.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔹 6. String to Sign
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;string_to_sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;amz_date&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;credential_scope&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canonical_request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 This is what gets signed.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔑 7. Signing Key
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;k_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;date_stamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVICE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k_signing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k_service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aws4_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;👉 Multi-step key derivation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Secret → Date → Region → Service → aws4_request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🔐 8. Signature
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;k_signing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;string_to_sign&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sha256&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Final cryptographic signature.&lt;/p&gt;




&lt;h2&gt;
  
  
  📬 9. Authorization Header
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-amz-date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;amz_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;authorization_header&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 This header authenticates your request.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 10. Sending Request
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👉 Sends request → AWS validates → returns response.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧠 Simple Analogy
&lt;/h1&gt;

&lt;p&gt;Think of SigV4 like a sealed envelope:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Canonical request → message&lt;/li&gt;
&lt;li&gt;Signing key → secret stamp&lt;/li&gt;
&lt;li&gt;Signature → seal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS checks the seal before accepting it.&lt;/p&gt;




&lt;h1&gt;
  
  
  ✅ Real Output
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Status Code: &lt;code&gt;200&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Instance created successfully&lt;/li&gt;
&lt;li&gt;Instance ID: &lt;code&gt;i-069a545b1814c6cec&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  ⚠️ Common Errors
&lt;/h1&gt;

&lt;h3&gt;
  
  
  ❌ SignatureDoesNotMatch
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Wrong encoding&lt;/li&gt;
&lt;li&gt;Params not sorted&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I got SignatureDoesNotMatch for almost 30 minutes before realizing I wasn’t sorting parameters correctly.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ UnauthorizedOperation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Missing IAM permissions&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  ❌ InvalidAMIID.NotFound
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Wrong AMI&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  ⚖️ boto3 vs requests
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;boto3&lt;/th&gt;
&lt;th&gt;requests + SigV4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ease&lt;/td&gt;
&lt;td&gt;✅ Easy&lt;/td&gt;
&lt;td&gt;❌ Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;❌ Limited&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Case&lt;/td&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;Learning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  🧠 Key Takeaway
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;After doing this, boto3 didn’t feel like magic anymore — just automation over HTTP.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  🚨 Important Note
&lt;/h1&gt;

&lt;p&gt;Use this approach for:&lt;/p&gt;

&lt;p&gt;✅ Learning&lt;br&gt;
✅ Debugging&lt;br&gt;
✅ Deep understanding&lt;/p&gt;

&lt;p&gt;❌ Not production&lt;/p&gt;




&lt;h1&gt;
  
  
  ✍️ Final Thought
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The hardest part wasn’t writing the code — it was getting the signature exactly right.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>api</category>
      <category>aws</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🐳 Containerizing a Python FastAPI Application with Docker (and Solving ARM vs x86 Architecture Issues)</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Sat, 07 Mar 2026 07:18:19 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/containerizing-a-python-fastapi-application-with-docker-and-solving-arm-vs-x86-architecture-1gfh</link>
      <guid>https://forem.com/jayakrishnayadav24/containerizing-a-python-fastapi-application-with-docker-and-solving-arm-vs-x86-architecture-1gfh</guid>
      <description>&lt;p&gt;When working with containerized applications, Docker usually makes deployments predictable and consistent. Once everything is packaged inside a container, the expectation is simple: “If it works on my machine, it should work everywhere.”&lt;/p&gt;

&lt;p&gt;However, real-world environments sometimes introduce subtle issues — especially when applications are built on machines with different CPU architectures, such as x86 (AMD64) and ARM64.&lt;/p&gt;

&lt;p&gt;Recently, I was containerizing a small Python FastAPI application, and I noticed something interesting. The Docker image worked perfectly on my Ubuntu server but behaved differently on another machine. After some investigation, the root cause turned out to be architecture differences between systems.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk through the entire process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Containerizing a FastAPI application with Docker&lt;/li&gt;
&lt;li&gt;Running the application using Docker Compose&lt;/li&gt;
&lt;li&gt;Understanding ARM vs x86 architecture differences&lt;/li&gt;
&lt;li&gt;Troubleshooting Docker daemon issues&lt;/li&gt;
&lt;li&gt;Building multi-architecture images&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you work with Python, FastAPI, Docker, or cloud deployments, this guide will help you avoid some common pitfalls.&lt;/p&gt;

&lt;p&gt;📁 Project Structure&lt;/p&gt;

&lt;p&gt;For this example, we'll use a simple API service called task-api-service.&lt;/p&gt;

&lt;p&gt;The project structure looks like this:&lt;/p&gt;

&lt;p&gt;task-api-service&lt;br&gt;
│&lt;br&gt;
├── Dockerfile&lt;br&gt;
├── docker-compose.yml&lt;br&gt;
├── requirements.txt&lt;br&gt;
├── main.py&lt;br&gt;
└── app/&lt;/p&gt;

&lt;p&gt;The FastAPI application exposes a REST API running on port 8080.&lt;/p&gt;

&lt;p&gt;🐍 Step 1 — Writing the Dockerfile&lt;/p&gt;

&lt;p&gt;The first step is creating a Dockerfile to containerize the application.&lt;/p&gt;

&lt;p&gt;We start with the official Python slim image, which provides a lightweight base environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.10-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update &amp;amp;&amp;amp; apt-get install -y \
    libgl1 \
    libglib2.0-0 \
    build-essential \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

RUN pip install --upgrade pip \
    &amp;amp;&amp;amp; pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8080

CMD ["uvicorn","main:app","--host","0.0.0.0","--port","8080"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why these optimizations?&lt;/p&gt;

&lt;p&gt;There are a few small improvements here that make the container more production-friendly.&lt;/p&gt;

&lt;p&gt;1️⃣ Prevent Python cache files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PYTHONDONTWRITEBYTECODE=1

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

&lt;/div&gt;



&lt;p&gt;This prevents .pyc files from being created inside the container.&lt;/p&gt;

&lt;p&gt;2️⃣ Better logging&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PYTHONUNBUFFERED=1

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

&lt;/div&gt;



&lt;p&gt;This ensures logs are immediately visible in Docker logs.&lt;/p&gt;

&lt;p&gt;3️⃣ Removing package cache&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm -rf /var/lib/apt/lists/*

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

&lt;/div&gt;



&lt;p&gt;This reduces the final image size.&lt;/p&gt;

&lt;p&gt;🏗 Step 2 — Building the Docker Image&lt;/p&gt;

&lt;p&gt;Once the Dockerfile is ready, we can build the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t task-api-service .

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

&lt;/div&gt;



&lt;p&gt;After building, verify the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker images

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

&lt;/div&gt;



&lt;p&gt;You should see the new image listed.&lt;/p&gt;

&lt;p&gt;🚀 Step 3 — Running the Container&lt;/p&gt;

&lt;p&gt;Now we can run the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 8088:8080 task-api-service

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

&lt;/div&gt;



&lt;p&gt;The application will now be accessible at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8088

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

&lt;/div&gt;



&lt;p&gt;Docker maps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host Port 8088 → Container Port 8080

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

&lt;/div&gt;



&lt;p&gt;⚙️ Step 4 — Using Docker Compose&lt;/p&gt;

&lt;p&gt;Managing containers manually becomes inconvenient as applications grow.&lt;/p&gt;

&lt;p&gt;This is where Docker Compose becomes useful.&lt;/p&gt;

&lt;p&gt;Create a file called docker-compose.yml.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.9"

services:
  fastapi-app:
    container_name: fastapi-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8088:8080"
    volumes:
      - .:/app
    restart: unless-stopped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;📂 Why Use Volumes?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;volumes:
  - .:/app

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

&lt;/div&gt;



&lt;p&gt;This mounts the local project directory into the container.&lt;/p&gt;

&lt;p&gt;Benefits include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instant reflection of code changes&lt;/li&gt;
&lt;li&gt;Faster development workflow&lt;/li&gt;
&lt;li&gt;No need to rebuild images repeatedly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you run Uvicorn with the --reload flag, the server automatically restarts when files change.&lt;/p&gt;

&lt;p&gt;▶️ Running with Docker Compose&lt;/p&gt;

&lt;p&gt;Start the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up --build

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

&lt;/div&gt;



&lt;p&gt;Run it in the background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up -d

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

&lt;/div&gt;



&lt;p&gt;Stop the containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose down

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

&lt;/div&gt;



&lt;p&gt;⚠️ The Architecture Problem (ARM vs x86)&lt;/p&gt;

&lt;p&gt;Everything worked perfectly on my Ubuntu machine.&lt;/p&gt;

&lt;p&gt;To check the system architecture, I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uname -m

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

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x86_64

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

&lt;/div&gt;



&lt;p&gt;This means the system uses AMD64 architecture.&lt;/p&gt;

&lt;p&gt;However, many modern systems now use ARM architecture, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apple Silicon Macs&lt;/li&gt;
&lt;li&gt;AWS Graviton instances&lt;/li&gt;
&lt;li&gt;Raspberry Pi servers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running the same command on those systems usually returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arm64

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

&lt;/div&gt;



&lt;p&gt;This difference can cause compatibility issues when Docker images are built on one architecture and run on another.&lt;/p&gt;

&lt;p&gt;🔧 Forcing a Specific Docker Platform&lt;/p&gt;

&lt;p&gt;Docker allows specifying the target architecture during builds.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build --platform linux/arm64 -t task-api-service .

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

&lt;/div&gt;



&lt;p&gt;This forces Docker to build an ARM-compatible image.&lt;/p&gt;

&lt;p&gt;You can also define the platform inside Docker Compose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
  fastapi-app:
    build:
      context: .
    platform: linux/arm64
    ports:
      - "8088:8080"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛠 Troubleshooting Docker Daemon Issues&lt;/p&gt;

&lt;p&gt;During testing, I encountered an error like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cannot connect to the Docker daemon at unix:///var/run/docker.sock

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

&lt;/div&gt;



&lt;p&gt;This usually means the Docker daemon is not running.&lt;/p&gt;

&lt;p&gt;To verify Docker status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl status docker

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

&lt;/div&gt;



&lt;p&gt;If the service is inactive, restart it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl restart docker

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

&lt;/div&gt;



&lt;p&gt;Then confirm Docker is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps

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

&lt;/div&gt;



&lt;p&gt;🔐 Fixing Docker Permission Issues&lt;/p&gt;

&lt;p&gt;Another common issue occurs when Docker commands require sudo.&lt;/p&gt;

&lt;p&gt;This happens because the user is not part of the Docker group.&lt;/p&gt;

&lt;p&gt;To fix it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo usermod -aG docker $USER

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

&lt;/div&gt;



&lt;p&gt;Then reload the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;newgrp docker

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

&lt;/div&gt;



&lt;p&gt;Now Docker commands can run without sudo.&lt;/p&gt;

&lt;p&gt;🌍 Best Practice: Multi-Architecture Docker Images&lt;/p&gt;

&lt;p&gt;Instead of building separate images for ARM and x86 systems, Docker allows multi-architecture builds.&lt;/p&gt;

&lt;p&gt;Using Docker Buildx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker buildx build \
--platform linux/amd64,linux/arm64 \
-t myrepo/task-api-service:latest \
--push .

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

&lt;/div&gt;



&lt;p&gt;This creates a single image compatible with multiple architectures.&lt;/p&gt;

&lt;p&gt;Official Docker images such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;all use this approach.&lt;/p&gt;

&lt;p&gt;🧠 Final Thoughts&lt;/p&gt;

&lt;p&gt;Docker makes it easy to package and deploy applications consistently, but architecture differences can sometimes introduce unexpected issues.&lt;/p&gt;

&lt;p&gt;A few key lessons from this experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always check system architecture using uname -m&lt;/li&gt;
&lt;li&gt;Use Docker Compose for easier container management&lt;/li&gt;
&lt;li&gt;Ensure the Docker daemon is running before troubleshooting builds&lt;/li&gt;
&lt;li&gt;Consider multi-architecture images for production deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding these concepts, you can ensure your containerized applications run smoothly across different environments, cloud platforms, and development machines.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>fastapi</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>🚀 Real-Time Data Replication Using MySQL, Debezium, Kafka, and Docker (CDC Guide)</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 20 Feb 2026 03:11:12 +0000</pubDate>
      <link>https://forem.com/aws-builders/real-time-data-replication-using-mysql-debezium-kafka-and-docker-cdc-guide-4i88</link>
      <guid>https://forem.com/aws-builders/real-time-data-replication-using-mysql-debezium-kafka-and-docker-cdc-guide-4i88</guid>
      <description>&lt;h2&gt;
  
  
  📌 Introduction
&lt;/h2&gt;

&lt;p&gt;Modern applications often need data to move between systems in real time — analytics platforms, microservices, search indexes, or backup databases.&lt;/p&gt;

&lt;p&gt;Traditional approaches like batch jobs or cron-based sync introduce delays, inconsistencies, and operational complexity.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Change Data Capture (CDC)&lt;/strong&gt; becomes powerful.&lt;/p&gt;

&lt;p&gt;In this article, we’ll build a simple but powerful &lt;strong&gt;real-time database replication pipeline&lt;/strong&gt; using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;Debezium&lt;/li&gt;
&lt;li&gt;Apache Kafka&lt;/li&gt;
&lt;li&gt;Kafka Connect (JDBC Sink)&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the end, you’ll have a working system that automatically replicates inserts, updates, and deletes from one database to another.&lt;/p&gt;




&lt;h1&gt;
  
  
  🔥 What is Change Data Capture (CDC)?
&lt;/h1&gt;

&lt;p&gt;Change Data Capture is a technique used to capture database changes (INSERT, UPDATE, DELETE) and stream them to other systems in real time.&lt;/p&gt;

&lt;p&gt;Instead of polling the database repeatedly, CDC reads the &lt;strong&gt;database transaction log&lt;/strong&gt; (binlog in MySQL).&lt;/p&gt;

&lt;p&gt;This makes CDC:&lt;/p&gt;

&lt;p&gt;✅ Real-time&lt;br&gt;
✅ Efficient&lt;br&gt;
✅ Reliable&lt;br&gt;
✅ Scalable&lt;/p&gt;


&lt;h1&gt;
  
  
  ❓ Why Do We Need CDC?
&lt;/h1&gt;

&lt;p&gt;Common use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Real-time analytics pipelines&lt;/li&gt;
&lt;li&gt;Microservices data synchronization&lt;/li&gt;
&lt;li&gt;Data warehousing&lt;/li&gt;
&lt;li&gt;Cache invalidation&lt;/li&gt;
&lt;li&gt;Event-driven architectures&lt;/li&gt;
&lt;li&gt;Search indexing (Elasticsearch)&lt;/li&gt;
&lt;li&gt;Zero-downtime migrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without CDC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App → DB → Batch Job → Other Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With CDC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App → DB → CDC Stream → Multiple Systems
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much faster and cleaner.&lt;/p&gt;




&lt;h1&gt;
  
  
  🏗 Architecture Overview
&lt;/h1&gt;

&lt;p&gt;We will build the following pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MySQL Source
     ↓ (binlog)
Debezium Connector
     ↓
Kafka Topic
     ↓
JDBC Sink Connector
     ↓
MySQL Target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🐳 Step 1 — Docker Compose Setup
&lt;/h1&gt;

&lt;p&gt;We’ll run everything using Docker so the setup is easy and reproducible.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;strong&gt;docker-compose.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;zookeeper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-zookeeper:7.5.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ZOOKEEPER_CLIENT_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2181&lt;/span&gt;

  &lt;span class="na"&gt;kafka&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;confluentinc/cp-kafka:7.5.0&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zookeeper&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9092:9092"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_BROKER_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ZOOKEEPER_CONNECT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zookeeper:2181&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAINTEXT://0.0.0.0:9092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_ADVERTISED_LISTENERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PLAINTEXT://localhost:9092&lt;/span&gt;
      &lt;span class="na"&gt;KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;

  &lt;span class="na"&gt;mysql-source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;company&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;--server-id=1&lt;/span&gt;
      &lt;span class="s"&gt;--log-bin=mysql-bin&lt;/span&gt;
      &lt;span class="s"&gt;--binlog-format=ROW&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3306:3306"&lt;/span&gt;

  &lt;span class="na"&gt;mysql-target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3307:3306"&lt;/span&gt;

  &lt;span class="na"&gt;connect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;debezium/connect:2.5&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;kafka&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mysql-source&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8083:8083"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;BOOTSTRAP_SERVERS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kafka:9092&lt;/span&gt;
      &lt;span class="na"&gt;GROUP_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;CONFIG_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;connect_configs&lt;/span&gt;
      &lt;span class="na"&gt;OFFSET_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;connect_offsets&lt;/span&gt;
      &lt;span class="na"&gt;STATUS_STORAGE_TOPIC&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;connect_status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it ~30 seconds for services to fully start.&lt;/p&gt;




&lt;h1&gt;
  
  
  🗄 Step 2 — Create Database and Table (Source)
&lt;/h1&gt;

&lt;p&gt;Because MySQL is running inside Docker, we execute commands using Docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; mysql-source mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
CREATE DATABASE IF NOT EXISTS company;
USE company;

CREATE TABLE IF NOT EXISTS employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100),
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-T&lt;/span&gt; mysql-target mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
CREATE DATABASE IF NOT EXISTS company;
USE company;

DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100),
    created_at TIMESTAMP NULL
);
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insert some sample data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-source mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
USE company;
INSERT INTO employees(name,email)
VALUES ('John Doe','john@example.com');
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🔌 Step 3 — Configure Debezium Source Connector
&lt;/h1&gt;

&lt;p&gt;This connector reads MySQL binlog and publishes events into Kafka.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8083/connectors &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
  "name": "mysql-connector",
  "config": {
    "connector.class": "io.debezium.connector.mysql.MySqlConnector",
    "database.hostname": "mysql-source",
    "database.port": "3306",
    "database.user": "root",
    "database.password": "root",
    "database.server.id": "184054",
    "topic.prefix": "dbserver1",
    "database.include.list": "company",
    "table.include.list": "company.employees",
    "schema.history.internal.kafka.bootstrap.servers": "kafka:9092",
    "schema.history.internal.kafka.topic": "schema-changes.company",

    "transforms": "unwrap",
    "transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState"
  }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kafka topic created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dbserver1.company.employees
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  🎯 Step 4 — Configure Sink Connector (Target MySQL)
&lt;/h1&gt;

&lt;p&gt;Create target database first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-target mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
CREATE DATABASE IF NOT EXISTS company;
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the sink connector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8083/connectors &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
  "name": "mysql-sink",
  "config": {
    "connector.class": "io.debezium.connector.jdbc.JdbcSinkConnector",
    "topics": "dbserver1.company.employees",

    "connection.url": "jdbc:mysql://mysql-target:3306/company",
    "connection.username": "root",
    "connection.password": "root",

    "insert.mode": "upsert",
    "delete.enabled": "true",
    "primary.key.mode": "record_key",
    "primary.key.fields": "id",

    "auto.create": "true",
    "auto.evolve": "true",
    "table.name.format": "employees"
  }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  ⚠️ Important — Restart Connector if Needed
&lt;/h1&gt;

&lt;p&gt;Sometimes connectors fail initially due to schema timing or table issues.&lt;/p&gt;

&lt;p&gt;Restart connector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"http://localhost:8083/connectors/mysql-sink/restart?includeTasks=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8083/connectors/mysql-sink/status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is completely normal when working with Kafka Connect.&lt;/p&gt;




&lt;h1&gt;
  
  
  🧪 Step 5 — Test Real-Time Replication
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Insert
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-source mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
USE company;
INSERT INTO employees(name,email)
VALUES ('Alice','alice@test.com');
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-source mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
USE company;
UPDATE employees
SET name='Updated User'
WHERE id=1;
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Delete
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-source mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
USE company;
DELETE FROM employees
WHERE id=2;
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  📥 Verify Data in Target
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;mysql-target mysql &lt;span class="nt"&gt;-uroot&lt;/span&gt; &lt;span class="nt"&gt;-proot&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
USE company;
SELECT * FROM employees;
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If data doesn’t appear immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wait a few seconds&lt;/li&gt;
&lt;li&gt;Restart connector&lt;/li&gt;
&lt;li&gt;Try again&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  🧠 How It Works Internally
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;MySQL writes change to binlog&lt;/li&gt;
&lt;li&gt;Debezium reads binlog&lt;/li&gt;
&lt;li&gt;Kafka stores event&lt;/li&gt;
&lt;li&gt;Sink connector consumes event&lt;/li&gt;
&lt;li&gt;JDBC writes to target DB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All within seconds.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚠️ Lessons Learned
&lt;/h1&gt;

&lt;p&gt;During setup we faced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connector schema issues&lt;/li&gt;
&lt;li&gt;Table mapping problems&lt;/li&gt;
&lt;li&gt;Sink auto-creation failures&lt;/li&gt;
&lt;li&gt;Connector crashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key learnings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always unwrap Debezium events&lt;/li&gt;
&lt;li&gt;Pre-create tables in production&lt;/li&gt;
&lt;li&gt;Restart connector tasks when failed&lt;/li&gt;
&lt;li&gt;Understand topic naming&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  🚀 Production Best Practices
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Use Schema Registry&lt;/li&gt;
&lt;li&gt;Enable monitoring&lt;/li&gt;
&lt;li&gt;Use DLQ&lt;/li&gt;
&lt;li&gt;Use migration tools&lt;/li&gt;
&lt;li&gt;Secure credentials&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  ✅ Conclusion
&lt;/h1&gt;

&lt;p&gt;CDC enables real-time data movement with minimal overhead.&lt;/p&gt;

&lt;p&gt;Debezium + Kafka provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scalability&lt;/li&gt;
&lt;li&gt;Reliability&lt;/li&gt;
&lt;li&gt;Low latency&lt;/li&gt;
&lt;li&gt;Event-driven architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is widely used in modern distributed systems.&lt;/p&gt;




&lt;h1&gt;
  
  
  🙌 Final Thoughts
&lt;/h1&gt;

&lt;p&gt;If you are working in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Engineering&lt;/li&gt;
&lt;li&gt;DevOps&lt;/li&gt;
&lt;li&gt;Backend Systems&lt;/li&gt;
&lt;li&gt;Platform Engineering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learning CDC is extremely valuable.&lt;/p&gt;




&lt;p&gt;⭐ If you enjoyed this article, feel free to connect and share your feedback!&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>mysql</category>
      <category>docker</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Zero‑Downtime Deployments on AKS with Azure Application Gateway Ingress Controller (AGIC)</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Fri, 23 Jan 2026 15:10:27 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/zero-downtime-deployments-on-aks-with-azure-application-gateway-ingress-controller-agic-on5</link>
      <guid>https://forem.com/jayakrishnayadav24/zero-downtime-deployments-on-aks-with-azure-application-gateway-ingress-controller-agic-on5</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;While deploying applications on &lt;strong&gt;Azure Kubernetes Service (AKS)&lt;/strong&gt; behind &lt;strong&gt;Azure Application Gateway Ingress Controller (AGIC)&lt;/strong&gt;, I repeatedly faced &lt;strong&gt;brief but noticeable downtime&lt;/strong&gt; during deployments.&lt;/p&gt;

&lt;p&gt;The issue was not with Kubernetes itself, but with &lt;strong&gt;how AGIC updates backend pool IPs&lt;/strong&gt; when pods are replaced during a deployment.&lt;/p&gt;

&lt;p&gt;By default, during a rollout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Old pods are terminated&lt;/li&gt;
&lt;li&gt;New pods come up with new IPs&lt;/li&gt;
&lt;li&gt;AGIC takes &lt;strong&gt;around 30 seconds&lt;/strong&gt; (sometimes more) to detect and update these new pod IPs in Application Gateway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During this window, Application Gateway may still route traffic to terminating pods → resulting in &lt;strong&gt;5xx errors or downtime&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Root Cause
&lt;/h2&gt;

&lt;p&gt;Let’s understand what was happening internally:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Kubernetes starts terminating old pods&lt;/li&gt;
&lt;li&gt;Pods are removed from Endpoints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AGIC needs time&lt;/strong&gt; to:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Detect endpoint changes&lt;/li&gt;
&lt;li&gt;Update Application Gateway backend pool&lt;/li&gt;
&lt;li&gt;Push config updates

&lt;ol&gt;
&lt;li&gt;Meanwhile, traffic is still flowing&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If pods terminate &lt;strong&gt;too fast&lt;/strong&gt;, Application Gateway temporarily has &lt;strong&gt;no healthy backend&lt;/strong&gt;, causing downtime.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Strategy That Fixed It
&lt;/h2&gt;

&lt;p&gt;After digging into this and testing a few approaches in production, I implemented &lt;strong&gt;three small but very effective changes&lt;/strong&gt; in my Deployment YAML:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. RollingUpdate Strategy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;
  &lt;span class="na"&gt;rollingUpdate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;maxSurge&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;maxUnavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensures &lt;strong&gt;at least one pod is always available&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;New pod comes up &lt;strong&gt;before&lt;/strong&gt; old pod is removed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Increased Termination Grace Period
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;terminationGracePeriodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gives Kubernetes &lt;strong&gt;5 minutes&lt;/strong&gt; before force‑killing the pod&lt;/li&gt;
&lt;li&gt;Allows existing connections to complete&lt;/li&gt;
&lt;li&gt;Buys time for AGIC to update backend pool&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. preStop Hook to Delay Pod Shutdown
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;lifecycle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;preStop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;exec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/bin/sh"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sleep&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;280"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pod stays in &lt;code&gt;Terminating&lt;/code&gt; state for ~280 seconds&lt;/li&gt;
&lt;li&gt;Application Gateway continues routing traffic safely&lt;/li&gt;
&lt;li&gt;AGIC finishes updating new pod IPs before traffic stops&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Changed After This?
&lt;/h2&gt;

&lt;p&gt;After applying this configuration in production, the difference was immediately noticeable:&lt;/p&gt;

&lt;p&gt;✅ No more deployment‑time downtime&lt;/p&gt;

&lt;p&gt;✅ Zero 502 / 504 errors from Application Gateway&lt;/p&gt;

&lt;p&gt;✅ Smooth traffic transition between old and new pods&lt;/p&gt;

&lt;p&gt;✅ AGIC gets enough time to sync backend pool changes&lt;/p&gt;

&lt;p&gt;Even during peak traffic, deployments became &lt;strong&gt;completely seamless&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is Important for AGIC Users
&lt;/h2&gt;

&lt;p&gt;AGIC is &lt;strong&gt;not instant&lt;/strong&gt;. It operates asynchronously and depends on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kubernetes endpoint updates&lt;/li&gt;
&lt;li&gt;ARM / Application Gateway config propagation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So &lt;strong&gt;fast pod termination = broken traffic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This pattern ensures:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Never kill a pod until the load balancer has fully learned about the new one.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Final Thoughts (From Real Experience)
&lt;/h2&gt;

&lt;p&gt;If you are using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AKS&lt;/li&gt;
&lt;li&gt;Azure Application Gateway&lt;/li&gt;
&lt;li&gt;AGIC&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and facing &lt;strong&gt;deployment‑time downtime&lt;/strong&gt;, this approach is &lt;strong&gt;mandatory&lt;/strong&gt;, not optional.&lt;/p&gt;

&lt;p&gt;Kubernetes already gives us the right tools — we just need to tune them correctly based on how cloud load balancers like Application Gateway behave in the real world.&lt;/p&gt;




&lt;p&gt;Happy deploying 🚀&lt;/p&gt;

&lt;p&gt;Let me know if you want a version with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Diagrams&lt;/li&gt;
&lt;li&gt;AGIC internals&lt;/li&gt;
&lt;li&gt;Comparison with NGINX ingress&lt;/li&gt;
&lt;li&gt;Real production metrics&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>aks</category>
      <category>devops</category>
      <category>agic</category>
    </item>
    <item>
      <title>Reducing Sentry APM Costs in FastAPI by Sending Only What Matters</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Thu, 08 Jan 2026 06:41:51 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/reducing-sentry-apm-costs-in-fastapi-by-sending-only-what-matters-2lmm</link>
      <guid>https://forem.com/jayakrishnayadav24/reducing-sentry-apm-costs-in-fastapi-by-sending-only-what-matters-2lmm</guid>
      <description>&lt;p&gt;When I first enabled managed Sentry APM for a FastAPI application, the visibility felt amazing.&lt;br&gt;
Every request was traced. Every endpoint had performance data.&lt;/p&gt;

&lt;p&gt;But that excitement didn’t last long.&lt;/p&gt;

&lt;p&gt;After a few days in production, I realized something important:&lt;/p&gt;

&lt;p&gt;Most of my Sentry APM usage was coming from perfectly healthy, fast requests that I never looked at again.&lt;/p&gt;

&lt;p&gt;Successful GETs, quick POSTs, OpenAPI calls — all of them were being sent to Sentry, eating up the quota and increasing cost without providing real value.&lt;/p&gt;

&lt;p&gt;So instead of scaling my Sentry plan, I chose a different approach:&lt;/p&gt;

&lt;p&gt;👉 Send fewer transactions, but send the right ones.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Real Problem with Default APM
&lt;/h2&gt;

&lt;p&gt;By default, Sentry APM is very generous:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every request becomes a transaction&lt;/li&gt;
&lt;li&gt;Even sub-second successful calls are recorded&lt;/li&gt;
&lt;li&gt;Docs and schema endpoints are also traced&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For high-traffic APIs, this quickly turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large transaction volume&lt;/li&gt;
&lt;li&gt;Faster quota exhaustion&lt;/li&gt;
&lt;li&gt;Paying for noise instead of insight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, I only needed visibility into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests that fail (5xx)&lt;/li&gt;
&lt;li&gt;Requests that are slow&lt;/li&gt;
&lt;li&gt;Anything abnormal or risky&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything else was just background noise.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Cost-Saving Strategy
&lt;/h2&gt;

&lt;p&gt;I defined very simple rules:&lt;/p&gt;
&lt;h2&gt;
  
  
  Always Send to Sentry
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Any request returning 5xx&lt;/li&gt;
&lt;li&gt;Any request taking more than 5 seconds&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Drop from Sentry
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fast GET / POST / PUT requests&lt;/li&gt;
&lt;li&gt;Successful requests completing under 3 seconds&lt;/li&gt;
&lt;li&gt;/docs and /openapi.json endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps Sentry focused on problems, not traffic volume.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Two Middlewares Are Required
&lt;/h2&gt;

&lt;p&gt;This part is important and often misunderstood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.add_middleware(SentryAsgiMiddleware)
app.add_middleware(TimingMiddleware)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two middlewares do different jobs, and both are required.&lt;/p&gt;

&lt;h2&gt;
  
  
  SentryAsgiMiddleware – Enables APM
&lt;/h2&gt;

&lt;p&gt;SentryAsgiMiddleware is what actually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts and finishes Sentry transactions&lt;/li&gt;
&lt;li&gt;Hooks into the ASGI request lifecycle&lt;/li&gt;
&lt;li&gt;Sends performance data to Sentry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this middleware:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No transactions are created&lt;/li&gt;
&lt;li&gt;before_send_transaction is never called&lt;/li&gt;
&lt;li&gt;APM simply does not work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;p&gt;No SentryAsgiMiddleware = No APM&lt;/p&gt;

&lt;h2&gt;
  
  
  TimingMiddleware – Adds Intelligence
&lt;/h2&gt;

&lt;p&gt;The second middleware is custom.&lt;/p&gt;

&lt;p&gt;It measures the real execution time of each request and attaches it to the Sentry scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class TimingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        start_time = time.time()
        response = await call_next(request)
        duration = time.time() - start_time

        with sentry_sdk.configure_scope() as scope:
            scope.set_extra("duration", duration)

        return response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this is needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Execution time is required to decide whether a request is “important”&lt;/li&gt;
&lt;li&gt;Sentry’s internal timing isn’t easily usable for filtering&lt;/li&gt;
&lt;li&gt;Without this, cost-control logic becomes guesswork&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it this way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SentryAsgiMiddleware is the pipeline&lt;/li&gt;
&lt;li&gt;TimingMiddleware is the brain&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Filtering Transactions Before They Are Sent
&lt;/h2&gt;

&lt;p&gt;Sentry provides a hook called before_send_transaction.&lt;br&gt;
This runs just before a transaction is sent to Sentry and allows you to drop it.&lt;/p&gt;

&lt;p&gt;This is where the cost optimization happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def before_send_transaction(event, hint):
    transaction_name = event.get("transaction", "")
    request_method = event.get("request", {}).get("method", "")
    status_code = event.get("contexts", {}).get("response", {}).get("status_code", 0)

    duration = event.get("extra", {}).get("duration")

    # Ignore docs and schema
    if "/docs" in transaction_name or "/openapi.json" in transaction_name:
        return None

    # Always send server errors
    if 500 &amp;lt;= status_code &amp;lt;= 599:
        return event

    # Send slow requests
    if duration and duration &amp;gt; 5:
        return event

    # Drop fast successful requests
    if request_method in ["GET", "POST", "PUT"] \
       and 200 &amp;lt;= status_code &amp;lt; 400 \
       and duration and duration &amp;lt; 3:
        return None

    return event
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this function returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;event → transaction is sent&lt;/li&gt;
&lt;li&gt;None → transaction is dropped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple, predictable, and fully under your control.&lt;/p&gt;

&lt;p&gt;Initializing Sentry with Custom Filtering&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sentry_sdk.init(
    dsn="SENTRY_DSN",
    send_default_pii=True,
    traces_sample_rate=1.0,
    before_send_transaction=before_send_transaction,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of relying on random sampling, this approach gives deterministic filtering based on real behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed After This
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Lower Cost
&lt;/h2&gt;

&lt;p&gt;Transaction volume dropped sharply.&lt;br&gt;
Sentry usage slowed down immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaner Dashboards
&lt;/h2&gt;

&lt;p&gt;Only slow or failing requests appeared.&lt;br&gt;
Debugging became easier, not harder.&lt;/p&gt;

&lt;p&gt;Better Signal&lt;/p&gt;

&lt;p&gt;Every transaction in Sentry now means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“This is worth looking at.”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When This Approach Makes Sense
&lt;/h2&gt;

&lt;p&gt;This works best when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your API traffic is high&lt;/li&gt;
&lt;li&gt;Most requests are successful and fast&lt;/li&gt;
&lt;li&gt;You care more about issues than metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want every request traced forever, this is not the right approach.&lt;br&gt;
If you want useful observability without burning money, it absolutely is.&lt;/p&gt;

&lt;p&gt;Final Thoughts&lt;/p&gt;

&lt;p&gt;APM should help you find problems, not create new ones in your billing dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  By combining:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;SentryAsgiMiddleware&lt;/li&gt;
&lt;li&gt;A simple timing middleware&lt;/li&gt;
&lt;li&gt;before_send_transaction&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  You turn Sentry from:
&lt;/h2&gt;

&lt;p&gt;“collect everything”&lt;br&gt;
into&lt;br&gt;
“collect what actually matters”&lt;/p&gt;

&lt;p&gt;And that small change makes a huge difference in real production systems.&lt;/p&gt;

</description>
      <category>sentry</category>
      <category>python</category>
    </item>
    <item>
      <title>Automating S3 Data Retention by Prefix Using Python (DevOps Automation Story)</title>
      <dc:creator>POTHURAJU JAYAKRISHNA YADAV</dc:creator>
      <pubDate>Thu, 08 Jan 2026 06:25:05 +0000</pubDate>
      <link>https://forem.com/jayakrishnayadav24/automating-s3-data-retention-by-prefix-using-python-devops-automation-story-3kjk</link>
      <guid>https://forem.com/jayakrishnayadav24/automating-s3-data-retention-by-prefix-using-python-devops-automation-story-3kjk</guid>
      <description>&lt;p&gt;In many production systems, object storage slowly becomes a dumping ground.&lt;/p&gt;

&lt;p&gt;Logs, reports, media files, exports — everything lands in the same S3 bucket, but not all data needs to live forever. The real challenge is not deleting data, but deleting the right data at the right time, without relying on manual processes.&lt;/p&gt;

&lt;p&gt;This post explains how I automated folder-level retention policies in Amazon S3 using Python, turning a repetitive console task into a clean, auditable automation.&lt;/p&gt;

&lt;p&gt;The scenario (fictional but realistic)&lt;/p&gt;

&lt;p&gt;Imagine a shared S3 bucket used by multiple internal teams:&lt;/p&gt;

&lt;p&gt;company-shared-storage/&lt;br&gt;
 ├── analytics/&lt;br&gt;
 ├── audit-logs/&lt;br&gt;
 ├── temp-exports/&lt;br&gt;
 ├── media-processing/&lt;br&gt;
 └── legal-archive/&lt;/p&gt;

&lt;p&gt;Each folder has a different data lifecycle requirement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Prefix    Retention
&amp;gt; analytics/    3 months
&amp;gt; audit-logs/   6 months
&amp;gt; temp-exports/ 30 days
&amp;gt; media-processing/ 90 days
&amp;gt; legal-archive/    retain forever
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Managing this manually in the AWS Console does not scale and is easy to misconfigure.&lt;/p&gt;

&lt;p&gt;Why automation was necessary&lt;/p&gt;

&lt;p&gt;Manually configuring lifecycle rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires repetitive console work&lt;/li&gt;
&lt;li&gt;Is difficult to review and audit&lt;/li&gt;
&lt;li&gt;Does not fit infrastructure-as-code practices&lt;/li&gt;
&lt;li&gt;Is error-prone during changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So instead of treating retention as a one-time setup, I treated it as automation logic.&lt;/p&gt;

&lt;p&gt;Important constraints to understand first&lt;/p&gt;

&lt;p&gt;Before writing any automation, it’s critical to understand how S3 behaves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 lifecycle expiration is based on object creation time&lt;/li&gt;
&lt;li&gt;It does not track last access or last modification&lt;/li&gt;
&lt;li&gt;S3 has no real folders — only prefixes&lt;/li&gt;
&lt;li&gt;Lifecycle rules delete objects, not folders&lt;/li&gt;
&lt;li&gt;Buckets without versioning only need “expire current versions”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Designing automation without knowing this leads to surprises later.&lt;/p&gt;

&lt;p&gt;Automation design approach&lt;/p&gt;

&lt;p&gt;The goal was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define retention rules as data&lt;/li&gt;
&lt;li&gt;Convert retention into lifecycle policies programmatically&lt;/li&gt;
&lt;li&gt;Skip prefixes that should never be touched&lt;/li&gt;
&lt;li&gt;Make the process repeatable and reviewable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Retention rules were expressed in a simple mapping structure, not hardcoded logic.&lt;/p&gt;

&lt;p&gt;Python automation example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3

bucket_name = "company-shared-storage"
profile = "prod-profile"

retention_map = {
    "analytics/": 90,
    "audit-logs/": 180,
    "temp-exports/": 30,
    "media-processing/": 90,
    "legal-archive/": None
}

session = boto3.Session(profile_name=profile)
s3 = session.client("s3")

rules = []

for prefix, days in retention_map.items():
    if not days:
        continue

    rules.append({
        "ID": f"expire-{prefix.strip('/')}-{days}-days",
        "Status": "Enabled",
        "Filter": {"Prefix": prefix},
        "Expiration": {"Days": days}
    })

if rules:
    s3.put_bucket_lifecycle_configuration(
        Bucket=bucket_name,
        LifecycleConfiguration={"Rules": rules}
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this automation achieves&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Objects under analytics/ are deleted after 90 days&lt;/li&gt;
&lt;li&gt;Objects under audit-logs/ are deleted after 180 days&lt;/li&gt;
&lt;li&gt;Objects under legal-archive/ are never deleted&lt;/li&gt;
&lt;li&gt;Overwriting an object resets its expiration timer&lt;/li&gt;
&lt;li&gt;Lifecycle execution is handled asynchronously by S3
No human intervention required after setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this is real automation&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Removes manual AWS Console dependency&lt;/li&gt;
&lt;li&gt;Makes retention policy code-driven&lt;/li&gt;
&lt;li&gt;Allows easy updates through version control&lt;/li&gt;
&lt;li&gt;Reduces the risk of accidental data loss&lt;/li&gt;
&lt;li&gt;Aligns with Infrastructure-as-Code principles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Retention stops being “someone’s responsibility” and becomes system behavior.&lt;/p&gt;

&lt;p&gt;Key lessons learned&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lifecycle policies are based on creation time, not inactivity&lt;/li&gt;
&lt;li&gt;Prefix-based retention works well when automation-driven&lt;/li&gt;
&lt;li&gt;Empty retention should explicitly mean “no rule”&lt;/li&gt;
&lt;li&gt;Lifecycle rules overwrite existing configuration — automation must be intentional&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where this can be extended&lt;/p&gt;

&lt;p&gt;This automation can easily evolve into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reading retention from a CSV or database&lt;/li&gt;
&lt;li&gt;A scheduled compliance check&lt;/li&gt;
&lt;li&gt;Validation against existing lifecycle rules&lt;/li&gt;
&lt;li&gt;Integration into CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Final takeaway&lt;/p&gt;

&lt;p&gt;S3 lifecycle policies are powerful, but their real value comes when they are automated, not manually configured.&lt;/p&gt;

&lt;p&gt;Small automations like this reduce operational overhead and prevent long-term storage sprawl — which is exactly what good DevOps is about.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>automation</category>
      <category>python</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
