Aller au contenu

PD-4 — Plan d'implémentation


📚 Navigation User Story | Document | | | ---------- | -- | | 📋 [Spécification](PD-4-specification.md) | | | 🛠️ **Plan d'implémentation** | *(ce document)* | | ✅ [Critères d'acceptation](PD-4-acceptability.md) | | | 📝 [Retour d'expérience](PD-4-rex.md) | | [← Retour à storage](../PD-198-epic.md) · [↑ Index User Story](index.md)

Objectif

Provisionner les buckets AWS S3 avec Object Lock (WORM) pour le stockage immuable des documents chiffrés, logs d'audit et backups.

Choix techniques retenus

  • Provider : AWS S3 (eu-west-3 Paris)
  • WORM : Object Lock mode COMPLIANCE (documents, audit) / GOVERNANCE (backups)
  • Versioning : Activé (requis pour Object Lock)
  • Chiffrement : SSE-KMS avec clé dédiée Paris

Architecture ciblée

terraform/
├── storage-aws-s3.tf           # Buckets AWS S3
├── storage-aws-policies.tf     # Bucket policies
├── storage-aws-lifecycle.tf    # Lifecycle rules
├── storage-aws-kms.tf          # Clé KMS dédiée
└── storage-aws-iam.tf          # Rôles IAM

Buckets créés (×3 par environnement) :
├── probatiovault-{env}-documents-cold  # Documents chiffrés (COMPLIANCE, 3-100 ans)
├── probatiovault-{env}-audit-logs      # Logs d'audit (COMPLIANCE, 50 ans)
└── probatiovault-{env}-backups         # Backups PostgreSQL (GOVERNANCE, 30j)

Découpage technique

Phase 1 : Clé KMS dédiée

  1. Créer clé KMS pour chiffrement SSE :
resource "aws_kms_key" "s3_paris" {
  description             = "ProbatioVault S3 encryption key (Paris)"
  deletion_window_in_days = 30
  enable_key_rotation     = true

  tags = {
    Environment = var.environment
    Purpose     = "s3-encryption"
  }
}

resource "aws_kms_alias" "s3_paris" {
  name          = "alias/probatiovault-s3-${var.environment}"
  target_key_id = aws_kms_key.s3_paris.key_id
}

Phase 2 : Bucket Documents

  1. Créer bucket avec Object Lock COMPLIANCE :
resource "aws_s3_bucket" "documents" {
  bucket              = "probatiovault-${var.environment}-documents-cold"
  object_lock_enabled = true

  tags = {
    Environment = var.environment
    Purpose     = "encrypted-documents"
    Compliance  = "WORM-COMPLIANCE"
  }
}

resource "aws_s3_bucket_object_lock_configuration" "documents" {
  bucket = aws_s3_bucket.documents.id

  rule {
    default_retention {
      mode  = "COMPLIANCE"
      years = 10  # Default, override per-object (3-100 ans)
    }
  }
}

Phase 3 : Bucket Audit

  1. Créer bucket audit avec rétention 50 ans :
resource "aws_s3_bucket" "audit" {
  bucket              = "probatiovault-${var.environment}-audit-logs"
  object_lock_enabled = true

  tags = {
    Environment = var.environment
    Purpose     = "audit-logs"
    Compliance  = "NF-Z42-013"
  }
}

resource "aws_s3_bucket_object_lock_configuration" "audit" {
  bucket = aws_s3_bucket.audit.id

  rule {
    default_retention {
      mode  = "COMPLIANCE"
      years = 50
    }
  }
}

Phase 4 : Bucket Backups

  1. Créer bucket backups avec GOVERNANCE 30j :
resource "aws_s3_bucket" "backups" {
  bucket              = "probatiovault-${var.environment}-backups"
  object_lock_enabled = true

  tags = {
    Environment = var.environment
    Purpose     = "database-backups"
  }
}

resource "aws_s3_bucket_object_lock_configuration" "backups" {
  bucket = aws_s3_bucket.backups.id

  rule {
    default_retention {
      mode = "GOVERNANCE"
      days = 30
    }
  }
}

Phase 5 : Versioning (×3)

  1. Activer versioning sur tous les buckets :
resource "aws_s3_bucket_versioning" "documents" {
  bucket = aws_s3_bucket.documents.id
  versioning_configuration { status = "Enabled" }
}

resource "aws_s3_bucket_versioning" "audit" {
  bucket = aws_s3_bucket.audit.id
  versioning_configuration { status = "Enabled" }
}

resource "aws_s3_bucket_versioning" "backups" {
  bucket = aws_s3_bucket.backups.id
  versioning_configuration { status = "Enabled" }
}

Phase 6 : Chiffrement SSE-KMS (×3)

  1. Configurer SSE-KMS avec clé dédiée :
resource "aws_s3_bucket_server_side_encryption_configuration" "all" {
  for_each = toset([
    aws_s3_bucket.documents.id,
    aws_s3_bucket.audit.id,
    aws_s3_bucket.backups.id
  ])

  bucket = each.value

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.s3_paris.arn
    }
    bucket_key_enabled = true
  }
}

Phase 7 : Bucket Policies

  1. Créer policies restrictives :
resource "aws_s3_bucket_policy" "documents" {
  bucket = aws_s3_bucket.documents.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid       = "DenyDeleteObject"
        Effect    = "Deny"
        Principal = "*"
        Action    = ["s3:DeleteObject", "s3:DeleteObjectVersion"]
        Resource  = "${aws_s3_bucket.documents.arn}/*"
      },
      {
        Sid       = "EnforceTLS"
        Effect    = "Deny"
        Principal = "*"
        Action    = "s3:*"
        Resource  = ["${aws_s3_bucket.documents.arn}", "${aws_s3_bucket.documents.arn}/*"]
        Condition = {
          Bool = { "aws:SecureTransport" = "false" }
        }
      }
    ]
  })
}

Phase 8 : Lifecycle Documents

  1. Transition vers Glacier Deep Archive après 90j :
resource "aws_s3_bucket_lifecycle_configuration" "documents" {
  bucket = aws_s3_bucket.documents.id

  rule {
    id     = "transition-to-glacier"
    status = "Enabled"

    transition {
      days          = 90
      storage_class = "DEEP_ARCHIVE"
    }
  }
}

Phase 9 : Lifecycle Backups

  1. Suppression automatique après 30j :
resource "aws_s3_bucket_lifecycle_configuration" "backups" {
  bucket = aws_s3_bucket.backups.id

  rule {
    id     = "expire-old-backups"
    status = "Enabled"

    expiration {
      days = 30
    }

    noncurrent_version_expiration {
      noncurrent_days = 7
    }
  }
}

Phase 10 : IAM Roles

  1. Créer rôles distincts :
# Rôle backend (put/get documents)
resource "aws_iam_role" "backend_s3" {
  name = "probatiovault-${var.environment}-backend-s3"
  # ...
}

# Rôle auditor (read-only audit logs)
resource "aws_iam_role" "auditor_s3" {
  name = "probatiovault-${var.environment}-auditor-s3"
  # ...
}
  1. Stocker credentials dans Vault :
vault kv put kv/storage/aws-s3 \
  access_key="..." \
  secret_key="..."

Phase 11 : Access Logging

  1. Créer bucket de logs dédié
  2. Activer logging sur les 3 buckets
  3. Rétention logs : 1 an

Points de vigilance

  • Object Lock COMPLIANCE : Irréversible, impossible de réduire la rétention
  • Coûts long terme : 50-100 ans de stockage = budget significatif
  • KMS Key Rotation : Activer la rotation automatique
  • Région Paris : Conformité RGPD et souveraineté
  • Tests en dev : Valider exhaustivement avant prod

Hors périmètre

  • Migration vers Glacier Deep Archive (→ PD-5)
  • Cross-Region Replication Frankfurt (→ PD-6)
  • OVH Cold Archive optionnel (→ PD-7)
  • Upload depuis backend (→ autre US)