GitOps Patterns for Multi-Cloud (2025)

GitOps has evolved significantly to address the complexities of multi-cloud environments. This guide presents modern GitOps patterns for 2025 that enable reliable, consistent management of infrastructure and applications across AWS, Azure, and GCP.

Core GitOps Principles: 2025 Edition

The foundational principles of GitOps have expanded to accommodate multi-cloud realities:

  1. Declarative Infrastructure - All infrastructure, not just applications, is defined declaratively

  2. Git as Single Source of Truth - All changes across clouds are tracked in version control

  3. Pull-Based Deployments - Controllers in each cloud pull desired state from Git

  4. Continuous Reconciliation - System automatically corrects drift from the desired state

  5. Immutable Infrastructure - Resources are replaced, not modified

  6. Security by Default - Security controls are embedded in the GitOps workflow

  7. Observability Integration - GitOps workflows emit metrics, logs, and traces

Implementation Architecture

Centralized vs. Federated GitOps Models

1. Centralized Model

In a centralized model, a single Git repository contains configurations for all clouds, with separate directories for each provider:

infrastructure/
├── aws/
│   ├── eks/
│   ├── networking/
│   └── security/
├── azure/
│   ├── aks/
│   ├── networking/
│   └── security/
└── gcp/
    ├── gke/
    ├── networking/
    └── security/

Benefits:

  • Unified view across all environments

  • Consistent policies and patterns

  • Simplified cross-cloud orchestration

  • Single approval workflow

Challenges:

  • Repository can become large and complex

  • Teams may have different cloud ownership

  • Security boundaries might be more complex

Example implementation with Flux:

# Root Kustomization for multi-cloud deployment
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 10m
  path: ./infrastructure
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system

---
# Cloud-specific Kustomizations
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: aws-infrastructure
  namespace: flux-system
spec:
  dependsOn:
    - name: infrastructure
  interval: 10m
  path: ./infrastructure/aws
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: azure-infrastructure
  namespace: flux-system
spec:
  dependsOn:
    - name: infrastructure
  interval: 10m
  path: ./infrastructure/azure
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system

2. Federated Model

In a federated model, separate repositories exist for each cloud provider with a "meta-repo" that references them:

# Meta repository structure
fleet/
├── aws-fleet.yaml
├── azure-fleet.yaml
└── gcp-fleet.yaml

Each cloud-specific repository contains its own configuration:

# aws-infrastructure repository
eks/
networking/
security/

Benefits:

  • Clear separation of concerns

  • Independent team ownership

  • Granular access control

  • Smaller, more focused repositories

Challenges:

  • Cross-cloud coordination is more complex

  • Requires additional synchronization mechanisms

  • Can be challenging to implement holistic policies

Example implementation with ArgoCD:

# Application of applications pattern
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: fleet-of-clouds
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/organization/fleet.git
    targetRevision: HEAD
    path: .
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd

---
# AWS-specific application in fleet repo
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: aws-infrastructure
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/organization/aws-infrastructure.git
    targetRevision: HEAD
    path: .
  destination:
    server: https://kubernetes.default.svc
    namespace: aws-infra

Multi-Cloud GitOps Tools

1. Flux

Flux is a set of continuous and progressive delivery solutions for Kubernetes that can be extended to manage cloud resources.

# Example Flux Terraform Controller deployment
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
  name: terraform-aws
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/organization/terraform-aws
  ref:
    branch: main

---
apiVersion: infra.contrib.fluxcd.io/v1alpha1
kind: Terraform
metadata:
  name: aws-vpc
  namespace: flux-system
spec:
  interval: 10m
  path: ./vpc
  sourceRef:
    kind: GitRepository
    name: terraform-aws
  approvePlan: auto
  writeOutputsToSecret:
    name: aws-vpc-outputs

2. ArgoCD

ArgoCD is a declarative GitOps continuous delivery tool for Kubernetes that can be extended with plugins for multi-cloud scenarios.

# ArgoCD with AWS plugin
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: aws-resources
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/organization/aws-resources.git
    targetRevision: HEAD
    path: .
    plugin:
      name: argocd-vault-plugin
  destination:
    server: https://kubernetes.default.svc
    namespace: aws-resources

3. Crossplane

Crossplane is a control plane that enables platform teams to create cloud-native applications using managed services from multiple providers.

# Crossplane AWS VPC configuration
apiVersion: ec2.aws.crossplane.io/v1beta1
kind: VPC
metadata:
  name: production-vpc
spec:
  forProvider:
    region: us-west-2
    cidrBlock: 10.0.0.0/16
    enableDnsSupport: true
    enableDnsHostNames: true
    tags:
      environment: production
  providerConfigRef:
    name: aws-provider

Advanced GitOps Patterns

1. Multi-Cluster Configuration Management

For organizations managing multiple Kubernetes clusters across different clouds:

# Centralized configuration with cluster-specific overlays
clusters/
├── base/
│   ├── monitoring/
│   │   └── prometheus.yaml
│   └── security/
│       └── network-policies.yaml
└── overlays/
    ├── aws-prod/
    │   ├── kustomization.yaml
    │   └── monitoring/
    │       └── prometheus-aws.yaml
    ├── azure-prod/
    │   ├── kustomization.yaml
    │   └── monitoring/
    │       └── prometheus-azure.yaml
    └── gcp-prod/
        ├── kustomization.yaml
        └── monitoring/
            └── prometheus-gcp.yaml

2. Progressive Delivery Across Clouds

Implementing canary and blue/green deployments across multiple cloud environments:

# Flux Canary Release for multi-cloud
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: podinfo
  namespace: podinfo
spec:
  interval: 5m
  chart:
    spec:
      chart: podinfo
      version: '>=6.0.0'
      sourceRef:
        kind: HelmRepository
        name: podinfo
  values:
    replicaCount: 3
  upgrade:
    # Gradual rollout across clusters
    remediation:
      remediateLastFailure: true
    strategy:
      canary:
        steps:
          - setWeight: 5
          - pause: {duration: 5m}
          - setWeight: 20
          - pause: {duration: 10m}
          - setWeight: 50
          - pause: {duration: 10m}

3. Policy-as-Code Integration

Enforcing consistent policies across all cloud environments:

# OPA/Gatekeeper constraint template
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }

4. Secret Management in GitOps Workflows

Secure handling of secrets across multiple clouds:

# External Secrets Operator with AWS Parameter Store
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: aws-secret
spec:
  refreshInterval: "1h"
  secretStoreRef:
    name: aws-parameterstore
    kind: ClusterSecretStore
  target:
    name: application-secrets
    creationPolicy: Owner
  data:
  - secretKey: dbPassword
    remoteRef:
      key: /myapp/production/db-password

CI/CD Integration with GitOps

1. Pull Request Workflows

Modern GitOps implementations include CI processes that validate changes before they're merged:

# GitHub Actions workflow for multi-cloud validation
name: Validate Changes

on:
  pull_request:
    branches: [ main ]
    paths:
      - 'infrastructure/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        provider: [aws, azure, gcp]
        include:
          - provider: aws
            workdir: ./infrastructure/aws
            validate_cmd: terraform validate
          - provider: azure
            workdir: ./infrastructure/azure
            validate_cmd: az bicep build --file main.bicep
          - provider: gcp
            workdir: ./infrastructure/gcp
            validate_cmd: gcloud beta terraform vet

    steps:
    - uses: actions/checkout@v3
      
    - name: Setup provider tools
      run: |
        if [ "${{ matrix.provider }}" == "aws" ]; then
          # AWS setup
          curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
          unzip awscliv2.zip
          sudo ./aws/install
          # Install Terraform
          curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
          sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
          sudo apt-get update && sudo apt-get install terraform
        elif [ "${{ matrix.provider }}" == "azure" ]; then
          # Azure setup
          curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
          az bicep install
        elif [ "${{ matrix.provider }}" == "gcp" ]; then
          # GCP setup
          echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
          curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
          sudo apt-get update && sudo apt-get install google-cloud-sdk
        fi
      
    - name: Validate ${{ matrix.provider }} configuration
      working-directory: ${{ matrix.workdir }}
      run: ${{ matrix.validate_cmd }}
      
    - name: Run Policy Checks
      uses: open-policy-agent/conftest-action@v2.0.0
      with:
        files: ${{ matrix.workdir }}
        policy: ./policies/${{ matrix.provider }}

2. Post-Merge Verification

After changes are merged to the main branch, automated processes verify successful application:

# GitLab CI post-merge verification
stages:
  - validate
  - apply
  - verify

verify-aws:
  stage: verify
  script:
    - aws cloudformation describe-stacks --stack-name production-stack --query "Stacks[0].StackStatus" | grep -q "COMPLETE"
    - aws eks describe-cluster --name production --query "cluster.status" | grep -q "ACTIVE"
  only:
    - main

verify-azure:
  stage: verify
  script:
    - az deployment group show --name production-deployment --resource-group production --query "properties.provisioningState" | grep -q "Succeeded"
  only:
    - main

verify-gcp:
  stage: verify
  script:
    - gcloud deployment-manager deployments describe production --format="json" | jq '.operation.status' | grep -q "DONE"
  only:
    - main

Multi-Cloud GitOps Best Practices

  1. Adopt Common Tooling: Use the same GitOps tools across clouds when possible

  2. Define Consistent Patterns: Create templates and standards that work across providers

  3. Implement Strong RBAC: Use granular permissions to control who can change what

  4. Cross-Cloud Testing: Implement testing across all target environments

  5. Standardize Observability: Use consistent monitoring and alerting across clouds

  6. Automate Drift Detection: Implement regular checks for configuration drift

  7. Document Failure Modes: Plan for GitOps controller failures or Git outages

  8. Implement Backup Strategies: Ensure GitOps state can be recovered

Real-World Examples

Example 1: Financial Services Multi-Cloud Deployment

A financial services company implements GitOps across AWS (primary) and Azure (secondary) for regulatory compliance:

# ArgoCD ApplicationSet for multi-region deployment
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: financial-application
spec:
  generators:
  - list:
      elements:
      - cloud: aws
        region: us-east-1
        clusterUrl: https://aws-east.example.com
      - cloud: aws
        region: us-west-2
        clusterUrl: https://aws-west.example.com
      - cloud: azure
        region: eastus
        clusterUrl: https://azure-east.example.com
  template:
    metadata:
      name: '{{cloud}}-{{region}}-app'
    spec:
      project: default
      source:
        repoURL: https://github.com/financial-org/app-configs.git
        targetRevision: main
        path: overlays/{{cloud}}/{{region}}
      destination:
        server: '{{clusterUrl}}'
        namespace: financial-app
      syncPolicy:
        automated:
          prune: true
          selfHeal: true

Example 2: Retail Company with Edge Locations

A retail company manages Kubernetes clusters across AWS, Azure, and edge locations:

# Flux deployment with multi-type structure
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: retail-infrastructure
  namespace: flux-system
spec:
  interval: 10m
  path: ./base
  prune: true
  sourceRef:
    kind: GitRepository
    name: retail-infrastructure
  postBuild:
    substituteFrom:
    - kind: ConfigMap
      name: cluster-config
---
# ConfigMap with cluster-specific values
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-config
  namespace: flux-system
data:
  CLUSTER_TYPE: "EDGE" # Alternative: AWS, AZURE
  REGION: "store-1234"
  RESOURCE_TIER: "small" # Depends on the location's size

Conclusion

Modern GitOps patterns enable organizations to maintain consistency across multi-cloud environments while respecting the unique characteristics of each provider. By implementing these patterns, teams can achieve greater reliability, improved security, and faster deployment cycles across their entire infrastructure.

Resources

Last updated