GitHub Actions → ECR → Kubernetes: Production CI/CD Architecture

📅 Published: 2026-09-20 ⏱ 14 min read 🏷 CI/CD & GitOps 👤 Naveed Ahmed
Embedding long-lived AWS secret keys in GitHub Actions secrets is a major security hazard. True production CI/CD architectures decouple build and deployment: GitHub Actions builds secure, immutable containers via OIDC authentication, while ArgoCD reconciles declarative cluster state using GitOps. Here is the reference architecture.

The Decoupled GitOps Architecture

A modern, production-grade delivery pipeline separates Continuous Integration (CI) from Continuous Deployment (CD):

  1. CI (GitHub Actions): Runs unit/integration tests, compiles code, builds container images with BuildKit, scans for vulnerabilities with Trivy, and pushes immutable signed images to Amazon ECR.
  2. The Hand-Off: The CI runner commits an updated image tag into a dedicated infrastructure-gitops repository.
  3. CD (ArgoCD inside EKS): ArgoCD detects the new git commit, verifies health checks, and initiates a progressive canary or rolling deployment to Kubernetes.
Authentication

Keyless AWS Authentication via GitHub OIDC

Establish a trust relationship between your AWS IAM role and GitHub Actions. No static credentials exist to be stolen.

# GitHub Actions workflow step for keyless AWS authentication
- name: Configure AWS Credentials via OIDC
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::347166961665:role/github-actions-ecr-push-role
    aws-region: us-east-1
    audience: sts.amazonaws.com

The IAM Role's trust policy restricts access strictly to your specific repository and branch (e.g. repo:org/app:ref:refs/heads/main).

Build & Security

BuildKit Caching & Automated Vulnerability Scanning

Building lean, secure containers requires multi-stage Dockerfiles and automated vulnerability gates in the CI workflow:

# Build and scan workflow steps
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and Push to Amazon ECR
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: 347166961665.dkr.ecr.us-east-1.amazonaws.com/api:${{ github.sha }}
    cache-from: type=gha
    cache-to: type=gha,mode=max

- name: Scan Image for High/Critical Vulnerabilities
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 347166961665.dkr.ecr.us-east-1.amazonaws.com/api:${{ github.sha }}
    format: 'table'
    exit-code: '1'
    ignore-unfixed: true
    severity: 'CRITICAL,HIGH'

If Trivy detects unmitigated CRITICAL CVEs with available upstream patches, the pipeline fails immediately, preventing vulnerable code from ever reaching the registry.

Deployment

GitOps Deployment with ArgoCD & Automated Rollbacks

Once the image passes security scanning, the CI workflow updates the image tag in the GitOps repository using kustomize or yq:

cd deploy/overlays/production
kustomize edit set image api=347166961665.dkr.ecr.us-east-1.amazonaws.com/api:${{ github.sha }}
git commit -am "chore(release): update api image to ${{ github.sha }} [skip ci]"
git push origin main

ArgoCD detects the commit and synchronizes the cluster state. Paired with Argo Rollouts, canary deployments can evaluate real-time Prometheus error rates (e.g., HTTP 5xx > 0.2%) and automatically abort and roll back within 15 seconds.

Have questions about this architecture or scaling your infrastructure?

Whether you're planning a complex cloud migration, optimizing Kubernetes reliability, or designing autonomous AI workflows, I'm always open to discussing architecture and technical challenges with engineering teams.

Connect with Naveed on LinkedIn →

Frequently Asked Questions

Why should you use AWS IAM OIDC instead of AWS Access Keys in GitHub Actions?

AWS IAM OpenID Connect (OIDC) federates authentication directly between GitHub and AWS, exchanging a short-lived cryptographic JWT token for temporary AWS STS credentials valid for only 1 hour. This eliminates static, long-lived AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY credentials that could be leaked, compromised, or require manual rotation.

Why should CI build pipelines never push directly to Kubernetes with kubectl?

Giving CI pipelines direct cluster admin write access (kubectl apply) violates the principle of least privilege, exposes the cluster control plane to compromised CI runners, and causes configuration drift between git and runtime. The GitOps model with ArgoCD ensures the cluster pulls desired state declaratively from git.

How does Docker BuildKit caching optimize GitHub Actions build times?

Docker BuildKit enables advanced multi-stage caching using the GitHub Actions cache backend (type=gha) or Amazon ECR cache manifests (type=inline). Unchanged application dependency layers (npm, pip, go mod) are retrieved from cache in seconds, reducing build times from 12+ minutes to under 90 seconds.

Naveed Ahmed

Naveed Ahmed (Kumbhar)

Senior DevOps & Cloud Engineer with 10+ years specializing in AWS, Kubernetes, Platform Engineering, SRE incident response, and autonomous AI infrastructure agents.

Have a technical challenge or architecture question? Connect on LinkedIn →