Project Links
Tech Stack
GitOps CI/CD — GitHub Actions + Argo CD with Multi-Environment Promotion
Built on top of EKS Platform Engineering — Deploying and Scaling Applications. The application, Helm chart, and EKS cluster from that project are what this pipeline builds, scans, and deploys.
A fully automated GitOps pipeline where every deployment starts with a commit and ends with Argo CD syncing the cluster. No manual kubectl commands, no shell scripts run from a laptop, no guessing what version is running. Git is the single source of truth — every change has an author, a timestamp, and a reason.
Why I Built This
I'd deployed to Kubernetes manually enough times to know the problems: someone forgets to tag the image correctly, a rollback means digging through terminal history, and nobody knows exactly what's running in production without checking the cluster directly. Moving everything through Git and Argo CD fixes all three. Every deployment is a commit, rollback is a git revert, and the cluster state is always visible in the repo.
Built Across Two Repos
eks-app-deployment — application code, Dockerfile, Helm chart, CodeBuild config, and GitHub Actions workflow
eks-gitops — Argo CD Application manifests and environment values. Every image tag update is a commit here. This is what Argo CD watches.
What's Included
Two CI/CD pipelines — CodeBuild (active, AWS-native) and GitHub Actions (GitOps, portable)
OIDC authentication — no AWS credentials stored in GitHub, temporary tokens only
Trivy vulnerability scanning — blocks the push if CRITICAL or HIGH CVEs are found
GitOps deployment — GitHub Actions updates the image tag in
eks-gitops, Argo CD deploysSelf-healing — Argo CD reverts any manual cluster change automatically
Multi-environment — production and dev environments managed from a single config repo
Key Architecture Decisions
Two pipelines, one codebase. CodeBuild runs inside AWS — no credentials leave the account, deep native integration. GitHub Actions lives where the code lives — visible to every engineer without AWS Console access, portable to any cloud. Neither is universally better. Knowing the trade-offs is the point, and having both in the repo demonstrates that.
OIDC over stored credentials. No long-lived access keys in GitHub secrets. The workflow requests a short-lived token via GitHub's OIDC provider and AWS STS exchanges it for temporary credentials scoped to a specific IAM role. Nothing to rotate, nothing to leak.
Trivy pinned to a commit SHA, not @master. A security scanner running from an unpinned tag is a supply chain risk — a bad push from the action's maintainer gets picked up by every pipeline immediately. Pinning to a commit SHA means updates are intentional and reviewed.
Images tagged with commit SHA, never just latest. latest is mutable. A commit SHA is immutable — when you see the image tag on a running pod, you know exactly which commit it came from, who authored it, and what tests it passed.
GitHub Actions updates GitOps, Argo CD deploys. The pipeline doesn't run helm upgrade or kubectl set image directly. It commits an updated image tag to eks-gitops and stops. Argo CD handles the deployment — so every deploy is a Git commit with a diff, an author, and a timestamp. Rollback is a git revert.
selfHeal: true. Any manual change to the cluster — scaling a deployment, editing a ConfigMap — is automatically reverted by Argo CD. The cluster always converges to what Git says. Drift is impossible to sustain.
How to Use It
git clone https://github.com/TisigheLivinstone/eks-app-deployment
git clone https://github.com/TisigheLivinstone/eks-gitops
# GitHub Actions triggers automatically on push to master
# Argo CD syncs eks-gitops within 3 minutes of each image tag update
# Verify deployment
kubectl get applications -n argocd
kubectl get pods -n production# Manual rollback via GitOps (preferred — leaves a trace)
git revert HEAD && git push
# Emergency rollback via Argo CD CLI
argocd app rollback api-production 1What I Learned
The OIDC trust policy took the longest to get right. GitHub's sub claim now uses an immutable format that includes numeric user and repository IDs — not just the repo name. The trust policy must match exactly or the assume-role call fails with a generic auth error. I only found the exact claim value by decoding the JWT mid-pipeline and inspecting it directly.
The other lesson: don't run GitHub Actions and Argo CD both trying to own the same Helm release. After Argo CD claims the resources, a direct helm upgrade from CI fails because the ownership annotations don't match. The correct pattern is CI updates the image tag in Git, Argo CD does the deployment — not both.
Results
Zero stored AWS credentials — OIDC only, temporary tokens only
Every deployment traceable to a commit — author, timestamp, image SHA, test results
Vulnerable images blocked before they reach ECR or the cluster
Manual cluster changes reverted automatically — self-healing via Argo CD
Rollback in under 2 minutes via
git revertBoth pipelines in the codebase — AWS-native and portable approaches side by side
Read Part 4 — GitHub Actions CI/CD · Read Part 5 — GitOps with Argo CD · eks-app-deployment · eks-gitops