Prérequis
Ce guide suppose une connaissance de base des trois clouds majeurs (IAM, VPC, CLI) et de Terraform. Les exemples de code sont production-ready mais doivent être adaptés à votre contexte.
Introduction : le modèle de responsabilité partagée
La sécurité cloud repose sur un principe fondamental que la majorité des incidents vient valider de la pire façon : le modèle de responsabilité partagée. Le cloud provider sécurise l'infrastructure physique, l'hyperviseur, le réseau global et les services managés. Vous sécurisez tout le reste — configurations IAM, données, réseau virtuel, applications, secrets.
En pratique, cela signifie que AWS, GCP et Azure ne peuvent pas vous protéger contre un bucket S3 public, des clés root qui tournent en CI/CD, ou un Security Group qui ouvre le port 22 à 0.0.0.0/0. Ces erreurs, vous les faites vous-même, et le cloud provider ne les détecte pas par défaut.
Les 5 erreurs cloud les plus communes
Ces cinq patterns sont responsables de la grande majorité des incidents cloud documentés.
1. Buckets S3 (ou GCS / Azure Blob) publics — La configuration par défaut a évolué : AWS bloque désormais l'accès public par défaut depuis 2023. Mais il suffit d'une propriété mal configurée dans Terraform, d'un bucket créé manuellement avant la politique globale, ou d'un développeur qui coche "public" sans réfléchir pour exposer des téraoctets de données. Des millions de credentials, logs applicatifs et données personnelles ont été exfiltrés de cette manière.
2. Utilisation des clés root AWS — Le compte root AWS a des droits illimités et irréversibles. Créer des access keys root pour "aller plus vite" est une faute grave : ces clés ne peuvent pas être restreintes par des politiques IAM, et leur compromission signifie la compromission totale du compte. Désactivez les clés root, activez le MFA matériel et ne les utilisez jamais pour des opérations quotidiennes.
3. Politiques IAM avec wildcard (*) — "Action": "*", "Resource": "*" donne à n'importe quelle ressource tous les droits sur tout le compte. C'est l'équivalent cloud du chmod 777 /. Pourtant, cette configuration se retrouve régulièrement dans des rôles d'automatisation "pour aller vite". Le blast radius d'une compromission est alors maximal.
4. Security Groups ouverts à 0.0.0.0/0 — Ouvrir les ports SSH (22), RDP (3389) ou les bases de données (3306, 5432) à Internet entier expose vos instances à des scanners automatisés qui tentent des authentifications en permanence. Chaque jour, des milliers de machines bot scannent l'intégralité des plages IP AWS à la recherche de ces ports ouverts.
5. Secrets dans les variables d'environnement ou le code source — Clés API en dur dans le code, credentials de base de données dans les variables d'environnement de la définition de tâche ECS, tokens dans les Dockerfiles. Ces secrets se retrouvent dans les logs, les images Docker, les dépôts Git et les snapshots. Utilisez les services de secrets managés décrits dans ce guide.
1. IAM Security : least privilège en pratique
Le principe de moindre privilège (least privilège) est simple à énoncer et difficile à maintenir à l'échelle. Une politique IAM correcte donne exactement les droits nécessaires à une ressource pour accomplir sa tâche, ni plus, ni moins.
AWS IAM : rôles vs utilisateurs
La règle générale : les humains utilisent SSO (AWS IAM Identity Center), les workloads utilisent des rôles IAM, et les utilisateurs IAM traditionnels avec des clés d'accès longue durée sont à éviter sauf cas spécifiques documentés.
Exemple d'une politique IAM least privilège pour une Lambda qui lit depuis S3 et écrit dans DynamoDB :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadSpecificS3Bucket",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::mon-bucket-prod/data/*"
},
{
"Sid": "WriteSpecificDynamoTable",
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:GetItem"
],
"Resource": "arn:aws:dynamodb:eu-west-1:123456789012:table/MaTable"
},
{
"Sid": "DecryptWithSpecificKey",
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey"
],
"Resource": "arn:aws:kms:eu-west-1:123456789012:key/mrk-abc123"
}
]
}
Créer ce rôle et l'attacher à une Lambda via AWS CLI :
# 1. Créer le rôle avec une trust policy pour Lambda
aws iam create-role
--role-name lambda-data-processor
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}'
# 2. Créer la politique inline (ou managed)
aws iam put-role-policy
--role-name lambda-data-processor
--policy-name least-privilege-policy
--policy-document file://policy.json
# 3. Attacher la politique AWSLambdaBasicExecutionRole pour les logs CloudWatch
aws iam attach-role-policy
--role-name lambda-data-processor
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# 4. Vérifier les permissions effectives
aws iam simulate-principal-policy
--policy-source-arn arn:aws:iam::123456789012:role/lambda-data-processor
--action-names s3:GetObject s3:DeleteObject
--resource-arns arn:aws:s3:::mon-bucket-prod/data/fichier.csv
AWS Organizations et SCPs
Les Service Control Policies (SCPs) sont des garde-fous organisationnels : elles définissent le maximum de permissions qu'un compte peut avoir, indépendamment des politiques IAM internes. Même un administrateur d'un compte membre ne peut pas dépasser ce que la SCP autorise.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootAccountActions",
"Effect": "Deny",
"Principal": "*",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
},
{
"Sid": "DenyLeavingOrganization",
"Effect": "Deny",
"Action": "organizations:LeaveOrganization",
"Resource": "*"
},
{
"Sid": "DenyDisablingCloudTrail",
"Effect": "Deny",
"Action": [
"cloudtrail:StopLogging",
"cloudtrail:DeleteTrail",
"cloudtrail:UpdateTrail"
],
"Resource": "*"
},
{
"Sid": "RestrictRegions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": [
"eu-west-1",
"eu-west-3",
"us-east-1"
]
}
}
}
]
}
AWS IAM Access Analyzer
Access Analyzer détecte automatiquement les ressources accessibles depuis l'extérieur du compte ou de l'organisation. Activez-le dans chaque région et région globale :
# Activer Access Analyzer dans toutes les régions actives
for region in $(aws ec2 describe-regions --query 'Regions[].RegionName' --output text); do
aws accessanalyzer create-analyzer
--analyzer-name "org-analyzer-${region}"
--type ORGANIZATION
--region "$region" 2>/dev/null && echo "Créé : $region"
done
# Lister les findings (ressources publiques ou cross-account)
aws accessanalyzer list-findings
--analyzer-arn arn:aws:access-analyzer:eu-west-1:123456789012:analyzer/org-analyzer-eu-west-1
--filter '{"status": {"eq": ["ACTIVE"]}}'
GCP : Workload Identity et bindings conditionnels
Sur GCP, Workload Identity Federation remplace les clés de service (service account keys) pour les workloads externes. Le principe est identique à OIDC : le workload s'authentifie avec son token natif, GCP l'échange contre un token de service account temporaire.
# workload-identity-binding.yaml
# Permet à GitHub Actions de se faire passer pour un service account GCP
apiVersion: iam.googleapis.com/v1
kind: WorkloadIdentityPoolProvider
metadata:
name: github-provider
spec:
workloadIdentityPool: projects/123456/locations/global/workloadIdentityPools/github-pool
displayName: "GitHub Actions Provider"
oidc:
issuerUri: "https://token.actions.githubusercontent.com"
attributeMapping:
google.subject: "assertion.sub"
attribute.repository: "assertion.repository"
attribute.ref: "assertion.ref"
attributeCondition: >
attribute.repository == "mon-org/mon-repo" &&
attribute.ref == "refs/heads/main"
# Créer le pool et le provider
gcloud iam workload-identity-pools create "github-pool"
--project="mon-projet-gcp"
--location="global"
--display-name="GitHub Actions Pool"
gcloud iam workload-identity-pools providers create-oidc "github-provider"
--project="mon-projet-gcp"
--location="global"
--workload-identity-pool="github-pool"
--display-name="GitHub Actions Provider"
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"
--issuer-uri="https://token.actions.githubusercontent.com"
--attribute-condition="attribute.repository=='mon-org/mon-repo'"
# Lier le provider au service account (binding conditionnel)
gcloud iam service-accounts add-iam-policy-binding
"ci-deployer@mon-projet-gcp.iam.gserviceaccount.com"
--project="mon-projet-gcp"
--role="roles/iam.workloadIdentityUser"
--member="principalSet://iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/github-pool/attribute.repository/mon-org/mon-repo"
Azure : PIM et Conditional Access
Azure Privileged Identity Management (PIM) permet d'accorder des droits élevés de manière temporelle (just-in-time) plutôt que permanente. Les administrateurs activent leur rôle pour une durée limitée avec justification et validation optionnelle.
# Assigner un rôle éligible (pas permanent) via PIM
az role assignment create
--assignee "user@domain.com"
--role "Contributor"
--scope "/subscriptions/sub-id/resourceGroups/rg-prod"
--description "PIM eligible assignment - requires activation"
# Lister les assignations PIM actives
az rest
--method GET
--url "https://management.azure.com/subscriptions/sub-id/providers/Microsoft.Authorization/roleEligibilityScheduleInstances?api-version=2020-10-01"
# Conditional Access : bloquer l'accès hors MFA pour les admins
az ad conditional-access policy create
--name "Require MFA for admins"
--state "enabled"
--conditions '{
"users": {"includeRoles": ["62e90394-69f5-4237-9190-012177145e10"]},
"applications": {"includeApplications": ["All"]}
}'
--grant-controls '{
"operator": "OR",
"builtInControls": ["mfa"]
}'
Commentaires