Terraform + AWS EKS : la combinaison de référence pour Kubernetes en production

Amazon EKS (Elastic Kubernetes Service) est la plateforme Kubernetes managée d’AWS, le plan de contrôle (API server, etcd) est géré par AWS, vous gérez uniquement les nodes workers. En 2026, EKS est la solution Kubernetes la plus déployée en entreprise selon le rapport CNCF Annual Survey, devant GKE et AKS.

Terraform, avec le provider AWS HashiCorp, permet de provisionner et gérer un cluster EKS complet en code versionné dans Git. L’avantage du Terraform sur les alternatives (eksctl, CDK, CloudFormation) est la portabilité et la richesse de l’écosystème : modules Terraform EKS de la communauté, intégration avec Terragrunt pour la gestion multicompte, et plan/apply qui montrent précisément ce qui va changer avant application.

Ce guide crée un cluster EKS production-ready : VPC dédié avec subnets publics et privés, node groups managés en auto-scaling, IAM Roles for Service Accounts (IRSA) pour les permissions pod-level, addon Karpenter pour l’autoscaling avancé, et intégration CloudWatch Logs + Prometheus.

Architecture réseau : VPC et subnets EKS

L’architecture réseau d’un cluster EKS production-ready suit des patterns établis. Le VPC dédié (jamais le VPC default AWS) avec des plages CIDR adaptées à votre croissance future. Les subnets sont divisés en trois tiers : publics (load balancers, NAT Gateways), privés (nodes EKS), et isolés (RDS, ElastiCache).

Les nodes EKS doivent être dans des subnets privés, ils ne doivent pas avoir d’adresses IP publiques directement accessibles depuis Internet. Le trafic entrant passe par des load balancers dans les subnets publics, le trafic sortant par des NAT Gateways. Cette topologie est la baseline de sécurité réseau AWS.

Pour le sizing des subnets, planifiez large : EKS assigne une IP par pod (via VPC CNI), et un nœud EC2 de type m5.xlarge peut accueillir jusqu’à 58 pods selon les limites d’ENI AWS. Un subnet /24 (254 IPs) peut s’avérer trop petit pour un cluster qui scale. Préférez des /21 ou /22 pour les subnets de nodes.

Node Groups et Karpenter : stratégie d’autoscaling

EKS propose deux approches pour les nodes workers. Les Managed Node Groups (MNG) sont des groupes de nodes managés par AWS avec mise à jour automatique et monitoring intégré. Karpenter est un autoscaler de nodes plus flexible : il analyse les pods en attente et provisionne le type d’instance exact (parmi des milliers de types EC2) qui répond le mieux aux besoins.

La combinaison recommandée en 2026 : un MNG avec des instances On-Demand pour les workloads critiques (base de ~3 nodes m5.large permanents), et Karpenter pour le scale-out qui peut utiliser des instances Spot (jusqu’à 90 % moins chères) pour les workloads tolérant des interruptions.

Configurez des nodeAffinity et tolerations pour diriger les workloads vers les bons types de nodes : workloads critiques → On-Demand, jobs batch → Spot, GPU workloads → instances g5 gérées par Karpenter. Cette stratégie peut réduire la facture EC2 de 40 à 60 % sur un cluster de taille significative.

IAM IRSA : permissions Kubernetes sans credentials dans les pods

IRSA (IAM Roles for Service Accounts) est le mécanisme qui permet à des pods Kubernetes d’assumer des rôles IAM AWS sans stocker de credentials dans des variables d’environnement ou des secrets Kubernetes. Le pod reçoit un token JWT signé par EKS, qu’il présente à AWS STS pour obtenir des credentials temporaires.

Sans IRSA, les patterns dangereux sont courants : credentials AWS hardcodés dans les Dockerfiles, accessKeyId/secretAccessKey dans des ConfigMaps Kubernetes, ou pire, des node IAM roles trop permissifs qui donnent à tous les pods sur un node les mêmes droits AWS. IRSA permet le principe du moindre privilège au niveau pod.

Configurez un rôle IAM par service applicatif qui a besoin d’accès AWS (S3, DynamoDB, SQS…). Le rôle est lié au ServiceAccount Kubernetes via une Trust Policy qui vérifie l’identité EKS. Le pod assume ce rôle et n’a accès qu’aux ressources AWS explicitement autorisées dans la policy du rôle.

Monitoring et observabilité EKS

Un cluster EKS production-ready nécessite trois couches de monitoring. Les logs du plan de contrôle (API server, controller manager, scheduler) doivent être activés et envoyés à CloudWatch Logs. Ces logs sont critiques pour déboguer les problèmes au niveau cluster (pods qui ne démarrent pas, erreurs d’admission controllers).

Les métriques des nodes et pods (CPU, mémoire, réseau, disque) sont collectées par Prometheus (via kube-prometheus-stack, le Helm chart de référence) et visualisées dans Grafana. Les dashboards Kubernetes par défaut de Grafana (ceux du community board, IDs 315 et 6417) donnent une vue immédiate de la santé du cluster.

L’alerting doit couvrir : pods en état CrashLoopBackOff pendant plus de 5 minutes, utilisation CPU/mémoire des nodes >85 %, pods en état Pending depuis plus de 10 minutes (indique un problème de scaling ou de ressources), et erreurs 5xx sur les services en production. Ces alertes doivent aller vers PagerDuty pour les heures ouvrées et déclencher un appel pour les incidents critiques hors horaires.

Gestion des coûts EKS : rightsizing et optimisation

Un cluster EKS peut rapidement devenir coûteux sans gestion active des ressources. La première source de gaspillage : les resource requests trop élevées. Si tous vos pods demandent 1 CPU et 2 Go de RAM mais n’en utilisent réellement que 0,2 CPU et 0,5 Go, vous payez 5 fois plus que nécessaire.

Utilisez Goldilocks (un outil open source basé sur Vertical Pod Autoscaler en mode recommendation) pour analyser l’utilisation réelle de vos pods et recommander des resource requests optimisés. En appliquant ces recommandations, les équipes économisent typiquement 30 à 50 % sur leur facture de compute EKS.

Activez les Savings Plans AWS (engagement de consommation 1 ou 3 ans) pour les instances On-Demand de votre cluster : une réduction de 30 à 40 % sur le prix à la demande. Combiné avec l’utilisation de Spot pour les workloads éligibles, le coût total du cluster peut être réduit de 50 à 60 % par rapport à une utilisation naïve On-Demand sans gestion des coûts.

# Terraform — Cluster AWS EKS production-ready (extrait)
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "eks-production-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
  private_subnets = ["10.0.1.0/22", "10.0.5.0/22", "10.0.9.0/22"]
  public_subnets  = ["10.0.100.0/24", "10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway   = true
  single_nat_gateway   = false  # HA: 1 NAT par AZ
  enable_dns_hostnames = true

  tags = {
    "kubernetes.io/cluster/eks-production" = "shared"
    Environment = "production"
  }
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = "1"
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = "eks-production"
  cluster_version = "1.29"

  cluster_endpoint_public_access  = false   # Accès API uniquement depuis VPC
  cluster_endpoint_private_access = true

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  # Activer les logs du plan de contrôle
  cluster_enabled_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]

  eks_managed_node_groups = {
    system = {
      instance_types = ["m5.large"]
      min_size       = 3
      max_size       = 6
      desired_size   = 3

      labels = { role = "system" }
      taints = [{ key = "CriticalAddonsOnly", value = "true", effect = "NO_SCHEDULE" }]
    }
  }

  # IRSA activé par défaut avec le provider OIDC
  enable_irsa = true
}

Gerer l’etat Terraform en equipe : backend distant et verrouillage

Le piege numero un d’un projet Terraform qui passe de une a plusieurs personnes est le fichier d’etat (state) local. Des que deux ingenieurs lancent un apply en meme temps sur un etat partage par e-mail ou par depot Git, la corruption est quasi certaine : l’infrastructure reelle et l’etat divergent, et le cluster EKS devient ingerable. La solution production-ready est un backend distant avec verrouillage : l’etat vit dans un bucket S3 chiffre, et une table de verrouillage empeche tout apply concurrent.

Cette mise en place est la toute premiere chose a faire avant d’ecrire la moindre ressource serieuse, pas un raffinement tardif. Elle conditionne la capacite de l’equipe a collaborer sans se marcher dessus et rend les operations reproductibles, y compris depuis un pipeline d’integration continue.

# backend.tf -- etat distant chiffre + verrouillage concurrent
terraform {
  backend "s3" {
    bucket         = "monorg-tfstate-prod"
    key            = "eks/cluster.tfstate"
    region         = "eu-west-3"
    encrypt        = true               # chiffrement au repos
    dynamodb_table = "tf-locks"         # verrou anti-apply concurrent
  }
}

Securiser le cluster des le provisioning : endpoint prive et secrets chiffres

La securite d’un cluster EKS ne se rajoute pas apres coup : elle se decide dans le code Terraform qui le cree. Deux reglages changent radicalement la surface d’attaque. D’abord, restreindre l’endpoint de l’API Kubernetes a un acces prive (ou a une liste d’IP de confiance) plutot que de l’exposer publiquement par defaut. Ensuite, activer le chiffrement des secrets Kubernetes via une cle KMS, pour qu’un acces en lecture a etcd ne livre pas les mots de passe en clair.

Ces decisions rejoignent les principes generaux d’un audit de securite selon l’ANSSI : reduire l’exposition et chiffrer les donnees sensibles. Combinees a des images de conteneurs durcies, elles forment une defense en profondeur coherente du build au runtime.

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  cluster_name    = "prod"
  cluster_version = "1.31"

  # API Kubernetes NON exposee a l'Internet public
  cluster_endpoint_public_access  = false
  cluster_endpoint_private_access = true

  # Chiffrement des secrets Kubernetes par KMS
  cluster_encryption_config = {
    provider_key_arn = aws_kms_key.eks.arn
    resources        = ["secrets"]
  }
}

Valider l’infrastructure avant production : tests et analyse statique

Un code Terraform qui s’applique sans erreur n’est pas pour autant un code sur : il peut creer un bucket public, un groupe de securite ouvert a 0.0.0.0/0 ou un cluster sans chiffrement. La parade est d’inserer une etape de validation automatique entre l’ecriture et le deploiement. Des outils comme tfsec ou Checkov analysent le code a la recherche de mauvaises configurations de securite connues, avant meme qu’une ressource ne soit creee.

Cette analyse statique transforme des incidents potentiels en avertissements corriges en quelques minutes. Couplee a terraform validate et a un format impose, elle constitue un filet de securite peu couteux qui evite les erreurs de configuration les plus courantes – et les plus cheres.

# Chaine de validation avant tout apply
terraform fmt -check        # style homogene
terraform validate          # coherence syntaxique et types

# Analyse statique de securite (mauvaises configs connues)
tfsec .                     # ou : checkov -d .
# -> echoue si un SG est ouvert au monde, si le chiffrement manque, etc.

Industrialiser le provisioning : plan controle en pipeline GitOps

Lancer terraform apply depuis un poste de developpeur est acceptable pour experimenter, dangereux en production : aucune trace, aucune revue, aucun garde-fou. La pratique mature consiste a faire transiter chaque changement d’infrastructure par une pull request. Le pipeline execute alors un terraform plan automatiquement, affiche le diff dans la PR pour relecture humaine, et n’applique qu’apres approbation et fusion sur la branche principale.

Cette discipline rejoint la logique du Platform Engineering : standardiser et securiser les operations sensibles derriere un chemin pave. L’infrastructure devient auditable, reversible et collaborative, exactement comme du code applicatif.

# .github/workflows/terraform.yml -- plan en PR, apply apres fusion
on:
  pull_request: { paths: ["infra/**"] }
  push:         { branches: [main], paths: ["infra/**"] }
jobs:
  terraform:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - run: terraform init
      - run: terraform plan -no-color    # diff visible dans la PR
        if: github.event_name == 'pull_request'
      - run: terraform apply -auto-approve
        if: github.ref == 'refs/heads/main'   # apply seulement apres fusion

Sources et références

WP Admin Lab
· Chef de la rédaction

La rédaction de WP Admin Lab réunit des praticiens WordPress, sécurité et développement web. Nous publions des guides testés en conditions réelles, vérifiés en production et régulièrement mis à jour, sans jargon inutile. Chaque procédure est relue avant publication.