Validation¶
Cette page est la recette de conformité qui suit l'installation. Elle ne remplace aucune vérification du Pas-à-pas : chaque étape y porte déjà la sienne, sur place, au moment où elle produit son effet. Ce que la recette ajoute, c'est une relecture globale de l'installation terminée, en une commande, par huit contrôles qui constatent des effets observables et non l'exécution d'une commande.
Chaque contrôle en échec désigne l'étape du pas-à-pas qui l'a produit. C'est la question utile
quand un KO apparaît : non pas « qu'est-ce qui est cassé maintenant », mais « laquelle des
étapes précédentes a échoué sans le dire ». Les renvois sont donnés contrôle par contrôle plus
bas.
La commande unique¶
Le script ne modifie rien, à une exception près : le contrôle 4 crée un pod temporaire dans le
namespace default, décrit avec ce contrôle. Il n'écrit aucun fichier et ne touche à aucun
manifeste.
| Sortie | Signification |
|---|---|
ok <message> sur la sortie standard |
le contrôle a constaté l'effet attendu |
KO <message> sur la sortie d'erreur |
le contrôle a constaté autre chose, ou n'a pas pu conclure |
-- <message> (saute) sur la sortie standard |
ce point n'a pas pu être exercé ; le KO qui précède en donne la cause |
VALIDATION : tous les controles passent., code de sortie 0 |
installation conforme au périmètre de la recette |
VALIDATION : N controle(s) en echec. sur la sortie d'erreur, code de sortie 1 |
au moins un contrôle a échoué |
Le script ne s'arrête pas au premier KO. Il déroule les huit contrôles, compte les échecs
et ne sort en 1 qu'à la fin. Une seule exécution donne donc la liste complète des défauts, pas
seulement le premier. Ne pas relancer la recette après chaque correction tant que la liste n'est
pas traitée en entier.
Sur une installation conforme, chaque contrôle porte au moins une ligne ok : une seule pour
chacun des contrôles 1 à 6, puis une ligne par host pour les contrôles 7 et 8. Ces deux
listes de hosts se dérivent des manifests livrés, elles ne sont écrites ni dans le script ni
dans cette page, et leur longueur suit donc les manifests sans que cette page la fige. Le
contrôle le plus rapide est de vérifier que chacun des huit titres numérotés est suivi d'au
moins une ligne : un contrôle qui n'affiche ni ok ni KO n'a pas tourné.
Une ligne -- n'apparaît jamais sur une installation conforme. Elle accompagne toujours un KO
qui en donne la cause et nomme un point que la recette n'a pas pu exercer, cas des hosts
internes quand le résolveur public est injoignable. Aucun point ne disparaît donc silencieusement
de la sortie.
Pour lister les huit contrôles et leurs commandes sans rien exécuter, avant même que le cluster existe :
La sortie reprend les valeurs déjà substituées depuis la fiche client, ce qui permet de vérifier d'un coup d'oeil que la recette interroge bien le domaine, la VIP et le realm du client :
1. noeuds prets
kubectl get nodes
2. certificats emis
kubectl get certificate -A
3. Traefik sur la VIP
kubectl get svc -n traefik-ingress
4. CoreDNS resout
kubectl run ... -- getent hosts hub.${TV_DOMAIN}
5. ExternalSecret synchronises
kubectl get externalsecret -A
6. issuer OIDC
curl https://auth.${TV_DOMAIN}/realms/${TV_KC_REALM}/.well-known/openid-configuration
7. hosts publics
curl -sSI -m 10 https://hub.${TV_DOMAIN}
8. hosts internes non publies
dig +short <host>.${TV_DOMAIN} @1.1.1.1
Avant de lancer la recette¶
La recette s'exécute depuis le poste de l'opérateur, pas depuis le cluster. Elle a donc besoin de ce poste autant que du cluster.
| Prérequis | Contrôles concernés | Ce qui se passe s'il manque |
|---|---|---|
kubectl dans le PATH, kubeconfig pointé sur le cluster du client |
1 à 5 | KO kubectl absent du PATH, ... sur chacun des cinq contrôles |
curl dans le PATH |
6 et 7 | KO curl absent du PATH, ... |
dig dans le PATH |
8 | KO dig absent du PATH, impossible de verifier le cloisonnement public/interne, suivi d'une ligne -- par host interne dérivé |
Le poste résout publiquement hub, portal et auth sous ${TV_DOMAIN} |
7 | les trois hosts remontent injoignables, alors que la plateforme peut être saine |
Le poste joint un résolveur DNS public (1.1.1.1, port 53 sortant) |
8 | KO resolveur public injoignable, ..., suivi d'une ligne -- par host interne dérivé : ils ne sont pas testés du tout |
Aucun contrôle n'est jamais sauté : un outil absent ou un réseau fermé produit un KO, pas un
avertissement. C'est délibéré, une recette qui saute silencieusement la moitié de ses contrôles
donnerait une conformité qu'elle n'a pas vérifiée. Les lignes -- du contrôle 8 ne font pas
exception : elles suivent le KO, elles ne le remplacent pas, et elles servent à nommer un par
un les hosts que ce KO a laissés non testés. La contrepartie est qu'un KO ne dit pas à lui
seul si le défaut est dans la plateforme ou dans le poste : lire le message, il distingue
toujours les deux.
Une fiche incomplète est refusée avant le premier contrôle
Le script dérive ses valeurs de la fiche client. Il vérifie d'abord que TV_DOMAIN,
TV_KC_REALM, TV_VIP, TV_TRAEFIK_CLUSTERIP et TV_NODE_COUNT y sont présentes et non
vides. Si l'une manque, il sort en 1 sur
ERREUR : fiche incomplete, variable(s) absente(s) ou vide(s) : <noms>, avant d'exécuter le
moindre contrôle et sans écrire de ligne VALIDATION :. Aucun contrôle ne tourne à moitié,
et le message donne d'un coup toutes les variables à compléter
(Paramètres). TV_NODE_COUNT est en plus refusée si elle n'est pas un
entier positif, sur ERREUR : TV_NODE_COUNT=<valeur> n'est pas un nombre de noeuds valide.
La vérification est la même en --dry-run.
La fiche est lue par le lecteur strict du guide, jamais exécutée. Une ligne qui n'est ni un
commentaire, ni une ligne vide, ni une affectation simple fait sortir le script en 1 avec le
numéro de la ligne fautive, avant tout contrôle.
Les huit contrôles¶
Ils sont numérotés ici comme dans le script et sortent dans cet ordre.
1. Noeuds prêts¶
| Vérifie | que chaque noeud du cluster porte la condition Ready=True, et que le cluster en compte autant que ${TV_NODE_COUNT} |
| Commande | kubectl get nodes en jsonpath, une ligne <nom>=<statut Ready> par noeud |
| Succès | aucune ligne ne diffère de =True et le compte vaut ${TV_NODE_COUNT}, message ok les <n> noeuds sont Ready |
| Échec | noeuds non Ready : <nom>=False nomme les noeuds fautifs ; <n> noeud(s) Ready, <attendu> attendus par la fiche (TV_NODE_COUNT) quand tous sont prêts mais que le compte ne tombe pas juste ; aucun noeud retourne, resultat inexploitable signifie que kubectl a répondu sans lister de noeud ; kubectl injoignable, l'etat des noeuds n'a pas pu etre verifie : <sortie> reprend l'erreur brute de kubectl |
Renvoi en cas d'échec : étape 1 du pas-à-pas, « Amorcer le cluster Talos ». Un noeud NotReady
juste après une installation pointe le plus souvent install.disk ou les extensions du profil
worker ; un noeud absent de la liste n'a jamais reçu sa configuration machine.
Le contrôle compte les noeuds, et le nombre attendu vient de la fiche, pas du script :
TV_NODE_COUNT (Paramètres). L'architecture de référence en pose
six, trois control-plane et trois workers, et c'est la valeur d'exemple de la fiche ; un client
qui dimensionne autrement écrit son propre nombre et le contrôle passe au vert sur son cluster à
lui. Un noeud de moins que ce nombre, tous Ready, produit un KO, et c'est l'effet recherché :
un noeud qui n'a jamais reçu sa configuration machine ne se voit d'aucune autre façon dans cette
recette.
2. Certificats émis¶
| Vérifie | qu'aucun Certificate du cluster n'est en attente ou en échec |
| Commande | kubectl get certificate -A en jsonpath, une ligne <namespace>/<nom>=<statut Ready> par certificat |
| Succès | aucune ligne ne diffère de =True, message ok tous les Certificate sont Ready |
| Échec | certificat(s) non Ready : <namespace>/<nom>=False ; aucun certificat retourne, resultat inexploitable ; kubectl injoignable, l'etat du certificat n'a pas pu etre verifie : <sortie> |
Le titre et le message parlent de tous les certificats parce que le contrôle porte sur tous les
Certificate de tous les namespaces, pas seulement sur le wildcard. Depuis le retrait du CA
interne le 2026-09-10, il n'en reste que deux, le wildcard et celui de trust-manager, mais la
portée du contrôle est volontairement large : un certificat ajouté demain sera couvert sans que
personne n'ait à y penser. Lire le nom que le message donne avant de conclure.
Renvoi en cas d'échec :
=Falsesur le wildcard : étape 9, « Émettre les certificats ». La cause est presque toujours en amont, à l'étape 8, « Matérialiser le jeton Cloudflare danscert-manager» (le Secretcloudflare-dns-tokenn'existe pas danscert-manager), ou à l'étape 6.4, « Écrire le secret d'amorçage » (le jeton n'a jamais été écrit dans Vault).kubectl describe certificatesur le certificat nommé détaille le challenge DNS-01 en échec.aucun certificat retourne: soitcerts/n'a jamais été appliqué, soit les CRD de cert-manager sont absentes, donc la couche de base de l'étape 3, « Poser la couche de base », n'a pas abouti.
3. Traefik sur la VIP¶
| Vérifie | que le service LoadBalancer du namespace traefik-ingress porte bien ${TV_VIP} comme EXTERNAL-IP |
| Commande | kubectl get svc -n traefik-ingress en jsonpath, une ligne <nom>=<EXTERNAL-IP> par service de type LoadBalancer |
| Succès | une des lignes porte exactement l'adresse de la fiche, message ok Traefik EXTERNAL-IP=<VIP> sur le service <nom> |
| Échec | aucun service LoadBalancer de traefik-ingress ne porte <VIP de la fiche>, trouve : <nom>=<adresse> ; aucune EXTERNAL-IP retournee pour Traefik, resultat inexploitable quand l'adresse est encore <pending> ; kubectl injoignable, le service Traefik n'a pas pu etre verifie : <sortie> |
Renvoi en cas d'échec :
aucune EXTERNAL-IP: étape 5, « Publier la VIP de service : kube-vip ». La VIP demandée sort de${TV_VIP_RANGE}, ou kube-vip n'a pas démarré.aucun service LoadBalancer ... ne porte <VIP>: kube-vip a bien attribué une adresse, mais pas celle-là, et le message donne celles qu'il a trouvées. Soit la fiche a changé après l'étape 2, « Appliquer la fiche client aux manifests », sans querender-config.shait été rejoué, soit une autre ressource occupait déjà la VIP. Comparer avec la valeurTV_VIPde la fiche (Paramètres) avant de toucher au cluster.
La commande lit chaque service LoadBalancer du namespace sur sa propre ligne, et le contrôle
compare ligne à ligne. Si le namespace en porte plusieurs, il conclut au succès dès qu'une ligne
correspond à la VIP, et nomme les autres dans le message pour que leur présence reste visible.
Sur une installation conforme, ce namespace n'a qu'un seul service LoadBalancer.
4. CoreDNS résout¶
| Vérifie | que depuis l'intérieur du cluster, hub.${TV_DOMAIN} se résout vers la ClusterIP de Traefik, et non vers l'adresse publique |
| Commande | kubectl run validate-install-dns -n default --rm -i --restart=Never --image=debian:stable-slim --quiet -- getent hosts hub.${TV_DOMAIN} |
| Succès | la première adresse renvoyée est exactement ${TV_TRAEFIK_CLUSTERIP}, message ok hub.${TV_DOMAIN} resout vers la ClusterIP Traefik |
| Échec | hub.${TV_DOMAIN} n'est resolu par aucune adresse depuis le cluster : getent sort en 2, CoreDNS ne connait pas ce nom, c'est le défaut que le contrôle existe pour attraper ; hub.${TV_DOMAIN} resout vers <adresse>, attendu <ClusterIP de la fiche> quand la résolution aboutit sur autre chose ; aucune reponse de getent, resultat inexploitable ; echec de kubectl run, la resolution CoreDNS n'a pas pu etre verifiee : <sortie> pour tout autre code non nul, un kubectl injoignable ou un pod qui n'a pas démarré, la sortie brute distinguant les deux |
C'est le seul contrôle qui écrit dans le cluster : il crée un pod nommé validate-install-dns
dans le namespace default, quel que soit le namespace courant du kubeconfig, puis le supprime.
Deux conséquences pratiques. Le cluster doit pouvoir tirer l'image debian:stable-slim, ce qui
suppose un accès sortant au registre public ou un miroir configuré. Et si une exécution est
interrompue avant la suppression, la suivante échoue sur un pod déjà existant : supprimer le
reliquat avec kubectl delete pod validate-install-dns -n default avant de relancer.
L'image est une image glibc, la même que celle prescrite à l'étape 10, « Le reste de la couche
réseau, ingress et DNS interne ». getent est
une commande de la libc : une image qui ne l'embarque pas ferait échouer le contrôle quelle que
soit la santé réelle de CoreDNS.
Renvoi en cas d'échec : étape 10 du pas-à-pas, « Le reste de la couche réseau, ingress
et DNS interne ». La règle CoreDNS n'a pas été appliquée, ne respecte pas le format answer
auto, ou a déjà été écrasée par Talos, cas explicitement documenté à cette étape. Une résolution
qui rend l'adresse publique au lieu de la ClusterIP est le symptôme le plus courant, et il ne se
voit d'aucune autre façon.
5. ExternalSecret synchronisés¶
| Vérifie | que chaque ExternalSecret du cluster a effectivement matérialisé son Secret depuis Vault |
| Commande | kubectl get externalsecret -A en jsonpath, une ligne <namespace>/<nom>=<raison de la condition Ready> |
| Succès | toutes les lignes valent SecretSynced, message ok tous les ExternalSecret sont SecretSynced |
| Échec | ExternalSecret(s) non synchronises : <namespace>/<nom>=SecretSyncedError ; aucun ExternalSecret retourne, resultat inexploitable ; kubectl injoignable, l'etat des ExternalSecret n'a pas pu etre verifie : <sortie> |
Le contrôle porte sur la raison de la condition, pas sur l'existence de la ressource : un
ExternalSecret créé mais jamais synchronisé est un KO, ce qui est bien l'effet recherché.
Renvoi en cas d'échec, du plus probable au moins probable :
aucun ExternalSecret retourne: External Secrets Operator n'est pas installé, ses CRD manquent. Étape 6.1, « External Secrets Operator ».- un ou deux
SecretSyncedErrorseulement, sur des noms précis : le chemin Vault correspondant est absent ou mal orthographié.kubectl describe externalsecret <nom> -n <namespace>nomme le chemin,vault kv get -mount=secrets prod/<service>confirme s'il existe. Étape 6.4, « Écrire le secret d'amorçage », pour le jeton Cloudflare ; étape 11, « Couche de données », pour les six endpoints de la couche de données et, par la question ouverte de cette même étape, pour la base de Keycloak. - tous les
ExternalSecretenSecretSyncedError: leClusterSecretStoren'est pas prêt, ou Vault est rescellé.kubectl get clustersecretstore vault-storedoit valoirREADY=True. Étape 7, « Fermer la boucle : leClusterSecretStore», et l'étape 6.2, « Initialiser et desceller Vault », si Vault a redémarré depuis (un Vault rescellé ne se signale nulle part ailleurs dans cette recette).
La matrice des chemins Vault et des Secrets qu'ils produisent est à la page Configuration.
6. Issuer OIDC¶
| Vérifie | que le document de découverte OIDC de Keycloak annonce exactement l'issuer attendu, https://auth.${TV_DOMAIN}/realms/${TV_KC_REALM} |
| Commande | curl -sS -m 10 https://auth.${TV_DOMAIN}/realms/${TV_KC_REALM}/.well-known/openid-configuration, puis extraction du champ issuer |
| Succès | le champ lu est identique à l'issuer dérivé de la fiche, message ok issuer=<url> |
| Échec | issuer=<url lue>, attendu <url dérivée> : Keycloak fige son issuer dans KC_HOSTNAME, valeur qui n'a pas ete rendue avec le domaine de la fiche ; champ issuer absent de la reponse, resultat inexploitable ; aucune reponse du document de decouverte, resultat inexploitable ; curl injoignable, l'issuer n'a pas pu etre verifie : <sortie> |
Renvoi en cas d'échec :
issuer=différent de l'attendu : Keycloak fige son issuer dansKC_HOSTNAME, et cette valeur ne porte pas le domaine dérivé de la fiche. Deux chemins y mènent : la recette tourne avec une fiche dont leTV_DOMAINn'est pas celui qui a été appliqué aux manifests, ou le déploiement Keycloak a été réappliqué depuis un manifeste non rendu, qui porte encore le domaine d'origine du dépôt. Étape 2 du pas-à-pas, « Appliquer la fiche client aux manifests », puis réappliquer Keycloak comme à l'étape 13, « Applications et exposition ».champ issuer absent: Keycloak répond, mais pas ce document. Le realm${TV_KC_REALM}n'a pas été créé, ou son nom diffère de la fiche. Étape 14, « Keycloak et son realm ».aucune reponseoucurl injoignable: le hostauthne répond pas du tout, ce qui est le même défaut que le contrôle 7 relèvera sur ce host. Traiter le contrôle 7 d'abord.
Un ok sur ce contrôle ne couvre que le chemin public
Le contrôle appelle https://auth.${TV_DOMAIN} depuis le poste, donc à travers Traefik. Un
ok dit que l'issuer annoncé sur ce chemin est celui dérivé de la fiche, rien de plus. Il
ne dit pas que le chemin interne, celui qu'empruntent les services .NET pour valider les
jetons, annonce la même valeur. Le défaut où les deux chemins annoncent deux issuers
différents passe donc ce contrôle au vert, et se voit ailleurs : IDX10205 dans les journaux
et 401 sur tous les appels d'API. Le seul test qui conclut compare les deux chemins, il est
décrit à l'entrée
4 du Troubleshooting.
7. Hosts publics¶
| Vérifie | que les trois hosts publics répondent en HTTPS depuis l'extérieur, avec un certificat valide |
| Commande | curl -sSI -m 10 sur https://hub.${TV_DOMAIN}, https://portal.${TV_DOMAIN} et https://auth.${TV_DOMAIN}, code HTTP et cible de redirection |
| Succès | code 200, ou redirection 301, 302, 307 ou 308 dont la cible reste sous ${TV_DOMAIN} et en https, sur les trois : ok <host> HTTP 200, ou ok <host> HTTP <code>, redirection vers <cible>, sous <domaine> |
| Échec | <host> HTTP <code>, redirection vers <cible>, hors de <domaine> quand la redirection sort du domaine ; <host> HTTP <code>, redirection vers <cible>, hote <hôte> sous <domaine> mais ecrit autrement : la comparaison exige <hôte attendu>, en minuscules et sans point final quand la cible est sous le domaine mais son hôte est écrit dans une autre casse ou avec un point final ; <host> HTTP <code>, redirection vers <cible>, sous <domaine> mais en <schéma> au lieu de https quand la cible reste sous le domaine mais retombe en clair ; <host> HTTP <code> sans cible de redirection, resultat inexploitable ; <host> HTTP <code> pour tout autre code ; <host> injoignable via curl : <message de curl> quand curl lui-même échoue (DNS, TLS ou délai de dix secondes dépassé) |
Ce contrôle s'exécute depuis le poste de l'opérateur et emprunte donc le chemin public complet : DNS public, tunnel Cloudflare, Traefik, certificat wildcard, application. Il ne distingue pas ces maillons entre eux.
Renvoi en cas d'échec :
injoignablesur les trois hosts à la fois : l'enregistrement DNS public ou le tunnel. Étape 13 du pas-à-pas, « Applications et exposition ». Vérifier d'abord que les podscloudflaredtournent et que l'UUID du tunnel a bien été reporté dans sa configuration.injoignablesur un seul host : l'enregistrement DNS de ce host, ou sa route de tunnel, manque. Même étape.- un code HTTP
502ou503: le chemin public fonctionne, c'est l'application derrière qui ne répond pas.kubectl get pods -n web -n internalpuis-n api -n authdistingue immédiatementImagePullBackOff(étape 12, « Images et secrets de registre ») deCrashLoopBackOff(étape 11, « Couche de données », et étape 13, « Applications et exposition » : secrets et endpoints de données). - un code
404surauthalors quehubetportalrépondent : Keycloak tourne mais sa route d'ingress ne le sert pas. - une redirection sous le domaine mais en
http: la cible vient de l'application ou de sa route, pas du chemin public lui-même. Étape 13 du pas-à-pas, « Applications et exposition ». hote <hôte> sous <domaine> mais ecrit autrement: la cible est bien sous${TV_DOMAIN}, mais son hôte n'est pas écrit comme la comparaison l'attend, casse ou point final. Le contrôle refuse délibérément de normaliser : cette comparaison exacte est ce qui distingue le domaine de la fiche d'un domaine qui l'imite, et l'élargir affaiblirait le seul garde-fou du contrôle. Faire écrire l'hôte en minuscules et sans point final par l'application ou par sa route. Étape 13 du pas-à-pas, « Applications et exposition ».
Le contrôle tranche lui-même les redirections
L'étape 10, « Le reste de la couche réseau, ingress et DNS interne », accepte 200, 302
ou 307 sur une route servie ; le contrôle
accepte de même 200, 301, 302, 307 et 308. Un host qui redirige légitimement, par
exemple vers un chemin de connexion, ne produit donc pas de KO, à condition que la cible
reste sous ${TV_DOMAIN} et en https. Le script extrait le schéma et l'hôte de l'en-tête
Location : sous le domaine et en https, c'est un ok qui nomme la cible ; hors du
domaine, c'est un KO de routage ; sous le domaine mais en http, c'est un KO de
rétrogradation de schéma, la ligne « Vérifie » promet trois hosts qui répondent en HTTPS et
un host public qui renvoie en clair ne tient pas cette promesse. Aucune ligne ok ne demande
donc de vérification supplémentaire, et compter les lignes ok reste un raccourci valable.
Le script porte en plus une branche cible sans hote, pour un en-tête Location qui ne
porterait pas d'hôte. C'est une garde défensive, pas un cas à attendre : curl résout les
cibles relatives en absolu avant de les exposer dans %{redirect_url}, donc cette branche ne
se déclenche pas. Inutile de la chercher devant un KO.
La requête est un HEAD (curl -sSI). Un service qui refuse la méthode HEAD répondrait
405 en étant sain ; aucun des trois hosts publics n'est dans ce cas sur l'instance de
référence, mais c'est la première chose à écarter devant un 405.
8. Hosts internes non publiés¶
| Vérifie | qu'aucun host interne ne se résout depuis un résolveur DNS public. La liste n'est pas écrite dans le script : elle se dérive des manifests livrés, les host: des Ingress moins les hostname: que route le tunnel |
| Commande | dig +short <host>.${TV_DOMAIN} @1.1.1.1, précédé d'une requête témoin sur ce même résolveur |
| Succès | aucune réponse pour aucun host interne, un message ok <host> non resolu publiquement par host dérivé |
| Échec | <host> resout publiquement en <adresse> pour chaque host exposé ; resolveur public injoignable, le cloisonnement public/interne n'a pas pu etre verifie si le témoin ne répond pas, suivi d'une ligne -- <host> non teste (saute) par host dérivé |
Les hosts contrôlés ne sont pas énumérés ici, et c'est délibéré : les nommer ferait une seconde
liste à tenir, qui se périmerait au premier Ingress ajouté. La liste est celle que le script
dérive à chaque exécution : les host: de tous les Ingress livrés, moins les hostname: que
route core/cloudflare/cloudflared-config.yaml, chaque premier label étant recomposé sous le
TV_DOMAIN de la fiche. Un Ingress ajouté à la livraison entre donc dans le contrôle sans qu'il
faille toucher au script ni à cette page. Pour lire la liste d'une livraison donnée, dérouler la
sortie du contrôle 8 : elle nomme un host par ligne, ok ou --.
Depuis l'abandon du TLD interne, ce contrôle est le seul garde-fou automatique du cloisonnement entre ce qui est public et ce qui ne l'est pas. Il n'est pas exhaustif pour autant, sa portée est celle de sa dérivation : un host publié autrement que par un Ingress, ou sous un autre domaine que celui de la fiche, n'est vu par aucun contrôle de cette recette. Le reste ne tient qu'à la discipline d'exploitation : ne publier que trois enregistrements DNS et n'ouvrir que les trois routes de tunnel correspondantes.
Renvoi en cas d'échec :
- un host qui se résout publiquement : un enregistrement DNS de trop a été publié, ou une route
de tunnel de trop a été ouverte. Étape 13 du pas-à-pas, encart « Trois hosts publics, pas un de
plus ». Retirer l'enregistrement dans la zone Cloudflare et la route dans la configuration du
tunnel, puis relancer la recette. Tant que ce
KOsubsiste, une interface d'exploitation (Vault, Grafana, Longhorn) est atteignable depuis internet. resolveur public injoignable: le poste de l'opérateur ne joint pas1.1.1.1, souvent parce que le réseau du client filtre le DNS sortant. Ce n'est pas un défaut de l'installation, mais aucun host interne n'est alors testé : le contrôle s'arrête sur le témoin et nomme les hosts un par un en--, pour qu'aucun ne disparaisse de la sortie. Rejouer la recette depuis un réseau qui joint un résolveur public avant de prononcer la conformité, sans quoi le seul garde-fou du cloisonnement n'a pas été exercé.digabsent duPATHproduit le même effet, et les mêmes lignes--.
Ce que la recette ne prouve pas¶
Huit contrôles verts signifient que la plateforme est installée conformément à ce que le guide décrit. Ils ne signifient pas qu'elle est prête à porter la production. Restent hors du périmètre de cette recette :
- La tenue en charge. Aucun contrôle n'envoie plus d'une requête par host. Les scénarios k6
versionnés dans
loadtest/sont le moyen prévu pour cela, et ils s'exécutent séparément. - Les parcours fonctionnels applicatifs. Un
HTTP 200surhubprouve qu'une page est servie, pas qu'une déclaration se crée, qu'un évènement circule sur le bus ou qu'un média s'affiche. Ces parcours se recettent avec le client, à partir des cas d'usage métier. - La restauration des sauvegardes. Ni les sauvegardes ni leur restauration ne sont exercées ici ; elles relèvent de la page Exploitation.
- La supervision. Aucun contrôle ne regarde la stack
monitoring, ni ses tableaux de bord, ni la collecte des journaux : voir Observabilité, en gardant à l'esprit que c'est la stackmonitoringqui compte, pas la stackobservabilityhéritée. - L'état des pods applicatifs pris un par un. Les sept APIs et les portails internes ne sont
atteints par aucun contrôle. Un service en
CrashLoopBackOffqui n'est pas sur le chemin des trois hosts publics passe la recette sans être vu. Compléter parkubectl get podssur les quatre zones avant de prononcer la conformité. - L'accès interne par VPN. Le contrôle 8 vérifie que les hosts internes ne sont pas publics, jamais qu'ils sont joignables par les personnes qui doivent y accéder. Le tester à la main depuis un poste raccordé au VPN.
- L'état du sceau de Vault. Un Vault rescellé après l'installation ne se voit ici
qu'indirectement, par le contrôle 5, et seulement si un
ExternalSecretresynchronise entre temps.
Tenir la page et le script alignés¶
Cette page décrit scripts/validate-install.sh contrôle par contrôle, avec ses messages exacts.
Les deux se modifient ensemble, dans le même commit : une page qui décrit un contrôle que le
script n'exécute plus est pire qu'une page absente, parce que l'opérateur la croit. Après toute
modification du script, comparer les deux avec :