MFormations
Modern DevOps Engineering

Chapitre 16

16 - Projet Fil Rouge : Enterprise Cloud Platform

16 - Projet Fil Rouge : Enterprise Cloud Platform

Chapitre 16 : Projet Fil Rouge - Enterprise Cloud Platform

16.1 Architecture et Design

16.1.1 Diagramme d'architecture

                           Internet
                              │
                     ┌────────┴────────┐
                     │   CloudFront     │
                     │   / Global       │
                     │   Accelerator    │
                     └────────┬────────┘
                              │
              ┌───────────────┴───────────────┐
              │                               │
      ┌───────┴───────┐               ┌───────┴───────┐
      │  AWS us-east-1│               │ GCP eu-west-1 │
      │               │               │               │
      │ ┌───────────┐ │               │ ┌───────────┐ │
      │ │  EKS      │ │               │ │  GKE      │ │
      │ │  Cluster  │ │               │ │  Cluster  │ │
      │ └─────┬─────┘ │               │ └─────┬─────┘ │
      │       │       │               │       │       │
      │ ┌─────┴─────┐ │               │ ┌─────┴─────┐ │
      │ │  Istio    │ │               │ │  Istio    │ │
      │ │  Ingress  │ │               │ │  Ingress  │ │
      │ └───────────┘ │               │ └───────────┘ │
      └───────┬───────┘               └───────┬───────┘
              │                               │
              └───────────────┬───────────────┘
                              │
                     ┌────────┴────────┐
                     │   ArgoCD        │
                     │   (Multi-       │
                     │    Cluster)     │
                     └─────────────────┘

16.1.2 Principes d'architecture

architecture_principles:
  - "Multi-cloud par necessite, pas par dogme"
  - "Infrastructure as Code (Terraform + Crossplane)"
  - "GitOps pour tous les deploiements"
  - "Zero Trust Security (mTLS partout)"
  - "Observabilite par defaut (metrics, logs, traces)"
  - "Self-service via Backstage"
  - "Incident management avec SLO/SLI"

16.2 Infrastructure Multi-Cloud

16.2.1 Terraform - Provider AWS

# main.tf
provider "aws" {
  region = "us-east-1"
}

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"
  name = "enterprise-platform-vpc"
  cidr = "10.0.0.0/16"
  
  azs             = ["us-east-1a", "us-east-1b", "us-east-1c"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
  
  enable_nat_gateway = true
  enable_vpn_gateway = false
  enable_dns_hostnames = true
  
  tags = {
    Environment = "production"
    ManagedBy   = "terraform"
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"
  
  cluster_name    = "enterprise-platform-eks"
  cluster_version = "1.28"
  
  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets
  
  eks_managed_node_groups = {
    main = {
      desired_size = 3
      min_size     = 3
      max_size     = 10
      
      instance_types = ["m5.xlarge"]
      capacity_type  = "ON_DEMAND"
    }
    
    spot = {
      desired_size = 2
      min_size     = 2
      max_size     = 20
      
      instance_types = ["m5.xlarge"]
      capacity_type  = "SPOT"
    }
  }
  
  cluster_addons = {
    coredns    = {}
    kube-proxy = {}
    vpc-cni    = {}
  }
  
  tags = {
    Environment = "production"
  }
}

16.2.2 Terraform - Provider GCP

# main-gcp.tf
provider "google" {
  region = "europe-west1"
}

module "gke" {
  source  = "terraform-google-modules/kubernetes-engine/google"
  version = "~> 28.0"
  
  name       = "enterprise-platform-gke"
  region     = "europe-west1"
  network    = "enterprise-platform-vpc"
  
  node_pools = [
    {
      name         = "main-pool"
      machine_type = "e2-standard-4"
      min_count    = 3
      max_count    = 10
      disk_size_gb = 100
    },
    {
      name         = "spot-pool"
      machine_type = "e2-standard-4"
      min_count    = 2
      max_count    = 20
      disk_size_gb = 100
      spot         = true
    }
  ]
  
  release_channel = "STABLE"
  
  cluster_telemetry_type = "SYSTEM_ONLY"
}

16.3 Clusters Kubernetes

16.3.1 Configuration Cilium

# cilium-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: cilium-config
  namespace: kube-system
data:
  kube-proxy-replacement: strict
  enable-endpoint-routes: "true"
  auto-direct-node-routes: "true"
  tunnel: "disabled"
  native-routing-cidr: "10.0.0.0/8"
  enable-hubble: "true"
  hubble-listen-address: ":4244"
  hubble-relay-enabled: "true"
  hubble-ui-enabled: "true"
  cluster-name: "prod-eks-1"
  cluster-id: "1"
  ipam: "cluster-pool"
  enable-ipv4: "true"
  enable-ipv6: "false"

16.3.2 ClusterMesh Cilium (multi-cluster)

# clustermesh.yaml
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: clustermesh-global
spec:
  endpointSelector: {}
  ingress:
    - fromEntities:
        - cluster
  egress:
    - toEntities:
        - cluster
---
# Configurer ClusterMesh
cilium clustermesh enable --context=eks-cluster --service-type=LoadBalancer
cilium clustermesh enable --context=gke-cluster --service-type=LoadBalancer

# Connecter les clusters
cilium clustermesh connect --context=eks-cluster --destination-context=gke-cluster

16.4 Service Mesh (Istio)

16.4.1 Installation Istio

# istio-operator.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: enterprise-istio
spec:
  profile: production
  components:
    pilot:
      k8s:
        resources:
          requests:
            cpu: 500m
            memory: 2Gi
        hpaSpec:
          minReplicas: 3
          maxReplicas: 10
    ingressGateways:
      - name: istio-ingressgateway
        enabled: true
        k8s:
          hpaSpec:
            minReplicas: 3
            maxReplicas: 10
  meshConfig:
    accessLogFile: /dev/stdout
    enableTracing: true
    defaultConfig:
      proxyMetadata:
        ISTIO_META_DNS_CAPTURE: "true"
    extensionProviders:
      - name: oauth2-proxy
        envoyExtAuthzGrpc:
          service: oauth2-proxy.istio-system.svc.cluster.local
          port: "50001"

16.4.2 Configuration mTLS globale

# peer-authentication.yaml
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT
---
# destination-rule-mtls.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: default
  namespace: istio-system
spec:
  host: "*.local"
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL

16.5 GitOps (ArgoCD Multi-Cluster)

16.5.1 Configuration ArgoCD Multi-Cluster

# argocd-install.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: argocd
---
apiVersion: argoproj.io/v1alpha1
kind: ArgoCD
metadata:
  name: argocd
  namespace: argocd
spec:
  server:
    replicas: 2
    route:
      enabled: true
      host: argocd.enterprise.company.com
  applicationSet:
    replicas: 2
  repo:
    replicas: 2
  notifications:
    enabled: true

16.5.2 Cluster Registration

# argocd-cluster-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: eks-cluster
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
  name: eks-production
  server: https://EKS_CLUSTER_ENDPOINT
  config: |
    {
      "bearerToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkVYUEFNUE...
      "tlsClientConfig": {
        "insecure": false,
        "caData": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t..."
      }
    }

16.5.3 ApplicationSet Multi-Cluster

# appset-all-clusters.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: enterprise-apps
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            environment: production
  template:
    metadata:
      name: '{{name}}-platform-components'
    spec:
      project: platform
      source:
        repoURL: https://github.com/company/gitops-platform.git
        targetRevision: main
        path: 'clusters/{{name}}'
      destination:
        server: '{{server}}'
        namespace: platform
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

16.6 Observabilite

16.6.1 Stack Complete

# observability-stack.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: observability
---
# Prometheus Operator
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: kube-prometheus-stack
  namespace: observability
spec:
  chart:
    spec:
      chart: kube-prometheus-stack
      version: "51.x"
      sourceRef:
        kind: HelmRepository
        name: prometheus-community
  values:
    prometheus:
      prometheusSpec:
        retention: 30d
        retentionSize: 100GB
        thanos:
          objectStorageConfig:
            name: thanos-objectstorage
            key: thanos.yaml
    grafana:
      ingress:
        enabled: true
        hosts:
          - grafana.enterprise.company.com
---
# Loki
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: loki
  namespace: observability
spec:
  chart:
    spec:
      chart: loki
      version: "5.x"
      sourceRef:
        kind: HelmRepository
        name: grafana
  values:
    loki:
      auth_enabled: false
      ingester:
        chunk_idle_period: 1h
      storage:
        type: s3
        s3:
          endpoint: s3.amazonaws.com
          bucket: enterprise-logs
    gateway:
      ingress:
        enabled: true
        hosts:
          - loki.enterprise.company.com
---
# Tempo (Tracing)
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: tempo
  namespace: observability
spec:
  chart:
    spec:
      chart: tempo
      version: "1.x"
      sourceRef:
        kind: HelmRepository
        name: grafana
  values:
    tempo:
      storage:
        trace:
          backend: s3
          s3:
            bucket: enterprise-traces
            endpoint: s3.amazonaws.com

16.7 Securite

16.7.1 HashiCorp Vault (Multi-Cluster)

# vault-helm-values.yaml
server:
  ha:
    enabled: true
    replicas: 3
    raft:
      enabled: true
      config: |
        ui = true
        listener "tcp" {
          address = "0.0.0.0:8200"
          cluster_address = "0.0.0.0:8201"
          tls_disable = false
          tls_cert_file = "/vault/certs/cert.pem"
          tls_key_file = "/vault/certs/key.pem"
        }
        storage "raft" {
          path = "/vault/data"
        }
        seal "awskms" {
          region = "us-east-1"
          kms_key_id = "alias/vault-unseal"
        }

ui:
  enabled: true
  serviceType: LoadBalancer

16.7.2 Kyverno Policies

# kyverno-policies.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enterprise-security
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-mtls
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "All pods must have Istio sidecar injection"
        pattern:
          metadata:
            labels:
              sidecar.istio.io/inject: "true"

    - name: block-privileged
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "Privileged containers are not allowed"
        pattern:
          spec:
            containers:
              - securityContext:
                  privileged: false

    - name: require-resource-limits
      match:
        any:
          - resources:
              kinds: ["Pod", "Deployment"]
      validate:
        message: "Resource limits are required"
        pattern:
          spec:
            template:
              spec:
                containers:
                  - resources:
                      limits:
                        memory: "?*"
                        cpu: "?*"

16.8 Platform Engineering (Backstage)

16.8.1 Backstage Configuration

# app-config.yaml
app:
  title: "Enterprise Developer Portal"
  baseUrl: https://developer.enterprise.company.com

organization:
  name: "Enterprise Company"

integrations:
  github:
    - host: github.com
      token: ${GITHUB_TOKEN}

techdocs:
  builder: local
  publisher:
    type: local

auth:
  providers:
    okta:
      issuer: https://company.okta.com
      clientId: ${AUTH_OKTA_CLIENT_ID}
      clientSecret: ${AUTH_OKTA_CLIENT_SECRET}

catalog:
  rules:
    - allow: [Component, API, Group, User, System, Domain, Resource]
  locations:
    - type: url
      target: https://github.com/company/enterprise-catalog/main/catalog-info.yaml

kubernetes:
  serviceLocatorMethod:
    type: multiCluster
  clusterLocatorMethods:
    - type: config
      clusters:
        - name: eks-production
          url: https://EKS_CLUSTER_ENDPOINT
          authProvider: serviceAccount
          skipTLSVerify: false
        - name: gke-production
          url: https://GKE_CLUSTER_ENDPOINT
          authProvider: googleServiceAccount
          skipTLSVerify: false

16.8.2 Golden Path Template

# golden-path-microservice.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: enterprise-ms
  title: "Enterprise Microservice"
  description: "Standard microservice with full observability, security, and GitOps"
spec:
  owner: platform-team
  type: service
  parameters:
    - title: Service Details
      required:
        - serviceName
        - team
      properties:
        serviceName:
          title: Service Name
          type: string
        team:
          title: Team
          type: string
          ui:field: OwnerPicker
        database:
          title: Database Required
          type: boolean
          default: false
  steps:
    - id: scaffold
      name: Scaffold Service
      action: fetch:template
      input:
        url: ./skeleton
        values:
          serviceName: ${{ parameters.serviceName }}
    - id: create-repo
      name: Create Repository
      action: publish:github
      input:
        repoUrl: github.com?owner=${{ parameters.team }}&repo=${{ parameters.serviceName }}
    - id: register-catalog
      name: Register in Catalog
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.create-repo.output.repoContentsUrl }}

16.9 CI/CD Pipeline

# .github/workflows/enterprise-pipeline.yml
name: Enterprise CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: semgrep/semgrep-action@v1
        with:
          config: p/owasp-top-ten p/secrets
      - uses: actions/dependency-review-action@v3
        with:
          fail-on-severity: high

  build:
    needs: security
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: docker build -t enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }} .
      
      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }}
          format: cyclonedx-json
      
      - name: Push to ECR
        run: docker push enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }}
      
      - name: Sign image
        run: cosign sign --key awskms:///${{ secrets.KMS_KEY }} enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }}

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Update GitOps manifests
        run: |
          git clone https://github.com/company/gitops-platform.git
          cd gitops-platform
          kustomize edit set image enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }}
          git commit -m "Update ${{ github.event.repository.name }} to ${{ github.sha }}"
          git push

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Promote to production
        run: |
          git clone https://github.com/company/gitops-platform.git
          cd gitops-platform/apps/${{ github.event.repository.name }}/overlays/production
          kustomize edit set image enterprise.ecr.amazonaws.com/${{ github.event.repository.name }}:${{ github.sha }}
          git commit -m "Promote ${{ github.event.repository.name }}:${{ github.sha }} to production"
          git push

Resume

  • Architecture multi-cloud (AWS EKS + GCP GKE)
  • Service Mesh Istio avec mTLS strict
  • GitOps multi-cluster avec ArgoCD
  • Observabilite complete (Prometheus, Grafana, Loki, Tempo)
  • Securite Zero Trust (Vault, Kyverno, Cosign)
  • Platform Engineering (Backstage, Crossplane)
  • CI/CD securise avec SBOM et signature
  • Chaos Engineering pour la resilience
  • Toute decision documentee avec ADR