ChatGPT a cassé mon serveur - mais il l'a réparé
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
#title: ""
|
||||||
|
attribution: "ChatGPT"
|
||||||
|
description: "Il ne faut pas brider des LLM, il faut les cadrer."
|
||||||
|
#prompt: ""
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
@@ -0,0 +1,213 @@
|
|||||||
|
---
|
||||||
|
comments_url: https://com.richard-dern.fr/post/550
|
||||||
|
cover: images/cover.png
|
||||||
|
date: '2026-04-01 18:05:51'
|
||||||
|
entreprises:
|
||||||
|
- OpenAI
|
||||||
|
tags:
|
||||||
|
- ChatGPT
|
||||||
|
- NixOS
|
||||||
|
- SOPS
|
||||||
|
title: ChatGPT a cassé mon serveur - mais il l'a réparé
|
||||||
|
weather:
|
||||||
|
humidity: 56.0
|
||||||
|
illuminance: 16328.4
|
||||||
|
precipitations: false
|
||||||
|
pressure: 1022.68936938298
|
||||||
|
source:
|
||||||
|
- influxdb
|
||||||
|
temperature: 8.88888888888889
|
||||||
|
wind_direction: 102.0
|
||||||
|
wind_speed: 5.632704
|
||||||
|
---
|
||||||
|
|
||||||
|
Suite à [un article](https://xieme-art.org/post/gerer-ses-secrets-avec-sops/) relayé par [le journal du hacker](https://www.journalduhacker.net/s/v5e4rj/g_rer_ses_secrets_avec_sops), j'ai décidé de passer à [SOPS](https://getsops.io) pour la [gestion des secrets](https://github.com/Mic92/sops-nix) dans ma configuration de [NixOS](https://nixos.org/).
|
||||||
|
|
||||||
|
En parallèle, j'ai confié à [ChatGPT](https://chat.openai.com/) [les clés de mon réseau](/interets/informatique/2026/03/04/free-ipv6-et-opnsense/) : je l'ai rendu capable d'administrer l'ensemble de mes serveurs.
|
||||||
|
C'est lui qui a procédé à la migration vers SOPS, et ça a été un succès total pendant plusieurs jours.
|
||||||
|
Jusqu'à aujourd'hui, que je redémarre mon serveur et qu'il ne réponde plus.
|
||||||
|
|
||||||
|
## (kernel) panique
|
||||||
|
|
||||||
|
Après avoir branché un écran et un clavier, je vois que le chargement de NixOS bute (avec un `kernel panic`) sur la création du fichier de secret déchiffré pour la clé d'API de MeiliSearch, en raison d'un utilisateur inconnu (`meilisearch`).
|
||||||
|
Logique : je (le module NixOS) n'ai pas créé d'utilisateur spécifique pour MeiliSearch.
|
||||||
|
|
||||||
|
Je me dis que ce n'est pas bien grave, il me suffit de redémarrer sur une génération antérieure de NixOS.
|
||||||
|
Après tout, le système est fait pour ça.
|
||||||
|
Sauf que, c'est plus compliqué que ça, et aucune génération ne pouvait plus booter.
|
||||||
|
|
||||||
|
Je redémarre la machine sur une clé d'installation de NixOS, pour au moins avoir un shell et accéder à mes fichiers sur le disque, au cas où tout espoir de reprise serait vaincu, puis j'en profite quand même pour voir ce que c'est que cette histoire d'utilisateur inconnu.
|
||||||
|
|
||||||
|
Je monte les disques pour que l'installateur y ait accès :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
mkdir /mnt/boot
|
||||||
|
mount /dev/disk/by-label/nixos /mnt
|
||||||
|
mount /dev/disk/by-label/boot /mnt/boot
|
||||||
|
```
|
||||||
|
|
||||||
|
Et j'inspecte ma configuration, stockée dans `/mnt/etc/nixos/`.
|
||||||
|
Je réalise alors que ChatGPT avait affecté ce fameux utilisateur `meilisearch` au fichier concerné :
|
||||||
|
|
||||||
|
```nix
|
||||||
|
secrets."services/meilisearch/master-key" = mkSecret {
|
||||||
|
path = "/etc/nixos/secrets/services/meilisearch/master-key";
|
||||||
|
owner = "meilisearch";
|
||||||
|
group = "meilisearch";
|
||||||
|
restartUnits = [ "meilisearch.service" ];
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
C'est parfaitement logique pour un outil prédictif : s'il y a un service `meilisearch`, l'administrateur a forcément créé un utilisateur `meilisearch`.
|
||||||
|
Principe de base de la sécurité informatique.
|
||||||
|
|
||||||
|
Mais le paquet fournit par NixOS ne crée pas automatiquement cet utilisateur, et en prime, ce fichier doit être lisible à un utilisateur particulier (que j'avais pourtant indiqué à ChatGPT dans mes instructions).
|
||||||
|
|
||||||
|
Je corrige la déclaration d'appartenance de ce fichier selon ma convenance, puis j'essaye de me `chroot` avec `nix-enter` afin d'appliquer ma configuration.
|
||||||
|
Et là, les ennuis ont réellement commencé.
|
||||||
|
|
||||||
|
## Shell en état de choc
|
||||||
|
|
||||||
|
```shell
|
||||||
|
[root@nixos:~]# nixos-enter --root /mnt setting up /etc
|
||||||
|
... setting up secrets...
|
||||||
|
/nix/store/r6wx09ss7v1775x67pypl5gqzwm71irg-sops-install-secrets-0.0.1/bin/sops-install-secrets: manifest is not valid: failed to lookup user 'meilisearch': user: unknown user meilisearch
|
||||||
|
Activation script snippet 'setupSecrets' failed (1) /nix/var/nix/profiles/system/activate: line 247: /run/current-system/sw/bin/mktemp: No such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
Le problème à ce stade, c'est que j'ai cramé mes tokens Codex jusqu'au 3 avril (on est le 1er).
|
||||||
|
Il n'y a que le chat en ligne qui peut m'aider, et il n'a pas accès à ma configuration (que je n'ai pas envie de lui envoyer compte tenu de sa complexité).
|
||||||
|
Néanmoins, il me suggère quand même de faire autrement, sans `chroot`, avec un simple `nixos-install --root /mnt`.
|
||||||
|
La commande échoue sur `error: path '/var/lib/sops-nix/recovery-keys.txt' does not exist`.
|
||||||
|
|
||||||
|
Le point important est le suivant : en Nix, un chemin écrit comme un vrai chemin Nix, par exemple `/var/lib/...`, est traité comme un objet `path` et il doit exister au moment de l’évaluation.
|
||||||
|
[La documentation Nix](https://nix.dev/manual/nix/2.18/language/builtins) indique bien qu’un chemin référencé doit exister, et que l’existence d’un chemin peut être testée à l’évaluation avec `builtins.pathExists`.
|
||||||
|
Donc, dans ma configuration, au lieu de faire :
|
||||||
|
|
||||||
|
```nix
|
||||||
|
sops.age.keyFile = /var/lib/sops-nix/recovery-keys.txt;
|
||||||
|
```
|
||||||
|
|
||||||
|
Je devais faire :
|
||||||
|
|
||||||
|
```nix
|
||||||
|
sops.age.keyFile = "/var/lib/sops-nix/recovery-keys.txt";
|
||||||
|
```
|
||||||
|
|
||||||
|
Notez les guillemets.
|
||||||
|
|
||||||
|
Après cette rapide correction, je relance l'installation :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
[root@nixos:~]# nixos-install --root /mnt
|
||||||
|
copying channel...
|
||||||
|
building the configuration in /mnt/etc/nixos/configuration.nix...
|
||||||
|
these 2 derivations will be built:
|
||||||
|
/nix/store/r4bgszxqmfikbsg9xv40a1p034gl597g-manifest.json.drv
|
||||||
|
/nix/store/rf2zl9lh7qiidifvckfr1c0kl633ss97-nixos-system-server-main-25.11.8023.4590696c8693.drv
|
||||||
|
building '/nix/store/r4bgszxqmfikbsg9xv40a1p034gl597g-manifest.json.drv'...
|
||||||
|
building '/nix/store/rf2zl9lh7qiidifvckfr1c0kl633ss97-nixos-system-server-main-25.11.8023.4590696c8693.drv'...
|
||||||
|
/nix/store/isdjvp7wwxwi1a7c8vp3l8hgrdh5yfny-nixos-system-server-main-25.11.8023.4590696c8693
|
||||||
|
installing the boot loader...
|
||||||
|
setting up /etc...
|
||||||
|
setting up secrets...
|
||||||
|
sops-install-secrets: Imported /etc/ssh/ssh_host_ed25519_key as age key with fingerprint age13kq73j2ka8y5tq7nl4cccajk9dftz45k2jl7v2ymuuu24n5frues58h2r5
|
||||||
|
/nix/var/nix/profiles/system/activate: line 230: /run/current-system/sw/bin/mktemp: No such file or directory
|
||||||
|
/nix/var/nix/profiles/system/sw/bin/bash: line 12: /run/current-system/bin/switch-to-configuration: No such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
ChatGPT me conseille alors de rebooter sans tenir compte de ces erreurs.
|
||||||
|
Je redémarre, mais je vois qu'il n'y a aucune entrée GRUB pour la nouvelle génération (logique : regardez la dernière ligne d'historique ci-dessus).
|
||||||
|
Malheureusement, nouveau `kernel panic`, cette fois sur l'absence de `mktemp`.
|
||||||
|
Nouveau redémarrage sur la clé et nouveau montage des disques, et en faisant `nixos-enter`, je commence à me dire qu'il ne sait pas où chercher ses exécutables.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
[root@nixos:~]# ls -l /mnt/nix/var/nix/profiles/system/bin
|
||||||
|
ls -l /mnt/nix/var/nix/profiles/system/sw/bin | grep bootctl
|
||||||
|
ls: cannot access '/mnt/nix/var/nix/profiles/system/bin': No such file or directory
|
||||||
|
ls: cannot access '/mnt/nix/var/nix/profiles/system/sw/bin': No such file or directory
|
||||||
|
```
|
||||||
|
|
||||||
|
On sait qu'un truc déconne bien quand même `ls` ne répond pas...
|
||||||
|
Pourtant, je vois que de nouvelles générations ont été produites :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
/run/current-system/sw/bin/ls -l /boot/loader/entries | /run/current-system/sw/bin/tail -n 10
|
||||||
|
```
|
||||||
|
|
||||||
|
Me montre bien un fichier `nixos-generation-481.conf`.
|
||||||
|
C'est donc à l'étape de la génération du bootloader que ça déconne.
|
||||||
|
|
||||||
|
## Laisser NixOS gérer les chemins de fichiers...
|
||||||
|
|
||||||
|
On a finalement déterminé la cause exacte de mon problème :
|
||||||
|
|
||||||
|
```nix
|
||||||
|
tmp=$(/run/current-system/sw/bin/mktemp)
|
||||||
|
trap 'rm -f "$tmp"' EXIT
|
||||||
|
|
||||||
|
/run/current-system/sw/bin/ssh-to-age -private-key -i "$agentSshKey" > "$tmp"
|
||||||
|
```
|
||||||
|
|
||||||
|
On ne devrait jamais déclarer un chemin vers un exécutable sans l'extrapoler depuis `pkgs`.
|
||||||
|
Il a suffi de corriger cela :
|
||||||
|
|
||||||
|
```nix
|
||||||
|
tmp=$(${pkgs.coreutils}/bin/mktemp -p /run sops-age-key.XXXXXXXXXX)
|
||||||
|
trap '${pkgs.coreutils}/bin/rm -f "$tmp"' EXIT
|
||||||
|
|
||||||
|
${pkgs.ssh-to-age}/bin/ssh-to-age -private-key -i "$agentSshKey" > "$tmp"
|
||||||
|
```
|
||||||
|
|
||||||
|
Nouveau `nixos-install`.
|
||||||
|
Les dernières étapes sont toujours problématiques, notamment la mise à jour de GRUB.
|
||||||
|
Mais au moins, je pouvais enfin accéder à mon `chroot`, en précisant à `nixos-enter` la génération 482 qui devait avoir réglé mes problèmes, afin de régénérer GRUB manuellement :
|
||||||
|
|
||||||
|
```shell
|
||||||
|
[root@nixos:~]# nixos-enter --root /mnt --system /nix/var/nix/profiles/system-482-link -- \
|
||||||
|
/nix/var/nix/profiles/system-482-link/sw/bin/bash --noprofile --norc
|
||||||
|
setting up /etc...
|
||||||
|
setting up secrets...
|
||||||
|
sops-install-secrets: Imported /etc/ssh/ssh_host_ed25519_key as age key with fingerprint age13kq73j2ka8y5tq7nl4cccajk9dftz45k2jl7v2ymuuu24n5frues58h2r5
|
||||||
|
/nix/var/nix/profiles/system-482-link/activate: line 230: /run/current-system/sw/bin/mktemp: No such file or directory
|
||||||
|
bash-5.3# /nix/var/nix/profiles/system-482-link/sw/bin/mkdir -p /run
|
||||||
|
/nix/var/nix/profiles/system-482-link/sw/bin/ln -sfn /nix/var/nix/profiles/system-482-link /run/current-system
|
||||||
|
export PATH=/run/current-system/sw/bin:/nix/var/nix/profiles/system-482-link/sw/bin:$PATH
|
||||||
|
NIXOS_INSTALL_BOOTLOADER=1 /run/current-system/bin/switch-to-configuration boot
|
||||||
|
Running in a chroot, enabling --graceful.
|
||||||
|
Copied "/nix/store/bigkpra9jw48fip69q4wndsf4kb3d2w9-systemd-258.3/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/systemd/systemd-bootx64.efi".
|
||||||
|
Copied "/nix/store/bigkpra9jw48fip69q4wndsf4kb3d2w9-systemd-258.3/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/BOOT/BOOTX64.EFI".
|
||||||
|
⚠️ Mount point '/boot' which backs the random seed file is world accessible, which is a security hole! ⚠️
|
||||||
|
⚠️ Random seed file '/boot/loader/random-seed' is world accessible, which is a security hole! ⚠️
|
||||||
|
Random seed file /boot/loader/random-seed successfully refreshed (32 bytes).
|
||||||
|
Created EFI boot entry "Linux Boot Manager".
|
||||||
|
bash-5.3# /run/current-system/sw/bin/ls -l /boot/loader/entries | /run/current-system/sw/bin/tail -n 10
|
||||||
|
total 16
|
||||||
|
-rwxr-xr-x 1 root root 473 Apr 1 15:25 nixos-generation-479.conf
|
||||||
|
-rwxr-xr-x 1 root root 473 Apr 1 15:25 nixos-generation-480.conf
|
||||||
|
-rwxr-xr-x 1 root root 473 Apr 1 15:25 nixos-generation-481.conf
|
||||||
|
-rwxr-xr-x 1 root root 473 Apr 1 15:25 nixos-generation-482.conf
|
||||||
|
bash-5.3#
|
||||||
|
```
|
||||||
|
|
||||||
|
Un dernier `nixos-install` et, cette fois, il va jusqu'au bout, sans le moindre message d'erreur.
|
||||||
|
J'ai redémarré, les entrées GRUB étaient mises à jour, et NixOS a démarré sans broncher.
|
||||||
|
Aucune perte à déplorer.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
Franchement, c'est flippant à mort quand on fait ce genre d'expérience pour la première fois.
|
||||||
|
J'en ai voulu à ChatGPT, à SOPS et à NixOS, et j'étais en train de me demander si je n'allais pas formater et réinstaller.
|
||||||
|
|
||||||
|
Le problème s'est révélé être double :
|
||||||
|
|
||||||
|
- ChatGPT a présumé de l'existence d'un utilisateur, parce qu'en théorie, installer un service devrait s'accompagner de la création d'un utilisateur dédié (tous les modules que j'utilise le font, à l'exception donc de MeiliSearch)
|
||||||
|
- ChatGPT n'a pas utilisé des chemins construits par NixOS (extrapolés par `pkgs`).
|
||||||
|
|
||||||
|
Je suis totalement responsable du second point étant donné que je ne le fais pas toujours.
|
||||||
|
Mais ChatGPT aurait pu prendre les devants et m'aider à les corriger, au lieu de se contenter de (mal) faire comme moi.
|
||||||
|
|
||||||
|
Mais maintenant, je sais quelles instructions supplémentaires je dois donner à ChatGPT pour éviter qu'il ne commette à nouveau ce genre d'erreur (ne jamais indiquer des chemins sans extrapoler `pkgs` quand c'est possible, par exemple).
|
||||||
|
Je n'ai pas moins confiance en ce que produit ChatGPT.
|
||||||
|
Je ne crois pas que l'on doit donner moins de privilèges aux LLM.
|
||||||
|
Je crois juste qu'ils ont besoin d'être cadrés, et je ne l'ai pas fait suffisamment.
|
||||||
Reference in New Issue
Block a user