Un server Ubuntu folosește un modul kernel construit intern, iar după activarea Secure Boot încărcarea lui se oprește cu mesajul Key was rejected by service. Vom crea o cheie proprie pentru semnarea modulelor, o vom înscrie în Machine Owner Key — MOK, vom semna un modul demonstrativ și vom automatiza reconstruirea lui pentru kernelurile instalate ulterior.
Rezultatul este verificabil: Secure Boot rămâne activ, cheia privată rămâne accesibilă numai administratorului, iar kernelul acceptă modulul internal_guard deoarece semnătura sa corespunde certificatului MOK înscris. Un serviciu systemd reconstruiește modulul pentru kernelurile noi, iar un timer separat verifică periodic starea Secure Boot, certificatul, semnatarul și încărcarea modulului.
Acest proiect folosește MOK, nu înlocuiește cheile Platform Key, KEK sau db din firmware. Înlocuirea completă a cheilor UEFI diferă între producători și poate face sistemul imposibil de pornit dacă executabilele EFI necesare nu sunt semnate corect. MOK este mecanismul oferit de Ubuntu prin shim pentru a autoriza chei administrate de proprietarul sistemului, inclusiv pentru module kernel dezvoltate local.
Execută proiectul mai întâi pe o mașină de test cu acces la consola fizică sau la consola virtuală a hypervisorului. Înscrierea MOK necesită interacțiune la următoarea pornire și nu poate fi finalizată exclusiv prin SSH.
Modulul intern va supraviețui atât Secure Boot, cât și schimbării kernelului
Scenariul folosește Ubuntu Server 24.04 LTS, instalat în mod UEFI, cu Secure Boot activ. Sunt necesare minimum două nuclee CPU, 2 GB RAM și aproximativ 1 GB liber pentru compilator, antetele kernelului și directoarele de construire. Implementarea durează aproximativ 45–60 de minute, incluzând repornirea pentru înscrierea certificatului.
Modulul demonstrativ nu interceptează apeluri și nu modifică mecanisme de securitate. El publică parametrul read-only build_label și scrie în jurnal un mesaj la încărcare și descărcare. Este suficient pentru a reproduce întregul lanț aplicat ulterior unui modul intern real.
Verifică mediul înainte de modificări:
printf '%sn' '=== Sistem ==='
. /etc/os-release
printf 'Distribuție: %s %sn' "$NAME" "$VERSION_ID"
printf '%sn' '=== Firmware și Secure Boot ==='
test -d /sys/firmware/efi && echo 'Pornire UEFI: da' || echo 'Pornire UEFI: nu'
mokutil --sb-state
printf '%sn' '=== Kernel și arhitectură ==='
uname -r
uname -m
printf '%sn' '=== Resurse ==='
nproc
free -h
df -h / /var
printf '%sn' '=== Unelte, dacă sunt deja instalate ==='
mokutil --version 2>/dev/null || true
openssl version 2>/dev/null || true
modinfo --version 2>/dev/null || true
systemctl --version | head -n 1
Un exemplu de rezultat, cu versiunile și valorile care pot diferi după actualizările instalate, este:
=== Sistem ===
Distribuție: Ubuntu 24.04
=== Firmware și Secure Boot ===
Pornire UEFI: da
SecureBoot enabled
=== Kernel și arhitectură ===
6.8.0-xx-generic
x86_64
Dacă apare EFI variables are not supported on this system, sistemul nu a fost pornit în UEFI sau mediul virtual nu expune variabilele EFI. Dacă apare SecureBoot disabled, oprește serverul și activează Secure Boot din firmware ori din configurația mașinii virtuale înainte de continuare.
Pentru administrarea sigură de la distanță, acest proiect poate fi combinat cu autentificarea SSH prin chei și dezactivarea parolei. Păstrează însă accesul la consola sistemului până când ai confirmat că noul kernel pornește și modulul este acceptat.
Instalăm compilatorul, antetele și instrumentele MOK într-o singură etapă
Actualizează indexul pachetelor și instalează uneltele folosite în restul proiectului:
sudo apt-get update
sudo apt-get install --yes
build-essential
kmod
linux-headers-"$(uname -r)"
linux-headers-generic
mokutil
openssl
build-essential instalează compilatorul și make, linux-headers-$(uname -r) oferă infrastructura de construire pentru kernelul curent, iar linux-headers-generic menține antetele pentru kernelurile generice viitoare. mokutil gestionează cererile MOK, iar openssl creează cheia privată și certificatul X.509.
Confirmă versiunile instalate:
gcc --version | head -n 1
make --version | head -n 1
mokutil --version
openssl version
modinfo --version
test -x "/usr/src/linux-headers-$(uname -r)/scripts/sign-file"
Exemplu de rezultat:
gcc (Ubuntu ...) ...
GNU Make ...
mokutil ...
OpenSSL ...
kmod version ...
Ultima comandă nu produce output când sign-file există. Un cod de ieșire diferit de zero indică faptul că antetele pentru kernelul curent nu sunt instalate în calea așteptată.
Separăm sursa, cheia, automatizarea și controlul periodic
Proiectul va folosi următoarea structură:
/usr/local/src/internal_guard/
├── internal_guard.c # sursa completă a modulului
└── Makefile # reguli de construire pentru un kernel ales
/etc/secureboot/keys/
├── internal-modules.key # cheia privată, permisiuni 600
└── internal-modules.der # certificatul X.509 în format DER
/usr/local/sbin/
├── rebuild-internal-guard # construiește și semnează pentru fiecare kernel
└── check-internal-guard # verifică Secure Boot, MOK și modulul încărcat
/etc/systemd/system/
├── internal-guard-build.service
├── internal-guard-build.timer
├── internal-guard.service
├── internal-guard-check.service
└── internal-guard-check.timer
/var/lib/internal-guard/
├── build/ # directoare de compilare per kernel
└── state/ # hash-ul sursei instalate per kernel
Modulul rezultat este instalat în /lib/modules/<versiune>/updates/internal/internal_guard.ko. Nu se modifică modulele livrate de Ubuntu și nu se copiază cheia privată în /boot, în initramfs sau în directorul sursei.
Pasul 1 — Generăm cheia de semnare fără a expune secretul
Cheia privată trebuie să rămână disponibilă pentru reconstruirile automate, dar numai pentru root. Certificatul public poate fi citit și înscris în MOK.
Creează directorul și perechea criptografică:
sudo install -d -m 0700 -o root -g root /etc/secureboot/keys
sudo openssl req
-new
-x509
-newkey rsa:3072
-sha256
-nodes
-days 3650
-subj "/CN=Internal Kernel Module Signing/"
-keyout /etc/secureboot/keys/internal-modules.key
-outform DER
-out /etc/secureboot/keys/internal-modules.der
sudo chmod 0600 /etc/secureboot/keys/internal-modules.key
sudo chmod 0644 /etc/secureboot/keys/internal-modules.der
sudo chown root:root /etc/secureboot/keys/internal-modules.key
/etc/secureboot/keys/internal-modules.der
-newkey rsa:3072 generează o cheie RSA nouă, iar -x509 produce un certificat autosemnat. -outform DER este necesar deoarece mokutil --import așteaptă certificatul în format DER. -nodes înseamnă că cheia nu este protejată de o parolă; protecția este asigurată aici prin proprietar, permisiuni și directorul inaccesibil utilizatorilor obișnuiți. Această alegere permite semnarea automată după actualizări, dar impune protejarea strictă a contului root și a backupului cheii.
Inspectează certificatul fără a afișa cheia privată:
sudo openssl x509
-inform DER
-in /etc/secureboot/keys/internal-modules.der
-noout
-subject
-issuer
-fingerprint
-sha256
sudo stat -c '%U:%G %a %n'
/etc/secureboot/keys/internal-modules.key
/etc/secureboot/keys/internal-modules.der
Exemplu de output:
subject=CN = Internal Kernel Module Signing
issuer=CN = Internal Kernel Module Signing
sha256 Fingerprint=...
root:root 600 /etc/secureboot/keys/internal-modules.key
root:root 644 /etc/secureboot/keys/internal-modules.der
Punct de control: dacă fișierul .key are alte permisiuni decât 600, corectează-le înainte să continui și nu copia cheia într-o locație partajată.
Pasul 2 — Înscriem certificatul în MOK prin consola de pornire
Importul creează o cerere de înscriere. Certificatul nu devine de încredere până când cererea nu este confirmată în interfața MokManager la repornire.
Pornește importul:
sudo mokutil --import /etc/secureboot/keys/internal-modules.der
sudo mokutil --list-new
mokutil solicită introducerea și confirmarea unei parole temporare. Aceasta protejează operațiunea de înscriere de la următoarea pornire; nu este parola cheii și nu trebuie păstrată în fișiere sau în shell history.
Exemplu de rezultat pentru cererea în așteptare:
[key 1]
SHA1 Fingerprint: ...
Certificate:
Data:
Subject: CN=Internal Kernel Module Signing
Repornește numai după ce ai deschis consola fizică, consola KVM/IPMI sau consola mașinii virtuale:
sudo systemctl reboot
În MokManager selectează Enroll MOK, apoi Continue, confirmă cu Yes, introdu parola temporară și alege Reboot. Denumirile pot avea mici diferențe vizuale între versiunile shim, dar certificatul afișat trebuie să aibă subiectul Internal Kernel Module Signing.
După revenirea sistemului, verifică înscrierea:
mokutil --sb-state
sudo mokutil --test-key /etc/secureboot/keys/internal-modules.der
Exemplu de output:
SecureBoot enabled
/etc/secureboot/keys/internal-modules.der is already enrolled
Punct de control: nu continua dacă testul spune că certificatul nu este înscris. Repetă mokutil --import, verifică cererea cu --list-new și finalizează operațiunea din consolă.
Pasul 3 — Construim un modul intern care poate fi identificat fără ambiguitate
Înainte de a crea sursa, păstrează copii dacă laboratorul are deja fișiere cu aceleași nume:
sudo install -d -m 0755 /usr/local/src/internal_guard
stamp="$(date -u +%Y%m%dT%H%M%SZ)"
for path in
/usr/local/src/internal_guard/internal_guard.c
/usr/local/src/internal_guard/Makefile
do
if sudo test -e "$path"; then
sudo cp -a "$path" "${path}.bak.${stamp}"
fi
done
Fișierul /usr/local/src/internal_guard/internal_guard.c:
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
static char *build_label = "internal-office-module";
module_param(build_label, charp, 0444);
MODULE_PARM_DESC(build_label, "Read-only deployment label");
static int __init internal_guard_init(void)
{
pr_info("internal_guard: loaded label=%sn", build_label);
return 0;
}
static void __exit internal_guard_exit(void)
{
pr_info("internal_guard: unloadedn");
}
module_init(internal_guard_init);
module_exit(internal_guard_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Internal Linux Operations");
MODULE_DESCRIPTION("Signed internal module used to validate the Secure Boot workflow");
MODULE_VERSION("1.0");
Scrie-l pe disc:
sudo tee /usr/local/src/internal_guard/internal_guard.c >/dev/null <<'EOF'
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
static char *build_label = "internal-office-module";
module_param(build_label, charp, 0444);
MODULE_PARM_DESC(build_label, "Read-only deployment label");
static int __init internal_guard_init(void)
{
pr_info("internal_guard: loaded label=%sn", build_label);
return 0;
}
static void __exit internal_guard_exit(void)
{
pr_info("internal_guard: unloadedn");
}
module_init(internal_guard_init);
module_exit(internal_guard_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Internal Linux Operations");
MODULE_DESCRIPTION("Signed internal module used to validate the Secure Boot workflow");
MODULE_VERSION("1.0");
EOF
Fișierul /usr/local/src/internal_guard/Makefile:
obj-m += internal_guard.o
KDIR ?= /lib/modules/$(shell uname -r)/build
.PHONY: all clean
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
Scrie Makefile-ul, păstrând caracterele tab din comenzile $(MAKE):
sudo tee /usr/local/src/internal_guard/Makefile >/dev/null <<'EOF'
obj-m += internal_guard.o
KDIR ?= /lib/modules/$(shell uname -r)/build
.PHONY: all clean
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
EOF
sudo chown -R root:root /usr/local/src/internal_guard
sudo find /usr/local/src/internal_guard -type d -exec chmod 0755 {} +
sudo find /usr/local/src/internal_guard -type f -exec chmod 0644 {} +
Parametrul 0444 poate fi citit din sysfs, dar nu modificat după încărcare. Mesajele pr_info permit confirmarea în jurnalul kernelului. Modulul nu deschide porturi, nu citește date de utilizator și nu schimbă politica Secure Boot.
Punct de control: rulează make -n -C /usr/local/src/internal_guard; dacă apare missing separator, Makefile-ul conține spații în loc de tab înaintea celor două comenzi $(MAKE).
Pasul 4 — Semnăm fiecare construcție cu aceeași cheie MOK
Scriptul va detecta kernelurile instalate, va ignora directoarele fără antete, va construi separat pentru fiecare ABI și va instala numai un modul a cărui semnătură poate fi citită cu modinfo.
Fișierul /usr/local/sbin/rebuild-internal-guard:
#!/usr/bin/env bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
export LC_ALL=C
readonly SOURCE_DIR=/usr/local/src/internal_guard
readonly PRIVATE_KEY=/etc/secureboot/keys/internal-modules.key
readonly CERTIFICATE=/etc/secureboot/keys/internal-modules.der
readonly WORK_ROOT=/var/lib/internal-guard/build
readonly STATE_ROOT=/var/lib/internal-guard/state
readonly EXPECTED_SIGNER='Internal Kernel Module Signing'
exec 9>/run/lock/internal-guard-build.lock
if ! flock -n 9; then
echo 'internal_guard: another build is already running'
exit 0
fi
for required in
"$SOURCE_DIR/internal_guard.c"
"$SOURCE_DIR/Makefile"
"$PRIVATE_KEY"
"$CERTIFICATE"
do
if [[ ! -f "$required" ]]; then
echo "internal_guard: required file missing: $required" >&2
exit 1
fi
done
install -d -m 0755 "$WORK_ROOT" "$STATE_ROOT"
mapfile -t kernels < <(
find /lib/modules -mindepth 1 -maxdepth 1 -type d -printf '%fn' |
sort -V
)
if [[ "${#kernels[@]}" -eq 0 ]]; then
echo 'internal_guard: no installed kernel directories found' >&2
exit 1
fi
source_hash="$(
sha256sum "$SOURCE_DIR/internal_guard.c" "$SOURCE_DIR/Makefile" |
sha256sum |
awk '{print $1}'
)"
for kernel in "${kernels[@]}"; do
kernel_dir="/lib/modules/$kernel"
headers="$kernel_dir/build"
sign_file="$headers/scripts/sign-file"
destination="$kernel_dir/updates/internal"
module="$destination/internal_guard.ko"
work="$WORK_ROOT/$kernel"
state="$STATE_ROOT/$kernel.sha256"
if [[ ! -d "$headers" || ! -x "$sign_file" ]]; then
echo "internal_guard: skip $kernel; matching headers are absent"
continue
fi
if [[ -f "$module" && -f "$state" ]] &&
[[ "$(<"$state")" == "$source_hash" ]] &&
[[ "$(modinfo -F signer "$module" 2>/dev/null || true)" == "$EXPECTED_SIGNER" ]]; then
echo "internal_guard: $kernel already has the expected signed module"
continue
fi
rm -rf "$work"
install -d -m 0755 "$work"
install -m 0644 "$SOURCE_DIR/internal_guard.c" "$work/internal_guard.c"
install -m 0644 "$SOURCE_DIR/Makefile" "$work/Makefile"
make -C "$work" KDIR="$headers" clean
make -C "$work" KDIR="$headers" all
"$sign_file" sha256 "$PRIVATE_KEY" "$CERTIFICATE" "$work/internal_guard.ko"
if [[ "$(modinfo -F signer "$work/internal_guard.ko")" != "$EXPECTED_SIGNER" ]]; then
echo "internal_guard: signer verification failed for $kernel" >&2
exit 1
fi
install -d -m 0755 "$destination"
install -m 0644 "$work/internal_guard.ko" "$module"
depmod "$kernel"
printf '%sn' "$source_hash" >"$state"
echo "internal_guard: installed signed module for $kernel"
done
Instalează scriptul:
sudo tee /usr/local/sbin/rebuild-internal-guard >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
export LC_ALL=C
readonly SOURCE_DIR=/usr/local/src/internal_guard
readonly PRIVATE_KEY=/etc/secureboot/keys/internal-modules.key
readonly CERTIFICATE=/etc/secureboot/keys/internal-modules.der
readonly WORK_ROOT=/var/lib/internal-guard/build
readonly STATE_ROOT=/var/lib/internal-guard/state
readonly EXPECTED_SIGNER='Internal Kernel Module Signing'
exec 9>/run/lock/internal-guard-build.lock
if ! flock -n 9; then
echo 'internal_guard: another build is already running'
exit 0
fi
for required in
"$SOURCE_DIR/internal_guard.c"
"$SOURCE_DIR/Makefile"
"$PRIVATE_KEY"
"$CERTIFICATE"
do
if [[ ! -f "$required" ]]; then
echo "internal_guard: required file missing: $required" >&2
exit 1
fi
done
install -d -m 0755 "$WORK_ROOT" "$STATE_ROOT"
mapfile -t kernels < <(
find /lib/modules -mindepth 1 -maxdepth 1 -type d -printf '%fn' |
sort -V
)
if [[ "${#kernels[@]}" -eq 0 ]]; then
echo 'internal_guard: no installed kernel directories found' >&2
exit 1
fi
source_hash="$(
sha256sum "$SOURCE_DIR/internal_guard.c" "$SOURCE_DIR/Makefile" |
sha256sum |
awk '{print $1}'
)"
for kernel in "${kernels[@]}"; do
kernel_dir="/lib/modules/$kernel"
headers="$kernel_dir/build"
sign_file="$headers/scripts/sign-file"
destination="$kernel_dir/updates/internal"
module="$destination/internal_guard.ko"
work="$WORK_ROOT/$kernel"
state="$STATE_ROOT/$kernel.sha256"
if [[ ! -d "$headers" || ! -x "$sign_file" ]]; then
echo "internal_guard: skip $kernel; matching headers are absent"
continue
fi
if [[ -f "$module" && -f "$state" ]] &&
[[ "$(<"$state")" == "$source_hash" ]] &&
[[ "$(modinfo -F signer "$module" 2>/dev/null || true)" == "$EXPECTED_SIGNER" ]]; then
echo "internal_guard: $kernel already has the expected signed module"
continue
fi
rm -rf "$work"
install -d -m 0755 "$work"
install -m 0644 "$SOURCE_DIR/internal_guard.c" "$work/internal_guard.c"
install -m 0644 "$SOURCE_DIR/Makefile" "$work/Makefile"
make -C "$work" KDIR="$headers" clean
make -C "$work" KDIR="$headers" all
"$sign_file" sha256 "$PRIVATE_KEY" "$CERTIFICATE" "$work/internal_guard.ko"
if [[ "$(modinfo -F signer "$work/internal_guard.ko")" != "$EXPECTED_SIGNER" ]]; then
echo "internal_guard: signer verification failed for $kernel" >&2
exit 1
fi
install -d -m 0755 "$destination"
install -m 0644 "$work/internal_guard.ko" "$module"
depmod "$kernel"
printf '%sn' "$source_hash" >"$state"
echo "internal_guard: installed signed module for $kernel"
done
EOF
sudo chown root:root /usr/local/sbin/rebuild-internal-guard
sudo chmod 0750 /usr/local/sbin/rebuild-internal-guard
sudo /usr/local/sbin/rebuild-internal-guard
Exemplu de rezultat:
internal_guard: installed signed module for 6.8.0-xx-generic
sign-file atașează semnătura la modul după compilare; orice modificare ulterioară a fișierului invalidează semnătura. depmod reconstruiește dependențele și permite găsirea modulului prin nume.
Punct de control: înainte să încarci modulul, modinfo -F signer internal_guard trebuie să afișeze exact Internal Kernel Module Signing.
Pasul 5 — Încărcăm modulul printr-un serviciu controlat
Fișierul /etc/systemd/system/internal-guard.service:
[Unit]
Description=Load the signed internal_guard kernel module
After=systemd-modules-load.service
Requires=internal-guard-build.service
[Service]
Type=oneshot
ExecStart=/sbin/modprobe internal_guard
ExecStop=/sbin/modprobe --remove internal_guard
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Creează întâi serviciul de construire, /etc/systemd/system/internal-guard-build.service:
[Unit]
Description=Build and sign internal_guard for installed kernels
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/rebuild-internal-guard
PrivateTmp=yes
PrivateDevices=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=/lib/modules /var/lib/internal-guard /run/lock
NoNewPrivileges=yes
Instalează cele două unități:
sudo tee /etc/systemd/system/internal-guard-build.service >/dev/null <<'EOF'
[Unit]
Description=Build and sign internal_guard for installed kernels
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/rebuild-internal-guard
PrivateTmp=yes
PrivateDevices=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=/lib/modules /var/lib/internal-guard /run/lock
NoNewPrivileges=yes
EOF
sudo tee /etc/systemd/system/internal-guard.service >/dev/null <<'EOF'
[Unit]
Description=Load the signed internal_guard kernel module
After=systemd-modules-load.service
Requires=internal-guard-build.service
[Service]
Type=oneshot
ExecStart=/sbin/modprobe internal_guard
ExecStop=/sbin/modprobe --remove internal_guard
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now internal-guard.service
Exemplu de rezultat:
Created symlink .../multi-user.target.wants/internal-guard.service → .../internal-guard.service.
Verifică parametrul și jurnalul:
cat /sys/module/internal_guard/parameters/build_label
sudo journalctl -k --grep='internal_guard:' --no-pager
Exemplu de output:
internal-office-module
kernel: internal_guard: loaded label=internal-office-module
Punct de control: dacă modprobe eșuează, nu dezactiva Secure Boot. Verifică semnatarul, înscrierea MOK și mesajul exact din jurnal.
Pasul 6 — Reconstruim automat înaintea următoarei porniri
Timerul rulează după pornire și apoi periodic. Astfel, un kernel instalat împreună cu antetele sale primește modulul semnat înainte de o repornire planificată.
Fișierul /etc/systemd/system/internal-guard-build.timer:
[Unit]
Description=Periodically build signed internal_guard modules
[Timer]
OnBootSec=5min
OnUnitActiveSec=6h
Persistent=true
Unit=internal-guard-build.service
[Install]
WantedBy=timers.target
Instalează și pornește timerul:
sudo tee /etc/systemd/system/internal-guard-build.timer >/dev/null <<'EOF'
[Unit]
Description=Periodically build signed internal_guard modules
[Timer]
OnBootSec=5min
OnUnitActiveSec=6h
Persistent=true
Unit=internal-guard-build.service
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now internal-guard-build.timer
systemctl list-timers internal-guard-build.timer
Exemplu de rezultat, unde orele diferă:
NEXT LEFT LAST PASSED UNIT
... ... ... ... internal-guard-build.timer
Timerul nu înlocuiește administrarea actualizărilor. Pentru sistemele care primesc patch-uri fără intervenție zilnică, vezi și configurarea actualizărilor automate de securitate pe Ubuntu Server.
Punct de control: după instalarea unui kernel nou, pornește manual sudo systemctl start internal-guard-build.service înainte de repornire și confirmă existența modulului în directorul acelui kernel.
Pasul 7 — Alertăm prin jurnal când lanțul de încredere se rupe
Fișierul /usr/local/sbin/check-internal-guard:
#!/usr/bin/env bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
export LC_ALL=C
readonly CERTIFICATE=/etc/secureboot/keys/internal-modules.der
readonly EXPECTED_SIGNER='Internal Kernel Module Signing'
fail()
{
echo "internal_guard check failed: $*" >&2
exit 1
}
[[ "$(mokutil --sb-state)" == 'SecureBoot enabled' ]] ||
fail 'Secure Boot is not enabled'
mokutil --test-key "$CERTIFICATE" >/dev/null 2>&1 ||
fail 'the module-signing certificate is not enrolled'
[[ -d /sys/module/internal_guard ]] ||
fail 'the module is not loaded'
signer="$(modinfo -F signer internal_guard)"
[[ "$signer" == "$EXPECTED_SIGNER" ]] ||
fail "unexpected signer: $signer"
label="$(cat /sys/module/internal_guard/parameters/build_label)"
[[ "$label" == 'internal-office-module' ]] ||
fail "unexpected build label: $label"
echo "internal_guard check passed: Secure Boot enabled; MOK enrolled; signer=$signer"
Unitatea /etc/systemd/system/internal-guard-check.service:
[Unit]
Description=Verify the internal_guard Secure Boot chain
After=internal-guard.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/check-internal-guard
Timerul /etc/systemd/system/internal-guard-check.timer:
[Unit]
Description=Periodically verify the internal_guard trust chain
[Timer]
OnBootSec=10min
OnUnitActiveSec=1h
Persistent=true
Unit=internal-guard-check.service
[Install]
WantedBy=timers.target
Instalează componentele și rulează primul control:
sudo tee /usr/local/sbin/check-internal-guard >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
export LC_ALL=C
readonly CERTIFICATE=/etc/secureboot/keys/internal-modules.der
readonly EXPECTED_SIGNER='Internal Kernel Module Signing'
fail()
{
echo "internal_guard check failed: $*" >&2
exit 1
}
[[ "$(mokutil --sb-state)" == 'SecureBoot enabled' ]] ||
fail 'Secure Boot is not enabled'
mokutil --test-key "$CERTIFICATE" >/dev/null 2>&1 ||
fail 'the module-signing certificate is not enrolled'
[[ -d /sys/module/internal_guard ]] ||
fail 'the module is not loaded'
signer="$(modinfo -F signer internal_guard)"
[[ "$signer" == "$EXPECTED_SIGNER" ]] ||
fail "unexpected signer: $signer"
label="$(cat /sys/module/internal_guard/parameters/build_label)"
[[ "$label" == 'internal-office-module' ]] ||
fail "unexpected build label: $label"
echo "internal_guard check passed: Secure Boot enabled; MOK enrolled; signer=$signer"
EOF
sudo chmod 0750 /usr/local/sbin/check-internal-guard
sudo chown root:root /usr/local/sbin/check-internal-guard
sudo tee /etc/systemd/system/internal-guard-check.service >/dev/null <<'EOF'
[Unit]
Description=Verify the internal_guard Secure Boot chain
After=internal-guard.service
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/check-internal-guard
EOF
sudo tee /etc/systemd/system/internal-guard-check.timer >/dev/null <<'EOF'
[Unit]
Description=Periodically verify the internal_guard trust chain
[Timer]
OnBootSec=10min
OnUnitActiveSec=1h
Persistent=true
Unit=internal-guard-check.service
[Install]
WantedBy=timers.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now internal-guard-check.timer
sudo systemctl start internal-guard-check.service
sudo journalctl -u internal-guard-check.service -n 10 --no-pager
Exemplu de rezultat:
internal_guard check passed: Secure Boot enabled; MOK enrolled; signer=Internal Kernel Module Signing
O execuție eșuată lasă serviciul în starea failed și mesajul exact în journal. Integrarea cu un sistem central de monitorizare trebuie să urmărească starea unității internal-guard-check.service; tutorialul nu presupune existența unei platforme externe.
Punct de control: systemctl is-failed internal-guard-check.service nu trebuie să returneze failed.
Proba cap-coadă confirmă certificatul, semnătura și încărcarea
Rulează testul final după ce toate unitățile sunt instalate:
set -euo pipefail
mokutil --sb-state
sudo mokutil --test-key /etc/secureboot/keys/internal-modules.der
modinfo -F filename internal_guard
modinfo -F signer internal_guard
modinfo -F sig_hashalgo internal_guard
test -d /sys/module/internal_guard
cat /sys/module/internal_guard/parameters/build_label
sudo systemctl start internal-guard-check.service
systemctl is-active internal-guard.service
systemctl is-active internal-guard-build.timer
systemctl is-active internal-guard-check.timer
Rezultatul așteptat, cu versiunea kernelului dependentă de sistem, este:
SecureBoot enabled
/etc/secureboot/keys/internal-modules.der is already enrolled
/lib/modules/6.8.0-xx-generic/updates/internal/internal_guard.ko
Internal Kernel Module Signing
sha256
internal-office-module
active
active
active
Repornirea este testul operațional final:
sudo systemctl reboot
După revenire:
mokutil --sb-state
systemctl status internal-guard.service --no-pager
sudo /usr/local/sbin/check-internal-guard
sudo journalctl -b -k --grep='internal_guard:' --no-pager
Modulul trebuie să fie încărcat automat și validat de același certificat. Dacă serverul este administrat de mai multe persoane, limitează separat cine se poate conecta și de unde; ghidul despre restricționarea accesului SSH la utilizatori sau IP-uri aprobate completează protecția cheii de semnare.
Mesajele care separă o cheie neînscrisă de un ABI nepotrivit
modprobe: ERROR: could not insert 'internal_guard': Key was rejected by service
Kernelul nu are încredere în cheia care a semnat modulul sau fișierul a fost modificat după semnare.
sudo mokutil --test-key /etc/secureboot/keys/internal-modules.der
modinfo -F signer internal_guard
sudo journalctl -k -n 50 --no-pager
Dacă cheia nu este înscrisă, repetă importul și confirmarea din MokManager. Dacă semnatarul este gol sau diferit, reconstruiește:
sudo rm -f "/var/lib/internal-guard/state/$(uname -r).sha256"
sudo /usr/local/sbin/rebuild-internal-guard
modprobe: ERROR: could not insert 'internal_guard': Invalid module format
Modulul a fost construit pentru alt kernel sau cu antete nepotrivite. Compară câmpul vermagic:
uname -r
modinfo -F vermagic internal_guard
Elimină construcția curentă și reconstruiește pentru kernelul pornit:
sudo rm -rf "/var/lib/internal-guard/build/$(uname -r)"
sudo rm -f "/var/lib/internal-guard/state/$(uname -r).sha256"
sudo /usr/local/sbin/rebuild-internal-guard
sudo depmod "$(uname -r)"
make: *** /lib/modules/<kernel>/build: No such file or directory
Lipsesc antetele care corespund exact kernelului țintă:
sudo apt-get install --yes "linux-headers-$(uname -r)"
sudo /usr/local/sbin/rebuild-internal-guard
Pentru un kernel instalat, dar încă nepornit, folosește versiunea exactă din /lib/modules, nu rezultatul uname -r.
SSL error: ... sau sign-file: ... No such file or directory
sign-file nu poate citi cheia, certificatul sau scriptul furnizat de antetele kernelului. Verifică fără a afișa conținutul secret:
sudo test -r /etc/secureboot/keys/internal-modules.key
sudo test -r /etc/secureboot/keys/internal-modules.der
sudo test -x "/lib/modules/$(uname -r)/build/scripts/sign-file"
sudo openssl x509
-inform DER
-in /etc/secureboot/keys/internal-modules.der
-noout
-subject
Nu rezolva eroarea prin permisiuni globale pe cheia privată. Scriptul de construire trebuie să ruleze ca root.
internal_guard: skip <kernel>; matching headers are absent
Timerul a găsit un kernel instalat fără antetele lui. Identifică versiunea din mesaj și instalează pachetul corespunzător:
kernel='<versiunea-exactă-din-mesaj>'
sudo apt-get install --yes "linux-headers-$kernel"
sudo systemctl start internal-guard-build.service
Valoarea dintre ghilimele este versiunea exactă raportată local, nu un șablon care trebuie executat neschimbat.
internal_guard check failed: the module is not loaded
Certificatul poate fi corect, dar serviciul de încărcare nu a pornit sau modprobe a eșuat:
sudo systemctl restart internal-guard.service
sudo systemctl status internal-guard.service --no-pager
sudo journalctl -u internal-guard.service -b --no-pager
Nu masca problema modificând scriptul de control. Mesajul produs de modprobe indică dacă lipsește modulul, semnătura este respinsă sau ABI-ul nu corespunde.
Eliminăm modulul fără să dezactivăm protecția platformei
Oprirea proiectului nu necesită dezactivarea Secure Boot. Dezactivează timerele și serviciul, apoi șterge numai fișierele create aici:
sudo systemctl disable --now internal-guard-check.timer
sudo systemctl disable --now internal-guard-build.timer
sudo systemctl disable --now internal-guard.service
sudo rm -f
/etc/systemd/system/internal-guard.service
/etc/systemd/system/internal-guard-build.service
/etc/systemd/system/internal-guard-build.timer
/etc/systemd/system/internal-guard-check.service
/etc/systemd/system/internal-guard-check.timer
/usr/local/sbin/rebuild-internal-guard
/usr/local/sbin/check-internal-guard
for kernel_dir in /lib/modules/*; do
sudo rm -f "$kernel_dir/updates/internal/internal_guard.ko"
sudo depmod "$(basename "$kernel_dir")"
done
sudo rm -rf
/usr/local/src/internal_guard
/var/lib/internal-guard
sudo systemctl daemon-reload
sudo systemctl reset-failed
Păstrează cheia dacă alte module interne sunt semnate cu ea. Dacă această cheie nu mai trebuie să autorizeze niciun modul, solicită ștergerea certificatului din MOK:
sudo mokutil --delete /etc/secureboot/keys/internal-modules.der
sudo mokutil --list-delete
sudo systemctl reboot
Finalizează ștergerea din MokManager folosind parola temporară. Confirmă apoi că testul cheii nu o mai găsește. Abia după eliminarea certificatului și după ce ai verificat că nu mai există module dependente șterge perechea de chei:
sudo rm -f
/etc/secureboot/keys/internal-modules.key
/etc/secureboot/keys/internal-modules.der
sudo rmdir /etc/secureboot/keys 2>/dev/null || true
sudo rmdir /etc/secureboot 2>/dev/null || true
Dacă ai creat copiile .bak.<dată>, restaurează numai fișierele care existau anterior și verifică manual conținutul înainte de repornire.
Lista de control pentru serverul care va intra în exploatare
- ☐ Sistemul pornește în UEFI, iar
mokutil --sb-stateraporteazăSecureBoot enabled. - ☐ Certificatul MOK are subiectul
Internal Kernel Module Signing. - ☐ Cheia privată este deținută de
rootși are permisiuni600. - ☐
mokutil --test-keyconfirmă înscrierea certificatului. - ☐
modinfo -F signer internal_guardindică semnatarul așteptat. - ☐
modinfo -F sig_hashalgo internal_guardindicăsha256. - ☐ Modulul încărcat publică eticheta
internal-office-module. - ☐ Timerul de construire este activ și găsește antetele kernelurilor instalate.
- ☐ Timerul de control este activ, iar ultima execuție nu este
failed. - ☐ Modulul se încarcă după o repornire fără dezactivarea Secure Boot.
Următorul pas practic este mutarea cheii de semnare într-un proces de administrare separat, cu backup offline și acces auditat. Pentru mai multe module interne, păstrează aceeași infrastructură, dar construiește fiecare sursă într-un director propriu și validează explicit numele semnatarului înainte de instalare. Pentru module dezvoltate direct în arborele kernelului, proiectul despre construirea unui modul Rust oficial pentru Linux oferă contextul separat al toolchain-ului kernel.
Întrebări frecvente
Acest tutorial înlocuiește cheile PK, KEK și db din firmware?
Nu. Este folosită o cheie MOK proprie, acceptată prin shim pentru semnarea modulelor kernel. Cheile platformei UEFI rămân neschimbate.
De ce cheia privată nu are parolă?
Scriptul trebuie să poată semna automat modulele după instalarea unui kernel. Cheia este protejată prin proprietarul root, permisiuni 600 și un director cu permisiuni 700.
Modulul trebuie semnat din nou după fiecare actualizare de kernel?
Da, modulul trebuie construit pentru ABI-ul kernelului țintă și apoi semnat. Serviciul și timerul din proiect automatizează această operațiune pentru kernelurile care au antetele instalate.
Pot finaliza înscrierea MOK numai prin SSH?
Nu. Confirmarea are loc în MokManager la următoarea pornire, înaintea sistemului de operare, motiv pentru care este necesar acces la consola fizică sau virtuală.

















































