freundcloud

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