Production-grade AWS EKS platform with Helm-based service deployment, ArgoCD GitOps, KEDA autoscaling, and External Secrets Operator — for SaaS teams scaling multi-service architectures.
SaaS platforms running on Kubernetes inevitably outgrow manual deployment workflows. Services multiply, each needing its own Helm chart, IRSA role, secrets, autoscaling policy, and ArgoCD application. Without a standardized pattern, every new service becomes a snowflake — different environment variable naming, inconsistent resource limits, ad-hoc secret management. The existing DevOps engineer becomes a bottleneck because only they know where everything is configured. Onboarding a second engineer takes weeks instead of hours because there's no discoverable, repeatable pattern.
This repository provides a complete, opinionated infrastructure pattern for running a multi-service SaaS platform on AWS EKS. Terraform manages the foundational AWS resources (EKS, Aurora PostgreSQL, ElastiCache Redis, SQS/SNS, SES). A reusable Helm chart handles service deployment with IRSA, KEDA autoscaling, and health checks built in. ArgoCD manages GitOps delivery via an app-of-apps pattern. External Secrets Operator syncs secrets from AWS Secrets Manager into Kubernetes. SOPS + KMS encrypts any values committed to Git. GitHub Actions handles CI with OIDC auth — no static AWS credentials anywhere.
flowchart TB
subgraph Internet["🌐 Internet"]
Users["👥 Users"]
DNS["🌐 Route53"]
end
subgraph AWS["☁️ AWS Account"]
subgraph VPC["🔒 VPC — Multi-AZ"]
subgraph Public["Public Subnets"]
ALB["⚖️ ALB / Ingress"]
end
subgraph Private["Private Subnets"]
subgraph EKS["☸️ EKS Cluster"]
ArgoCD["🔄 ArgoCD"]
ESO["🔐 External Secrets Operator"]
KEDA["📈 KEDA"]
SVC1["📦 Service A"]
SVC2["📦 Service B"]
SVC3["📦 Service C"]
end
end
subgraph Data["Data Subnets"]
Aurora["🐘 Aurora PostgreSQL"]
Redis["⚡ ElastiCache Redis"]
end
end
SQS["📨 SQS Queues"]
SNS["📢 SNS Topics"]
SES["✉️ SES Email"]
SM["🔑 Secrets Manager"]
KMS["🔐 KMS"]
S3["🗂️ S3 / TF State"]
Lambda["⚡ Lambda"]
ECR["📦 ECR"]
end
subgraph CI["⚙️ GitHub Actions"]
Build["🔨 Build + Test"]
Push["📦 Push to GHCR/ECR"]
end
Users --> DNS --> ALB --> SVC1 & SVC2 & SVC3
ArgoCD -->|"sync"| SVC1 & SVC2 & SVC3
ESO -->|"fetch"| SM
KEDA -->|"scale on"| SQS
SVC1 --> Aurora & Redis
SVC2 --> SQS
SVC3 --> SES
Lambda --> SQS
SM --> KMS
CI --> Push -->|"OCI helm push"| ArgoCD
S3 -->|"TF state"| VPC
| Layer | Technology |
|---|---|
| Cloud | AWS (EKS, Aurora PostgreSQL, ElastiCache Redis, SQS, SNS, SES, Lambda, S3, KMS, ACM) |
| IaC | Terraform >= 1.6 with S3 + DynamoDB backend |
| Orchestration | Kubernetes (EKS) with IRSA pod identity |
| Package Management | Helm 3 with OCI registry (GHCR) |
| GitOps | ArgoCD with app-of-apps pattern |
| Autoscaling | KEDA (SQS queue depth, Redis list length, cron) |
| Secrets | External Secrets Operator + AWS Secrets Manager + SOPS/KMS |
| CI/CD | GitHub Actions with OIDC auth to AWS |
| DNS / Email | Route53, SES with DKIM/SPF/DMARC |
| Scripting | Bash, Node.js |
- Terraform >= 1.6 installed (
brew install terraform) - AWS CLI v2 configured (
aws configure) - kubectl installed (
brew install kubectl) - Helm 3 installed (
brew install helm) - SOPS installed (
brew install sops) - ArgoCD CLI installed (
brew install argocd) - AWS account with permissions for EKS, RDS, ElastiCache, SQS, SNS, SES, Secrets Manager, KMS, IAM, Route53
git clone https://github.com/NaumanMunir9/devops-eks-saas-platform-infrastructure.git
cd devops-eks-saas-platform-infrastructure
# Check prerequisites
./scripts/prerequisites.sh
# Deploy infrastructure (staging)
cd terraform
terraform init
terraform plan -var-file=environments/staging.tfvars -out=tfplan
terraform apply tfplan
# Configure kubectl
aws eks update-kubeconfig --name saas-platform-staging --region us-east-1
# Install platform components (ArgoCD, KEDA, External Secrets Operator)
./scripts/deploy.sh staging
# Deploy a service via ArgoCD
kubectl apply -f kubernetes/argocd/app-of-apps.yamlTerraform creates the VPC, EKS cluster, Aurora PostgreSQL, ElastiCache Redis, SQS queues, SNS topics, and SES domain configuration.
cd terraform
terraform init
terraform plan -var-file=environments/staging.tfvars -out=tfplan
terraform apply tfplanaws eks update-kubeconfig --name saas-platform-staging --region us-east-1
kubectl get nodes
kubectl get namespacesThe deploy script installs ArgoCD, KEDA, and External Secrets Operator via Helm, then configures the ClusterSecretStore.
./scripts/deploy.sh staging# Encrypt a values file with SOPS + KMS
export SOPS_KMS_ARN="arn:aws:kms:us-east-1:ACCOUNT_ID:key/KEY_ID"
sops --encrypt --in-place helm/platform-service/secrets.staging.yaml# Apply the app-of-apps root application
kubectl apply -f kubernetes/argocd/app-of-apps.yaml
# Monitor sync status
argocd app list
argocd app get platform-services --refresh./scripts/health-check.sh staging| Variable | Description | Default | Required |
|---|---|---|---|
project_name |
Project identifier for resource naming | saas-platform |
Yes |
environment |
Target environment (dev/staging/production) | — | Yes |
region |
AWS region | us-east-1 |
Yes |
vpc_cidr |
VPC CIDR block | 10.0.0.0/16 |
No |
availability_zones |
List of AZs | ["us-east-1a", "us-east-1b", "us-east-1c"] |
No |
eks_cluster_version |
Kubernetes version | 1.29 |
No |
eks_node_instance_types |
Node group instance types | ["m6i.large"] |
No |
eks_node_min_size |
Minimum nodes | 2 |
No |
eks_node_max_size |
Maximum nodes | 10 |
No |
aurora_instance_class |
Aurora instance type | db.r6g.large |
No |
aurora_engine_version |
PostgreSQL version | 15.4 |
No |
redis_node_type |
ElastiCache node type | cache.r6g.large |
No |
ses_domain |
SES verified domain | — | Yes |
alarm_email |
CloudWatch alarm destination | — | Yes |
- Why EKS over ECS Fargate: Multi-service SaaS platforms benefit from Kubernetes-native tooling — KEDA for event-driven autoscaling, ArgoCD for GitOps, External Secrets Operator for secret sync, RBAC for team-level access control. ECS lacks equivalents for these.
- Why KEDA over HPA: SQS queue depth and Redis list length are the real scaling signals for async workers. HPA only supports CPU/memory natively; custom metrics require CloudWatch adapter configuration. KEDA provides first-class triggers for SQS, Redis, and cron with zero custom metrics plumbing.
- Why External Secrets Operator over SOPS alone: SOPS encrypts secrets at rest in Git — necessary for GitOps. But ESO provides runtime sync from Secrets Manager into Kubernetes, auto-rotation, and a clean separation between encrypted-at-rest (SOPS) and live-in-cluster (ESO) secrets.
- Why ArgoCD app-of-apps over Flux: ArgoCD provides a web UI for sync status and diff visualization. For teams with a dedicated DevOps engineer plus additional contributors, the UI reduces "what's deployed where?" questions dramatically.
- Why Helm OCI on GHCR over ChartMuseum: GHCR is free for public repos, supports OCI artifacts natively, and integrates with GitHub Actions OIDC. No self-hosted chart registry to manage.
- Why Aurora PostgreSQL over RDS PostgreSQL: Aurora provides 3x throughput, automatic storage scaling, fast failover (< 30s), and up to 15 read replicas. For a SaaS platform with growing data needs, Aurora's storage auto-scaling avoids capacity planning overhead.
- Why multi-AZ with 3 subnets: EKS control plane requires subnets in at least 2 AZs. Using 3 AZs provides better fault tolerance and allows Aurora to spread replicas across zones.
| Resource | Monthly Cost |
|---|---|
| EKS control plane | ~$73 |
| EKS nodes (2× m6i.large) | ~$140 |
| Aurora PostgreSQL (db.r6g.large) | ~$175 |
| ElastiCache Redis (cache.r6g.large) | ~$130 |
| NAT Gateway (1 AZ) | ~$32 |
| ALB | ~$22 |
| SQS/SNS | ~$5 |
| Secrets Manager | ~$5 |
| S3 + CloudWatch | ~$10 |
| Total (Staging) | ~$592/month |
Production cost scales with node count, Aurora instances, and Redis replicas. Expect 2–3× staging for a production workload.
# Remove ArgoCD applications first
kubectl delete -f kubernetes/argocd/app-of-apps.yaml
# Uninstall platform components
./scripts/deploy.sh staging --uninstall
# Destroy infrastructure
cd terraform
terraform destroy -var-file=environments/staging.tfvarsNauman Munir — Senior DevOps & Cloud Engineer
Available for DevOps and Cloud Engineering engagements. Open to discussing your infrastructure challenges.