<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://venky-profile.myvnc.com/blog</id>
    <title>Venky Profile Hub Blog</title>
    <updated>2026-07-06T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://venky-profile.myvnc.com/blog"/>
    <subtitle>Venky Profile Hub Blog</subtitle>
    <icon>https://venky-profile.myvnc.com/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Argo CD 3.5: Solving Real GitOps Problems at Scale]]></title>
        <id>https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale</id>
        <link href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale"/>
        <updated>2026-07-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Running GitOps at enterprise scale sounds straightforward until you actually do it. Once you have hundreds of applications spread across multiple Kubernetes clusters, regions, and teams, the real challenges surface: visibility into what is deployed where, security boundaries between teams, ownership clarity, and supply chain integrity. Argo CD 3.5 tackles these problems head-on with a set of features that feel like they were designed by people who have lived through these exact pain points.]]></summary>
        <content type="html"><![CDATA[<p>Running GitOps at enterprise scale sounds straightforward until you actually do it. Once you have hundreds of applications spread across multiple Kubernetes clusters, regions, and teams, the real challenges surface: visibility into what is deployed where, security boundaries between teams, ownership clarity, and supply chain integrity. Argo CD 3.5 tackles these problems head-on with a set of features that feel like they were designed by people who have lived through these exact pain points.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>Our GitOps platform had grown to serve dozens of engineering teams deploying hundreds of applications across multiple Kubernetes clusters in different AWS regions. The core deployment mechanics worked well enough, but the operational challenges had shifted. Teams could not easily see which ApplicationSets belonged to them. Security boundaries between team namespaces were blurry. There was no built-in mechanism to verify that manifests had not been tampered with between commit and deploy. And onboarding new teams meant platform engineers manually configuring RBAC for every new project.</p>
<p>These are not beginner problems. They are the problems that emerge when GitOps succeeds and scales beyond a single team.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Evaluate how Argo CD 3.5 addresses the challenges we were experiencing at scale, specifically around multi-team visibility, security posture, supply chain integrity, and developer self-service. The goal was to determine which new capabilities could be adopted immediately and which required changes to our platform architecture.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="applicationset-ui-improvements">ApplicationSet UI Improvements<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#applicationset-ui-improvements" class="hash-link" aria-label="Direct link to ApplicationSet UI Improvements" title="Direct link to ApplicationSet UI Improvements" translate="no">​</a></h3>
<p>Previously, ApplicationSets were invisible in the Argo CD UI. You could see the generated Applications but had no way to trace them back to the template that created them. Version 3.5 introduces first-class ApplicationSet visibility in the dashboard, showing the relationship between sets and their child applications. This alone reduced the number of "who owns this app?" questions from teams significantly.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="applicationsets-in-any-namespace">ApplicationSets in Any Namespace<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#applicationsets-in-any-namespace" class="hash-link" aria-label="Direct link to ApplicationSets in Any Namespace" title="Direct link to ApplicationSets in Any Namespace" translate="no">​</a></h3>
<p>Before 3.5, all ApplicationSets lived in the argocd namespace. This made it impossible to give teams true ownership over their deployment templates without granting them access to the Argo CD control plane namespace. Now ApplicationSets can exist in any namespace, meaning each team manages their own sets within their own namespace boundary. Platform engineers define the guardrails; teams operate within them.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="source-integrity-verification">Source Integrity Verification<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#source-integrity-verification" class="hash-link" aria-label="Direct link to Source Integrity Verification" title="Direct link to Source Integrity Verification" translate="no">​</a></h3>
<p>Supply chain security moved from "nice to have" to "mandatory" after several high-profile attacks in the industry. Argo CD 3.5 introduces source integrity verification, allowing the platform to cryptographically verify that the manifests being deployed match what was committed. This closes the gap between "we trust our Git repository" and "we can prove nothing was altered in transit."</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="mutual-tls-between-components">Mutual TLS Between Components<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#mutual-tls-between-components" class="hash-link" aria-label="Direct link to Mutual TLS Between Components" title="Direct link to Mutual TLS Between Components" translate="no">​</a></h3>
<p>Zero Trust networking within the Argo CD control plane is now achievable through mutual TLS between all internal components. In a shared cluster where multiple teams have workloads running, this prevents lateral movement attacks from compromising the deployment pipeline. We enabled mTLS between the API server, repo server, and application controller without any application-level changes.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="impersonation-for-developer-self-service">Impersonation for Developer Self-Service<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#impersonation-for-developer-self-service" class="hash-link" aria-label="Direct link to Impersonation for Developer Self-Service" title="Direct link to Impersonation for Developer Self-Service" translate="no">​</a></h3>
<p>One of the most impactful features for our platform. Impersonation allows Argo CD to assume different identities when deploying to target clusters, governed by RBAC policies. This means developers can trigger deployments through self-service workflows while the platform enforces what each team can actually deploy and where. No more platform engineers acting as gatekeepers for every deployment configuration change.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="source-hydrator">Source Hydrator<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#source-hydrator" class="hash-link" aria-label="Direct link to Source Hydrator" title="Direct link to Source Hydrator" translate="no">​</a></h3>
<p>The Source Hydrator addresses a subtle but important problem: ensuring that what you see in Git is exactly what gets deployed, even when Helm values, Kustomize overlays, or parameter overrides are involved. It pre-renders manifests and commits the hydrated output, giving teams a clear audit trail of the exact resources that will be applied. This eliminated an entire class of "it worked in staging but not production" issues caused by environment-specific rendering differences.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="helm-4-support">Helm 4 Support<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#helm-4-support" class="hash-link" aria-label="Direct link to Helm 4 Support" title="Direct link to Helm 4 Support" translate="no">​</a></h3>
<p>With Helm 4 introducing breaking changes to chart packaging and dependency management, having native support in Argo CD prevents teams from being stuck on older chart versions. We migrated several charts to Helm 4 format and confirmed that the rendering pipeline handled them correctly without requiring workarounds.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/argocd-35-gitops-at-scale#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>Argo CD 3.5 represents a maturity shift for GitOps platforms. The features are not about making basic deployments work; they are about making GitOps governable, secure, and scalable across an entire organisation. After adopting these capabilities:</p>
<ul>
<li class="">Teams manage their own ApplicationSets without platform engineer intervention</li>
<li class="">Supply chain integrity is verifiable for every deployment</li>
<li class="">Internal communication between Argo CD components is encrypted and authenticated</li>
<li class="">Developer self-service operates within enforced RBAC boundaries</li>
<li class="">Deployment drift caused by rendering inconsistencies is eliminated</li>
<li class="">New Helm 4 charts deploy without compatibility workarounds</li>
</ul>
<p>GitOps platforms are maturing from "alternative deployment tool" to "enterprise delivery platform." Argo CD 3.5 is a significant step in that direction, and the features align directly with the challenges platform teams face when operating at scale.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="ArgoCD" term="ArgoCD"/>
        <category label="gitops" term="gitops"/>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Implementing an AI-Powered DevOps Agent in a Multi-Account AWS Environment]]></title>
        <id>https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account</id>
        <link href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account"/>
        <updated>2026-07-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Engineers investigating production issues in a multi-account AWS environment spend most of their time collecting data rather than analysing it. Switching between accounts, navigating different consoles, correlating metrics across services, and piecing together timelines manually is exhausting and error-prone. We built an AI-powered DevOps agent that answers operational questions in natural language, pulling context from across the entire AWS organisation in seconds.]]></summary>
        <content type="html"><![CDATA[<p>Engineers investigating production issues in a multi-account AWS environment spend most of their time collecting data rather than analysing it. Switching between accounts, navigating different consoles, correlating metrics across services, and piecing together timelines manually is exhausting and error-prone. We built an AI-powered DevOps agent that answers operational questions in natural language, pulling context from across the entire AWS organisation in seconds.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>Our engineering organisation operates across multiple AWS accounts following a landing zone pattern: separate accounts for production, staging, development, shared services, security, and logging. Engineers investigating incidents or performing routine operational checks needed to manually switch between accounts, navigate to the relevant service console, and mentally correlate data from CloudWatch, EKS, ECS, Lambda, RDS, and other services. A single investigation could involve five or more accounts and a dozen different dashboards.</p>
<p>The cognitive overhead was significant. Senior engineers could do it from muscle memory, but junior engineers struggled, and everyone found it tedious. Information that should take seconds to retrieve was taking minutes or hours to assemble.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Build an AI-powered agent that integrates with our existing enterprise platform to provide engineers with contextual insights across the entire AWS organisation. The agent needed to respect existing security boundaries, authenticate properly across accounts, and deliver accurate, correlated information in response to natural language questions. Security, governance, and operational efficiency were non-negotiable requirements.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="natural-language-interface">Natural Language Interface<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#natural-language-interface" class="hash-link" aria-label="Direct link to Natural Language Interface" title="Direct link to Natural Language Interface" translate="no">​</a></h3>
<p>The agent accepts questions in plain English. Engineers ask things like "What caused the spike in errors on the payment service in production yesterday afternoon?" or "Show me the resource utilisation across all EKS clusters in eu-west-1." The agent interprets the intent, identifies which accounts and services to query, and assembles a coherent response.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="secure-cross-account-authentication">Secure Cross-Account Authentication<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#secure-cross-account-authentication" class="hash-link" aria-label="Direct link to Secure Cross-Account Authentication" title="Direct link to Secure Cross-Account Authentication" translate="no">​</a></h3>
<p>Authentication uses cross-account IAM role assumption with strict least-privilege policies. The agent assumes read-only roles in target accounts, with each role scoped to the minimum permissions needed for data retrieval. All role assumptions are logged in CloudTrail, providing a complete audit trail of what the agent accessed and when. No long-lived credentials are stored anywhere in the system.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="multi-service-data-correlation">Multi-Service Data Correlation<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#multi-service-data-correlation" class="hash-link" aria-label="Direct link to Multi-Service Data Correlation" title="Direct link to Multi-Service Data Correlation" translate="no">​</a></h3>
<p>The agent correlates data from across the AWS ecosystem:</p>
<ul>
<li class=""><strong>Compute</strong>: EKS cluster health, ECS service status, EC2 instance metrics, Lambda invocation patterns</li>
<li class=""><strong>Infrastructure</strong>: CloudFormation stack status, VPC flow logs, networking configuration</li>
<li class=""><strong>Monitoring</strong>: CloudWatch metrics, alarms, log insights queries</li>
<li class=""><strong>Management</strong>: Systems Manager inventory, IAM policy analysis, AWS Config compliance</li>
<li class=""><strong>Data</strong>: RDS performance insights, connection pool metrics</li>
<li class=""><strong>Organisation</strong>: AWS Organizations structure, account relationships, SCPs</li>
</ul>
<p>Rather than presenting raw data from each service, the agent correlates information to provide explanations. A "why is the service slow?" question might combine RDS connection pool exhaustion, ECS task CPU throttling, and a recent CloudFormation deployment into a single narrative.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="extended-integrations">Extended Integrations<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#extended-integrations" class="hash-link" aria-label="Direct link to Extended Integrations" title="Direct link to Extended Integrations" translate="no">​</a></h3>
<p>Beyond AWS native services, the agent integrates with:</p>
<ul>
<li class=""><strong>Datadog</strong> for application-level metrics and APM traces</li>
<li class=""><strong>Slack</strong> for delivering findings directly to incident channels</li>
<li class=""><strong>GitHub</strong> for correlating deployments with issues</li>
<li class=""><strong>Jira</strong> for linking operational events to change requests</li>
<li class=""><strong>Terraform</strong> for understanding infrastructure state and recent changes</li>
<li class=""><strong>Kubernetes and Helm</strong> for workload-level insights within EKS clusters</li>
<li class=""><strong>CI/CD pipelines</strong> for identifying recent deployments that may correlate with issues</li>
<li class=""><strong>Internal runbooks</strong> for suggesting remediation steps based on known patterns</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="contextual-awareness">Contextual Awareness<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#contextual-awareness" class="hash-link" aria-label="Direct link to Contextual Awareness" title="Direct link to Contextual Awareness" translate="no">​</a></h3>
<p>The agent maintains awareness of the organisational structure, knowing which teams own which accounts, which services run where, and what the expected baseline behaviour looks like. This means responses are contextualised: the agent does not just report that CPU is high; it reports that CPU is higher than the baseline for that specific service in that specific account at that time of day.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/ai-devops-agent-multi-account#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The impact on operational efficiency was immediate and measurable:</p>
<ul>
<li class="">Time spent on routine operational investigations dropped dramatically, from an average of 30 to 45 minutes of manual data gathering to a single question and answer in under a minute</li>
<li class="">Junior engineers can now investigate issues that previously required senior engineers to navigate the multi-account structure</li>
<li class="">Incident response times improved because the first responder arrives at the problem with full context rather than spending the first 20 minutes collecting data</li>
<li class="">Cross-account visibility that previously required manual effort is now available instantly</li>
</ul>
<p>The focus has shifted from collecting data to resolving problems. Engineers ask a single question and receive a consolidated explanation that would have taken dozens of clicks, account switches, and mental correlation to assemble manually. The agent does not replace engineering judgement; it removes the friction that prevented engineers from applying that judgement quickly.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="ai" term="ai"/>
        <category label="AWS" term="AWS"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="devops" term="devops"/>
        <category label="Automation" term="Automation"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building an Internal Developer Platform from the Ground Up on Amazon EKS]]></title>
        <id>https://venky-profile.myvnc.com/blog/internal-developer-platform-eks</id>
        <link href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks"/>
        <updated>2026-07-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A Kubernetes cluster is not a platform. Teams do not need access to the Kubernetes API; they need the ability to ship software safely, observe it running, and fix it when things go wrong. Building an Internal Developer Platform on Amazon EKS meant designing a system where the complexity of multi-region infrastructure is absorbed by the platform so that application teams can focus entirely on delivering business value.]]></summary>
        <content type="html"><![CDATA[<p>A Kubernetes cluster is not a platform. Teams do not need access to the Kubernetes API; they need the ability to ship software safely, observe it running, and fix it when things go wrong. Building an Internal Developer Platform on Amazon EKS meant designing a system where the complexity of multi-region infrastructure is absorbed by the platform so that application teams can focus entirely on delivering business value.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>Engineering teams across the organisation needed more than raw Kubernetes clusters. They needed a platform they could trust across multiple AWS regions, one that handled provisioning, deployments, networking, security, and observability without requiring every developer to become a Kubernetes expert. Teams were spending too much time on infrastructure concerns and not enough on their applications. Each team had slightly different cluster configurations, addon versions, and deployment practices, leading to inconsistency, operational drift, and difficulty troubleshooting across environments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Design and deliver a complete Internal Developer Platform built on Amazon EKS with standardised provisioning, GitOps-driven delivery, production-grade observability, and genuine developer self-service. The platform needed to work identically across multiple AWS regions, support dozens of teams with varying workload profiles, and reduce the time from "new team" to "first production deployment" from weeks to hours.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="multi-region-eks-architecture">Multi-Region EKS Architecture<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#multi-region-eks-architecture" class="hash-link" aria-label="Direct link to Multi-Region EKS Architecture" title="Direct link to Multi-Region EKS Architecture" translate="no">​</a></h3>
<p>The foundation is a multi-region EKS deployment with consistent configuration across all regions. Each region runs identical cluster configurations with region-specific networking, ensuring that workloads can be deployed to any region without changes to deployment manifests. Failover patterns are built into the platform layer rather than requiring application teams to implement them.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="standardised-cluster-provisioning-via-infrastructure-as-code">Standardised Cluster Provisioning via Infrastructure as Code<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#standardised-cluster-provisioning-via-infrastructure-as-code" class="hash-link" aria-label="Direct link to Standardised Cluster Provisioning via Infrastructure as Code" title="Direct link to Standardised Cluster Provisioning via Infrastructure as Code" translate="no">​</a></h3>
<p>Every cluster is provisioned through Terraform modules that encode our organisational standards. Node group configurations, VPC layouts, subnet strategies, and security group rules are all defined as code and versioned. Spinning up a new cluster in a new region takes a single pull request rather than days of manual configuration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="production-ready-core-addons">Production-Ready Core Addons<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#production-ready-core-addons" class="hash-link" aria-label="Direct link to Production-Ready Core Addons" title="Direct link to Production-Ready Core Addons" translate="no">​</a></h3>
<p>Clusters are delivered with a full set of pre-configured addons: ingress controllers, certificate managers, external DNS, metrics servers, log collectors, and policy engines. These are not optional extras that teams install themselves; they are part of the platform contract. Every cluster has them, configured identically, upgraded in coordination.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="gitops-driven-deployments">GitOps-Driven Deployments<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#gitops-driven-deployments" class="hash-link" aria-label="Direct link to GitOps-Driven Deployments" title="Direct link to GitOps-Driven Deployments" translate="no">​</a></h3>
<p>All application deployments flow through GitOps pipelines. Teams commit their Helm charts or Kubernetes manifests to Git, and the platform handles reconciliation, drift detection, and rollback. There is no kubectl access in production. The deployment pipeline is the only path to production, and it enforces all organisational policies automatically.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="automated-networking-security-iam-and-rbac">Automated Networking, Security, IAM, and RBAC<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#automated-networking-security-iam-and-rbac" class="hash-link" aria-label="Direct link to Automated Networking, Security, IAM, and RBAC" title="Direct link to Automated Networking, Security, IAM, and RBAC" translate="no">​</a></h3>
<p>Networking is automated end-to-end: VPC peering, transit gateway attachments, security groups, and network policies are all managed by the platform. IAM roles for service accounts (IRSA) are provisioned automatically when teams onboard. RBAC policies follow a least-privilege model, granting teams access only to their own namespaces and resources.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ingress-dns-and-certificate-management">Ingress, DNS, and Certificate Management<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#ingress-dns-and-certificate-management" class="hash-link" aria-label="Direct link to Ingress, DNS, and Certificate Management" title="Direct link to Ingress, DNS, and Certificate Management" translate="no">​</a></h3>
<p>Every service deployed to the platform automatically receives DNS entries, TLS certificates, and properly configured ingress routes. Teams declare their desired hostname in their Helm values, and the platform handles certificate provisioning via Let's Encrypt, DNS record creation in Route 53, and ingress controller configuration. No tickets, no waiting.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="observability-from-day-one">Observability from Day One<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#observability-from-day-one" class="hash-link" aria-label="Direct link to Observability from Day One" title="Direct link to Observability from Day One" translate="no">​</a></h3>
<p>Every workload deployed to the platform is automatically instrumented for metrics, logs, and traces. Dashboards are generated automatically based on workload type. Alerting rules follow organisational standards with team-specific notification channels. Teams have full visibility into their applications from the first deployment without configuring any observability tooling themselves.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="helm-based-application-lifecycle">Helm-Based Application Lifecycle<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#helm-based-application-lifecycle" class="hash-link" aria-label="Direct link to Helm-Based Application Lifecycle" title="Direct link to Helm-Based Application Lifecycle" translate="no">​</a></h3>
<p>Applications are packaged as Helm charts following a standardised chart structure. The platform provides base charts that encode best practices for resource limits, health checks, pod disruption budgets, and security contexts. Teams extend these base charts with their application-specific configuration, inheriting platform standards automatically.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="radar-ui-for-cluster-visualisation">Radar UI for Cluster Visualisation<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#radar-ui-for-cluster-visualisation" class="hash-link" aria-label="Direct link to Radar UI for Cluster Visualisation" title="Direct link to Radar UI for Cluster Visualisation" translate="no">​</a></h3>
<p>We integrated a Radar UI that provides real-time cluster visualisation covering health status, namespace utilisation, workload distribution, traffic flows between services, Helm release status, and resource consumption patterns. This gives both platform engineers and application teams a single pane of glass for understanding what is running, where, and how it is performing.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/internal-developer-platform-eks#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>New engineering teams now onboard to the platform in hours rather than weeks. They deploy securely, scale confidently, and troubleshoot efficiently without needing deep Kubernetes expertise. The platform absorbs the complexity of multi-region infrastructure, networking, security, and observability so that developers deliver value rather than wrestle with infrastructure.</p>
<p>Key outcomes:</p>
<ul>
<li class="">Time to first production deployment reduced from weeks to hours for new teams</li>
<li class="">Zero configuration drift between environments thanks to GitOps enforcement</li>
<li class="">Consistent security posture across all clusters and regions</li>
<li class="">Full observability without any setup effort from application teams</li>
<li class="">Platform upgrades roll out across all clusters without disrupting application teams</li>
<li class="">Operational incidents reduced significantly due to standardised configurations and automated health checks</li>
</ul>
<p>The platform is not finished; it never will be. But it has reached the point where developers genuinely trust it, and that trust is the real measure of a successful Internal Developer Platform.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="EKS" term="EKS"/>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="idp" term="idp"/>
        <category label="AWS" term="AWS"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Fixing DNS in EKS Hybrid Clusters: A Layered Platform Solution]]></title>
        <id>https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster</id>
        <link href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster"/>
        <updated>2026-06-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[DNS is one of those things that should just work. In a hybrid EKS cluster spanning AWS and on-premises nodes, it did not. CoreDNS pods clustered on cloud nodes, leaving on-premises workloads routing DNS queries across network boundaries to pods that could not always serve them. The failures were silent, intermittent, and maddening to debug. Fixing it required a layered approach that we eventually packaged as a reusable platform component.]]></summary>
        <content type="html"><![CDATA[<p>DNS is one of those things that should just work. In a hybrid EKS cluster spanning AWS and on-premises nodes, it did not. CoreDNS pods clustered on cloud nodes, leaving on-premises workloads routing DNS queries across network boundaries to pods that could not always serve them. The failures were silent, intermittent, and maddening to debug. Fixing it required a layered approach that we eventually packaged as a reusable platform component.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>We were operating a hybrid EKS cluster connecting AWS-hosted nodes with on-premises infrastructure. The cluster ran hundreds of services resolving thousands of DNS queries per second. CoreDNS pods were not distributing evenly across all nodes in the cluster. The Kubernetes scheduler, following its default behaviour, concentrated CoreDNS replicas on cloud nodes where resources were more readily available.</p>
<p>This meant on-premises workloads were sending DNS queries across the network to CoreDNS pods running in AWS. When network latency spiked or connectivity became unreliable, those queries failed silently. Applications received SERVFAIL responses or timed out entirely, but the errors were intermittent and did not correlate with any obvious infrastructure event. We spent days tracking the root cause before realising it was a DNS topology problem.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Ensure reliable DNS resolution across the entire mixed topology at scale. The solution needed to handle hundreds of services resolving thousands of queries per second, work correctly regardless of whether a pod was running on a cloud node or an on-premises node, and be resilient to network disruptions between the two environments. Additionally, we wanted the solution to be reusable across other hybrid clusters rather than a one-off fix.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="layer-1-topology-spread-constraints">Layer 1: Topology Spread Constraints<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#layer-1-topology-spread-constraints" class="hash-link" aria-label="Direct link to Layer 1: Topology Spread Constraints" title="Direct link to Layer 1: Topology Spread Constraints" translate="no">​</a></h3>
<p>The first step was forcing CoreDNS pods to distribute across both cloud and on-premises nodes. We applied Topology Spread Constraints using both <code>topology.kubernetes.io/region</code> and <code>kubernetes.io/hostname</code> as topology keys with <code>maxSkew: 1</code> and <code>whenUnsatisfiable: DoNotSchedule</code>. This guarantees that CoreDNS pods spread evenly across regions and individual nodes rather than clustering where the scheduler finds it convenient.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">topologySpreadConstraints</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">maxSkew</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">topologyKey</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> topology.kubernetes.io/region</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">whenUnsatisfiable</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> DoNotSchedule</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">labelSelector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token key atrule">k8s-app</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> kube</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">dns</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token key atrule">maxSkew</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">topologyKey</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> kubernetes.io/hostname</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">whenUnsatisfiable</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> DoNotSchedule</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">labelSelector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token key atrule">k8s-app</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> kube</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">dns</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="layer-2-horizontal-pod-autoscaler-for-coredns">Layer 2: Horizontal Pod Autoscaler for CoreDNS<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#layer-2-horizontal-pod-autoscaler-for-coredns" class="hash-link" aria-label="Direct link to Layer 2: Horizontal Pod Autoscaler for CoreDNS" title="Direct link to Layer 2: Horizontal Pod Autoscaler for CoreDNS" translate="no">​</a></h3>
<p>With pods properly distributed, we needed to ensure there were enough of them under load. We configured an HPA targeting CoreDNS based on CPU utilisation and custom metrics for DNS query rate. During traffic spikes, the HPA scales CoreDNS replicas up, and the topology constraints ensure new replicas distribute correctly across the topology.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="layer-3-traffic-distribution-with-preferclose">Layer 3: Traffic Distribution with PreferClose<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#layer-3-traffic-distribution-with-preferclose" class="hash-link" aria-label="Direct link to Layer 3: Traffic Distribution with PreferClose" title="Direct link to Layer 3: Traffic Distribution with PreferClose" translate="no">​</a></h3>
<p>Even with properly distributed pods, the default Kubernetes service routing sends traffic to any backend pod regardless of topology. We patched the <code>kube-dns</code> service with <code>trafficDistribution: PreferClose</code>, which instructs kube-proxy to prefer routing to pods that are topologically close to the client. On-premises workloads now prefer on-premises CoreDNS pods, and cloud workloads prefer cloud CoreDNS pods, with cross-topology routing only as a fallback.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> v1</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Service</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> kube</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">dns</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> kube</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">system</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">trafficDistribution</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> PreferClose</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="layer-4-nodelocal-dnscache">Layer 4: NodeLocal DNSCache<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#layer-4-nodelocal-dnscache" class="hash-link" aria-label="Direct link to Layer 4: NodeLocal DNSCache" title="Direct link to Layer 4: NodeLocal DNSCache" translate="no">​</a></h3>
<p>The final layer deploys NodeLocal DNSCache as a DaemonSet on every node in the cluster. Each node runs a local DNS cache that serves queries from a local cache before forwarding to CoreDNS. This reduces the load on CoreDNS pods dramatically, eliminates network hops for cached queries, and provides resilience during brief network disruptions between cloud and on-premises environments.</p>
<p>NodeLocal DNSCache handles the majority of repeat queries locally, meaning that even if cross-topology connectivity degrades temporarily, applications continue resolving DNS from their local cache without errors.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/coredns-hybrid-eks-cluster#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>After deploying all four layers:</p>
<ul>
<li class="">DNS failure rates dropped to near zero across both cloud and on-premises workloads</li>
<li class="">CoreDNS pod load reduced significantly as NodeLocal DNSCache handles the majority of queries locally</li>
<li class="">Latency for DNS resolution improved measurably, particularly for on-premises workloads that previously crossed network boundaries</li>
<li class="">The solution is resilient to brief network disruptions between environments</li>
</ul>
<p>We packaged the entire solution as a reusable IDP component: a Helm chart that deploys all four layers with environment-specific configuration. It is now deployed across every hybrid and multi-region cluster we operate. Application teams never think about DNS topology, which is exactly how it should be.</p>
<p>The key insight was that no single fix was sufficient. Topology constraints without traffic distribution still sent queries cross-topology. Traffic distribution without proper pod placement had nothing local to route to. Local caching without proper CoreDNS scaling still had a fragile backend. Each layer addresses a different failure mode, and together they provide robust DNS resolution regardless of topology.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="EKS" term="EKS"/>
        <category label="dns" term="dns"/>
        <category label="hybrid-cloud" term="hybrid-cloud"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[From 4 Days to 4 Hours: An AI Agent for EKS Cluster Upgrades]]></title>
        <id>https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent</id>
        <link href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent"/>
        <updated>2026-06-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Upgrading an EKS cluster used to take four days. Not because the technical steps were complex, but because the coordination, validation, sequencing, and communication overhead consumed the vast majority of the time. We built an AI-powered agent that performs the entire upgrade lifecycle autonomously, reducing the process to three to four hours with zero unplanned downtime.]]></summary>
        <content type="html"><![CDATA[<p>Upgrading an EKS cluster used to take four days. Not because the technical steps were complex, but because the coordination, validation, sequencing, and communication overhead consumed the vast majority of the time. We built an AI-powered agent that performs the entire upgrade lifecycle autonomously, reducing the process to three to four hours with zero unplanned downtime.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>Every EKS version upgrade was a multi-day affair. The process involved checking compatibility matrices for every addon, coordinating maintenance windows with application teams, taking backups, running pre-flight checks, upgrading the control plane, upgrading node groups in sequence, upgrading each addon in the correct order, validating cluster health at every step, and communicating progress to stakeholders. A single upgrade consumed approximately four days of a platform engineer's time, and we had multiple clusters to maintain across environments and regions.</p>
<p>The process was well-documented in runbooks, but the documentation itself was part of the problem. Engineers followed steps manually, occasionally missed validation checks, and spent significant time on communication overhead rather than technical work. The toil was predictable and repeatable, which made it a prime candidate for automation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Automate the entire EKS upgrade lifecycle while maintaining the same level of confidence in cluster stability that a careful manual upgrade provides. The solution needed to handle the full sequence from pre-upgrade validation through post-upgrade verification, including addon compatibility, proper sequencing, health checks, and stakeholder communication. It also needed to be trustworthy enough that platform engineers could let it run without constant supervision.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="agentic-ai-architecture">Agentic AI Architecture<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#agentic-ai-architecture" class="hash-link" aria-label="Direct link to Agentic AI Architecture" title="Direct link to Agentic AI Architecture" translate="no">​</a></h3>
<p>We built the upgrade agent using an agentic AI approach with steering files and spec-driven workflows. The agent is not a simple script with conditional logic; it reasons about the upgrade process, adapts to unexpected conditions, and makes decisions about sequencing based on the current cluster state. Steering files define the upgrade policies, required validations, and acceptable risk thresholds. Spec-driven workflows define the expected sequence but allow the agent to adjust when conditions differ from expectations.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pre-upgrade-phase">Pre-Upgrade Phase<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#pre-upgrade-phase" class="hash-link" aria-label="Direct link to Pre-Upgrade Phase" title="Direct link to Pre-Upgrade Phase" translate="no">​</a></h3>
<p>The agent begins by taking comprehensive backups: etcd snapshots, Helm release histories, custom resource definitions, and critical ConfigMaps. It then conducts a thorough cluster health assessment, checking node readiness, pod scheduling, persistent volume claims, certificate expiry, and resource utilisation. If any pre-flight check fails, the agent reports the issue and pauses for human review rather than proceeding with a potentially risky upgrade.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="upgrade-execution">Upgrade Execution<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#upgrade-execution" class="hash-link" aria-label="Direct link to Upgrade Execution" title="Direct link to Upgrade Execution" translate="no">​</a></h3>
<p>The control plane upgrade proceeds first, followed by node groups in a controlled rolling fashion. The agent monitors the upgrade progress, watching for nodes to drain cleanly and new nodes to become ready. It handles the addon upgrade sequence intelligently, understanding dependencies between addons and upgrading them in the correct order. For example, it knows that the VPC CNI plugin must be upgraded before certain other networking addons, and that CoreDNS should be validated before proceeding with application-level addons.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="post-upgrade-validation">Post-Upgrade Validation<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#post-upgrade-validation" class="hash-link" aria-label="Direct link to Post-Upgrade Validation" title="Direct link to Post-Upgrade Validation" translate="no">​</a></h3>
<p>After the upgrade completes, the agent runs the full health check suite again, comparing results against the pre-upgrade baseline. It validates that all workloads are running, all services are reachable, DNS resolution is functioning, and metrics pipelines are reporting correctly. Any regression triggers an alert and detailed diagnostic report.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="communication-and-documentation">Communication and Documentation<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#communication-and-documentation" class="hash-link" aria-label="Direct link to Communication and Documentation" title="Direct link to Communication and Documentation" translate="no">​</a></h3>
<p>The agent reports status to the team throughout the process via Slack notifications at key milestones. Upon completion, it publishes a comprehensive summary including the new version capabilities, relevant release notes, any issues encountered and how they were resolved, and the full timeline of the upgrade. This documentation is automatically published to Confluence, creating a permanent record that teams can reference.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/ai-eks-upgrade-agent#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The impact was transformative for the platform team:</p>
<ul>
<li class="">Upgrade duration reduced from four days to three to four hours</li>
<li class="">Zero unplanned downtime across all upgrades performed by the agent</li>
<li class="">Platform engineers freed from repetitive toil to focus on higher-value work</li>
<li class="">Enhanced visibility for application teams who receive clear communication about what changed and when</li>
<li class="">Consistent quality of upgrades regardless of which engineer initiates them</li>
<li class="">Complete audit trail of every upgrade published automatically</li>
</ul>
<p>Customers deploy on upgraded clusters immediately with complete confidence because the agent has already validated everything they would need to check manually. The upgrade process went from being a dreaded quarterly event to a routine operation that barely registers on the team's workload.</p>
<p>The key lesson was that the value of the AI agent is not just speed. It is consistency, thoroughness, and the elimination of human error in a process where a missed step can have significant consequences. The agent never skips a validation check because it is Friday afternoon.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="ai" term="ai"/>
        <category label="EKS" term="EKS"/>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="Automation" term="Automation"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Choosing Cilium as the CNI for Our EKS Hybrid Cluster]]></title>
        <id>https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks</id>
        <link href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks"/>
        <updated>2026-06-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Getting networking right in a hybrid EKS cluster connecting AWS nodes with on-premises Nutanix nodes was one of the most frustrating exercises we went through. We tested multiple CNIs, broke configurations more times than anyone wants to admit, and eventually landed on Cilium. The journey involved fixing four major issues before we had stable, observable, and secure networking across both environments.]]></summary>
        <content type="html"><![CDATA[<p>Getting networking right in a hybrid EKS cluster connecting AWS nodes with on-premises Nutanix nodes was one of the most frustrating exercises we went through. We tested multiple CNIs, broke configurations more times than anyone wants to admit, and eventually landed on Cilium. The journey involved fixing four major issues before we had stable, observable, and secure networking across both environments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>We were setting up a hybrid EKS cluster that connected AWS-hosted nodes with on-premises nodes running on Nutanix infrastructure. The networking requirements were non-trivial: pods on AWS nodes needed to communicate seamlessly with pods on on-premises nodes, NetworkPolicies needed to work consistently across both environments, and we needed deep visibility into traffic flows for troubleshooting and security. We tried multiple CNI plugins, and each one broke in different ways when confronted with the realities of hybrid networking.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Get networking right across the mixed environment with deep visibility and security. The CNI needed to handle cross-environment pod-to-pod communication, provide consistent NetworkPolicy enforcement regardless of where pods were scheduled, offer observability into traffic flows without requiring additional tooling, and perform well enough that the networking layer was never the bottleneck.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-cilium">Why Cilium<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#why-cilium" class="hash-link" aria-label="Direct link to Why Cilium" title="Direct link to Why Cilium" translate="no">​</a></h3>
<p>We chose Cilium for several reasons that aligned with our hybrid requirements:</p>
<ul>
<li class=""><strong>eBPF-based networking</strong> eliminates the iptables overhead that becomes a performance problem at scale. In a hybrid environment where packets may traverse multiple hops, every bit of latency reduction matters.</li>
<li class=""><strong>Hubble</strong> provides L3/L4/L7 visibility into traffic flows without deploying a separate service mesh or packet capture infrastructure.</li>
<li class=""><strong>L7 NetworkPolicies</strong> allow us to enforce security at the application layer, not just IP and port level.</li>
<li class=""><strong>Hybrid routing support</strong> handles the complexities of routing between AWS VPC networking and on-premises network infrastructure.</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="issue-1-dns-caching-on-on-premises-nodes">Issue 1: DNS Caching on On-Premises Nodes<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#issue-1-dns-caching-on-on-premises-nodes" class="hash-link" aria-label="Direct link to Issue 1: DNS Caching on On-Premises Nodes" title="Direct link to Issue 1: DNS Caching on On-Premises Nodes" translate="no">​</a></h3>
<p>On-premises nodes experienced DNS resolution latency of approximately 150ms because every query traversed the network to CoreDNS pods running on AWS nodes. We deployed NodeLocal DNS v2.0.6 with Local Redirect Policy (LRP) in Cilium, which intercepts DNS traffic at the eBPF level and routes it to a local cache without leaving the node. Latency dropped from 150ms to 40ms immediately.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="issue-2-ip-conflicts-between-environments">Issue 2: IP Conflicts Between Environments<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#issue-2-ip-conflicts-between-environments" class="hash-link" aria-label="Direct link to Issue 2: IP Conflicts Between Environments" title="Direct link to Issue 2: IP Conflicts Between Environments" translate="no">​</a></h3>
<p>The default IPAM configuration allocated pod CIDRs that overlapped with existing on-premises network ranges. Pods could not communicate across environments because routers did not know which path to take for overlapping addresses. We switched to cluster-pool IPAM with explicitly split CIDRs: one range for AWS nodes and a separate, non-overlapping range for on-premises nodes. This gave us predictable, routable pod addresses across both environments.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">ipam</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">mode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> cluster</span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain">pool</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">operator</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">clusterPoolIPv4PodCIDRList</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"10.100.0.0/16"</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># AWS nodes</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"10.200.0.0/16"</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># On-premises nodes</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="issue-3-hubble-relay-failures">Issue 3: Hubble Relay Failures<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#issue-3-hubble-relay-failures" class="hash-link" aria-label="Direct link to Issue 3: Hubble Relay Failures" title="Direct link to Issue 3: Hubble Relay Failures" translate="no">​</a></h3>
<p>Hubble Relay could not connect to Hubble instances on on-premises nodes. The Relay was configured with an internal FQDN that did not resolve correctly across the hybrid boundary. We corrected the internal FQDN to use the cluster DNS name that was resolvable from all nodes, and added a backoff delay configuration to handle the brief periods during node scaling where some Hubble instances are temporarily unavailable.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="issue-4-kube-proxy-conflicts-in-mixed-mode">Issue 4: kube-proxy Conflicts in Mixed Mode<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#issue-4-kube-proxy-conflicts-in-mixed-mode" class="hash-link" aria-label="Direct link to Issue 4: kube-proxy Conflicts in Mixed Mode" title="Direct link to Issue 4: kube-proxy Conflicts in Mixed Mode" translate="no">​</a></h3>
<p>We initially attempted to run Cilium in full kube-proxy replacement mode. This worked perfectly on on-premises nodes but conflicted with AWS-specific networking that expects kube-proxy to be present for certain load balancer integrations. Rather than fighting this, we disabled full kube-proxy replacement and let AWS handle kube-proxy on cloud nodes while Cilium managed the data plane. This mixed mode required explicit configuration but proved stable.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token key atrule">kubeProxyReplacement</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"false"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">nodePort</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">enabled</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/cilium-cni-hybrid-eks#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>After resolving all four issues, we achieved:</p>
<ul>
<li class="">Unified networking between AWS and on-premises nodes with seamless pod-to-pod communication across environments</li>
<li class="">Stable DNS caching with sub-50ms resolution times on all nodes regardless of topology</li>
<li class="">Full visibility through Hubble into traffic flows across the entire cluster, including cross-environment traffic</li>
<li class="">Consistent NetworkPolicy behaviour that enforces the same rules whether a pod runs on AWS or on-premises</li>
</ul>
<p>The cluster has been running in production for months without networking-related incidents. Cilium's eBPF foundation means we are not accumulating iptables rules as the cluster scales, and Hubble gives us the observability we need to quickly identify and resolve any networking anomalies.</p>
<p>The key takeaway is that hybrid networking is harder than it appears on paper. Every CNI plugin claims to support hybrid environments, but the edge cases around IPAM, DNS, proxy replacement, and service discovery only surface when you actually deploy across mixed infrastructure. Being willing to iterate and fix each issue systematically rather than switching CNIs again was the right call.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="cilium" term="cilium"/>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="EKS" term="EKS"/>
        <category label="hybrid-cloud" term="hybrid-cloud"/>
        <category label="networking" term="networking"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Migrating from Ansible Tower to AAP: Real Challenges and How We Fixed Them]]></title>
        <id>https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration</id>
        <link href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration"/>
        <updated>2026-06-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Migrating from Ansible Tower to the Ansible Automation Platform is not a lift-and-shift exercise. It is a fundamental shift in how automation is built, executed, and governed. When a client running Tower across hybrid cloud infrastructure hit the ceiling on execution control, containerisation, and multi-region scaling, we took on the challenge of making their automation estate enterprise-ready.]]></summary>
        <content type="html"><![CDATA[<p>Migrating from Ansible Tower to the Ansible Automation Platform is not a lift-and-shift exercise. It is a fundamental shift in how automation is built, executed, and governed. When a client running Tower across hybrid cloud infrastructure hit the ceiling on execution control, containerisation, and multi-region scaling, we took on the challenge of making their automation estate enterprise-ready.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>The client had been running Ansible Tower for several years to automate provisioning, configuration management, and application deployments across a hybrid cloud estate spanning on-premises data centres and two public cloud providers. Tower was doing its job, but cracks were forming.</p>
<p>Playbooks ran in a shared Python environment with no isolation. One team's dependency upgrade would break another team's workflows. Execution control was limited, meaning there was no way to guarantee reproducible runs across environments. Scaling horizontally required spinning up more Tower nodes, which introduced state synchronisation headaches. Credential management was scattered, with some stored in Tower, others in flat files, and a handful in a partially configured Vault instance.</p>
<p>The writing was on the wall: Tower could not keep pace with the organisation's growth.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Our mandate was clear. Migrate the entire automation estate from Ansible Tower to the Ansible Automation Platform (AAP), making it enterprise-ready, secure, and scalable across three geographic regions. The migration needed to be non-disruptive, meaning production automation could not go dark during the transition.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-1-audit-and-export">Phase 1: Audit and Export<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#phase-1-audit-and-export" class="hash-link" aria-label="Direct link to Phase 1: Audit and Export" title="Direct link to Phase 1: Audit and Export" translate="no">​</a></h3>
<p>We started by cataloguing every job template, workflow, credential, inventory, and project in Tower. Using <code>awx-manage export</code>, we extracted the full configuration into a portable format. This gave us a baseline to validate against post-migration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-2-building-custom-execution-environments">Phase 2: Building Custom Execution Environments<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#phase-2-building-custom-execution-environments" class="hash-link" aria-label="Direct link to Phase 2: Building Custom Execution Environments" title="Direct link to Phase 2: Building Custom Execution Environments" translate="no">​</a></h3>
<p>One of AAP's biggest shifts is the move to containerised Execution Environments (EEs). We used <code>ansible-builder</code> to construct purpose-built EEs for each team, bundling the exact Python dependencies, collections, and system libraries each workflow required. This solved the "it works on my Tower node" problem permanently.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-3-deploying-the-platform">Phase 3: Deploying the Platform<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#phase-3-deploying-the-platform" class="hash-link" aria-label="Direct link to Phase 3: Deploying the Platform" title="Direct link to Phase 3: Deploying the Platform" translate="no">​</a></h3>
<p>We automated the deployment of Automation Controller, Automation Hub, and Automation Mesh using infrastructure-as-code. Mesh nodes were deployed at each region to provide local execution capacity with centralised orchestration. Vault was integrated as the single source of truth for all secrets and credentials.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="phase-4-fixing-real-issues">Phase 4: Fixing Real Issues<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#phase-4-fixing-real-issues" class="hash-link" aria-label="Direct link to Phase 4: Fixing Real Issues" title="Direct link to Phase 4: Fixing Real Issues" translate="no">​</a></h3>
<p>Six significant issues surfaced during migration, and each required a targeted fix:</p>
<p><strong>1. Incompatible playbooks with Execution Environments</strong></p>
<p>Many playbooks relied on system packages or Python libraries installed directly on Tower nodes. These broke immediately inside containerised EEs. We used <code>ansible-builder</code> to create layered EE definitions, pulling in the required dependencies. For edge cases, we refactored playbooks to remove host-level assumptions.</p>
<p><strong>2. Credentials migration to Vault</strong></p>
<p>Tower stored credentials in its own encrypted database. Migrating these to Vault required building custom credential plugins that AAP Controller could consume natively. We wrote a migration script that extracted credentials from Tower's export, transformed them into Vault KV paths, and configured matching credential types in Controller.</p>
<p><strong>3. Mesh node sync failures</strong></p>
<p>Automation Mesh communicates over port 27199 using receptor. In the first deployment, hop nodes could not establish connections to execution nodes. Debugging revealed a combination of firewall rules not updated for the new port and DNS resolution failures where short hostnames were not resolving correctly across regions. We fixed the firewall rules and enforced FQDN usage in the mesh topology configuration.</p>
<p><strong>4. Failed job templates post-migration</strong></p>
<p>After importing job templates, roughly 30% failed on first run. Root causes varied: missing EE associations, changed variable names, and inventory source mismatches. We built a dry-run pipeline that executed every imported template in check mode before cutover. This pre-deployment sanity testing caught failures before they reached production.</p>
<p><strong>5. Confused users and broken workflows</strong></p>
<p>Teams accustomed to Tower's interface and workflow struggled with Controller's new layout and RBAC model. We created onboarding guides, pre-built role templates aligned to team functions, and integrated SSO so that users landed in their correct organisational context immediately on login.</p>
<p><strong>6. Content validation in Automation Hub</strong></p>
<p>Teams were pulling collections from Ansible Galaxy without any governance. We deployed an internal Automation Hub instance with curated, signed collections. Only validated and signed content could be consumed by EEs, giving the security team confidence in what was running in production.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/ansible-automation-platform-migration#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The migration completed across all three regions with zero unplanned downtime during cutover. Post-migration metrics told the story:</p>
<ul>
<li class=""><strong>82% reduction in playbook failures</strong> thanks to isolated Execution Environments and pre-deployment testing</li>
<li class=""><strong>60% faster deployment timelines</strong> as teams could now self-serve automation without waiting for shared Tower capacity</li>
<li class="">Fully automated credential rotation through Vault integration</li>
<li class="">Centralised governance with regional execution, giving teams local speed with global consistency</li>
</ul>
<p>The platform now serves as the backbone for all infrastructure and application automation across the organisation, handling thousands of job runs daily without the scaling concerns that plagued Tower.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="ansible" term="ansible"/>
        <category label="Automation" term="Automation"/>
        <category label="devops" term="devops"/>
        <category label="migration" term="migration"/>
        <category label="vault" term="vault"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Designing a Modular Terraform Ecosystem for Enterprise Platforms]]></title>
        <id>https://venky-profile.myvnc.com/blog/terraform-module-ecosystem</id>
        <link href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[When infrastructure-as-code grows organically, it tends to sprawl. Monolithic Terraform configurations become unmaintainable, teams duplicate effort, and environments drift apart. Building a composable module ecosystem changed how our platform teams deliver infrastructure, cutting provisioning time from days to under 30 minutes.]]></summary>
        <content type="html"><![CDATA[<p>When infrastructure-as-code grows organically, it tends to sprawl. Monolithic Terraform configurations become unmaintainable, teams duplicate effort, and environments drift apart. Building a composable module ecosystem changed how our platform teams deliver infrastructure, cutting provisioning time from days to under 30 minutes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>The organisation managed hundreds of AWS accounts across multiple business units. Each team had their own Terraform code, written independently with no shared standards. The problems were predictable:</p>
<ul>
<li class="">Massive monolithic configurations that took 20 minutes to plan and were terrifying to apply</li>
<li class="">Teams copy-pasting entire directory trees to create new environments, introducing subtle drift</li>
<li class="">No versioning on reusable components, meaning a change in one place could silently break consumers</li>
<li class="">Inconsistent tagging, networking, and security configurations across environments</li>
<li class="">New projects taking days to scaffold because engineers had to piece together infrastructure from scratch</li>
</ul>
<p>The platform team needed to impose order without slowing teams down.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Build a composable Terraform module ecosystem following DRY principles with semantic versioning. Each module needed to be single-responsibility, independently testable, and composable into larger platform deployments. Teams should be able to self-serve infrastructure by combining modules without deep Terraform expertise.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="designing-the-module-architecture">Designing the Module Architecture<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#designing-the-module-architecture" class="hash-link" aria-label="Direct link to Designing the Module Architecture" title="Direct link to Designing the Module Architecture" translate="no">​</a></h3>
<p>We established a clear contract for every module: defined inputs, predictable outputs, sensible defaults, and comprehensive documentation. Each module lived in its own Git repository with its own release lifecycle.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-eight-purpose-built-modules">The Eight Purpose-Built Modules<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#the-eight-purpose-built-modules" class="hash-link" aria-label="Direct link to The Eight Purpose-Built Modules" title="Direct link to The Eight Purpose-Built Modules" translate="no">​</a></h3>
<p><strong>1. VPC Module</strong></p>
<p>Provisions a production-ready VPC with multi-AZ subnets (public, private, database), NAT Gateways with redundancy options, Internet Gateway, and VPC Endpoints for AWS services. Supports customisable CIDR allocation and flow log configuration.</p>
<p><strong>2. EKS Module</strong></p>
<p>Deploys managed Kubernetes clusters for both cloud-native and hybrid workloads. Handles node group configuration, cluster add-on management, OIDC provider setup, and cluster autoscaler prerequisites. Supports both managed node groups and self-managed configurations for on-premises integration.</p>
<p><strong>3. IAM Module</strong></p>
<p>Manages IAM roles, policies, and trust relationships with a focus on IRSA (IAM Roles for Service Accounts) and OIDC federation. Provides pre-built role templates for common patterns like CI/CD runners, application workloads, and cross-account access.</p>
<p><strong>4. Networking Module</strong></p>
<p>Handles Transit Gateway attachments, Route53 zones and records, VPN connections, and VPC peering. Designed for hub-and-spoke topologies where a central networking account manages connectivity for spoke accounts.</p>
<p><strong>5. Security Module</strong></p>
<p>Provisions Security Groups with rule composition, KMS keys with cross-account sharing policies, and WAF web ACLs with managed rule groups. Enforces least-privilege defaults that teams can extend but not weaken.</p>
<p><strong>6. Karpenter Module</strong></p>
<p>Deploys Karpenter for Kubernetes node autoscaling with all supporting infrastructure: IAM roles, SQS queues for interruption handling, EventBridge rules for spot termination notices, and NodePool/EC2NodeClass definitions as Kubernetes manifests.</p>
<p><strong>7. EKS Addons Module</strong></p>
<p>Manages cluster add-ons as a composable unit: CoreDNS, vpc-cni, kube-proxy, EBS CSI Driver, and Pod Identity Agent. Handles version pinning, configuration values, and IAM role associations for each add-on.</p>
<p><strong>8. Tags Module</strong></p>
<p>A utility module that generates standardised tags based on organisational policy. Every other module consumes this to ensure consistent tagging for cost allocation, ownership, environment classification, and compliance.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="composition-with-terragrunt">Composition with Terragrunt<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#composition-with-terragrunt" class="hash-link" aria-label="Direct link to Composition with Terragrunt" title="Direct link to Composition with Terragrunt" translate="no">​</a></h3>
<p>Individual modules are powerful, but the real value comes from composition. We used Terragrunt to orchestrate module deployments, manage dependencies between them, and keep environment configurations DRY. A single Terragrunt configuration can stand up an entire platform stack by referencing versioned modules.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="versioning-and-release">Versioning and Release<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#versioning-and-release" class="hash-link" aria-label="Direct link to Versioning and Release" title="Direct link to Versioning and Release" translate="no">​</a></h3>
<p>Each module follows semantic versioning via Git tags. Breaking changes increment the major version. New features increment the minor version. Bug fixes increment the patch version. Consumers pin to a specific version and upgrade deliberately.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cookiecutter-templates">Cookiecutter Templates<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#cookiecutter-templates" class="hash-link" aria-label="Direct link to Cookiecutter Templates" title="Direct link to Cookiecutter Templates" translate="no">​</a></h3>
<p>To make onboarding frictionless, we built Cookiecutter templates that generate complete project scaffolding. Engineers answer a few questions (account, region, environment, required modules) and receive a ready-to-apply Terraform project with Terragrunt configuration, CI/CD pipeline definitions, and documentation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/terraform-module-ecosystem#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The module ecosystem transformed infrastructure delivery:</p>
<ul>
<li class=""><strong>Provisioning time dropped from days to under 30 minutes</strong> for a complete platform stack</li>
<li class=""><strong>Consistent, auditable deployments</strong> across all environments with no configuration drift</li>
<li class=""><strong>Teams self-serve</strong> by generating projects from Cookiecutter templates without needing deep Terraform knowledge</li>
<li class=""><strong>Reduced code duplication by over 70%</strong> across the organisation</li>
<li class=""><strong>Clear ownership and change management</strong> through semantic versioning and changelogs</li>
</ul>
<p>The ecosystem continues to grow as new patterns emerge, with each module maintained by the platform team and consumed by dozens of product teams across the organisation.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="Terraform" term="Terraform"/>
        <category label="Modules" term="Modules"/>
        <category label="AWS" term="AWS"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="IaC" term="IaC"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building a Production-Grade DevSecOps Pipeline on Kubernetes]]></title>
        <id>https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes</id>
        <link href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes"/>
        <updated>2026-05-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Security cannot be an afterthought bolted on at the end of a deployment pipeline. When vulnerabilities are discovered post-deployment, remediation is expensive, disruptive, and often too late. We built a DevSecOps pipeline that integrates security scanning at every stage, from the first commit through to production monitoring, running entirely on Kubernetes.]]></summary>
        <content type="html"><![CDATA[<p>Security cannot be an afterthought bolted on at the end of a deployment pipeline. When vulnerabilities are discovered post-deployment, remediation is expensive, disruptive, and often too late. We built a DevSecOps pipeline that integrates security scanning at every stage, from the first commit through to production monitoring, running entirely on Kubernetes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>The organisation ran over 40 microservices deployed to Kubernetes. Each team had its own deployment process, ranging from manual kubectl applies to partially automated scripts. Security scanning was inconsistent at best:</p>
<ul>
<li class="">Some teams ran linters locally but had no enforcement in CI</li>
<li class="">Container images were built from unvetted base images with no vulnerability scanning</li>
<li class="">Dependencies were not checked against known CVE databases</li>
<li class="">Production deployments happened without any security gate</li>
<li class="">When vulnerabilities were discovered (usually by a quarterly audit), remediation required emergency patches and out-of-hours deployments</li>
</ul>
<p>The security team was drowning in findings with no way to enforce standards proactively.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Build an end-to-end DevSecOps pipeline integrating security at every stage from commit to production. The pipeline needed to be consistent across all microservices, automated with no manual gates (except for critical findings), and provide real-time visibility into the security posture of every deployment.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="infrastructure-layer">Infrastructure Layer<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#infrastructure-layer" class="hash-link" aria-label="Direct link to Infrastructure Layer" title="Direct link to Infrastructure Layer" translate="no">​</a></h3>
<p>Terraform provisions the EKS cluster with all networking, IAM, and security configurations. The cluster runs in a dedicated VPC with private subnets, and node groups are configured with hardened AMIs. This gives us a secure foundation before any application workload lands.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="ci-pipeline-github-actions">CI Pipeline (GitHub Actions)<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#ci-pipeline-github-actions" class="hash-link" aria-label="Direct link to CI Pipeline (GitHub Actions)" title="Direct link to CI Pipeline (GitHub Actions)" translate="no">​</a></h3>
<p>Every push to a repository triggers the pipeline:</p>
<p><strong>Source Code Analysis (SAST)</strong></p>
<p>SonarQube analyses the codebase for security vulnerabilities, code smells, and bugs. Quality gates enforce minimum thresholds. If the gate fails, the pipeline stops immediately and the developer receives actionable feedback.</p>
<p><strong>Dependency Scanning</strong></p>
<p>OWASP Dependency Check scans all project dependencies against the National Vulnerability Database. Known vulnerable libraries are flagged with severity ratings. Critical and high findings break the build.</p>
<p><strong>Container Image Build</strong></p>
<p>Docker builds the application image using a hardened, minimal base image. Multi-stage builds ensure that build tools and source code never make it into the final image.</p>
<p><strong>Container Vulnerability Scanning</strong></p>
<p>Trivy scans the built container image for CVEs in OS packages and application dependencies. The scan runs against continuously updated vulnerability databases. Images with critical vulnerabilities are rejected before they reach any registry.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cd-pipeline-gitops-with-argocd">CD Pipeline (GitOps with ArgoCD)<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#cd-pipeline-gitops-with-argocd" class="hash-link" aria-label="Direct link to CD Pipeline (GitOps with ArgoCD)" title="Direct link to CD Pipeline (GitOps with ArgoCD)" translate="no">​</a></h3>
<p>ArgoCD watches Git repositories for changes to Kubernetes manifests. When a new image passes all security gates and its manifest is updated, ArgoCD synchronises the desired state to the cluster.</p>
<p>The application architecture follows a three-tier pattern:</p>
<ul>
<li class=""><strong>Frontend</strong>: React applications served from Nginx containers</li>
<li class=""><strong>Backend</strong>: API services handling business logic</li>
<li class=""><strong>Database</strong>: Managed database services with Kubernetes operators for connection management</li>
</ul>
<p>ArgoCD provides drift detection, automatic rollback on failed health checks, and a clear audit trail of every deployment.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="observability">Observability<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#observability" class="hash-link" aria-label="Direct link to Observability" title="Direct link to Observability" translate="no">​</a></h3>
<p>Prometheus scrapes metrics from all application pods, pipeline components, and cluster infrastructure. Grafana dashboards provide real-time visibility into:</p>
<ul>
<li class="">Pipeline execution times and failure rates</li>
<li class="">Vulnerability counts by severity across all services</li>
<li class="">Deployment frequency and lead time</li>
<li class="">Container image age and scan freshness</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="traffic-management-and-protection">Traffic Management and Protection<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#traffic-management-and-protection" class="hash-link" aria-label="Direct link to Traffic Management and Protection" title="Direct link to Traffic Management and Protection" translate="no">​</a></h3>
<p>Cloudflare sits in front of the infrastructure, managing DNS resolution and providing DDoS protection. Traffic routes through an Application Load Balancer to the appropriate Kubernetes services. This layered approach means malicious traffic is filtered before it ever reaches application pods.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/devsecops-pipeline-kubernetes#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The pipeline transformed the organisation's security posture:</p>
<ul>
<li class=""><strong>Every build is checked for vulnerabilities</strong> at source, dependency, and container levels before reaching production</li>
<li class=""><strong>Zero production security incidents from unchecked code</strong> since the pipeline was enforced across all services</li>
<li class=""><strong>Increased deployment confidence</strong> as teams know that anything reaching production has passed rigorous automated checks</li>
<li class=""><strong>Real-time visibility</strong> into security posture through Grafana dashboards, eliminating the surprise findings from quarterly audits</li>
<li class=""><strong>Deployment frequency increased by 3x</strong> because teams trusted the automated gates and stopped delaying releases out of caution</li>
</ul>
<p>Security shifted from being a bottleneck to being an enabler, integrated so deeply into the workflow that developers barely notice it is there.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="DevSecOps" term="DevSecOps"/>
        <category label="Kubernetes" term="Kubernetes"/>
        <category label="Security" term="Security"/>
        <category label="CI/CD" term="CI/CD"/>
        <category label="ArgoCD" term="ArgoCD"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Solving a Complex CI/CD Challenge: Clair v2 to v4 RHSA Vulnerability Scanning]]></title>
        <id>https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning</id>
        <link href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning"/>
        <updated>2026-04-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Sometimes the best engineering solutions are the ones that solve a hard problem without forcing teams to change their established workflows. A client needed the latest RHSA vulnerability data in their container scanning pipeline, but their tooling only supported an older database format. Replacing the tools was off the table. We found another way.]]></summary>
        <content type="html"><![CDATA[<p>Sometimes the best engineering solutions are the ones that solve a hard problem without forcing teams to change their established workflows. A client needed the latest RHSA vulnerability data in their container scanning pipeline, but their tooling only supported an older database format. Replacing the tools was off the table. We found another way.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>The client had a mature GitLab CI/CD pipeline for container image builds and deployments. Their workflow used a combination of Docker, Podman, and Kaniko for building container images depending on the runner environment. For vulnerability scanning, they used Klar as the scanning client, which communicated with a Clair v2 server to check images against known vulnerabilities.</p>
<p>The problem was that Klar only supports Clair v2's API. Clair v4 introduced a completely new architecture and API surface, along with significantly improved vulnerability data, particularly for Red Hat Security Advisories (RHSA). The client's Red Hat-based container images were not being checked against the latest RHSA vulnerabilities because that data only existed in Clair v4's format.</p>
<p>The client's constraint was firm: they did not want to replace Klar, change their scanning workflow, or re-architect their CI/CD pipeline. The existing process was well-understood, battle-tested, and integrated into their compliance reporting. They needed the latest vulnerability data injected into their existing system.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Enable up-to-date RHSA vulnerability scanning without changing the existing build and scan workflow. The solution needed to:</p>
<ul>
<li class="">Provide current Clair v4 RHSA vulnerability data to the Clair v2 scanner</li>
<li class="">Integrate transparently into the existing GitLab pipeline</li>
<li class="">Require no changes to how teams build or scan their images</li>
<li class="">Maintain the existing compliance reporting chain</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="nightly-vulnerability-database-pipeline">Nightly Vulnerability Database Pipeline<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#nightly-vulnerability-database-pipeline" class="hash-link" aria-label="Direct link to Nightly Vulnerability Database Pipeline" title="Direct link to Nightly Vulnerability Database Pipeline" translate="no">​</a></h3>
<p>We created a dedicated GitLab pipeline scheduled to run nightly. This pipeline pulls the latest Clair v4 vulnerability database, which contains the most current RHSA advisories, CVE data, and security metadata for Red Hat packages.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="database-conversion-process">Database Conversion Process<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#database-conversion-process" class="hash-link" aria-label="Direct link to Database Conversion Process" title="Direct link to Database Conversion Process" translate="no">​</a></h3>
<p>The core engineering challenge was transforming the Clair v4 database schema into the Clair v2 format. Clair v4 stores vulnerability data in a fundamentally different structure compared to v2. We built a conversion process that:</p>
<ol>
<li class="">Extracts RHSA vulnerability records from the Clair v4 database</li>
<li class="">Maps the v4 data model (vulnerabilities, distributions, packages) to the v2 schema (namespaces, features, vulnerabilities)</li>
<li class="">Generates a compatible PostgreSQL database that Clair v2 can query natively</li>
</ol>
<p>This conversion runs as part of the nightly pipeline, producing a fresh database every 24 hours.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="deployment-as-a-service">Deployment as a Service<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#deployment-as-a-service" class="hash-link" aria-label="Direct link to Deployment as a Service" title="Direct link to Deployment as a Service" translate="no">​</a></h3>
<p>The converted database is deployed as a PostgreSQL container accessible to the Clair v2 server. When Klar sends a scan request, Clair v2 queries this database and returns vulnerability matches using the latest RHSA data, all through the existing v2 API that Klar expects.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="integration-into-existing-pipelines">Integration into Existing Pipelines<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#integration-into-existing-pipelines" class="hash-link" aria-label="Direct link to Integration into Existing Pipelines" title="Direct link to Integration into Existing Pipelines" translate="no">​</a></h3>
<p>From the perspective of development teams, nothing changed. Their GitLab CI/CD pipelines still build images with Docker, Podman, or Kaniko. They still scan with Klar. They still see vulnerability reports in the same format. The only difference is that the underlying data is now current and comprehensive.</p>
<p>Builds are automatically broken when vulnerabilities above the configured severity threshold are detected. This enforcement happens at the same pipeline stage as before, maintaining the existing workflow.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="image-signing-and-promotion">Image Signing and Promotion<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#image-signing-and-promotion" class="hash-link" aria-label="Direct link to Image Signing and Promotion" title="Direct link to Image Signing and Promotion" translate="no">​</a></h3>
<p>Images that pass vulnerability scanning are signed using Simple-Signing before promotion to the production registry. This creates a cryptographic chain of trust: only images that have been built by the pipeline, scanned against current vulnerability data, and found to be clean can be deployed to production.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/clair-klar-cicd-vulnerability-scanning#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The solution delivered exactly what the client needed without disrupting their established processes:</p>
<ul>
<li class=""><strong>Production images are built, scanned, signed, and promoted without manual intervention</strong> through the same pipeline teams already knew</li>
<li class=""><strong>Up-to-date RHSA vulnerability data</strong> is available within 24 hours of publication, compared to weeks of lag with the old static database</li>
<li class=""><strong>No workflow changes required</strong> for any development team, meaning zero retraining and no migration period</li>
<li class=""><strong>Compliance reporting remained intact</strong> because the scanning interface and output format did not change</li>
<li class=""><strong>A mature, reliable, production-ready deployment pipeline</strong> that the client can maintain independently</li>
</ul>
<p>The approach demonstrated that constraints do not have to mean compromise. By engineering a bridge between the old and new systems, the client gained modern security capabilities without the cost and risk of a full tooling migration.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="Security" term="Security"/>
        <category label="CI/CD" term="CI/CD"/>
        <category label="containers" term="containers"/>
        <category label="gitlab" term="gitlab"/>
        <category label="DevSecOps" term="DevSecOps"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Automating AWS Infrastructure with Terraform and GitHub Actions]]></title>
        <id>https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions</id>
        <link href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions"/>
        <updated>2026-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Manual infrastructure deployments are a liability. They introduce human error, create inconsistencies between environments, and slow delivery to a crawl. We automated multi-environment Terraform deployments with GitHub Actions, achieving zero-touch infrastructure delivery on every merge to main.]]></summary>
        <content type="html"><![CDATA[<p>Manual infrastructure deployments are a liability. They introduce human error, create inconsistencies between environments, and slow delivery to a crawl. We automated multi-environment Terraform deployments with GitHub Actions, achieving zero-touch infrastructure delivery on every merge to main.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>The team was managing AWS infrastructure across three environments: development, staging, and production. Deployments followed a familiar but painful pattern:</p>
<ul>
<li class="">An engineer would check out the Terraform code locally</li>
<li class="">They would manually switch AWS credentials and select the correct workspace</li>
<li class="">They would run <code>terraform plan</code>, review the output, then run <code>terraform apply</code></li>
<li class="">Another engineer would repeat the same process for the next environment</li>
<li class="">Occasionally, someone would apply to the wrong environment or forget a variable override</li>
</ul>
<p>The consequences were predictable. Development and staging drifted apart because changes were applied inconsistently. Production deployments were nerve-wracking because no one was entirely sure what state the other environments were in. Rollbacks were manual and stressful. New engineers took weeks to learn the deployment process safely.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Automate multi-environment Terraform deployments with zero manual intervention on merge to main. The solution needed to:</p>
<ul>
<li class="">Deploy to all environments consistently from the same codebase</li>
<li class="">Prevent accidental or unauthorised changes</li>
<li class="">Provide clear visibility into what will change before it is applied</li>
<li class="">Scale easily to new environments and infrastructure components</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="directory-structure">Directory Structure<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#directory-structure" class="hash-link" aria-label="Direct link to Directory Structure" title="Direct link to Directory Structure" translate="no">​</a></h3>
<p>We organised the Terraform code with per-environment configurations:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">infrastructure/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">├── modules/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   ├── networking/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   ├── compute/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   └── database/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">├── environments/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   ├── dev/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── main.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── variables.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── terraform.tfvars</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   └── backend.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   ├── staging/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── main.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── variables.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   ├── terraform.tfvars</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   │   └── backend.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│   └── prod/</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│       ├── main.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│       ├── variables.tf</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│       ├── terraform.tfvars</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">│       └── backend.tf</span><br></div></code></pre></div></div>
<p>Each environment has its own backend configuration pointing to a dedicated S3 bucket and DynamoDB table for state locking. This prevents state file conflicts and ensures that concurrent operations against different environments cannot interfere with each other.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="remote-state-with-locking">Remote State with Locking<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#remote-state-with-locking" class="hash-link" aria-label="Direct link to Remote State with Locking" title="Direct link to Remote State with Locking" translate="no">​</a></h3>
<p>Every environment uses an S3 backend with DynamoDB state locking:</p>
<div class="language-hcl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-hcl codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">terraform</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">backend</span><span class="token keyword type variable" style="color:rgb(189, 147, 249);font-style:italic"> "s3" </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">bucket</span><span class="token plain">         </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"company-terraform-state-prod"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">key</span><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"infrastructure/terraform.tfstate"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">region</span><span class="token plain">         </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"eu-west-1"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">dynamodb_table</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"terraform-state-lock-prod"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">encrypt</span><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">=</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></div></code></pre></div></div>
<p>This guarantees that only one operation can modify state at a time, preventing corruption from concurrent applies.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="github-actions-workflow">GitHub Actions Workflow<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#github-actions-workflow" class="hash-link" aria-label="Direct link to GitHub Actions Workflow" title="Direct link to GitHub Actions Workflow" translate="no">​</a></h3>
<p>The automation workflow triggers on push to main and on pull requests:</p>
<p><strong>On Pull Request:</strong></p>
<ol>
<li class="">Checks out the code</li>
<li class="">Sets up Terraform with a pinned version</li>
<li class="">Initialises the backend for the target environment</li>
<li class="">Runs <code>terraform plan</code> and posts the output as a PR comment</li>
<li class="">Requires approval before merge</li>
</ol>
<p><strong>On Merge to Main:</strong></p>
<ol>
<li class="">Checks out the code</li>
<li class="">Sets up Terraform</li>
<li class="">Initialises the backend</li>
<li class="">Selects the correct workspace</li>
<li class="">Runs <code>terraform plan</code> followed by <code>terraform apply -auto-approve</code></li>
</ol>
<p>The workflow uses matrix strategies to run against multiple environments in parallel where appropriate, with production gated behind a manual approval step in GitHub Environments.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="security">Security<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#security" class="hash-link" aria-label="Direct link to Security" title="Direct link to Security" translate="no">​</a></h3>
<p>AWS credentials are stored as GitHub Secrets with environment-scoped access. Production credentials are only available to workflows running against the production environment, which requires reviewer approval. This prevents a compromised development workflow from touching production resources.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="pr-approval-gates">PR Approval Gates<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#pr-approval-gates" class="hash-link" aria-label="Direct link to PR Approval Gates" title="Direct link to PR Approval Gates" translate="no">​</a></h3>
<p>Branch protection rules require at least one approval before merge. The Terraform plan output is posted as a comment on the PR, giving reviewers visibility into exactly what infrastructure changes will be applied. No one merges blind.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/terraform-infra-automation-github-actions#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>The automation transformed infrastructure delivery:</p>
<ul>
<li class=""><strong>Fully automated, consistent deployments across all environments</strong> with no manual steps after code review</li>
<li class=""><strong>Scalable to new environments and components</strong> by simply adding a new directory and configuring the workflow matrix</li>
<li class=""><strong>Reduced deployment errors</strong> to near zero by eliminating manual credential switching and workspace selection</li>
<li class=""><strong>Improved team confidence</strong> because every change is planned, reviewed, and applied through the same tested process</li>
<li class=""><strong>New engineers productive on day one</strong> because they only need to understand Git and pull requests, not Terraform operational procedures</li>
<li class=""><strong>Complete audit trail</strong> of every infrastructure change through Git history and GitHub Actions logs</li>
</ul>
<p>The pattern has since been adopted across multiple teams in the organisation, with each team running their own infrastructure repositories following the same workflow structure.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="Terraform" term="Terraform"/>
        <category label="GitHub Actions" term="GitHub Actions"/>
        <category label="AWS" term="AWS"/>
        <category label="Automation" term="Automation"/>
        <category label="IaC" term="IaC"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Docker Hardened Images: Secure by Default Is Now a Reality]]></title>
        <id>https://venky-profile.myvnc.com/blog/docker-hardened-images</id>
        <link href="https://venky-profile.myvnc.com/blog/docker-hardened-images"/>
        <updated>2026-03-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[For years, DevOps teams have been bolting security onto container images after the fact. Custom non-root configurations, manual vulnerability scans, cobbled-together SBOM generation, and risky base images pulled from unofficial sources. Docker Hardened Images change that equation entirely, making secure-by-default a reality rather than an aspiration.]]></summary>
        <content type="html"><![CDATA[<p>For years, DevOps teams have been bolting security onto container images after the fact. Custom non-root configurations, manual vulnerability scans, cobbled-together SBOM generation, and risky base images pulled from unofficial sources. Docker Hardened Images change that equation entirely, making secure-by-default a reality rather than an aspiration.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="situation">Situation<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#situation" class="hash-link" aria-label="Direct link to Situation" title="Direct link to Situation" translate="no">​</a></h2>
<p>Across multiple client engagements, we saw the same container security challenges repeated:</p>
<ul>
<li class="">Teams pulling base images from unofficial registries with no provenance verification</li>
<li class="">Custom Dockerfiles adding non-root user configurations inconsistently across services</li>
<li class="">Manual or semi-automated vulnerability scanning that ran too late in the pipeline to be effective</li>
<li class="">SBOM (Software Bill of Materials) generation treated as an afterthought, often done separately from the build process</li>
<li class="">Compliance teams requesting evidence of CIS Benchmark adherence with no automated way to provide it</li>
<li class="">Image signing implemented differently (or not at all) across teams</li>
</ul>
<p>The result was a fragmented security posture where every team solved the same problems differently, introducing gaps and inconsistencies. Audits were painful, remediation was slow, and the risk of deploying a compromised image to production was real.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="task">Task<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#task" class="hash-link" aria-label="Direct link to Task" title="Direct link to Task" translate="no">​</a></h2>
<p>Evaluate and adopt Docker Hardened Images (HDIs) for production container security across our platform deployments. The goal was to replace the patchwork of manual security practices with a consistent, automated, and compliant foundation that works across AWS, GCP, and Azure environments.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="action">Action<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#action" class="hash-link" aria-label="Direct link to Action" title="Direct link to Action" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="evaluating-docker-hardened-images">Evaluating Docker Hardened Images<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#evaluating-docker-hardened-images" class="hash-link" aria-label="Direct link to Evaluating Docker Hardened Images" title="Direct link to Evaluating Docker Hardened Images" translate="no">​</a></h3>
<p>Docker released HDIs as production-grade base images with security built into every layer. We evaluated them against our existing practices and compliance requirements:</p>
<p><strong>Minimalist Base Layers</strong></p>
<p>HDIs ship with only the packages required for the runtime. No compilers, no package managers, no debugging tools in the final image. This dramatically reduces the attack surface compared to standard base images where unused packages introduce potential vulnerabilities.</p>
<p><strong>Non-Root User by Default</strong></p>
<p>Every HDI runs as a non-root user out of the box. This aligns directly with Kubernetes Pod Security Standards, which enforce non-root execution at the cluster level. No more custom USER directives or entrypoint scripts to drop privileges.</p>
<p><strong>SBOM Included</strong></p>
<p>Each image ships with an embedded Software Bill of Materials. This provides complete software transparency without requiring separate SBOM generation tooling. Supply chain audits become a matter of inspecting the included manifest rather than reverse-engineering image contents.</p>
<p><strong>Signed Images (Docker Content Trust)</strong></p>
<p>HDIs are cryptographically signed, providing tamper-evident provenance. We can verify that an image has not been modified since Docker published it, closing the supply chain integrity gap.</p>
<p><strong>Continuous CVE Scanning and Remediation</strong></p>
<p>Docker continuously scans HDIs against vulnerability databases and publishes updated images when fixes are available. This shifts the remediation burden from individual teams to the image provider, with teams only needing to update their base image reference.</p>
<p><strong>Compliance Alignment</strong></p>
<p>HDIs are built to comply with CIS Benchmarks, SLSA (Supply-chain Levels for Software Artifacts), and NIST 800-190 (Application Container Security Guide). This provides auditable evidence of compliance without manual configuration.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="integration-into-cicd-pipelines">Integration into CI/CD Pipelines<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#integration-into-cicd-pipelines" class="hash-link" aria-label="Direct link to Integration into CI/CD Pipelines" title="Direct link to Integration into CI/CD Pipelines" translate="no">​</a></h3>
<p>We replaced existing base images with HDIs across our platform deployments:</p>
<ol>
<li class="">Updated Dockerfiles to use HDI base images</li>
<li class="">Removed custom non-root user configurations (now unnecessary)</li>
<li class="">Removed manual SBOM generation steps from pipelines (now embedded)</li>
<li class="">Configured image verification in deployment pipelines to validate signatures</li>
<li class="">Set up automated base image update notifications to keep images current</li>
</ol>
<p>The integration worked consistently across AWS EKS, GCP GKE, and Azure AKS deployments, with no cloud-specific modifications required.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="validation">Validation<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#validation" class="hash-link" aria-label="Direct link to Validation" title="Direct link to Validation" translate="no">​</a></h3>
<p>We validated HDIs against our security requirements:</p>
<ul>
<li class="">Trivy scans confirmed significantly fewer CVEs compared to equivalent standard images</li>
<li class="">Pod Security Admission controllers accepted HDI-based pods without policy exceptions</li>
<li class="">SBOM contents matched expected package lists with no unexpected inclusions</li>
<li class="">Image signatures verified correctly through Docker Content Trust</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="result">Result<a href="https://venky-profile.myvnc.com/blog/docker-hardened-images#result" class="hash-link" aria-label="Direct link to Result" title="Direct link to Result" translate="no">​</a></h2>
<p>Adopting Docker Hardened Images simplified and strengthened container security across the board:</p>
<ul>
<li class=""><strong>DevSecOps made easier, faster, and more compliant</strong> without sacrificing developer velocity. Teams removed security configuration from their Dockerfiles and inherited it from the base image</li>
<li class=""><strong>Regulatory requirements met out of the box</strong> with CIS Benchmark, SLSA, and NIST 800-190 compliance built into the image rather than layered on top</li>
<li class=""><strong>Reduced container CVE counts by over 60%</strong> simply by switching base images, before any additional scanning or patching</li>
<li class=""><strong>Simplified audit processes</strong> because compliance evidence is embedded in the image provenance and SBOM</li>
<li class=""><strong>Consistent security posture</strong> across all cloud providers without environment-specific hardening scripts</li>
</ul>
<p>Docker Hardened Images represent a genuine shift in the container security model. Instead of every team independently solving the same security problems, the foundation is secure by default. Teams can focus on building application value rather than hardening infrastructure.</p>]]></content>
        <author>
            <name>Venkateswarareddy Sanikommu</name>
            <uri>https://github.com/venky1912</uri>
        </author>
        <category label="docker" term="docker"/>
        <category label="Security" term="Security"/>
        <category label="containers" term="containers"/>
        <category label="DevSecOps" term="DevSecOps"/>
        <category label="compliance" term="compliance"/>
    </entry>
</feed>