ADR 035 — Le NACL par défaut reste large en entrée, le FAIL CIS est accepté (2026-09-05)¶
Statut¶
Accepté, écrit le 2026-09-05. Issue #189 (action 14 de l'audit, diff CIS
5.2/5.3), Sprint 7 (Remédiation & Fiabilité).
Cette ADR tranche un arbitrage laissé ouvert par écrit le 2026-09-04, après le premier scan Prowler du compte. Elle ne change aucune ressource : elle acte une configuration existante et nomme ce qui la ferait revoir.
C'est la troisième voie que l'issue #199 avait nommée pour une autre question et qui vaut ici : accepter et documenter est une décision, pas une absence de décision.
Contexte¶
Ce que le NACL pose aujourd'hui¶
Un NACL (Network ACL) est le filtre réseau attaché au sous-réseau, en amont des groupes de sécurité qui, eux, sont attachés aux ressources.
terraform/modules/vpc/main.tf configure le NACL par défaut du VPC, en
entrée :
| # | Action | Protocole | Ports | Source |
|---|---|---|---|---|
| 100 | deny |
TCP | 22 | 0.0.0.0/0 |
| 110 | deny |
TCP | 3389 | 0.0.0.0/0 |
| 200 | allow |
tous | tous | 0.0.0.0/0 |
| 32767 | deny |
tous | tous | 0.0.0.0/0 (implicite) |
En sortie : 100 allow tout, puis le deny implicite.
Les règles sont évaluées par numéro croissant et la première qui correspond
gagne. Les deux deny étroits passent donc avant l'allow général : 22 et
3389 sont bien refusés depuis internet.
La règle 200 est large parce qu'un NACL est stateless : il n'a aucune mémoire des connexions. Le trafic de retour d'un appel sortant revient sur un port éphémère tiré au hasard, et doit être autorisé explicitement, sans quoi plus rien ne sort du VPC.
Ce que le scanner rapporte¶
Scan Prowler du 2026-09-04, VPC monté, région eu-west-3 :
| Check | fastapi-eks-default-nacl |
|---|---|
ec2_networkacl_allow_ingress_tcp_port_22 |
PASS |
ec2_networkacl_allow_ingress_tcp_port_3389 |
PASS |
ec2_networkacl_allow_ingress_any_port |
FAIL |
Le FAIL n'est pas un faux positif. ec2_networkacl_allow_ingress_any_port
ne demande pas « le port 22 est-il ouvert » mais « tous les ports sont-ils
ouverts ». La réponse est factuellement oui.
Les deux contrôles ne posent pas la même question, et un même objet peut être conforme à l'un et non conforme à l'autre sans contradiction. La configuration n'est pas fausse, elle est étroite : la défense en profondeur voulue par l'action 14 ne couvre que deux ports.
Où se trouvent réellement les ressources¶
C'est le fait qui manquait à l'arbitrage, et il change la conclusion.
Les nœuds EKS sont dans les subnets privés. terraform/modules/eks/main.tf
les place sur private_subnet_ids (lignes 135, 244, 292), et
create_nat_gateway vaut true par défaut.
internet
|
[ Internet Gateway ]
|
subnets PUBLICS 10.0.1.0/24 10.0.2.0/24
| NLB (80, 443) | NAT Gateway
| |
+-----------+-----------+
| (pas de route entrante)
subnets PRIVÉS 10.0.3.0/24 10.0.4.0/24
nœuds EKS, ENI du cluster, RDS
Un subnet privé n'a aucune route vers l'Internet Gateway. Un paquet non sollicité venu d'internet ne peut donc pas y arriver, quoi que dise le NACL. La règle 200 y est inatteignable depuis l'extérieur.
Restent les subnets publics. Ils portent exactement deux choses : le NLB d'Envoy Gateway, qui n'écoute que 80 et 443, et la NAT Gateway, qui n'écoute sur aucun port.
Ce que la parade fermerait vraiment¶
La parade cadrée remplace la règle 200 par quatre règles : 80, 443, les ports éphémères 1024-65535 pour le retour, et le trafic interne au VPC.
Après cette parade, 1024-65535 reste ouvert depuis 0.0.0.0/0, faute de
quoi le VPC se coupe du réseau. Le seul gain est donc la fermeture de 0-1023
sauf 80 et 443.
| Aujourd'hui | Après la parade | |
|---|---|---|
| Ports ouverts depuis internet | tous | 80, 443, 1024-65535 |
| Ce qui écoute sur les subnets publics | NLB sur 80/443 | inchangé |
| Réduction d'exposition | — | faible voire nulle |
| Risque | — | oublier une catégorie coupe le VPC |
Rien n'écoute sous 1024 sur ces subnets en dehors du NLB, déjà autorisé. RDS (5432) et kubelet (10250) sont au-dessus de 1024, donc la parade ne les couvrirait pas davantage, et ils vivent de toute façon dans les subnets privés.
Décision¶
Nous acceptons le FAIL de ec2_networkacl_allow_ingress_any_port sur le
NACL par défaut du VPC, parce que la restriction proposée n'apporte pas de
réduction d'exposition significative dans l'architecture actuelle, tout en
augmentant le risque de régression réseau.
Quatre points la précisent.
1. Le FAIL est connu et accepté, il n'est pas ignoré¶
La différence est tout le sujet. Un FAIL accepté est une ligne d'un scan qu'on
sait expliquer, rattachée à une décision datée. Un FAIL ignoré est une ligne
que personne n'a lue.
Tout scan CIS futur du compte fera ressortir ce contrôle. La réponse est cette ADR, pas une nouvelle enquête.
2. Le gain est jugé faible dans l'architecture actuelle, pas dans l'absolu¶
L'affirmation n'est pas « ce contrôle ne sert à rien ». Elle est : compte tenu de ce qui est déployé aujourd'hui dans les subnets publics, la réduction de surface serait faible voire nulle.
C'est une affirmation datée, qui dépend de faits vérifiables. Elle tombe si les faits changent, d'où le point 4.
3. Le contrôle réseau se lit sur trois niveaux, et le NACL n'est pas le principal¶
| Niveau | État | Ce qu'il assure |
|---|---|---|
| Groupes de sécurité des ressources | restrictifs | le contrôle fin, stateful, par ressource |
| Routage des subnets privés | pas de route entrante | l'inaccessibilité depuis internet |
| NACL, unique, sur tous les subnets | large en entrée, sauf 22 et 3389 | une barrière grossière, en défense en profondeur |
Il n'existe qu'un seul NACL. terraform/modules/vpc/main.tf l'associe aux
deux familles de subnets en un seul concat : les subnets privés portent donc
exactement le même NACL large que les publics. Ce qui les protège, c'est le
routage, pas une règle.
Ce point est écrit explicitement pour qu'aucune relecture ne suppose un NACL privé restrictif qui n'existe pas.
4. La décision est réévaluée si les flux publics changent¶
Elle repose sur un inventaire, donc elle doit être revue quand l'inventaire bouge. Quatre déclencheurs, à traiter comme une checklist de revue :
- une ressource exposée est ajoutée dans un subnet public ;
- un listener du NLB est ajouté ou modifié ;
- un service se met à écouter sur un autre port dans un subnet public ;
- la topologie réseau change, en particulier si des nœuds passent en public.
Dans ces cas, la parade de l'alternative B ci-dessous redevient candidate, et cette ADR doit être remplacée plutôt que citée.
Conséquences¶
Ce qui ne change pas. Aucune ressource n'est modifiée, aucun apply n'est
requis. Le NACL reste tel qu'il est déployé et vérifié le 2026-09-04.
Ce qui change. L'action 14 de l'audit est traitée : elle est livrée pour 22 et
3389, et son extension à any_port est explicitement écartée, avec sa
justification. La case NACL de #189 se ferme sur cette décision.
Ce qu'il faut accepter. Un scan CIS du compte continuera de sortir un FAIL
sur ce contrôle. C'est le prix assumé de ne pas faire de compliance theater :
transformer un FAIL en PASS sans réduire l'exposition réelle, en échange
d'une configuration plus longue et plus fragile.
Ce qui reste ouvert, hors périmètre. Le NACL du VPC par défaut de la région échoue sur les trois contrôles. Aucune ressource du projet n'y tourne, mais il vit dans le même compte et ressortira dans tout scan futur. À traiter dans une issue séparée.
Un contrôle qui n'existe que pendant une fenêtre d'infra montée n'existe pas. Le scan du 2026-09-04 a été joué à la main et n'aurait pas pu l'être après le teardown. L'absence de job CIS dans les configs CI est un manque distinct, également à traiter à part.
Alternatives écartées¶
A. Fermer any_port en énumérant les flux¶
Remplacer la règle 200 par 80, 443, 1024-65535 et le trafic interne au VPC.
Écartée pour la raison qui fait tout l'objet de cette ADR : elle laisse
1024-65535 ouvert de toute façon, donc ne ferme que 0-1023 hors 80 et 443, où
rien n'écoute. Elle achète un PASS au prix d'un risque de coupure réseau.
Oublier les ports éphémères est l'erreur classique du durcissement NACL : elle
ne se voit pas au plan, elle se voit quand plus rien ne sort du VPC.
B. Séparer le NACL public du NACL privé¶
Créer un second NACL, dédié aux subnets privés, autorisant le CIDR 10.0.0.0/16
et les ports éphémères, et refusant le reste.
Écartée pour l'instant, et nommée ici pour ne pas être réinventée. Trois raisons :
- le retour du trafic sortant traverse la NAT Gateway avec l'adresse publique
distante en source, donc le NACL privé devrait quand même ouvrir
1024-65535 depuis
0.0.0.0/0: le gain retombe au même niveau ; - le
FAILProwler resterait sur le NACL public, qui est celui que le contrôle regarde ; - elle ajoute une ressource à maintenir et une fenêtre d'association de subnets, là où le NACL par défaut n'en a aucune.
Elle redevient candidate si l'un des quatre déclencheurs du point 4 se produit.
C. Ne rien écrire et laisser le FAIL sans réponse¶
Écartée : c'est la seule option qui rendrait le constat invisible. Un FAIL
sans décision associée se represente à chaque scan et se re-instruit à chaque
fois.
Références¶
- Issue #189 — durcissement Terraform, flow logs, NACL, chiffrement EBS,
HTTPS sur le state (action 14, diff CIS
5.2/5.3) - ADR 031 — garde-fou de teardown : même forme de décision, un contrôle qu'on choisit de ne pas rendre bloquant, par écrit
terraform/modules/vpc/main.tf— la ressourceaws_default_network_acl.mainet son commentaire, qui pointe cette ADRdocs/infra-eks-summary.md, section « Durcissement Terraform » — les quatre réglages de l'action 14 tels que livrés par!341