Évaluation des Fuites d'Infrastructure
Évaluer si un ensemble d'infrastructure AWS (VPC + ressources associées) de HyperShift CI est sûr à supprimer. Chaque affirmation doit être soutenue par une requête AWS empirique — ne jamais supposer, toujours vérifier.
Entrée
L'utilisateur fournit l'un des éléments suivants :
- sortie de l'outil cleanleaked (un bloc d'ensemble infra)
- Un ID VPC (par ex.,
vpc-0abc123...) - Un infraID (par ex.,
00ab3695c5f73d4354b9ounode-pool-78vcg)
Extraire l'infraID et l'ID VPC de l'entrée. Si un seul est fourni, dériver l'autre :
- ID VPC →
aws ec2 describe-vpcs --vpc-ids <VPC> --query 'Vpcs[0].Tags'→ extraire infraID du tagkubernetes.io/cluster/<infraID>ou du tagName(supprimer le suffixe-vpc) - infraID →
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=<infraID>-vpc"→ récupérer l'ID VPC
Vérifications
Exécuter dans cet ordre. Pour chaque vérification, signaler PASS (signal sûr), FAIL (NE PAS supprimer), ou UNKNOWN (impossible à déterminer). Utiliser --region us-east-1 pour toutes les commandes.
1. Tags de protection
aws ec2 describe-vpcs --vpc-ids <VPC> --query 'Vpcs[0].Tags' --output json
- Vérifier
hypershift.openshift.io/do-not-delete=true→ si présent : FAIL - Vérifier
hypershift.openshift.io/ci-cluster→ si présent : FAIL (ceci est un cluster de gestion)
2. Nom VPC protégé
Depuis le tag Name : si c'est hypershift-ci-2-vpc, hypershift-ci-3-vpc, ou hypershift-ci-metrics-vpc → FAIL
3. Utilisateur protégé
Vérifier si l'infraID contient l'un de ces noms d'utilisateurs : aabdelre, agarcial, ahmed, alamela, alesross, bclement, brcox, celebdor, cewong, dario, dari2o, dmace, glipceanu, jiezhao, jparrill, mbhalodi, mbrown, meha, mgencur, mulham, mraee, rkshirsa, sdminonne, sjenning, tsegura, vismishr
Si correspondance → FAIL (cluster développeur, contacter le propriétaire)
4. Date d'expiration / Âge
Depuis les tags VPC, vérifier expirationDate :
- Si présent et pas encore expiré → FAIL
- Si présent et expiré → PASS
- Si absent → vérifier l'âge de la ressource à la place (le tag
expirationDaten'existe que sur les ressources créées au cours des ~2 dernières semaines)
Quand expirationDate est absent, déterminer l'âge à partir de la sous-ressource horodatée la plus ancienne :
aws ec2 describe-vpc-endpoints --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'VpcEndpoints[*].CreationTimestamp' --output text
aws ec2 describe-network-interfaces --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'NetworkInterfaces[*].Attachment.AttachTime' --output text
Prendre l'horodatage le plus ancien trouvé. Si la ressource est plus ancienne que 24 heures ET la vérification du motif CI (étape 5) est PASS → PASS. Si plus jeune que 24 heures → FAIL. Si aucun horodatage trouvé → UNKNOWN.
5. Correspondance au motif CI
L'infraID correspond-il à un motif de test CI connu ?
- ID Hex (20+ caractères hex minuscules, par ex.,
00ab3695c5f73d4354b9) → CI générique e2e → PASS - Test nommé :
create-cluster-*,node-pool-*,control-plane-upgrade-*,autoscaling-*,karpenter-*,karpenter-upgrade-control-plane-*,scale-from-zero-*,kms-verify-*,request-serving-*,private-*,proxy-*,spot-demo-*,ha-break-glass-creds-*,custom-config-*,ho-upgrade-*,multi-hop-upgrade-*→ PASS - Aucun de ce qui précède (par ex.,
hc1-*,clust-*,dev-*,test-dev-*) → UNKNOWN (pourrait être un cluster développeur)
6. Liveness OIDC S3
aws s3api head-object --bucket hypershift-ci-oidc --key "<infraID>/.well-known/openid-configuration" --region us-east-1
aws s3api head-object --bucket hypershift-ci-2-oidc --key "<infraID>/.well-known/openid-configuration" --region us-east-1
aws s3api head-object --bucket hypershift-ci-3-oidc --key "<infraID>/.well-known/openid-configuration" --region us-east-1
Si l'un retourne 200 → FAIL (cluster toujours actif). Si tous retournent 404/erreur → PASS.
7. Instances EC2
aws ec2 describe-instances --region us-east-1 \
--filters "Name=tag:kubernetes.io/cluster/<infraID>,Values=owned" \
"Name=instance-state-name,Values=pending,running,stopping,stopped" \
--query 'Reservations[*].Instances[*].[InstanceId,State.Name,Tags[?Key==`Name`].Value|[0]]' --output text
Si des instances retournées → FAIL. Si aucune → PASS.
8. Vérification red-hat-managed
aws ec2 describe-instances --region us-east-1 \
--filters "Name=vpc-id,Values=<VPC>" "Name=tag:red-hat-managed,Values=true" \
--query 'Reservations[*].Instances[*].InstanceId' --output text
Si des instances retournées → FAIL (infrastructure gérée ROSA). Si aucune → PASS.
9. Inventaire des sous-ressources (avec portée VPC)
Requêter chacune et signaler ID + Nom pour chaque ressource, pas seulement les comptages :
aws elbv2 describe-load-balancers --region us-east-1 --query "LoadBalancers[?VpcId=='<VPC>'].[LoadBalancerName,Type,Scheme,DNSName]" --output text
aws ec2 describe-vpc-endpoints --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'VpcEndpoints[*].[VpcEndpointId,VpcEndpointType,ServiceName,State]' --output text
aws ec2 describe-vpc-endpoint-service-configurations --region us-east-1 --output json | # filtrer par tag kubernetes.io/cluster/<infraID>
aws ec2 describe-nat-gateways --region us-east-1 --filter "Name=vpc-id,Values=<VPC>" --query 'NatGateways[*].[NatGatewayId,State,Tags[?Key==`Name`].Value|[0],NatGatewayAddresses[0].PublicIp]' --output text
aws ec2 describe-internet-gateways --region us-east-1 --filters "Name=attachment.vpc-id,Values=<VPC>" --query 'InternetGateways[*].[InternetGatewayId,Tags[?Key==`Name`].Value|[0]]' --output text
aws ec2 describe-subnets --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'Subnets[*].[SubnetId,CidrBlock,AvailabilityZone,Tags[?Key==`Name`].Value|[0]]' --output text
aws ec2 describe-security-groups --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'SecurityGroups[*].[GroupId,GroupName]' --output text
aws ec2 describe-network-interfaces --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'NetworkInterfaces[*].[NetworkInterfaceId,InterfaceType,Description]' --output text
aws ec2 describe-route-tables --region us-east-1 --filters "Name=vpc-id,Values=<VPC>" --query 'RouteTables[*].[RouteTableId,Associations[0].Main,Tags[?Key==`Name`].Value|[0]]' --output text
aws ec2 describe-addresses --region us-east-1 --filters "Name=domain,Values=vpc" --output text | # vérification croisée avec les EIP des passerelles NAT
Cette vérification est informationnelle — toujours PASS mais lister chaque ressource avec son ID et son nom.
10. Zones Route53
aws route53 list-hosted-zones --output text --query 'HostedZones[*].[Id,Name,Config.PrivateZone,ResourceRecordSetCount]'
Rechercher les zones correspondant à <infraID>.ci.hypershift.devcluster.openshift.com et <infraID>.hypershift.local. Pour chaque zone trouvée, lister ses enregistrements :
aws route53 list-resource-record-sets --hosted-zone-id <ZONE_ID> --query 'ResourceRecordSets[*].[Name,Type]' --output text
Signaler les IDs de zone, les noms, privé/public, et le compte des enregistrements. Informationnelle — toujours PASS.
11. Fournisseur OIDC IAM
aws iam list-open-id-connect-providers --output json
Rechercher les fournisseurs dont l'ARN contient l'infraID (motif : oidc-provider/hypershift-ci-*-oidc.s3.*.amazonaws.com/<infraID>). Signaler si trouvé — ceci est une ressource IAM orpheline qui devrait être nettoyée avec l'ensemble infra.
12. Rôles IAM (par préfixe infraID)
aws iam list-roles --query "Roles[?starts_with(RoleName, '<infraID>')].[RoleName,CreateDate]" --output text
Signaler tout rôle IAM dont le nom commence par l'infraID. Ce sont des rôles orphelins de type OIDC (cloud-controller, ebs-csi, ingress, etc.) qui appartiennent à cet ensemble infra.
Sortie
Présenter le rapport dans ce format :
## Évaluation : <infraID>
| # | Vérification | Résultat | Détail |
|---|-------|--------|--------|
| 1 | Tags de protection | PASS | Pas de tag do-not-delete ou ci-cluster |
| 2 | Nom VPC protégé | PASS | Le nom est "abcdef1234-vpc" |
| 3 | Utilisateur protégé | PASS | Pas de correspondance de nom d'utilisateur |
| 4 | Date d'expiration | PASS | Expiré 2026-07-03 (il y a 5 jours) |
| 5 | Correspondance au motif CI | PASS | ID Hex (e2e-générique) |
| 6 | Liveness OIDC S3 | PASS | Non trouvé dans aucun bucket |
| 7 | Instances EC2 | PASS | 0 instances |
| 8 | red-hat-managed | PASS | Aucune instance gérée |
| 9 | Sous-ressources | INFO | 1 IGW, 1 subnet, 1 RTB |
| 10 | Zones Route53 | INFO | 2 zones trouvées |
| 11 | Fournisseur OIDC IAM | INFO | 1 fournisseur orphelin trouvé |
| 12 | Rôles IAM | INFO | 0 rôles orphelins |
### Verdict : SÛR À SUPPRIMER
Cet ensemble infra n'a pas de tags de protection, aucune instance en cours d'exécution, aucun document OIDC,
et l'infraID correspond à un motif CI hex. Tous les contrôles de suppression réussissent.
Règles de verdict
Ces règles sont non négociables :
- Tout FAIL → verdict est NE PAS SUPPRIMER (expliquer quel contrôle a échoué et pourquoi)
- Tous les contrôles PASS et correspondance au motif CI → SÛR À SUPPRIMER
- Tous les contrôles PASS mais motif CI est UNKNOWN → INCERTAIN (pourrait être un cluster développeur)
- Si motif CI est PASS et âge/expiration est PASS (plus ancien que 24h ou expiré), les contrôles UNKNOWN restants ne bloquent pas → SÛR À SUPPRIMER (une ressource CI confirmée plus ancienne que 24h sans OIDC, sans instances, et sans tags de protection est en fuite)
- Si motif CI est UNKNOWN et N'IMPORTE QUEL contrôle est UNKNOWN → INCERTAIN — DÉCISION HUMAINE REQUISE