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