Ai

Fondation cloud sécurisée avec Terraform et DevSecOps

Damien LarqueyDamien Larquey
October 7, 2025
5 min read
Fondation cloud sécurisée avec Terraform et DevSecOps

Pourquoi ce guide : en 90 à 120 minutes, obtenez une feuille de route et des artefacts Terraform pour établir une fondation cloud sécurisée et auditable chez Codolie. Difficulté : intermédiaire/avancé. Orientation : production, sécurité par défaut, observabilité et mesures (MTTD/MTTR).

Objectif

Déployer en IaC (Terraform) et vérifier en CI (OPA/Conftest) une infrastructure cloud couvrant : responsabilité partagée, gouvernance et inventaire, contrôle d’accès (RBAC, MFA, ZTNA), chiffrement (repos/transit, KMS cross-comptes), gestion des secrets, journalisation exhaustive, normalisation SIEM (ECS/CEF), plan IR et KPIs (MTTD/MTTR).

Prérequis

  • Accès org-level (AWS Orgs/Azure MG/GCP Folders) et compte “sécurité” dédié.
  • Terraform >= 1.6, opa/conftest, git, pipeline CI/CD (GH Actions/GitLab CI).
  • IdP SSO (Okta/Entra ID/Google Workspace) + MFA.
  • SIEM (Splunk/Elastic/Sentinel), bucket/logs immuable.
  • Vault ou Secret Manager cloud.
  • Domaine et idéalement ZTNA (Cloudflare/Zscaler) pour accès admin.

Mise en œuvre pas à pas

Étape 1 – Gouvernance et inventaire

Standardiser le tagging, imposer des policies org et automatiser l’inventaire.

  • Tags obligatoires : Owner, Environment, DataClass, CostCenter.
  • AWS SCP/Policy Azure/GCP org-policy pour refuser sans tags.
  • Inventaire automatique via AWS Config/Azure Resource Graph/GCP Asset Inventory vers compte sécurité.
{
  "Version":"2012-10-17","Statement":[{
    "Sid":"DenyIfMissingTags","Effect":"Deny","Action":"*","Resource":"*",
    "Condition":{"Null":{
      "aws:RequestTag/Owner":"true","aws:RequestTag/Environment":"true",
      "aws:RequestTag/DataClass":"true","aws:RequestTag/CostCenter":"true"
    }}
  }]
}
package terraform.s3
deny[msg] {
  r := input.resource_changes[_]
  r.type=="aws_s3_bucket" && r.change.after.acl in ["public-read","public-read-write"]
  msg := sprintf("S3 bucket %s ne doit pas être public", [r.change.after.bucket])
}

Étape 2 – Identité & accès (RBAC, MFA, Zero Trust)

SAML/OIDC vers IdP, MFA obligatoire, rôles éphémères, ZTNA pour consoles/APIs.

resource "aws_iam_role" "dev_readonly" {
  name = "DeveloperReadOnly"
  assume_role_policy = jsonencode({
    Version:"2012-10-17",Statement:[{
      Effect:"Allow",Principal:{Federated:"arn:aws:iam::123456789012:oidc-provider/idp"},
      Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{
        "idp:aud":"sts.amazonaws.com"
      }}
    }]
  })
}
resource "aws_iam_role_policy_attachment" "ro" {
  role       = aws_iam_role.dev_readonly.name
  policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"
}

Pro-tip : iam:MaxSessionDuration réduit la session, ajouter session policies (ex. aws:PrincipalTag/Environment).

Étape 3 – Backend Terraform

Centraliser l’état, verrouiller, chiffrer et lier versions providers/modules.

terraform {
  required_version = ">=1.6"
  required_providers {
    aws   = { source="hashicorp/aws", version="~>5.0" }
    vault = { source="hashicorp/vault", version="~>3.0" }
  }
  backend "s3" {
    bucket         = "codolie-terraform-state"
    key            = "env/terraform.tfstate"
    region         = "eu-west-1"
    encrypt        = true
    kms_key_id     = aws_kms_key.backend.arn
    dynamodb_table = "codolie-tfstate-lock"
  }
}

Étape 4 – Chiffrement & KMS cross-comptes

Séparer gestion clés/données, rotation, policies strictes avec accès inter-comptes explicites.

data "aws_iam_policy_document" "data_key_policy" {
  statement {
    sid       = "AllowUsageFromAppAccount"
    effect    = "Allow"
    principals{type="AWS" identifiers=["arn:aws:iam::111122223333:role/SecurityRole"]}
    actions   = ["kms:Decrypt","kms:Encrypt","kms:GenerateDataKey*"]
    resources = ["*"]
  }
  statement {
    sid       = "FullAdmin"
    effect    = "Allow"
    principals{type="AWS" identifiers=["arn:aws:iam::444455556666:root"]}
    actions   = ["kms:*"]
    resources = ["*"]
  }
}
resource "aws_kms_key" "data" {
  description         = "Clé data Codolie"
  enable_key_rotation = true
  policy              = data.aws_iam_policy_document.data_key_policy.json
}

Vérifiez toujours les kms:Decrypt pour chaque principal cross-account.

Étape 5 – Gestion des secrets & données sensibles

Jamais de plaintext en IaC : utiliser Vault/Secret Manager et marquer sensitive=true.

provider "vault" { address = "https://vault.codolie.local" }
resource "vault_generic_secret" "db_creds" {
  path = "database/creds/readonly"
}
resource "module" "app" {
  source   = "./modules/app"
  db_pass  = vault_generic_secret.db_creds.data["password"]
}
output "db_password" {
  value     = vault_generic_secret.db_creds.data["password"]
  sensitive = true
}

Étape 6 – Journalisation, normalisation & SIEM

Centraliser CloudTrail/Logs, valider, normaliser en ECS/CEF, gérer rétention vs coût.

  • AWS CloudTrail org-trail vers bucket chiffré, validation activée.
  • Azure Activity Logs/Log Analytics, GCP Cloud Audit + Pub/Sub.
  • Firehose/EventHub pour Splunk/Elastic/Sentinel avec mapping ECS (event.action, source.ip) ou CEF.
  • Rétention : logs critiques 90 jours hot, 365 jours cold (S3 IA/Glacier).
resource "aws_cloudtrail" "org" {
  name                      = "codolie-org-trail"
  is_organization_trail     = true
  s3_bucket_name            = aws_s3_bucket.logs.id
  kms_key_id                = aws_kms_key.data.arn
  include_global_service_events = true
  is_multi_region_trail     = true
  enable_log_file_validation = true
}
// KQL détection bruteforce Azure Sentinel
SecurityEvent
| where EventID==4625
| extend Reason=tostring(parse_json(AdditionalFields).FailureReason)
| where Reason contains "Bad password"
| summarize cnt=count() by Computer, bin(TimeGenerated,5m)
| where cnt>=5
// SPL Splunk
index=security EventCode=4625
| stats count by src_ip,user
| where count>10

Étape 7 – Préventif en CI/CD (Policy-as-Code)

name: security-checks
on: [pull_request]
jobs:
  tf_plan:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init && terraform plan -out=tfplan
      - run: terraform show -json tfplan > tfplan.json
      - uses: instrumenta/conftest-action@v0.3.0
        with:
          files: tfplan.json

Interdire IP publiques, disques non chiffrés, SG 0.0.0.0/0, etc.

Étape 8 – Réponse à incident & conformité

  • Runbooks versionnés (docs/ir/) : triage, containment, recovery, postmortem.
  • Tabletop trimestriel (clé exposée, bucket public, ransomware VM).
  • Contrôles continus : Prowler/ScoutSuite/Steampipe pour CIS/GDPR/HIPAA.
# Scan CIS AWS critique
prowler aws --compliance cis_aws --only-critical --output-dir=reports/

Vérification

  • Inventaire : 100 % des comptes avec logs et >95 % ressources taggées.
  • CI : PR créant S3 public => échec Conftest avec message clair.
  • IAM : connexion SSO/MFA, pas de clefs longues (>90 jours).
  • Chiffrement : objet créé vérifie SSE=aws:kms et KMS key ARN.
  • SIEM : alerte test root sans MFA, MTTD < 5 min, MTTR < 60 min.

Dépannage (pitfalls courants)

  • MFA/SSO partiel : forcer iam:RequireMFA ou Conditional Access.
  • SCP trop strict : exceptions ciblées pour services sans tag-on-create.
  • CloudTrail bloqué : vérifier BucketPolicy et KMS grants pour logs.delivery.
  • KMS inter-comptes : ajouter kms:Decrypt/Encrypt pour principals source.
  • SIEM overload : filtrer ingeste, retentions différenciées par criticité.
  • OPA faux positifs : ajuster règles sur tfplan réel, messages actionnables.

Prochaines étapes

  • Classification avancée (Macie, DLP sur DataClass).
  • Rotation dynamique des secrets, transition complète vers Vault/Secret Manager.
  • Durcissement réseau : egress control, VPC endpoints, inspection TLS, ZTNA étendu.
  • KPI mensuels : MTTD/MTTR, couverture chiffrement, MFA/RBAC, score CIS.
  • ROI : prioriser IAM, chiffrement, logs, SIEM, mesurer coûts évités.
  • Tests de sécurité dans CI/CD et validation continue en production.
Damien Larquey

Damien Larquey

Author at Codolie

Passionate about technology, innovation, and sharing knowledge with the developer community.

Back to Blog