Démarrage du système Linux

Ce chapitre expose les principes du démarrage d’un système Linux en différentes étapes dans lesquelles interviennent le chargeur de démarrage Grub2, le noyau Linux et puis le lancement des services init ou systemd. On expliquera ici les différentes manière d’arrêter ou de réinitialiser un système Linux. Enfin, on monterera comment reprendre la main sur un système dont on a perdu le mot de passe (Password Recovery) et comment s’en protéger.

1. Démarrage du système

1.1. Processus de démarrage

Source de l’image

Source : https://commons.wikimedia.org/wiki/File:Linux_startup_process_wip.svg

1.2. Le BIOS

Le BIOS - Basic Input Output System (système d’entrée sortie de base) est essentiel à tout PC, il se trouve généralement dans une mémoire morte ou ROM qui est directement implantée sur la carte mère du PC. Il est associé à une mémoire sauvegardée par une petite pile bouton sur la carte mère (le “setup” qui est la sauvegarde de la configuration).

Si votre PC ne démarre pas (ou ne boot pas) c’est à cause du BIOS et de sa configuration (le setup). On peut accéder au setup et le modifier en pressant une touche dès la mise sous tension du PC. Selon les fabricants, cette touche est Suppr, F2, F10 … (la touche à utiliser est très brièvement affichée au tout début du démarrage).

Mais quelle est donc sa fonction ?

Le BIOS teste le matériel et y applique les réglages mémorisés dans le setup, tout en s’assurant qu’il n’existe pas de dis-fonctionnement matériel et que tout est présent dans la machine, mémoire CPU principalement. Ensuite il regarde la présence des périphériques nécessaires au boot : lecteur de disquette, cd rom, dvd rom, clef usb, mais surtout disque dur. Si vous avez installé un système d’exploitation Linux ou Windows, le BIOS est normalement configuré pour activer le MBR de celui ci, les étapes du démarrage peuvent alors commencer … (https://www.linuxpedia.fr/doku.php/util/boot)

1.3. Le MBR ( Boot Primaire )

Le Master Boot Record ou MBR (parfois aussi appelé “Zone amorce”) est le nom donné au premier secteur adressable d’un disque dur (cylindre 0, tête 0 et secteur 1, ou secteur 0 en adressage logique) dans le cadre d’un partitionnement Intel. Sa taille est de 512 octets. Le MBR contient la table des partitions (les 4 partitions primaires) du disque dur. Il contient également une routine d’amorçage dont le but est de charger le système d’exploitation (ou le boot loader/chargeur d’amorçage s’il existe) présent sur la partition active.

Mais quelle est donc sa fonction ?

Il s’agit du boot primaire , la taille du MBR étant limitée à 512 octets, ce petit programme n’a pour fonction que de lancer le boot secondaire qui occupe un plus gros espace ailleurs sur le disque.

1.4. Le Boot Secondaire

Il a pour fonction d’activer le système d’exploitation, c’est à dire d’activer le noyau. Les boot primaire et secondaire constituent ce qu’on appelle le chargeur ou loader tel que Lilo ou plus fréquemment Grub.

2. Chargeur de démarrage Grub2

  • GNU GRUB (acronyme signifiant en anglais « GRand Unified Bootloader ») est un programme d’amorçage GNU qui gère la gestion du chargement des systèmes d’exploitation disponibles sur le système. Il permet à l’utilisateur de choisir quel système démarrer. Il intervient après allumage de l’ordinateur et avant le chargement du système d’exploitation.
  • GRUB dans sa version 2 (entièrement réécrite) est un chargeur de démarrage libre au même titre que Das U-Boot ou Barebox pour du matériel embarqué.
  • Ses nombreux avantages, son histoire et son fonctionnement sont décrits dans la page : https://doc.fedora-fr.org/wiki/GRUB2_:_Les_bases_pour_Fedora

2.1. Fichiers Grub2

La configuration de GRUB2 est composé de trois principales dans des fichiers inclus :

  1. /etc/default/grub - le fichier contenant les paramètres du menu de GRUB 2,
  2. /etc/grub.d/ - le répertoire contenant les scripts de création du menu GRUB 2, permettant notamment de personnaliser le menu de démarrage,
  3. /boot/grub2/grub.cfg - le fichier de configuration final de GRUB 2, non modifiable. (/boot/grub/grub.cfg sous Debian).

Ce dernier fichier est généré automatiquement par le programme grub2-mkconfig à partir des scripts /etc/default/grubet /etc/grub.d/ :

Voici le contenu du fichier /etc/default/grub avec les principales variables d’environnement :

cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

Sous Debian/Ubuntu pour générer le fichier de configuration de GRUB2 :

update-grub

Sous Centos 7 :

grub2-mkconfig -o /boot/grub2/grub.cfg

2.2. Gestion

Obtenir la version du noyau courant :

grub2-editenv list
saved_entry=CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)

Pour connaître la liste des entrées du menu :

grep ^menu /boot/grub2/grub.cfg
menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-d83f59c0-e642-4682-87d4-de2c290a6484' {
menuentry 'CentOS Linux (0-rescue-647df4ed1d8e48c48d765271858a9a93) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-0-rescue-647df4ed1d8e48c48d765271858a9a93-advanced-d83f59c0-e642-4682-87d4-de2c290a6484' {

4.3. Exemple de modification de grub2

Le script ubuntu-grub-console.sh configure Grub en activant une console texte.

#!/bin/bash
# Works with Kali latest releases
if [ "$(id -u)" != "0" ]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi
cat << EOF > /etc/default/grub
# grub-mkconfig -o /boot/grub/grub.cfg
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200"
GRUB_CMDLINE_LINUX="initrd=/install/initrd.gz"
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"
EOF
grub-mkconfig -o /boot/grub/grub.cfg
reboot

2.4. Mettre à zéro grub2

rm /etc/grub.d/*
rm /etc/sysconfig/grub
yum reinstall grub2-tools
grub2-mkconfig -o /boot/grub2/grub.cfg

2.5. Réinstaller grub2

grub2-install /dev/sda1

La protection de Grub2 est vue plus bas.

3. init et systemd

La procédure de démarrage d’un ordinateur Linux peut se résumer de la manière suivante :

Le chargeur d’amorçage (GRUB2 a priori) charge le noyau, ensuite le noyau monte le système de fichier racine (le « / »), puis il initialise la console initiale :

  • init (abréviation de “initialization”) est le programme sous Unix qui lance ensuite toutes les autres tâches (sous forme de scripts). Il s’exécute comme un démon informatique. Son identifiant de processus (PID) est 1.
  • systemd est une alternative au démon init de System V. Il est spécifiquement conçu pour le noyau Linux. Il a pour but d’offrir un meilleur cadre pour la gestion des dépendances entre services, de permettre le chargement en parallèle des services au démarrage, et de réduire les appels aux scripts shell.

3.1. Systemd

Source de l’image

Source : https://commons.wikimedia.org/wiki/File:Linux_kernel_unified_hierarchy_cgroups_and_systemd.svg Systemd est le système d’initialisation installé par défaut avec les distributions Arch Linux, Centos 7, Debian 8 et à partir d’Ubuntu 15.04.

3.2. Niveaux d’exécution (run levels)

Le “run level”, ou niveau de fonctionnement, est un chiffre ou une lettre utilisé par le processus init des systèmes de type Unix pour déterminer les fonctions activées du système.

Dans cette organisation héritée de UNIX System V, les scripts de lancement des applications sont regroupés dans un répertoire commun /etc/init.d. Ces scripts reçoivent un paramètre qui peut être start, stop, restart, etc.

À chaque niveau correspond un répertoire (typiquement /etc/rc.d/rc2.d pour le niveau 2) de liens symboliques vers des fichiers de /etc/init.d. Ces liens symboliques portent des noms commençant par la lettre S ou K, suivi d’un numéro sur deux chiffres.

Lors d’un changement de run level :

  • les scripts dont le nom commence par un K dans le répertoire correspondant au niveau actuel sont lancés (dans l’ordre des numéros) avec le paramètre stop, ce qui a normalement pour effet d’arrêter le service correspondant,
  • les scripts du nouveau niveau qui commencent par S sont appelés successivement avec le paramètre start.

Avec init, les niveaux d’exécutions servent à ces usages :

  • Niveau 1. Mode mono-utilisateur ou maintenance
  • Niveau 2. mode multi-utilisateur sans ressources réseaux (NFS, etc)
  • Niveau 3. mode multi-utilisateur sans serveur graphique
  • Niveau 5. mode multi-utilisateur avec serveur graphique

Le niveau 0 arrête le système.

Le niveau 6 redémarre le système.

Sous Debian/Ubuntu, le Niveau 2 est le seul niveau fonctionnel avec réseau et serveur graphique. Les niveaux 3, 4 et 5 ne sont pas utilisés.

Pour mémoire, les niveaux d’exécution avec init System V sont définis dans /etc/inittab (RHEL7, Debian 7). Upstart est une alternative jusque Ubuntu 16.04 LTS.

Pour vérifier le niveau d’exécution courant :

runlevel
N 5

Pour se placer dans un des niveaux d’exécution (x) :

init x

Systemctl dispose de ses propres commandes pour les niveaux d’exécution :

Obtenir le niveaux d’éxécution par défaut :

systemctl get-default
graphical.target

Pour fixer le niveau d’exécution par défaut en mode multi-utilisateur avec serveur graphique :

systemctl set-default graphical.target

Pour passer mode maintenance avec un système de fichier local monté

systemctl rescue

Passer en mode maintenace avec seulement /root monté

systemctl emergency

Pour passer en mode multi-utilisateur sans serveur graphique (N 3)

systemctl isolate multi-user.target

Pour passer en mode multi-utilisateur avec serveur graphique (N 5)

systemctl isolate graphical.target

3.3. Scripts de démarrage de service

Dans les distributions antérieures à 2016, on retrouvera les scripts de démarrage dans le dossier /etc/init.d/ (System V / Upstart). Pour qu’ils soient liés à un niveau d’exécution, il sont présentés dans les dossier /etc/rc5/ par exemple sous forme de lien symbolique.

Pour activer ces services au démarrage du système, on utilise soit la commande update-rc.d ou chkconfig.

En Debian (Wheezy et antérieures) / Ubuntu, pour activer le service Web Apache :

update-rc.d apache2 defaults

Pour le désactiver :

update-rc.d apache2 remove

En Centos 5/6, pour activer le service Web Apache :

chkconfig --add httpd

Pour le désactiver :

chkconfig --del httpd

De manière simplifiée, il s’agit de scripts qui comportent au moins deux arguments possibles : start et stop. D’autres arguments sont souvent développés comme restart ou status. Aussi, les dépendances d’un service sont gérées à partir d’une séquence ordonnées de scripts dans le dossier /etc/rc* du niveau de service. Cette procédure n’est pas des plus robustes, car les événements pour un service ne sont pas gérés par System V, contrairement à Upstart et Systemd.

Voici un modèle formel de script :

#!/bin/bash

case $1 in
start)
# commande qui démarre le service
;;
stop)
# commande qui arrête le service
;;
esac

3.4. Commandes systemctl

On ira s’informer au préalable sur les systèmes de gestion de service et plus particulièrement systemd sur https://doc.fedora-fr.org/wiki/Systemd.

Il comporte de nombreux avantages. Selon moi, une simplicité d’utilisation et de configuration et un e gestion unifiée comme par exemple la possibilité de contôler des machines distantes voire des containers ou des machines virtuelles via les outils systemd

  • systemctl list-units
  • systemctl
  • systemctl status unit
  • systemctl enable | disable unit
  • systemctl start | stop | restart unit
  • systemctl kill unit
  • systemctl kill -s SIGKILL unit
  • /lib/systemd/system est le dossier où se situent les fichiers de configuration des services. Par exemple :
cat /lib/systemd/system/sshd.*

Autre exemple, service firewalld :

ls /etc/systemd/system/*.service
/etc/systemd/system/dbus-org.bluez.service
/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service
cat /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service
[Unit]
Description=firewalld - dynamic firewall daemon
Before=network.target
Before=libvirtd.service
Before=NetworkManager.service
Conflicts=iptables.service ip6tables.service ebtables.service

[Service]
EnvironmentFile=-/etc/sysconfig/firewalld
ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS
ExecReload=/bin/kill -HUP $MAINPID
# supress to log debug and error output also to /var/log/messages
StandardOutput=null
StandardError=null
Type=dbus
BusName=org.fedoraproject.FirewallD1

[Install]
WantedBy=basic.target
Alias=dbus-org.fedoraproject.FirewallD1.service

Dernier exemple du service httpd (Centos) :

cat /lib/systemd/system/httpd.service
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

3.5. Exercice démarrage des services avec systemctl

  • Vérifier l’installation du serveur SSH
  • Vérifier son état
  • Le désactiver au démarrage
  • Arrêter le service
  • Réactiver le service au démarrage
  • Vérifier l’état du service
  • Obtenir des journaux plus détaillés
  • Démarrer le service
  • Vérifier l’état du service
  • Relancer le service
  • Vérifier l’état du service
yum -y install openssh-server
systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since mer. 2016-02-17 22:14:57 CET; 6 days ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 830 (sshd)
CGroup: /system.slice/sshd.service
└─830 /usr/sbin/sshd -D

févr. 17 22:14:57 c7li systemd[1]: Started OpenSSH server daemon.
févr. 17 22:14:57 c7li systemd[1]: Starting OpenSSH server daemon...
févr. 17 22:14:57 c7li sshd[830]: Server listening on 0.0.0.0 port 22.
févr. 17 22:14:57 c7li sshd[830]: Server listening on :: port 22.
systemctl disable sshd
Removed symlink /etc/systemd/system/multi-user.target.wants/sshd.service.
systemctl stop sshd
systemctl enable sshd
Created symlink from /etc/systemd/system/multi-user.target.wants/sshd.service to /usr/lib/systemd/system/sshd.service.
systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:sshd(8)
man:sshd_config(5)

févr. 17 22:14:57 c7li systemd[1]: Started OpenSSH server daemon.
févr. 17 22:14:57 c7li systemd[1]: Starting OpenSSH server daemon...
févr. 17 22:14:57 c7li sshd[830]: Server listening on 0.0.0.0 port 22.
févr. 17 22:14:57 c7li sshd[830]: Server listening on :: port 22.
févr. 24 21:41:31 c7cli systemd[1]: Stopping OpenSSH server daemon...
févr. 24 21:41:31 c7cli systemd[1]: Stopped OpenSSH server daemon.
journalctl -xn
systemctl start sshd
systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since mer. 2016-02-24 21:44:48 CET; 2s ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 17318 (sshd)
CGroup: /system.slice/sshd.service
└─17318 /usr/sbin/sshd -D

févr. 24 21:44:48 c7cli systemd[1]: Started OpenSSH server daemon.
févr. 24 21:44:48 c7cli systemd[1]: Starting OpenSSH server daemon...
févr. 24 21:44:48 c7cli sshd[17318]: Server listening on 0.0.0.0 port 22.
févr. 24 21:44:48 c7cli sshd[17318]: Server listening on :: port 22.
systemctl restart sshd
systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since mer. 2016-02-24 21:44:56 CET; 2s ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 17454 (sshd)
CGroup: /system.slice/sshd.service
└─17454 /usr/sbin/sshd -D

févr. 24 21:44:56 c7cli systemd[1]: Started OpenSSH server daemon.
févr. 24 21:44:56 c7cli systemd[1]: Starting OpenSSH server daemon...
févr. 24 21:44:56 c7cli sshd[17454]: Server listening on 0.0.0.0 port 22.
févr. 24 21:44:56 c7cli sshd[17454]: Server listening on :: port 22.

4. Démarrer, redémarrer et éteindre un système normalement

Sur une machine locale ou virtuelle ou un serveur distant.

4.1. Redémarrer le système

On peut procéder de différentes manières :

systemctl reboot
shutdown -r now
reboot
init 6

4.2. Arrêter le système

On peut choisir :

systemctl halt
shutdown -h now
halt
init 0

4.3. Eteindre le système :

poweroff
systemctl poweroff

4.4. Suspendre le système

systemctl suspend

4.5. Hibernation

systemctl hibernate

4.6. Entre hibernation et suspension

systemctl hybrid-sleep

5. Password recovery

5.1. Méthode 1 (RHEL7, Debian 8)

  1. Au redémarrage de l’ordinateur, on peut interrompre grub en appuyant sur la touche «e» pour “edit”/éditer.
  2. A la ligne qui commence par «linux16» ou «linuxefi», effacer rhgb et quiet pour désactiver le démarrage graphique silencieux.
  3. Placer l’occurence init=/bin/bash à la fin de la ligne (CTRL-E) qui va démarrer une session bash sans démarrer le démon init.
  4. “CTRL-X” pour redémarrer.
  5. Remonter la racine pour accéder en lecture/écriture au système de fichier.mount -o remount,rw /
  6. Modifier / lire le mot de passe
  7. Replacer les contextes SELinux sur les fichiers via la commande touch /.autorelabel (si RHEL7)
  8. Redémarrer l’ordinateur : exec /sbin/reboot (peut nécessiter un redémarrage

5.2. Méthode 2 (RHEL7)

  1. Une méthode alternative plus sûre et plus simple consiste à placer rd.break au lieu de init=/bin/bash dans la ligne de démarrage de grub2 (voir première méthode). La procédure est la suivante :
  2. mount –o remount,rw /sysroot
  3. chroot /sysroot
  4. passwd
  5. touch /.autorelabel
  6. exit
  7. exit

5.3. Protections grub2

Mot de passe chiffré sur le menu grub2

Pour un utilisateur, pour toutes les entrées du menu.

Génération du mot de passe

grub-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.B1EB4DABDA2BC3A2243772405831E0F78BBF6F27A291E875478DAC4AD3FC7F0D402A7B976D65BF9A8ECA051ABA998956CE10217C10EB021A2F60E9025B4049C5.A14C5A56B96E8CD12437088F52A06EA1F37AB74AD365DDCA151CF8339B468FBF0A8BC113FFAE2C583E74E269CD69B279BD754350CDFCDDE6BC1756F23918F81B

Ajout d’un compte et d’un mot de passe dans /etc/grub.d/40_custom

#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

# define superusers
set superusers="francois"

#define users
password_pbkdf2 francois grub.pbkdf2.sha512.10000.B1EB4DABDA2BC3A2243772405831E00
F78BBF6F27A291E875478DAC4AD3FC7F0D402A7B976D65BF9A8ECA051ABA998956CE10217C10EB022
1A2F60E9025B4049C5.A14C5A56B96E8CD12437088F52A06EA1F37AB74AD365DDCA151CF8339B4688
FBF0A8BC113FFAE2C583E74E269CD69B279BD754350CDFCDDE6BC1756F23918F81B

Installation de la configuration :

grub-mkconfig -o /boot/grub/grub.cfg
reboot

A redémarrage, il faudra entrer un nom d’utillisateur et un mot de passe. En ajoutant --unrestricted à la fin de la ligne de chargement du noyau, tous les utilisateurs pourront charger une ligne sans pouvoir l’éditer sauf un super-utilisateur.

Désactivation du mode recovery

  • Désactivation du mode recovery : vérifier la valeur de la variable GRUB_DISABLE_RECOVERY.
  • Mettre à zéro la variable GRUB_TIMEOUT

Exercice de sécurisation

Comment peut-on automatiser la sécurisation d’une configuration de grub ?