← back to blog

Unifying GitOps for AWS: ArgoCD, Terraform, and Crossplane

A GitOps-driven infrastructure platform combining ArgoCD for application delivery, Terraform for foundational infrastructure, and Crossplane for Kubernetes-native AWS resource management.

SJ
Sabin Joshi
DevOps Engineer

Why a Unified GitOps Platform?

Most teams end up with two separate worlds: Terraform for infrastructure and a separate CI/CD pipeline for application deployment. This split creates a frustrating gap — infrastructure changes and application changes aren't correlated, drift is invisible, and rollbacks are manual and fragile.

After 18 months of pain with this split, we unified everything under a single GitOps model. Every change — infrastructure or application — is a pull request, reviewed, and reconciled automatically.

Platform Architecture

Unified GitOps Platform Flow
App Repo k8s manifests Infra Repo terraform + crossplane GitHub Actions CI: test, build, push ArgoCD continuous reconcile drift detection Terraform Cloud state + plans Crossplane k8s-native AWS resource management AWS Infra VPC, RDS, EKS... EKS Cluster apps + crossplane providers Slack / PagerDuty drift alerts ArgoCD reconcile CI trigger Crossplane provision

ArgoCD for Application Delivery

ArgoCD watches Git repositories and continuously reconciles the cluster state to match the desired state in Git. Any manual change to the cluster is automatically reverted — this is drift detection in action.

# ArgoCD Application CRD
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: api-service
  namespace: argocd
spec:
  project: production
  source:
    repoURL: https://github.com/yourorg/app-repo
    targetRevision: HEAD
    path: k8s/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true     # Remove resources deleted from Git
      selfHeal: true  # Auto-revert manual changes
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground

Crossplane: Kubernetes-Native AWS

Crossplane lets you provision AWS resources (RDS, S3, SQS) using Kubernetes manifests — the same tooling your team already uses for application deployment. The magic: application teams can self-service infrastructure by submitting PRs, without learning Terraform.

# Provision an RDS instance via Crossplane
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
  name: team-alpha-db
spec:
  forProvider:
    region: us-east-1
    instanceClass: db.t3.medium
    engine: postgres
    engineVersion: "15.4"
    allocatedStorage: 100
    storageEncrypted: true
    multiAz: true
  writeConnectionSecretToRef:
    namespace: team-alpha
    name: db-credentials

Terraform's Role

Terraform handles the "heavy" foundational infrastructure — VPCs, IAM roles, EKS clusters themselves, and any resource that predates Crossplane or doesn't have a mature Crossplane provider. We run Terraform via GitHub Actions on merge to main, with plan output posted as PR comments for review.

ℹ️The rule of thumb: if a resource needs to exist before EKS boots, it's Terraform. If it can be provisioned after EKS is running, consider Crossplane.

Impact After 6 Months

Before this platform, infrastructure changes took 3–5 days due to manual review and deployment. After: average infrastructure PR-to-deployed is 47 minutes. Drift incidents dropped from ~4 per month to zero. Developer satisfaction with infrastructure tooling went from 3.2/5 to 4.7/5 on our quarterly survey.