Linux things 🐧

un blog sur les technologies des logiciels libres et autres digressions


Ubuntu 24 desktop : auto-installation

personnalisation et auto installation d'une Ubuntu 24 LTS desktop

Sat, 09 Nov 2024 11:30:30 +0200
# ubuntu   # linux  

Introduction

Pour des raisons pro je maintenais une ISO Linux Ubuntu 20 puis 22 personnalisées. La création d’une ISO basée sur Debian utilise historiquement des programmes, scripts et un fichier .seed comme dans cet example.seed. Les programmes pour la construction de l’image sont entre autre chroot, xorriso, squashfs, des scripts bash etc.

Or depuis Ubuntu 23 environ, la construction d’une ISO a complètement changé et l’ancienne méthode ne fonctionne plus. Ce n’est pas plus mal de la part de Canonical de vouloir simplifier la personnalisation de leur OS.
Tout passe maintenant par un fichier autoinstall.yaml dans lequel on décrira la configuration souhaitée : partitionnement, création d’utilisateur, programmes à préinstaller, etc.

Le bémol est que la documentation de Canonical à ce sujet est très basique et si l’on souhaite une préinstallation un peu plus complexe il y a peu d’infos. Voici la configuration que j’ai pu réaliser grâce à un blog et qui pourra certainement servir à des équipes qui souhaitent personnaliser et faciliter le déploiement d’Ubuntu au sein de leurs services.

Les besoins

Dans cet exemple les PC cibles possèdent un seul disque SSD, on souhaite le chiffrer et le partitionner en 3 (/ , /home, swap). Par défaut lorsqu’un disque est chiffré avec Luks, Linux demande au boot le mot de passe pour le déchiffrer. Ici on va utiliser la puce TPM2 pour stocker un mot un pass généré et auto unlock le disque. Cela a une certaine utilité car la clé est alors plus robuste que si l’utilisateur devait en saisir une plus simple à chaque boot.
Évidement si le PC est volé le disque sera lisible au démarrage mais le voleur devra se connecter au système en essayant de craquer le pass d’un des comptes.
L’autre besoin, non abordé ici, est de centraliser l’authentification des comptes vers par exemple un serveur LDAP ou un Active Directory. Les paquets sssd et sssd-tools realmd adcli krb5-user libnss-sss libpam-sss permettent de configurer cela.

autoinstall.yaml

autoinstall:
  version: 1
#  refresh-installer:
#    update: true
#    channel: latest/beta
  shutdown: reboot
  source:
    id: ubuntu-desktop  
  locale: "fr_FR.UTF-8"
  keyboard:
    layout: fr
    variant: ""
    toggle: null
  identity:
    hostname: ubuntu-desktop
    username: admin
    password: '$1$sPm6PHMJ$OXDdHEovAWKO5Gu16xDvE1'
  storage:
#    layout:
#      name: hybrid
#      encrypted: yes
#      sizing-policy: scaled
#      password: tmp
    config:
      - id: disk0
        name: disk0
        type: disk
        ptable: gpt
        preserve: true
        path: /dev/nvme0n1
        grub_device: false
        match:
          ssd: true
      - id: esp
        type: partition
        device: disk0
        size: 1G
        flag: boot
        number: 1
        wipe: superblock
        grub_device: true
      - id: esp-format
        type: format
        fstype: fat32
        volume: esp
      - id: boot
        type: partition
        device: disk0
        size: 5G
        number: 2
        # preserve: true
      - id: boot-format
        type: format
        fstype: ext4
        volume: boot

      - id: root
        type: partition
        device: disk0
        size: -1
        number: 3
        wipe: superblock

      - id: root-crypt
        type: dm_crypt
        dm_name: root-crypt
        volume: root
        key: tmp

      - id: vgroot
        type: lvm_volgroup
        name: vgroot
        devices: [root-crypt]

      - id: lvroot
        type: lvm_partition
        name: lvroot
        volgroup: vgroot
        wipe: superblock
        size: 100G

      - id: lvroot-format
        type: format
        fstype: ext4
        volume: lvroot


      - id: lvswap
        type: lvm_partition
        name: lvswap
        volgroup: vgroot
        wipe: superblock
        size: 20G

      - id: lvswap-format
        type: format
        fstype: swap
        volume: lvswap


      - id: lvdata
        type: lvm_partition
        name: lvdata
        volgroup: vgroot
        wipe: superblock
        size: -1

      - id: lvdata-format
        type: format
        fstype: ext4
        volume: lvdata

      - id: boot-mount
        type: mount
        device: boot-format
        path: /boot
      - id: esp-mount
        type: mount
        device: esp-format
        path: /boot/efi

      - id: root-mount
        type: mount
        device: lvroot-format
        path: /
      - id: data-mount
        type: mount
        device: lvdata-format
        path: /home
  drivers:
    install: true                       
  snaps:
    - name: teams-for-linux
      classic: false
    - name: localsend
      classic: false
  packages:
    - vim
    - adcli
    - cifs-utils
    - clevis
    - clevis-tpm2
    - clevis-luks
    - clevis-initramfs
    - initramfs-tools
    - tss2
    - openssh-server
    - openssl
    - git
    - krb5-user
    - libnss-sss
    - libpam-sss
    - live-tools
    - oddjob
    - oddjob-mkhomedir
    - pwgen
    - realmd
    - samba
    - samba-common
    - samba-common-bin
    - sssd
    - sssd-tools
    - ntp
    - whois
    - python3-pip
    - python3-apt
    - evolution
    - evolution-ews
    - gnome-shell-extensions
    - powertop
    - htop
    - emacs
    - libfuse2
    - libnss3-tools
    - ncdu
    - qtcreator
    - curl
    - cryptsetup
  late-commands:
    - curtin in-target --target=/target -- curl https://codeberg.org/fredix/netboot/raw/branch/main/cryptsetup.sh -o /root/cryptsetup.sh
    - curtin in-target --target=/target -- /bin/bash /root/cryptsetup.sh
  user-data:
    timezone: Europe/Paris
    runcmd:
      - git clone https://codeberg.org/fredix/netboot.git /home/admin/netboot
      - chown -R admin:admin /home/admin/netboot

Tout d’abord on créé un compte admin qui sera en théorie le seul compte à authentification locale qui permettra d’administrer le PC à distance. Le mot de pass est chiffré avec openssl

echo "adminpass" > localpass
openssl passwd -in localpass
$1$sPm6PHMJ$OXDdHEovAWKO5Gu16xDvE1

J’ai laissé la section layout comme exemple en commentaire. En effet la documentation de Canonical propose cette section si l’on souhaite chiffrer le disque et stocker le mot de pass dans la TPM2. Or c’est une fausse piste car il n’est plus possible ensuite de définir des partitions personnalisées. Si la section layout est définie alors la section config ne sera pas lu par l’installateur.
La section config décrit le disque à chiffrer et les partitions à créer. Ici le disque est positionné en dur vers /dev/nvme0n1 c’est éventuellement à changer mais il est possible que path soit facultatif. Ensuite on créé les partitions pour l’EFI et boot (esp, boot) et la dernière root qui prend tout le reste du disque et qui est chiffré avec un mot de passe temporaire tmp.
Dans cette partition chiffrée on créé des volumes LVM dans lesquels il y aura les partitions / , /home , swap , les 2 premières sont formatées en ext4. La swap est encore utile si l’utilisateur souhaite passer son PC en hibernation. J’ai mis pour l’exemple 100Go pour la partition / et tout le reste pour /home, c’est à adapter en fonction de votre matériel et vos besoins.

On installe ensuite des paquets snap et deb en fonction des besoins utlisateurs. Attention les paquets clevis et cryptsetup sont obligatoire car il vont permettre d’auto unlock le disque chiffré et de générer une nouvelle clé Luks.

Pour cela on demande à l’auto installateur de récupérer le script cryptsetup.sh et de l’exécuter.

cryptsetup.sh

#!/bin/bash

echo -n "tmp" > /root/tmpkey
chmod 400 /root/tmpkey

clevis luks bind -f -k /root/tmpkey -d /dev/nvme0n1p3 tpm2 '{}'

openssl rand -hex 16 > /root/key
chmod 400 /root/key

cryptsetup luksAddKey /dev/nvme0n1p3 /root/key < /root/tmpkey

Ce script utilise le programme clevis (voir une doc sur le wiki de Arch) pour binder la partition chiffrée avec la puce TPM2 et déclencher l’auto-unlock. En cadeau je vous fais sauter des jours de debug avec le echo -n car sans le saut de ligne clevis indiquera que le mot de pass est incorrect sans plus de précision 😑
Ensuite on génère une clé aléatoire que l’on ajoute comme nouvelle clé à Luks. Si vous avez suivi vous devriez lever un problème. En effet si le PC a un problème matériel et qu’il est nécessaire de récupérer des données utlisateur sur le disque, il ne sera pas possible de le déchiffrer car la clé est sur le disque chiffré dans /root/key.
Il est nécessaire de bien sauvegarder cette clé en dehors du PC, dans Bitwarden par exemple ou bien de déployer un outil de gestion de parc type GLPI ou FusionInventory pour qu’il la remonte automatiquement dans l’inventaire.

Installation

J’ai installé ces scripts dans mon dépôt public https://codeberg.org/fredix/netboot que vous pouvez utiliser pour tester. La suite est de booter votre PC sur une clé USB Ubuntu 24 LTS desktop standard et se connecter au Wifi si vous n’etes pas en filaire. Arrivé sur l’écran Type d’installation il faut choisir Installation automatisée et saisir l’URL suivante :
https://codeberg.org/fredix/netboot/raw/branch/main/autoinstall.yaml

A savoir que si l’URL mène vers un certificat auto-signé ou signé par une autorité inconnue des navigateurs cela ne fonctionnera pas.

ubuntu_autoinstall

Lorsque l’installation est finie le PC reboot puis demande de saisir le mot de pass pour déchiffrer le disque. Il ne faut rien saisir, il suffit d’appuyer sur la touche Echap pour voir le log et attendre que l’installation se termine.
A la fin il va y avoir un git clone du dépôt git comme indiqué dans la section user-data : git clone https://codeberg.org/fredix/netboot.git /home/admin/netboot

Il vous suffit d’ajouter tout vos scripts dans ce dépôt pour lancer ensuite une post installation afin de finir de configurer le système, notamment lancer les configurations de sssd, l’installation de l’agent de votre gestionnaire de parc et des outils comme Rustdesk.

ubuntu_autoinstall2

Dans cette photo on voit que le dépôt netboot a bien été cloné, la commande lsblk montre que le chiffrement et les partitions sont en place.
Si vous avez des soucis vérifiez bien que TPM2 est activé dans le BIOS et que le PC en possède une évidement, sauf s’il est trop vieux.

Grub

La dernière sécurité à mettre en place est la protection du menu de boot Grub. Un attaquant qui y aurait accès pourrait modifier les paramètres de boot du kernel et obtenir l’accès root. Il suffit de lancer ce script en post installation pour ajouter un mot de pass généré si on veut accéder à l’édition du menu.

grub.sh

#!/bin/bash

# We need sudo privileges for this script
if [ $EUID != 0 ]; then
    sudo "$0" "$@"
    exit $?
fi

echo "set superusers=\"it\"" >> /etc/grub.d/40_custom
pass=$(pwgen -B 16 1)
echo "$pass" > /root/grub-key
chmod 700 /root/grub-key
password=$(echo -e "$pass\n$pass" | grub-mkpasswd-pbkdf2 | awk '/grub.pbkdf/{print $NF}')
echo "password_pbkdf2 it $password" >> /etc/grub.d/40_custom

# nécessaire si l'on veut éviter de saisir le mot de pass à chaque boot
sed -i "s/echo \"menuentry '\$(echo \"\$os\" | grub_quote)' \${CLASS}/echo \"menuentry '\$(echo \"\$os\" | grub_quote)' \${CLASS} --unrestricted/g" /etc/grub.d/10_linux

# Set grub keymap
grub-kbdcomp -o /boot/grub/french.gkb fr
echo "GRUB_TERMINAL_INPUT=\"at_keyboard\"" >> /etc/default/grub
echo "insmod keylayouts" >> /etc/grub.d/40_custom
echo 'keymap $prefix/french.gkb' >> /etc/grub.d/40_custom

#sed -i 's/#\(GRUB_TERMINAL=.*\)/\1/g' /etc/default/grub
sed -i 's/GRUB_TIMEOUT=0/GRUB_TIMEOUT=5/g' /etc/default/grub
sed -i 's/GRUB_TIMEOUT_STYLE=hidden/GRUB_TIMEOUT_STYLE=menu/g' /etc/default/grub

update-grub

Un utilisateur it est créé avec un mot de pass généré et stocké dans /root/grub-key (et à copier en dehors du PC).

Attention, bizarrement sur mon PC Asus de test le menu grub ne s’est pas affiché et le PC n’a pas booté tant que je n’appuyais pas sur la touche Echap. Le problème était résolu en forcant GRUB_TERMINAL=console mais alors le clavier dans grub reste en qwerty ce qui peut être bloquant si on doit saisir le mot de pass grub.

Optimisation

La première chose serait de ne plus avoir à booter par clé USB mais par un serveur PXE comme iVentoy. Mais à ce jour un bug plante l’auto-installation, l’installateur voit le disque monté par iVentoy et se crash.

Une autre optimisation serait de modifier le cloud init de l’ISO pour ajouter l’URL vers le fichier autoinstallation.yaml pour rendre l’install automatique.

On peut renforcer la sécurité en utlisant une Yubikey au lieu de la puce TPM2 comme le permet Clevis. Dans ce cas le PC sera illisible en cas de vol sans la Yubikey, mais également en cas de perte de celle-ci. A moduler selon la politique de sécurité choisie.

A suivre

Je ferais peut être une suite en attendant vous avez une bonne base pour personnaliser automatiquement Ubuntu.

Liens

(Ce texte a été écrit avec VNote)