Cloud & IaC

Cluster AWS EKS en Infrastructure as Code

Cluster Kubernetes managé déployé intégralement en Terraform, modulaire et réplicable sur plusieurs régions.

20 février 20263 min de lecture570 mots
TerraformAWSEKSKubernetesIAM

Fiche à compléter. Remplacez les valeurs entre crochets par celles de votre déploiement.

Objectif#

Déployer un cluster Kubernetes managé sur AWS sans aucune action manuelle dans la console. Tout est décrit en code, versionné, et rejouable à l'identique sur une autre région ou un autre compte.

Contrainte que je me suis fixée : passer d'un compte AWS vide à un cluster opérationnel par une seule commande terraform apply.

Découpage en modules#

text
terraform/
├── modules/
│   ├── network/       # VPC, sous-réseaux, NAT, tables de routage
│   ├── eks/           # plan de contrôle, groupes de nœuds, modules complémentaires
│   └── iam/           # rôles IRSA, politiques de moindre privilège
└── envs/
    ├── dev/
    └── prod/

Le découpage en modules sert un objectif précis : changer de région ne doit modifier qu'une variable, jamais la logique.

Réseau#

Un VPC réparti sur trois zones de disponibilité, avec séparation stricte entre sous-réseaux publics et privés.

ÉlémentChoix retenuJustification
Zones3Tolérance à la perte d'une zone
Sous-réseaux publics10.0.0.0/20 ×3Load balancers uniquement
Sous-réseaux privés10.0.48.0/20 ×3Nœuds de calcul, sans IP publique
NAT Gateway1 par zone en prod, 1 en devCompromis entre disponibilité et coût
Points de terminaison VPCS3, ECR, STSTrafic interne au réseau AWS, moins de coûts de NAT
hcl
module "network" {
  source             = "../../modules/network"
  cidr_block         = var.vpc_cidr
  availability_zones = slice(data.aws_availability_zones.available.names, 0, 3)
  single_nat_gateway = var.environment == "dev"
}

Plan de contrôle et groupes de nœuds#

hcl
module "eks" {
  source          = "../../modules/eks"
  cluster_name    = "${var.project}-${var.environment}"
  cluster_version = "1.31"

  # Le point de terminaison public reste filtré par IP.
  endpoint_public_access       = true
  endpoint_public_access_cidrs = var.admin_cidrs
  endpoint_private_access      = true

  node_groups = {
    general = {
      instance_types = ["t3.large"]
      min_size       = 2
      desired_size   = 3
      max_size       = 6
      capacity_type  = "ON_DEMAND"
    }
  }
}

Sécurité#

Moindre privilège avec IRSA#

Plutôt que d'attacher des permissions larges aux nœuds, chaque service account Kubernetes obtient son propre rôle IAM (IAM Roles for Service Accounts). Un pod compromis n'hérite ainsi que de ses propres droits, et non de ceux de tout le nœud.

Contrôles appliqués#

  • Nœuds dans des sous-réseaux privés, sans adresse IP publique.
  • Point de terminaison du serveur d'API restreint aux plages d'administration.
  • Chiffrement des secrets etcd via une clé KMS dédiée.
  • Journaux du plan de contrôle exportés vers CloudWatch (api, audit, authenticator).
  • RBAC Kubernetes aligné sur les groupes IAM, sans compte partagé.

Gestion de l'état Terraform#

L'état est stocké dans S3 avec versionnage et chiffrement, et verrouillé par une table DynamoDB pour empêcher deux apply concurrents.

hcl
terraform {
  backend "s3" {
    bucket         = "[nom-du-bucket]"
    key            = "eks/[env]/terraform.tfstate"
    region         = "eu-west-3"
    dynamodb_table = "[table-de-verrous]"
    encrypt        = true
  }
}

Déploiement multi-région#

Chaque région est un répertoire d'environnement avec sa propre clé d'état. Les modules sont identiques ; seules changent les variables.

bash
cd envs/prod-eu-west-3 && terraform apply
cd envs/prod-eu-central-1 && terraform apply

Coûts#

PosteEstimation mensuelle
Plan de contrôle EKS[à compléter]
Nœuds de calcul[à compléter]
NAT Gateway[à compléter]
Total[à compléter]

Ce que je retiens#

  • [À compléter] — par exemple : l'importance du verrouillage d'état dès le premier

    jour, ou le surcoût inattendu des NAT Gateway en multi-zone.