Azure - Avancé : AKS avancé, Azure DevOps et gouvernance
🎯 Objectifs
- ✅ Opérer AKS en production : scaling, workload identity, mise à niveau
- ✅ Créer des pipelines CI/CD complets avec Azure DevOps
- ✅ Gouverner son tenant avec Azure Policy, RBAC avancé et Management Groups
- ✅ Sécuriser les connexions avec Private Endpoints et Private Link
- ✅ Analyser et optimiser les coûts avec Azure Cost Management
📋 Prérequis
- Azure Intermédiaire (VNet, App Service, AKS de base, Bicep)
- CI/CD Intermédiaire (concepts pipelines, YAML)
- Kubernetes Avancé (Deployments, RBAC Kubernetes, Helm)
☸️ AKS Avancé
Cluster Autoscaler
Le Cluster Autoscaler ajuste automatiquement le nombre de noeuds selon la charge (pods en attente de scheduling) :
# Activer le cluster autoscaler sur un node pool existant
az aks nodepool update \
--resource-group rg-aks \
--cluster-name mon-cluster \
--name nodepool1 \
--enable-cluster-autoscaler \
--min-count 1 \
--max-count 10
# Vérifier l'état du scaler
kubectl describe configmap cluster-autoscaler-status -n kube-systemWorkload Identity
Le Workload Identity permet aux pods d'accéder aux ressources Azure (Key Vault, Blob Storage...) sans stocker de credentials. Il remplace l'ancienne approche AAD Pod Identity.
# Activer OIDC Issuer et Workload Identity sur le cluster
az aks update \
--resource-group rg-aks \
--name mon-cluster \
--enable-oidc-issuer \
--enable-workload-identity
# Créer un Managed Identity
az identity create \
--resource-group rg-aks \
--name mi-mon-app
# Créer la fédération OIDC entre le Service Account Kubernetes et la Managed Identity
az identity federated-credential create \
--name fc-mon-app \
--identity-name mi-mon-app \
--resource-group rg-aks \
--issuer $(az aks show --resource-group rg-aks --name mon-cluster --query oidcIssuerProfile.issuerUrl -o tsv) \
--subject system:serviceaccount:default:mon-service-account \
--audience api://AzureADTokenExchangeManifeste Kubernetes avec Workload Identity :
apiVersion: v1
kind: ServiceAccount
metadata:
name: mon-service-account
annotations:
azure.workload.identity/client-id: "<CLIENT_ID_DE_LA_MANAGED_IDENTITY>"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-app
spec:
template:
metadata:
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: mon-service-account
containers:
- name: mon-app
image: monregistryacr.azurecr.io/mon-app:v1Mise à Niveau d'un Cluster AKS
# Lister les versions disponibles
az aks get-upgrades \
--resource-group rg-aks \
--name mon-cluster \
--output table
# Mettre à niveau le plan de contrôle
az aks upgrade \
--resource-group rg-aks \
--name mon-cluster \
--kubernetes-version 1.30.0
# Mettre à niveau les node pools séparément (moins de disruption)
az aks nodepool upgrade \
--resource-group rg-aks \
--cluster-name mon-cluster \
--name nodepool1 \
--kubernetes-version 1.30.0 \
--max-surge 1🔄 Azure DevOps - Pipelines CI/CD
Concepts Azure DevOps
| Composant | Rôle |
|---|---|
| Boards | Gestion de projet (user stories, sprints) |
| Repos | Dépôts Git hébergés |
| Pipelines | CI/CD automatisé (YAML ou Classic) |
| Artifacts | Gestionnaire de packages (npm, Maven, NuGet) |
| Test Plans | Tests manuels et automatisés |
Pipeline YAML de bout en bout
# azure-pipelines.yml
trigger:
branches:
include: [main]
paths:
exclude: ['**/*.md']
variables:
acrName: 'monregistryacr'
imageName: 'mon-app'
kubernetesNamespace: 'production'
stages:
- stage: Build
jobs:
- job: BuildAndTest
pool:
vmImage: 'ubuntu-latest'
steps:
- task: NodeTool@0
inputs:
versionSpec: '20.x'
- script: |
npm ci
npm run test -- --coverage
npm run build
displayName: 'Tests et build'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/junit.xml'
- task: Docker@2
displayName: 'Build et push vers ACR'
inputs:
containerRegistry: 'connexion-acr'
repository: '$(imageName)'
command: buildAndPush
tags: |
$(Build.BuildId)
latest
- stage: DeployStaging
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployToStaging
environment: 'staging'
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
displayName: 'Déployer sur staging'
inputs:
action: 'deploy'
kubernetesServiceConnection: 'connexion-aks-staging'
namespace: 'staging'
manifests: 'k8s/*.yaml'
containers: '$(acrName).azurecr.io/$(imageName):$(Build.BuildId)'
- stage: DeployProduction
dependsOn: DeployStaging
jobs:
- deployment: DeployToProduction
environment: 'production' # ← Approbation manuelle requise
pool:
vmImage: 'ubuntu-latest'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@1
displayName: 'Déployer en production'
inputs:
action: 'deploy'
kubernetesServiceConnection: 'connexion-aks-prod'
namespace: 'production'
manifests: 'k8s/*.yaml'
containers: '$(acrName).azurecr.io/$(imageName):$(Build.BuildId)'💡 Environnements avec approbation : dans Azure DevOps, configurez des "Approvals" sur l'environnement
productionpour exiger une validation humaine avant tout déploiement en prod.
🏛️ Gouvernance Azure
Azure Policy
Azure Policy évalue les ressources selon des règles et peut les bloquer, les auditer ou les corriger automatiquement.
{
"displayName": "Interdire la création de ressources hors France",
"policyType": "Custom",
"mode": "All",
"parameters": {},
"policyRule": {
"if": {
"not": {
"field": "location",
"in": ["francecentral", "francesouth", "global"]
}
},
"then": {
"effect": "Deny"
}
}
}# Créer la définition de politique
az policy definition create \
--name 'interdire-hors-france' \
--display-name 'Interdire ressources hors France' \
--description 'RGPD : toutes les ressources doivent rester en France' \
--rules policy-rule.json \
--mode All
# Assigner la politique à un scope
az policy assignment create \
--name 'interdire-hors-france-prod' \
--display-name 'France only - Production' \
--policy 'interdire-hors-france' \
--scope /subscriptions/SUB_ID/resourceGroups/rg-prod
# Voir les ressources non conformes
az policy state list \
--filter "complianceState eq 'NonCompliant'" \
--output tableManagement Groups et Hiérarchie de gouvernance
Tenant Root Group
├── MG-Prod (politique : no public IPs, tags obligatoires)
│ ├── subscription-prod-france
│ └── subscription-prod-europe
├── MG-NonProd (politique : limites de coûts, régions de dev)
│ ├── subscription-dev
│ └── subscription-staging
└── MG-Sandbox (politique : destruction automatique après 7j)
└── subscription-sandboxRBAC Avancé - Rôles Personnalisés
# Créer un rôle personnalisé "Opérateur AKS"
az role definition create --role-definition '{
"Name": "Opérateur AKS",
"Description": "Peut lire et redémarrer les pods, mais pas modifier les configurations",
"Actions": [
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/listClusterAdminCredential/action"
],
"NotActions": [],
"DataActions": [
"Microsoft.ContainerService/managedClusters/pods/read",
"Microsoft.ContainerService/managedClusters/pods/delete"
],
"AssignableScopes": ["/subscriptions/SUB_ID"]
}'🔒 Sécurité Réseau Avancée
Private Endpoints
Un Private Endpoint donne à une ressource Azure (ex: Azure SQL, Key Vault, Storage) une adresse IP privée dans votre VNet. Le trafic ne passe plus par internet.
# Créer un Private Endpoint pour Azure SQL Database
az network private-endpoint create \
--resource-group rg-securite \
--name pe-sql \
--vnet-name mon-vnet \
--subnet subnet-prive \
--private-connection-resource-id /subscriptions/SUB_ID/resourceGroups/rg/providers/Microsoft.Sql/servers/mon-serveur-sql \
--group-id sqlServer \
--connection-name connexion-sql
# Configurer DNS privé pour résoudre l'IP privée
az network private-dns zone create \
--resource-group rg-securite \
--name "privatelink.database.windows.net"
az network private-dns link vnet create \
--resource-group rg-securite \
--zone-name "privatelink.database.windows.net" \
--name lien-dns \
--virtual-network mon-vnet \
--registration-enabled falseRésultat : mon-serveur-sql.database.windows.net se résout en 10.0.2.5 (IP privée) depuis votre VNet.
Microsoft Defender for Cloud
Defender for Cloud fournit un score de sécurité (Security Posture) et des recommandations actionables :
# Activer les plans Defender sur une subscription
az security pricing create \
--name VirtualMachines \
--tier Standard
az security pricing create \
--name SqlServers \
--tier Standard
# Lister les recommandations actives
az security assessment list --output table
# Exporter le Security Score
az security secure-score-controls list \
--output table💰 Azure Cost Management et FinOps
Analyser les coûts
# Coûts du mois courant par service
az consumption usage list \
--start-date 2024-11-01 \
--end-date 2024-11-30 \
--output table
# Créer un budget avec alerte
az consumption budget create \
--budget-name "Budget-Production-Nov" \
--amount 500 \
--time-grain Monthly \
--start-date 2024-11-01 \
--end-date 2025-10-31 \
--category Cost \
--resource-group rg-prod \
--notifications '[{
"enabled": true,
"operator": "GreaterThan",
"threshold": 80,
"contactEmails": ["equipe@example.com"],
"thresholdType": "Actual"
}]'Optimisations courantes
| Levier | Économie | Action |
|---|---|---|
| Azure Reservations | jusqu'à 72% | Réserver des VMs 1 ou 3 ans |
| Azure Hybrid Benefit | jusqu'à 40% | Apporter ses licences Windows/SQL Server |
| Spot VMs | jusqu'à 90% | Workloads interruptibles (batch, CI/CD) |
| Auto-shutdown VMs | 60-70% | Éteindre les VMs de dev la nuit |
| Rightsizing | variable | Réduire les VMs surdimensionnées |
# Activer l'arrêt automatique sur une VM (utile pour les environnements de dev)
az vm auto-shutdown \
--resource-group rg-dev \
--name vm-dev \
--time 1900 \
--email "equipe@example.com"📌 Points Clés
- Workload Identity remplace les secrets applicatifs par une fédération OIDC - plus sécurisé, pas de credentials à gérer
- Azure DevOps Environments permet d'ajouter des approbations humaines avant la production
- Azure Policy peut bloquer (
Deny), auditer (Audit) ou corriger automatiquement (DeployIfNotExists) les ressources non conformes - Private Endpoints = traffic réseau Azure entièrement privé, sans passer par Internet
- Hybrid Benefit + Reservations = jusqu'à 80% d'économies sur les workloads stables