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¶
- 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¶
- 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¶
- 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¶
- 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)¶
- 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)¶
- 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¶
- 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¶
- 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¶
- 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¶
- 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"
# ...
}
- Stocker credentials dans Vault :
Phase 11 : Access Logging¶
- Créer bucket de logs dédié
- Activer logging sur les 3 buckets
- 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)