prdlinage501.coolcorp.priv (Vault) et l'alias roger.coolcorp.priv (dashboard), CA racine ajoutée au magasin de confiance.hermes-roger-read et AppRole avec TTL et bound_cidrs limités à la VM.Dans la partie précédente, on a préparé la VM sous Rocky Linux 10 prdlinage501 : paquets, compte de service hermes, arborescence, SELinux, Podman rootless avec le mapping keep-id. On a également fait de premiers tests avec l'image conteneur d'Hermes. Sous proposition de l’IA, on a initié un dépôt Git pour versionner les configurations et sécuriser les éléments au fur et à mesure qu’on avance dans la réalisation.
Place maintenant aux deux briques qui tournent directement sur l'hôte : Vault, le coffre-fort qui stockera tous les secrets de Roger, et NGINX, le frontal HTTPS du dashboard d'Hermes.
Pour Vault, je reprends la logique de la partie 03 de la série OpenClaw, mais en corrigeant les points faibles que j'avais moi-même relevés : un accès AppRole limité à l'adresse de la VM, une durée de vie pour les identifiants, un journal d'audit, un vrai compte d'administration plutôt que le token root, et un port 8200 qui n'est plus ouvert à tout le LAN. N’hésitez pas à faire un tour sur l’ancien article sur OpenClaw pour en apprendre davantage sur Vault.
Côté NGINX, le changement est plus radical : il ne s'occupe plus de l'authentification, c'est Hermes qui s'en charge.
Avant tout cela, il nous faut des certificats et c'est par là que l'on commence.
Pourquoi ne pas se contenter de certificats auto-signés ? Parce qu'un certificat auto-signé oblige chaque client à désactiver la vérification ou à faire confiance à chaque certificat individuellement. Dans le premier cas, on perd toute protection contre l'interception. Dans le second, on multiplie les exceptions. Avec une PKI interne, il suffit de faire confiance une seule fois à l'autorité racine, sur chaque machine et dans chaque image, et tous les certificats qu'elle émet sont reconnus. Comme j'ai déjà une PKI Windows (AD CS) dans mon lab, autant s'en servir, comme j’ai toujours eu l’habitude de le faire.
Deux noms vont pointer vers la VM : son nom d'hôte, prdlinage501.coolcorp.priv, qui existe déjà dans mon DNS depuis la série OpenClaw, et le nom du dashboard de Roger, roger.coolcorp.priv. Pour ce dernier, je crée un alias (enregistrement de type CNAME) sur mon serveur DNS Active Directory, qui renvoie vers prdlinage501.coolcorp.priv. L'avantage : si l'adresse de la VM change un jour, il n'y aura qu'un seul enregistrement à modifier…un classique.
Cliquez sur l'image pour l'agrandir.
On vérifie depuis la VM :
dig +short prdlinage501.coolcorp.priv
dig +short roger.coolcorp.priv
La première commande renvoie l'adresse de la VM. La seconde affiche d'abord la cible de l'alias, puis la même adresse.
Cliquez sur l'image pour l'agrandir.
Tous les certificats de la série sont émis par ma PKI interne (AD CS). Pour que la VM leur fasse confiance, on commence par y installer le certificat de l'autorité racine.
Pas besoin d'aller le chercher sur le serveur de certification : je l'ai récupéré directement depuis l'un de mes sites qui exploite déjà un certificat émis par ma PKI. Le fichier se nomme CA-COOLCORP.crt et il est au format texte (PEM, encodé en Base64), donc aucune conversion n'est nécessaire. Je le dépose dans un dossier ~/pki de mon compte d'administration (bvivi57), par un simple glisser-déposer dans le navigateur de fichiers de MobaXterm (scp ou WinSCP font aussi bien l'affaire).
mkdir -p ~/pki && cd ~/pki
ls
cat CA-COOLCORP.crt
Le contenu doit commencer par -----BEGIN CERTIFICATE-----. Si vous obtenez des caractères illisibles, votre fichier est au format binaire (DER) : convertissez-le avec openssl x509 -inform der -in <fichier_in> -out <fichier_out>.crt.
Cliquez sur l'image pour l'agrandir.
On vérifie qu'il s'agit bien de l'autorité racine (le sujet et l'émetteur doivent être identiques), puis on l'ajoute au magasin de confiance de Rocky Linux :
openssl x509 -in CA-COOLCORP.crt -noout -subject -issuer -enddate
sudo cp CA-COOLCORP.crt /etc/pki/ca-trust/source/anchors/CA-COOLCORP.crt
sudo update-ca-trust
trust list | grep -i -A2 coolcorp
Cliquez sur l'image pour l'agrandir.
On en dépose aussi une copie pour les conteneurs du compte hermes. Elle servira au sidecar Vault Agent, aux tests et à la construction de l'image de Roger :
sudo install -o hermes -g hermes -m 644 ~/pki/CA-COOLCORP.crt /var/lib/hermes/vault/tls/ca.crt
sudo restorecon -v /var/lib/hermes/vault/tls/ca.crt
Cliquez sur l'image pour l'agrandir.
Si votre PKI comporte une autorité intermédiaire (ce qui normalement le cas en entreprise), il faudra faire de même avec son certificat et, plus loin, concaténer le certificat serveur et l'intermédiaire dans le fichier .crt utilisé par Vault et NGINX.
Il nous faut deux certificats serveur : un pour Vault (prdlinage501.coolcorp.priv) et un pour NGINX (roger.coolcorp.priv). Les navigateurs et les outils modernes ne regardent plus le CN, uniquement l'extension « Subject Alternative Name » (SAN). On prépare donc la demande avec un petit fichier de configuration OpenSSL qui inclut les SAN.
Pour Vault :
cd ~/pki
cat > prdlinage501.cnf <<'EOF'
[req]
default_bits = 4096
prompt = no
distinguished_name = dn
req_extensions = ext
[dn]
CN = prdlinage501.coolcorp.priv
O = COOLCORP
C = FR
[ext]
subjectAltName = DNS:prdlinage501.coolcorp.priv, DNS:prdlinage501, IP:192.168.10.41
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
EOF
openssl req -new -newkey rsa:4096 -nodes -config prdlinage501.cnf \
-keyout prdlinage501.key -out prdlinage501.csr
openssl req -in prdlinage501.csr -noout -text | grep -A1 "Subject Alternative Name"
Cliquez sur l'image pour l'agrandir.
Et pour le dashboard de Roger, on garde la même conf mais on remplace juste le nom associé au certificat (l’IA nous donne la petit commande sed qui va bien) :
sed -e 's/prdlinage501.coolcorp.priv/roger.coolcorp.priv/' \
-e 's/^subjectAltName = .*/subjectAltName = DNS:roger.coolcorp.priv/' \
prdlinage501.cnf > roger.cnf
openssl req -new -newkey rsa:4096 -nodes -config roger.cnf \
-keyout roger.key -out roger.csr
openssl req -in roger.csr -noout -text | grep -A1 "Subject Alternative Name"
chmod 600 ~/pki/*.key
Cliquez sur l'image pour l'agrandir.
On copie les deux fichiers .csr sur un poste Windows qui a accès à l'autorité (perso j’utilise le serveur de la CA elle-même, mais on évite dans la vrai vie), et on les soumet avec certreq en précisant le modèle de certificat. J'utilise mon modèle de serveur web habituel, TPL-SRV-WEB-DEFAULT, configuré pour accepter le nom fourni dans la demande.
C'est indispensable : si le modèle construit le sujet à partir d'Active Directory, les SAN de la demande sont ignorés.
Cliquez sur l'image pour l'agrandir.
certreq -submit -attrib "CertificateTemplate:TPL-SRV-WEB-DEFAULT" prdlinage501.csr prdlinage501.cer
certreq -submit -attrib "CertificateTemplate:TPL-SRV-WEB-DEFAULT" roger.csr roger.cer
certreq demande de choisir l'autorité, puis enregistre les certificats émis. Attention, l'attribut attend le nom du modèle, pas son nom complet affiché dans la console.
Cliquez sur l'image pour l'agrandir.
Je ne vais pas rentrer davantage dans le fonctionnement des certificats avec un écosystème Microsoft AD CS, ce n’est pas le but de l’article. Si vous avez d’autres mécanismes de PKI, vous pouvez tout aussi bien les utiliser, l’important reste d’avoir des certificats reconnu sur votre architecture.
De retour sur la VM, on vérifie les deux certificats. certreq produit en général du Base64 (PEM):
cd ~/pki
for c in prdlinage501 roger; do
openssl x509 -in $c.cer -out $c.crt
openssl x509 -in $c.crt -noout -subject -issuer -enddate -ext subjectAltName
openssl verify -CAfile CA-COOLCORP.crt $c.crt
done
Cliquez sur l'image pour l'agrandir.
On attend deux OK pour openssl verify.
Pour ceux qui découvrent la série, un petit rappel. Vault, édité par HashiCorp, est un coffre-fort à secrets. Plutôt que de laisser des mots de passe, des tokens et des clés d'API dans des fichiers de configuration, on les dépose dans Vault, qui les chiffre et ne les remet qu'à ceux qui ont le droit de les lire.
J'aime bien l'analogie du coffre de banque. La salle des coffres est fermée (Vault est « scellé ») tant que plusieurs détenteurs de clés ne sont pas venus l'ouvrir ensemble. Chaque client a son propre casier (un chemin dans le moteur KV(Key/Value)) et une carte d'accès qui ne donne accès qu'à celui-ci (une policy). Et le registre à l'entrée note chaque passage (le journal d'audit).
Pour Roger, on utilisera trois mécanismes :
role_id joue le rôle d'un identifiant, le secret_id celui d'un mot de passe, et les deux ensemble permettent d'obtenir un token temporaire.C'est le sidecar Vault Agent, que l'on démarrera dans la partie 06, qui utilisera cet AppRole. Roger lui-même ne parlera jamais directement à Vault.
Cliquez sur l'image pour l'agrandir.
Encore une fois n’hésitez pas à lire mon la partie 03 de mes articles sur OpenClaw ou j’explique davantage les principes derrières vault.
Vault s'installe depuis le dépôt officiel de HashiCorp. Je fige la version 2.2.1, la plus récente au moment de l'écriture (la série OpenClaw utilisait la 2.0.1) :
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo dnf install -y vault-2.2.1
vault version
Cliquez sur l'image pour l'agrandir.
Le paquet crée l'utilisateur vault, le service systemd et les dossiers /etc/vault.d et /opt/vault. Il génère aussi un certificat auto-signé (tls.crt et tls.key) dans /opt/vault/tls. On ne s'en servira pas : on dépose juste à côté le certificat émis par notre PKI.
On installe les fichiers TLS et on prépare le dossier du journal d'audit :
sudo install -o root -g vault -m 644 ~/pki/prdlinage501.crt /opt/vault/tls/vault.crt
sudo install -o root -g vault -m 640 ~/pki/prdlinage501.key /opt/vault/tls/vault.key
sudo mkdir -p /opt/vault/logs && sudo chown vault:vault /opt/vault/logs && sudo chmod 750 /opt/vault/logs
sudo ls -l /opt/vault/ /opt/vault/tls/
On doit retrouver vault.crt et vault.key dans /opt/vault/tls, ainsi que le dossier logs. Ne passez pas cette vérification : sans ces fichiers, Vault refusera de démarrer avec l'erreur error loading TLS cert: open /opt/vault/tls/vault.crt: no such file or directory.
Cliquez sur l'image pour l'agrandir.
On remplace le fichier de configuration par défaut. On passe sur une configuration à un seul node. Vault étant prévu pour s’exécuter en cluster via des mécanisme de résilience (protocole Raft), dans notre cas il faut partir sur un seul serveur, en écoute TLS sur le port 8200, avec l’interface web activée :
sudo tee /etc/vault.d/vault.hcl >/dev/null <<'EOF'
# /etc/vault.d/vault.hcl - Vault 2.2.1 mono-nœud (prdlinage501)
ui = true
cluster_name = "coolcorp-vault"
# Recommandé avec le stockage intégré ; la swap est désactivée sur la VM
disable_mlock = true
storage "raft" {
path = "/opt/vault/data"
node_id = "prdlinage501"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_cert_file = "/opt/vault/tls/vault.crt"
tls_key_file = "/opt/vault/tls/vault.key"
tls_min_version = "tls12"
}
api_addr = "https://prdlinage501.coolcorp.priv:8200"
cluster_addr = "https://prdlinage501.coolcorp.priv:8201"
EOF
sudo chown root:vault /etc/vault.d/vault.hcl && sudo chmod 640 /etc/vault.d/vault.hcl
Cliquez sur l'image pour l'agrandir.
Comme dans la série OpenClaw, on désactive la swap : avec disable_mlock, Vault ne peut plus empêcher le système d'écrire sa mémoire, et donc des secrets, sur le disque.
sudo swapoff -a
sudo sed -i '/\sswap\s/ s/^/#/' /etc/fstab
free -h | grep -i swap
Cliquez sur l'image pour l'agrandir.
Pour revenir sur la configuration à un seul node, en entreprise il est plutôt conseillé d’avoir plusieurs instance vault qui peuvent se secourir les unes les autres en cas d’incident. Attention néanmoins, cela implique un maintient en condition opérationnelle plus important, il y a des conditions à remplir pour que la résilience fonctionne correctement à commencer par un minimum de trois installations. C’est pourquoi, dans mon cas, je reste sur une seule instance.
Dans la série précédente avec OpenClaw, le port 8200 était ouvert à tout le LAN. Pourtant, ses seuls clients sont le sidecar Vault Agent, qui tourne sur la VM elle-même, et mon poste d'administration pour l'interface web. On restreint donc l'accès avec deux règles firewalld, en remplaçant <IP_POSTE_ADMIN> par l'adresse du poste ayant à accès à la GUI :
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.10.41/32" port port="8200" protocol="tcp" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="<IP_POSTE_ADMIN>/32" port port="8200" protocol="tcp" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules
Cliquez sur l'image pour l'agrandir.
Petite incertitude à signaler : l'adresse source sous laquelle Vault verra les requêtes des conteneurs rootless dépend du mode réseau de Podman. Je m'attends à ce qu'il s'agisse de l'adresse de la VM, mais on le vérifiera formellement dans la partie 06 grâce au journal d'audit. Si ce n'est pas le cas, on élargira la règle.
sudo systemctl enable --now vault
echo 'export VAULT_ADDR=https://prdlinage501.coolcorp.priv:8200' >> ~/.bashrc
source ~/.bashrc
vault status
Cliquez sur l'image pour l'agrandir.
On initialise Vault avec cinq clés de descellement, dont trois nécessaires pour l'ouvrir :
vault operator init -key-shares=5 -key-threshold=3
Cliquez sur l'image pour l'agrandir.
Pourquoi cinq clés, dont trois nécessaires ? Vault chiffre toutes ses données avec une clé maîtresse, qui n'est jamais stockée en clair. Cette clé est découpée en cinq morceaux selon l'algorithme de Shamir, et trois morceaux suffisent à la reconstituer. En entreprise, on confie chaque morceau à une personne différente : aucune personne seule ne peut ouvrir le coffre, et la perte d'une ou deux clés n'est pas fatale. Dans un homelab, je suis le seul détenteur.
On descelle ensuite Vault en saisissant trois des cinq clés, une par commande :
vault operator unseal
vault operator unseal
vault operator unseal
vault status | grep -E 'Sealed|Storage Type|HA Enabled'
On attend Sealed false et Storage Type raft.
Cliquez sur l'image pour l'agrandir.
Vault ne se descelle pas tout seul. À chaque redémarrage de la VM, il faudra refaire cette opération, faute de quoi Roger n'aura plus accès à ses secrets. Il existe des mécanismes de descellement automatique (« auto-unseal »), mais ils reposent sur un service externe : un KMS cloud, un HSM ou une seconde instance Vault. Pour un homelab, je reste sur le descellement manuel, et on mettra en place dans la partie 07 une alerte Telegram si Vault est scellé.
On se connecte temporairement avec le token root et on active le moteur de secrets KV en version 2, les méthodes d'authentification AppRole (pour les agents) et userpass (pour moi), ainsi que le journal d'audit :
vault login # saisir le token root
vault secrets enable -path=secret -version=2 kv
vault auth enable approle
vault auth enable userpass
vault audit enable file file_path=/opt/vault/logs/audit.log
vault secrets list && vault auth list && vault audit list
Cliquez sur l'image pour l'agrandir.
Le journal d'audit est une nouveauté par rapport à la série OpenClaw. Chaque requête faite à Vault y est consignée, avec l'identité et l'adresse source, les valeurs sensibles étant hachées. C'est lui qui nous dira qui a lu quoi, et quand.
Chaque ligne du fichier est un document JSON. On y trouve notamment le type d'événement (requête ou réponse), le chemin demandé, l'identité authentifiée (par exemple approle pour le sidecar de Roger) et l'adresse IP d'origine. Les valeurs des secrets n'apparaissent jamais en clair : Vault les remplace par une empreinte. On s'en servira dans la partie 06 pour vérifier l'adresse sous laquelle Vault voit les conteneurs, et dans la partie 07 pour l'audit.
Une précaution : ce journal grossit avec le temps. Sur un homelab, le volume reste modeste, mais pensez à prévoir une rotation avec logrotate si vous laissez tourner la plateforme plusieurs mois. Attention, si Vault ne peut plus écrire dans son unique journal d'audit, par exemple parce que le disque est plein, il refuse toutes les requêtes. C'est voulu : pas de trace, pas d'accès.
Dans la série précédente, je travaillais avec le token root du début à la fin. C'est pratique, mais c'est exactement ce qu'il ne faut pas faire. On crée donc une policy d'administration et un utilisateur vault bvivi57. Les policies sont versionnées dans le dépôt Git (cloné dans la partie 02) :
cd ~/roger.coolcorp.priv
cat > vault/policies/admin-coolcorp.hcl <<'EOF'
# Administration complète de Vault (compte humain uniquement)
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOF
vault policy write admin-coolcorp vault/policies/admin-coolcorp.hcl
Cliquez sur l'image pour l'agrandir.
set +o history
read -rsp "Mot de passe Vault pour bvivi57 : " VPASS && echo
vault write auth/userpass/users/bvivi57 password="$VPASS" policies="admin-coolcorp" token_ttl=8h token_max_ttl=24h
unset VPASS
set -o history
Cliquez sur l'image pour l'agrandir.
La commande set +o history évite que le mot de passe se retrouve dans l'historique du shell. On reprendra ce réflexe à chaque manipulation de secret.
On bascule sur ce nouveau compte, puis on révoque le token root :
read -rsp "Token root : " ROOT_TOKEN && echo
vault login -method=userpass username=bvivi57
vault token revoke "$ROOT_TOKEN"
unset ROOT_TOKEN
vault token lookup | grep -E 'display_name|policies'
Cliquez sur l'image pour l'agrandir.
Pas d'inquiétude : en cas de besoin, un nouveau token root peut être régénéré avec les clés de descellement (vault operator generate-root).
On arrive à la partie qui concerne directement Roger. Tous ses secrets vivront sous secret/hermes/roger/. Sa policy lui donne le droit de les lire, et rien d'autre :
cat > vault/policies/hermes-roger-read.hcl <<'EOF'
# Lecture seule sur la branche de Roger (toutes ses futures dépendances y vivent)
path "secret/data/hermes/roger/*" {
capabilities = ["read"]
}
path "secret/metadata/hermes/roger/*" {
capabilities = ["list", "read"]
}
# Renouvellement et consultation de son propre token par Vault Agent
path "auth/token/renew-self" {
capabilities = ["update"]
}
path "auth/token/lookup-self" {
capabilities = ["read"]
}
EOF
vault policy write hermes-roger-read vault/policies/hermes-roger-read.hcl
Cliquez sur l'image pour l'agrandir.
Puis le rôle AppRole, utilisé par le sidecar Vault Agent pour s'authentifier. C'est ici que se trouve l'essentiel du durcissement par rapport à OpenClaw :
vault write auth/approle/role/hermes-roger \
token_policies="hermes-roger-read" \
token_ttl=1h \
token_max_ttl=24h \
secret_id_ttl=8760h \
secret_id_num_uses=0 \
secret_id_bound_cidrs="192.168.10.41/32,127.0.0.1/32" \
token_bound_cidrs="192.168.10.41/32,127.0.0.1/32"
vault read auth/approle/role/hermes-roger
Quelques explications :
token_ttl et token_max_ttl : le token obtenu par l'agent vit une heure et ne peut pas être prolongé au-delà de 24 heures ; Vault Agent se réauthentifie automatiquement.secret_id_ttl=8760h : l'identifiant secret expire au bout d'un an, alors qu'il était éternel dans la série OpenClaw ; on verra son renouvellement dans la partie 07.secret_id_bound_cidrs et token_bound_cidrs : le secret_id et les tokens ne sont utilisables que depuis la VM. Volé, le couple role_id/secret_id ne servirait à rien depuis une autre machine.
Cliquez sur l'image pour l'agrandir.
Pour aller plus loin, Vault permet un niveau de protection supérieur : un secret_id à usage unique (secret_id_num_uses=1), transmis « emballé » (response wrapping) et déballé par l'agent au démarrage. Le secret n'existe alors en clair nulle part sur le disque, ou seulement quelques secondes. Je ne l'ai pas retenu ici : chaque redémarrage du sidecar demanderait de régénérer un secret, ce qui impose une automatisation supplémentaire que je trouve disproportionnée pour un homelab. Mais en entreprise, c'est une piste sérieuse.
Dernier point sur ces durées : elles ont un effet direct sur l'exploitation. Un token d'une heure, c'est un token qui ne vaut plus rien s'il est volé et non utilisé rapidement. Un secret_id d'un an, c'est un rendez-vous annuel à ne pas manquer, faute de quoi le sidecar ne pourra plus s'authentifier et Roger perdra ses secrets. On mettra en place un rappel dans la partie 07.
Le role_id n'est pas un secret en soi : c'est l'équivalent d'un nom d'utilisateur. On le dépose dès maintenant dans l'arborescence de hermes, en 600, puisque grâce à keep-id le conteneur le lira avec l'identité du compte hermes :
vault read -field=role_id auth/approle/role/hermes-roger/role-id | \
sudo install -o hermes -g hermes -m 600 /dev/stdin /var/lib/hermes/vault/roger-role-id
sudo restorecon -v /var/lib/hermes/vault/roger-role-id
sudo ls -lZ /var/lib/hermes/vault/
Cliquez sur l'image pour l'agrandir.
Le secret_id, lui, sera généré dans la partie 05, une fois tous les secrets de Roger enregistrés, ce qui permettra de tester la chaîne complète d'un coup.
L'interface de Vault est accessible depuis le poste d'administration sur https://prdlinage501.coolcorp.priv:8200/ui. On s'y connecte avec la méthode « Userpass », le compte bvivi57. Pour l'instant, le moteur secret/ est vide, ce qui est normal.
Cliquez sur l'image pour l'agrandir.
On passe au frontal. Le principe est le même que dans la série OpenClaw : NGINX termine le TLS sur roger.coolcorp.priv et transmet les requêtes au dashboard d'Hermes, qui écoutera uniquement sur 127.0.0.1:9119. La différence, c'est l'absence d'auth_basic : le dashboard d'Hermes impose sa propre authentification dès qu'on l'expose. Une double authentification n'apporterait qu'une double invite de connexion.
sudo dnf install -y nginx
sudo install -m 644 ~/pki/roger.crt /etc/pki/tls/certs/roger.coolcorp.priv.crt
sudo install -m 600 ~/pki/roger.key /etc/pki/tls/private/roger.coolcorp.priv.key
sudo restorecon -v /etc/pki/tls/certs/roger.coolcorp.priv.crt /etc/pki/tls/private/roger.coolcorp.priv.key
Cliquez sur l'image pour l'agrandir.
sudo tee /etc/nginx/conf.d/roger.conf >/dev/null <<'EOF'
# /etc/nginx/conf.d/roger.conf - TLS + FQDN devant le dashboard Hermes de Roger.
# L'authentification est celle du dashboard (pas d'auth_basic : éviter la double invite).
server {
listen 443 ssl;
http2 on;
server_name roger.coolcorp.priv;
ssl_certificate /etc/pki/tls/certs/roger.coolcorp.priv.crt;
ssl_certificate_key /etc/pki/tls/private/roger.coolcorp.priv.key;
ssl_protocols TLSv1.2 TLSv1.3;
# Restreindre au LAN d'administration
allow 192.168.10.0/24;
deny all;
location / {
proxy_pass http://127.0.0.1:9119;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
# Le chat intégré au dashboard utilise des WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
proxy_buffering off;
}
}
server {
listen 80;
server_name roger.coolcorp.priv;
return 301 https://$host$request_uri;
}
EOF
Cliquez sur l'image pour l'agrandir.
Quelques explications sur cette configuration :
allow 192.168.10.0/24 limite l'accès au dashboard à mon réseau local ; tout le reste reçoit une erreur 403 avant même d'atteindre Hermes.X-Forwarded-* et X-Real-IP transmettent à Hermes l'adresse réelle du navigateur et le fait que la connexion d'origine était chiffrée. Le dashboard en a besoin pour construire ses liens et sécuriser ses cookies.Upgrade et Connection permettent le passage des WebSockets, utilisés par le chat intégré au dashboard.proxy_read_timeout) évite que NGINX coupe une conversation pendant que le modèle réfléchit.Par défaut, SELinux interdit à NGINX d'ouvrir des connexions réseau vers un port arbitraire. On déclare le port 9119 comme port HTTP et on active le booléen correspondant :
sudo semanage port -a -t http_port_t -p tcp 9119
sudo setsebool -P httpd_can_network_connect 1
sudo semanage port -l | grep -w 9119
Cliquez sur l'image pour l'agrandir.
Si semanage port -a répond que le port est déjà défini, remplacez -a par -m.
On ouvre HTTP (pour la redirection) et HTTPS, on valide la configuration et on démarre :
sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload
sudo nginx -t
sudo systemctl enable --now nginx
Cliquez sur l'image pour l'agrandir.
Hermes ne tourne pas encore, donc on s'attend à une erreur 502. Mais c'est une bonne erreur : elle prouve que le TLS, le nom et le proxy fonctionnent.
curl -sI https://roger.coolcorp.priv | head -1
curl -sI http://roger.coolcorp.priv | grep -i -E '^HTTP|^location'
Cliquez sur l'image pour l'agrandir.
Depuis le navigateur du poste d'administration, la page https://roger.coolcorp.priv doit afficher le cadenas sans avertissement (si la CA racine est bien déployée sur votre poste), avec une page « 502 Bad Gateway ».
Cliquez sur l'image pour l'agrandir.
Pour ceux qui ont suivi la série précédente, voici le résumé des différences de cet article :
Aucune de ces améliorations n'est révolutionnaire prise isolément. Mises bout à bout, elles réduisent pourtant nettement la surface d'attaque. C'est souvent comme ça en sécurité : pas de solution miracle, mais une accumulation de petites précautions.
vault status indique Initialized true et Sealed false, et les clés de descellement sont rangées hors de la VM.secret/ (KV v2), les méthodes approle et userpass et le journal d'audit sont activés.hermes-roger-read et le rôle hermes-roger existent, avec les bound_cidrs./var/lib/hermes/vault/roger-role-id est en 600, propriétaire hermes, type SELinux container_file_t./var/lib/hermes/vault/tls/ca.crt.https://roger.coolcorp.priv répond 502 avec un certificat valide.
On termine en rapatriant les configurations dans le dépôt Git. Les policies sont déjà dans le dépôt ; le script récupère vault.hcl et roger.conf :
cd ~/roger.coolcorp.priv
sudo ./scripts/collect.sh
git status
git add -A && git commit -m "Partie 03 : Vault 2.2.1, policies et NGINX" && git push
Cliquez sur l'image pour l'agrandir.
Les fichiers du dossier ~/pki (clés privées comprises) restent sur la VM, hors du dépôt. Une fois les certificats installés, vous pouvez supprimer les clés privées de ce dossier (shred -u ~/pki/*.key), puisqu'elles ont été copiées à leur emplacement définitif.
Vault est en place, durci par rapport à la version de la série OpenClaw : AppRole lié à l'adresse de la VM, identifiants à durée de vie limitée, journal d'audit, compte d'administration nominatif et port 8200 filtré. NGINX attend le dashboard de Roger derrière un certificat de la PKI interne.
Il reste une limite assumée : le descellement manuel après chaque redémarrage. C'est le prix d'un Vault autonome sans service externe, et on en tiendra compte dans l'exploitation.
Dans le prochain article, on s'occupe des cerveaux de Roger : LM Studio sur le Mac, exposé proprement à la VM, et la clé GLM de Z.ai. Leurs premiers secrets viendront remplir notre coffre tout neuf. L’article arrive bientôt.