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