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.
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#
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ément | Choix retenu | Justification |
|---|---|---|
| Zones | 3 | Tolérance à la perte d'une zone |
| Sous-réseaux publics | 10.0.0.0/20 ×3 | Load balancers uniquement |
| Sous-réseaux privés | 10.0.48.0/20 ×3 | Nœuds de calcul, sans IP publique |
| NAT Gateway | 1 par zone en prod, 1 en dev | Compromis entre disponibilité et coût |
| Points de terminaison VPC | S3, ECR, STS | Trafic interne au réseau AWS, moins de coûts de NAT |
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#
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.
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.
cd envs/prod-eu-west-3 && terraform apply
cd envs/prod-eu-central-1 && terraform applyCoûts#
| Poste | Estimation 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.