triage-leaked-infra

Par openshift · hypershift

Évalue si un VPC AWS ou un ensemble d'infra de HyperShift CI peut être supprimé sans risque. À utiliser quand l'utilisateur colle une sortie cleanleaked et demande « puis-je supprimer ça ? », « est-ce sans risque de retirer ça ? », « triage cette infra », pose des questions sur un verdict LEAKED ou UNCERTAIN, fournit un VPC ID ou un infraID et veut savoir s'il est orphelin, ou dit « vérifie ce VPC ». À utiliser également quand l'utilisateur demande « dois-je supprimer ça ? » à propos de n'importe quelle ressource AWS dans le compte HyperShift CI.

npx skills add https://github.com/openshift/hypershift --skill triage-leaked-infra

É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., 00ab3695c5f73d4354b9 ou node-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 tag kubernetes.io/cluster/<infraID> ou du tag Name (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-vpcFAIL

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 expirationDate n'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 PASSPASS. 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 UNKNOWNINCERTAIN (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 UNKNOWNINCERTAIN — DÉCISION HUMAINE REQUISE

Skills similaires