# Transferer un secret entre deux machines sans jamais l'exposer Cas d'usage vecu (18/07/2026) : deplacer `HERMES_PERSO_OPENROUTER_KEY` du NAS (`hermes-platform/.env`) vers le VPS Contabo (`hermes-nabil/data/.env`), alors que **aucun canal direct NAS -> VPS n'existe** (SSH NAS->VPS non fonctionnel, Tailscale userspace sur Synology) et que le seul lien commun est l'agent (Claude), dont le contexte de conversation ne doit **jamais** contenir un secret en clair. ## Principe : chiffrement asymetrique, la cle privee ne bouge pas Seuls transitent par l'agent la **cle publique** (non sensible) et le **ciphertext** (opaque). Le secret n'apparait en clair a aucun moment dans la conversation, ni dans un log, ni dans un historique shell. La cle privee est **detruite immediatement apres usage** (secret de transit jetable). ## Procedure (RSA-3072 + OAEP-SHA256) ### 1. Machine destinataire — generer la paire, publier la cle publique ```bash umask 077; mkdir -p ~/.transit && cd ~/.transit openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out priv.pem openssl rsa -in priv.pem -pubout -out pub.pem chmod 600 priv.pem cat pub.pem # seule sortie affichee : non sensible ``` ### 2. Machine source — extraire sans afficher, chiffrer ```bash umask 077; mkdir -p /tmp/transit && cd /tmp/transit cat > pub.pem <<'PEM' PEM grep -m1 "^MA_VARIABLE=" /chemin/.env | cut -d= -f2- | tr -d '"'\''' | tr -d '\r\n' > secret.bin echo "longueur=$(wc -c < secret.bin)" # controle SANS afficher la valeur openssl pkeyutl -encrypt -pubin -inkey pub.pem \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \ -in secret.bin -out secret.enc shred -u secret.bin base64 -w0 secret.enc # ciphertext opaque, transitable ``` ### 3. Destinataire — dechiffrer, injecter, tout detruire ```bash cd ~/.transit base64 -d secret.b64 > secret.enc openssl pkeyutl -decrypt -inkey priv.pem \ -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \ -in secret.enc -out secret.bin echo "longueur=$(wc -c < secret.bin)" # doit egaler celle de la source ENV=~/projet/data/.env [ -n "$(tail -c1 $ENV)" ] && echo >> $ENV # garantir un saut de ligne final grep -v '^MA_VARIABLE=' $ENV > $ENV.tmp && mv $ENV.tmp $ENV # idempotence { printf 'MA_VARIABLE='; cat secret.bin; printf '\n'; } >> $ENV chmod 600 $ENV shred -u secret.bin secret.enc secret.b64 priv.pem pub.pem; rmdir ~/.transit ``` Puis cote source : `rm -rf /tmp/transit`. ## Regles - **Jamais** `echo $SECRET`, `cat .env`, ni un `grep` qui imprime la valeur. Controler par **longueur** (`wc -c`) et **prefixe booleen** (`head -c 6 f | grep -q '^sk-or-' && echo oui`). - Piege : `${#VAR}` sur le *nom* de variable renvoie la longueur du **nom**. Indirection obligatoire : `eval v=\${VAR}; echo ${#v}`. - RSA-3072 + OAEP-SHA256 : charge utile max ~318 octets — largement suffisant pour une cle API. Au-dela (fichier, keystore) : chiffrer le fichier en AES puis chiffrer la cle AES en RSA. - Cle privee **jetable et detruite** apres l'operation : meme si le ciphertext reste dans un historique, il devient indechiffrable (forward secrecy artisanale). - Ne dispense pas de la regle generale : un secret reellement expose en clair = **rotation immediate**.