Merge pull request 'remove secureboot' (#66) from remove-secureboot into main

Reviewed-on: #66
This commit is contained in:
Charlotte 🦝 Delenk 2023-05-25 08:08:36 +00:00
commit 5129914578
Signed by: gitea-bot
GPG key ID: C9974EDF9932B558
9 changed files with 4 additions and 878 deletions

View file

@ -14,7 +14,6 @@
./systemd-boot.nix
./desktop.nix
./services/tpm2.nix
./secureboot.nix
nixos-hardware.nixosModules.common-cpu-amd
nixos-hardware.nixosModules.common-gpu-amd
nixos-hardware.nixosModules.common-pc-ssd

View file

@ -1,23 +0,0 @@
{
pkgs,
config,
...
}: {
imports = [
../modules/systemd-secure-boot
# ../modules/systemd-cryptsetup.nix # broken
];
sops.secrets."secureboot/DB.key" = {};
boot.loader.systemd-boot = {
editor = false;
secureBoot = {
enable = true;
keyPath = config.sops.secrets."secureboot/DB.key".path;
certPath = builtins.toString ../efi/DB.crt;
};
};
system.extraSystemBuilderCmds = ''
substituteAll ${../extra/switch-to-configuration.pl} $out/bin/switch-to-configuration
'';
}

View file

@ -1,5 +1,4 @@
_: {
boot.loader.systemd-boot.enable = true;
boot.loader.systemd-boot.configurationLimit = 5;
boot.loader.efi.canTouchEfiVariables = true;
}

View file

@ -1,330 +0,0 @@
{
config,
lib,
pkgs,
system,
nixpkgs-systemd-249,
...
}:
with lib; let
inherit (nixpkgs-systemd-249.legacyPackages.${system}) systemd;
inherit (config.boot.initrd) luks;
inherit (config.boot) kernelPackages;
commonFunctions = ''
die() {
echo "$@" >&2
exit 1
}
dev_exist() {
local target="$1"
if [ -e $target ]; then
return 0
else
local uuid=$(echo -n $target | sed -e 's,UUID=\(.*\),\1,g')
blkid --uuid $uuid >/dev/null
return $?
fi
}
wait_target() {
local name="$1"
local target="$2"
local secs="''${3:-10}"
local desc="''${4:-$name $target to appear}"
if ! dev_exist $target; then
echo -n "Waiting $secs seconds for $desc..."
local success=false;
for try in $(seq $secs); do
echo -n "."
sleep 1
if dev_exist $target; then
success=true
break
fi
done
if [ $success == true ]; then
echo " - success";
return 0
else
echo " - failure";
return 1
fi
fi
return 0
}
'';
preCommands = ''
# A place to store crypto things
# A ramfs is used here to ensure that the file used to update
# the key slot with cryptsetup will never get swapped out.
# Warning: Do NOT replace with tmpfs!
mkdir -p /crypt-ramfs
mount -t ramfs none /crypt-ramfs
# Cryptsetup locking directory
mkdir -p /run/cryptsetup
# Disable all input echo for the whole stage. We could use read -s
# instead but that would ocasionally leak characters between read
# invocations.
stty -echo
'';
postCommands = ''
stty echo
umount /crypt-storage 2>/dev/null
umount /crypt-ramfs 2>/dev/null
'';
openCommand = name: dev:
assert name == dev.name; let
csopen =
"systemd-cryptsetup attach ${dev.name} ${dev.device} \"\" tpm2-device=/dev/tpmrm0"
+ optionalString dev.allowDiscards ",discard"
+ optionalString dev.bypassWorkqueues ",no-read-workqueue,no-write-workqueue"
+ optionalString (dev.header != null) ",header=${dev.header}";
in ''
# Wait for luksRoot (and optionally keyFile and/or header) to appear, e.g.
# if on a USB drive.
wait_target "device" ${dev.device} || die "${dev.device} is unavailable"
${optionalString (dev.header != null) ''
wait_target "header" ${dev.header} || die "${dev.header} is unavailable"
''}
# commands to run right before we mount our device
${dev.preOpenCommands}
mkdir -pv ${pkgs.tpm2-tss}
ln -svf /lib ${pkgs.tpm2-tss}
${csopen}
# commands to run right after we mounted our device
${dev.postOpenCommands}
'';
askPass = pkgs.writeScriptBin "cryptsetup-askpass" ''
#!/bin/sh
${commonFunctions}
while true; do
wait_target "luks" /crypt-ramfs/device 10 "LUKS to request a passphrase" || die "Passphrase is not requested now"
device=$(cat /crypt-ramfs/device)
echo -n "Passphrase for $device: "
IFS= read -rs passphrase
echo
rm /crypt-ramfs/device
echo -n "$passphrase" > /crypt-ramfs/passphrase
done
'';
preLVM = filterAttrs (n: v: v.preLVM) luks.devices;
postLVM = filterAttrs (n: v: !v.preLVM) luks.devices;
in {
imports = [
(mkRemovedOptionModule ["boot" "initrd" "luks" "enable"] "")
];
options = {
boot.initrd.luks.mitigateDMAAttacks = mkOption {
type = types.bool;
default = true;
description = ''
Unless enabled, encryption keys can be easily recovered by an attacker with physical
access to any machine with PCMCIA, ExpressCard, ThunderBolt or FireWire port.
More information is available at <link xlink:href="http://en.wikipedia.org/wiki/DMA_attack"/>.
This option blacklists FireWire drivers, but doesn't remove them. You can manually
load the drivers if you need to use a FireWire device, but don't forget to unload them!
'';
};
boot.initrd.luks.cryptoModules = mkOption {
type = types.listOf types.str;
default = [
"aes"
"aes_generic"
"blowfish"
"twofish"
"serpent"
"cbc"
"xts"
"lrw"
"sha1"
"sha256"
"sha512"
"af_alg"
"algif_skcipher"
];
description = ''
A list of cryptographic kernel modules needed to decrypt the root device(s).
The default includes all common modules.
'';
};
boot.initrd.luks.forceLuksSupportInInitrd = mkOption {
type = types.bool;
default = false;
internal = true;
description = ''
Whether to configure luks support in the initrd, when no luks
devices are configured.
'';
};
boot.initrd.luks.devices = mkOption {
default = {};
example = {luksroot.device = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08";};
description = ''
The encrypted disk that should be opened before the root
filesystem is mounted. Both LVM-over-LUKS and LUKS-over-LVM
setups are supported. The unencrypted devices can be accessed as
<filename>/dev/mapper/<replaceable>name</replaceable></filename>.
'';
type = with types;
attrsOf (submodule (
{name, ...}: {
options = {
name = mkOption {
visible = false;
default = name;
example = "luksroot";
type = types.str;
description = "Name of the unencrypted device in <filename>/dev/mapper</filename>.";
};
device = mkOption {
example = "/dev/disk/by-uuid/430e9eff-d852-4f68-aa3b-2fa3599ebe08";
type = types.str;
description = "Path of the underlying encrypted block device.";
};
header = mkOption {
default = null;
example = "/root/header.img";
type = types.nullOr types.str;
description = ''
The name of the file or block device that
should be used as header for the encrypted device.
'';
};
# FIXME: get rid of this option.
preLVM = mkOption {
default = true;
type = types.bool;
description = "Whether the luksOpen will be attempted before LVM scan or after it.";
};
allowDiscards = mkOption {
default = false;
type = types.bool;
description = ''
Whether to allow TRIM requests to the underlying device. This option
has security implications; please read the LUKS documentation before
activating it.
This option is incompatible with authenticated encryption (dm-crypt
stacked over dm-integrity).
'';
};
bypassWorkqueues = mkOption {
default = false;
type = types.bool;
description = ''
Whether to bypass dm-crypt's internal read and write workqueues.
Enabling this should improve performance on SSDs; see
<link xlink:href="https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance">here</link>
for more information. Needs Linux 5.9 or later.
'';
};
preOpenCommands = mkOption {
type = types.lines;
default = "";
example = ''
mkdir -p /tmp/persistent
mount -t zfs rpool/safe/persistent /tmp/persistent
'';
description = ''
Commands that should be run right before we try to mount our LUKS device.
This can be useful, if the keys needed to open the drive is on another partion.
'';
};
postOpenCommands = mkOption {
type = types.lines;
default = "";
example = ''
umount /tmp/persistent
'';
description = ''
Commands that should be run right after we have mounted our LUKS device.
'';
};
};
}
));
};
};
disabledModules = ["system/boot/luksroot.nix"];
config = mkIf (luks.devices != {} || luks.forceLuksSupportInInitrd) {
assertions = [
{
assertion =
any (dev: dev.bypassWorkqueues) (attrValues luks.devices)
-> versionAtLeast kernelPackages.kernel.version "5.9";
message = "boot.initrd.luks.devices.<name>.bypassWorkqueues is not supported for kernels older than 5.9";
}
];
boot.initrd.kernelModules = ["tpm"];
# actually, sbp2 driver is the one enabling the DMA attack, but this needs to be tested
boot.blacklistedKernelModules =
optionals luks.mitigateDMAAttacks
["firewire_ohci" "firewire_core" "firewire_sbp2"];
# Some modules that may be needed for mounting anything ciphered
boot.initrd.availableKernelModules =
["dm_mod" "dm_crypt" "cryptd" "input_leds"]
++ luks.cryptoModules
# workaround until https://marc.info/?l=linux-crypto-vger&m=148783562211457&w=4 is merged
# remove once 'modprobe --show-depends xts' shows ecb as a dependency
++ (
if builtins.elem "xts" luks.cryptoModules
then ["ecb"]
else []
);
# copy the cryptsetup binary and it's dependencies
boot.initrd.extraUtilsCommands = ''
copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup
copy_bin_and_libs ${askPass}/bin/cryptsetup-askpass
sed -i s,/bin/sh,$out/bin/sh, $out/bin/cryptsetup-askpass
copy_bin_and_libs ${systemd}/lib/systemd/systemd-cryptsetup
'';
boot.initrd.extraUtilsCommandsTest = ''
$out/bin/cryptsetup --version
$out/bin/systemd-cryptsetup
'';
boot.initrd.preFailCommands = postCommands;
boot.initrd.preLVMCommands = commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand preLVM) + postCommands;
boot.initrd.postDeviceCommands = commonFunctions + preCommands + concatStrings (mapAttrsToList openCommand postLVM) + postCommands;
environment.systemPackages = [pkgs.cryptsetup];
};
}

View file

@ -1,3 +0,0 @@
# Systemd Secure Boot
Taken from https://github.com/frogamic/nix-machines/tree/main/modules/systemd-secure-boot

View file

@ -1,212 +0,0 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.boot.loader.systemd-boot;
inherit (config.boot.loader) efi;
systemdBootBuilder = pkgs.substituteAll {
src = ./systemd-boot-builder.py;
isExecutable = true;
inherit (pkgs) python3 sbsigntool;
binutils = pkgs.binutils-unwrapped;
systemd = config.systemd.package;
nix = config.nix.package.out;
timeout =
if config.boot.loader.timeout != null
then config.boot.loader.timeout
else "";
editor =
if cfg.editor
then "True"
else "False";
configurationLimit =
if cfg.configurationLimit == null
then 0
else cfg.configurationLimit;
inherit (cfg) consoleMode;
inherit (cfg.secureBoot) keyPath certPath;
secureBootEnable = cfg.secureBoot.enable;
inherit (efi) efiSysMountPoint canTouchEfiVariables;
memtest86 =
if cfg.memtest86.enable
then pkgs.memtest86-efi
else "";
};
checkedSystemdBootBuilder =
pkgs.runCommand "systemd-boot"
{
nativeBuildInputs = [pkgs.mypy];
} ''
install -m755 ${systemdBootBuilder} $out
mypy \
--no-implicit-optional \
--disallow-untyped-calls \
--disallow-untyped-defs \
$out
'';
in {
disabledModules = ["system/boot/loader/systemd-boot/systemd-boot.nix"];
imports = [
(mkRenamedOptionModule ["boot" "loader" "gummiboot" "enable"] ["boot" "loader" "systemd-boot" "enable"])
];
options.boot.loader.systemd-boot = {
enable = mkOption {
default = false;
type = types.bool;
description = "Whether to enable the systemd-boot (formerly gummiboot) EFI boot manager";
};
editor = mkOption {
default = true;
type = types.bool;
description = ''
Whether to allow editing the kernel command-line before
boot. It is recommended to set this to false, as it allows
gaining root access by passing init=/bin/sh as a kernel
parameter. However, it is enabled by default for backwards
compatibility.
'';
};
configurationLimit = mkOption {
default = null;
example = 120;
type = types.nullOr types.int;
description = ''
Maximum number of latest generations in the boot menu.
Useful to prevent boot partition running out of disk space.
<literal>null</literal> means no limit i.e. all generations
that were not garbage collected yet.
'';
};
consoleMode = mkOption {
default = "keep";
type = types.enum ["0" "1" "2" "auto" "max" "keep"];
description = ''
The resolution of the console. The following values are valid:
<itemizedlist>
<listitem><para>
<literal>"0"</literal>: Standard UEFI 80x25 mode
</para></listitem>
<listitem><para>
<literal>"1"</literal>: 80x50 mode, not supported by all devices
</para></listitem>
<listitem><para>
<literal>"2"</literal>: The first non-standard mode provided by the device firmware, if any
</para></listitem>
<listitem><para>
<literal>"auto"</literal>: Pick a suitable mode automatically using heuristics
</para></listitem>
<listitem><para>
<literal>"max"</literal>: Pick the highest-numbered available mode
</para></listitem>
<listitem><para>
<literal>"keep"</literal>: Keep the mode selected by firmware (the default)
</para></listitem>
</itemizedlist>
'';
};
memtest86 = {
enable = mkOption {
default = false;
type = types.bool;
description = ''
Make MemTest86 available from the systemd-boot menu. MemTest86 is a
program for testing memory. MemTest86 is an unfree program, so
this requires <literal>allowUnfree</literal> to be set to
<literal>true</literal>.
'';
};
};
secureBoot = {
enable = mkOption {
default = false;
type = types.bool;
description = "Whether to enable secureboot for systemd-boot";
};
keyPath = mkOption {
default = null;
type = types.nullOr types.str;
description = "Path to the secureboot signing key";
};
certPath = mkOption {
default = null;
type = types.nullOr types.str;
description = "Path to the secureboot signing certificate";
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = !(cfg.secureBoot.enable && (cfg.secureBoot.keyPath == null));
message = "The secureboot signing key must be provided";
}
{
assertion = !(cfg.secureBoot.enable && (cfg.secureBoot.certPath == null));
message = "The secureboot signing certificate must be provided";
}
{
assertion = (config.boot.kernelPackages.kernel.features or {efiBootStub = true;}) ? efiBootStub;
message = "This kernel does not support the EFI boot stub";
}
];
boot.loader.grub.enable = mkDefault false;
boot.loader.supportsInitrdSecrets = true;
system = {
build.installBootLoader = checkedSystemdBootBuilder;
boot.loader.id = "systemd-boot";
requiredKernelConfig = with config.lib.kernelConfig; [
(isYes "EFI_STUB")
];
};
};
}

View file

@ -1,300 +0,0 @@
#! @python3@/bin/python3 -B
import argparse
import shutil
import os
import sys
import errno
import subprocess
import glob
import tempfile
import errno
import warnings
import ctypes
libc = ctypes.CDLL("libc.so.6")
import re
import datetime
import glob
import os.path
from typing import Tuple, List, Optional, Callable
def install_signed_if_required(source: Callable[[], str], dest: str) -> None:
if "@secureBootEnable@" == "1":
try:
subprocess.check_call(
["@sbsigntool@/bin/sbverify", "--cert=@certPath@", dest],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError:
subprocess.check_call([
"@sbsigntool@/bin/sbsign",
"--key=@keyPath@",
"--cert=@certPath@",
"--output=%s.tmp" % (dest),
source()],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
os.rename("%s.tmp" % (dest), dest)
elif not os.path.exists(dest):
shutil.copy(source(), dest)
def efi_section(name: str, path: str, vma: str) -> List[str]:
return [
"--add-section",
".%s=%s" % (name, path),
"--change-section-vma",
".%s=%s" % (name, vma)]
def system_dir(profile: Optional[str], generation: int) -> str:
if profile:
return "/nix/var/nix/profiles/system-profiles/%s-%d-link" % (profile, generation)
else:
return "/nix/var/nix/profiles/system-%d-link" % (generation)
# The boot loader entry for memtest86.
#
# TODO: This is hard-coded to use the 64-bit EFI app, but it could probably
# be updated to use the 32-bit EFI app on 32-bit systems. The 32-bit EFI
# app filename is BOOTIA32.efi.
MEMTEST_BOOT_ENTRY = """title MemTest86
efi /efi/memtest86/BOOTX64.efi
"""
def write_loader_conf(profile: Optional[str], generation: int) -> None:
with open("@efiSysMountPoint@/loader/loader.conf.tmp", 'w') as f:
if "@timeout@" != "":
f.write("timeout @timeout@\n")
if profile:
f.write("default nixos-%s-generation-%d.efi\n" % (profile, generation))
else:
f.write("default nixos-generation-%d.efi\n" % (generation))
if not @editor@:
f.write("editor 0\n");
f.write("console-mode @consoleMode@\n");
os.rename("@efiSysMountPoint@/loader/loader.conf.tmp", "@efiSysMountPoint@/loader/loader.conf")
def profile_path(profile: Optional[str], generation: int, name: str) -> str:
return os.path.realpath("%s/%s" % (system_dir(profile, generation), name))
def path_from_profile(profile: Optional[str], generation: int, name: str) -> str:
store_file_path = profile_path(profile, generation, name)
suffix = os.path.basename(store_file_path)
store_dir = os.path.basename(os.path.dirname(store_file_path))
efi_file_path = "/efi/nixos/%s-%s.efi" % (store_dir, suffix)
return efi_file_path
def describe_generation(generation_dir: str) -> str:
try:
with open("%s/nixos-version" % generation_dir) as f:
nixos_version = f.read()
except IOError:
nixos_version = "Unknown"
kernel_dir = os.path.dirname(os.path.realpath("%s/kernel" % generation_dir))
module_dir = glob.glob("%s/lib/modules/*" % kernel_dir)[0]
kernel_version = os.path.basename(module_dir)
build_time = int(os.path.getctime(generation_dir))
build_date = datetime.datetime.fromtimestamp(build_time).strftime('%F')
description = "NixOS {}, Linux Kernel {}, Built on {}".format(
nixos_version, kernel_version, build_date
)
return description
def write_entry(profile: Optional[str], generation: int) -> None:
if profile:
entry_file = "@efiSysMountPoint@/EFI/Linux/nixos-%s-generation-%d.efi" % (profile, generation)
else:
entry_file = "@efiSysMountPoint@/EFI/Linux/nixos-generation-%d.efi" % (generation)
with tempfile.TemporaryDirectory() as tmpdir:
def make_unified_kernel() -> str:
kernel = profile_path(profile, generation, "kernel")
initrd = profile_path(profile, generation, "initrd")
osrel = profile_path(profile, generation, "etc/os-release")
cmdline = "%s/cmdline" % (tmpdir)
efistub = profile_path(profile, generation, "sw/lib/systemd/boot/efi/linuxx64.efi.stub")
if not os.path.exists(efistub):
efistub = "@systemd@lib/systemd/boot/efi/linuxx64.efi.stub"
try:
append_initrd_secrets = profile_path(profile, generation, "append-initrd-secrets")
subprocess.check_call([append_initrd_secrets, initrd])
except FileNotFoundError:
pass
generation_dir = os.readlink(system_dir(profile, generation))
kernel_params = "init=%s/init " % generation_dir
with open("%s/kernel-params" % (generation_dir)) as params_file:
kernel_params = kernel_params + params_file.read()
with open(cmdline, 'w') as f:
f.write(kernel_params)
subprocess.check_call([
"@binutils@/bin/objcopy",
*efi_section("osrel", osrel, "0x20000"),
*efi_section("cmdline", cmdline, "0x30000"),
*efi_section("linux", kernel, "0x40000"),
*efi_section("initrd", initrd, "0x3000000"),
efistub,
"%s/unified.efi" % (tmpdir)])
return "%s/unified.efi" % (tmpdir)
install_signed_if_required(make_unified_kernel, entry_file)
def mkdir_p(path: str) -> None:
try:
os.makedirs(path)
except OSError as e:
if e.errno != errno.EEXIST or not os.path.isdir(path):
raise
def get_generations(profile: Optional[str] = None) -> List[Tuple[Optional[str], int]]:
gen_list = subprocess.check_output([
"@nix@/bin/nix-env",
"--list-generations",
"-p",
"/nix/var/nix/profiles/%s" % ("system-profiles/" + profile if profile else "system"),
"--option", "build-users-group", ""],
universal_newlines=True)
gen_lines = gen_list.split('\n')
gen_lines.pop()
configurationLimit = @configurationLimit@
return [ (profile, int(line.split()[0])) for line in gen_lines ][-configurationLimit:]
def remove_old_entries(gens: List[Tuple[Optional[str], int]]) -> None:
rex_profile = re.compile("^@efiSysMountPoint@/EFI/Linux/nixos-(.*)-generation-.*\.efi$")
rex_generation = re.compile("^@efiSysMountPoint@/EFI/Linux/nixos.*-generation-(.*)\.efi$")
known_paths = []
for gen in gens:
known_paths.append(path_from_profile(*gen, "kernel"))
known_paths.append(path_from_profile(*gen, "initrd"))
for path in glob.iglob("@efiSysMountPoint@/EFI/Linux/nixos*-generation-[1-9]*.efi"):
try:
if rex_profile.match(path):
prof = rex_profile.sub(r"\1", path)
else:
prof = "system"
gen_number = int(rex_generation.sub(r"\1", path))
if not (prof, gen_number) in gens:
os.unlink(path)
except ValueError:
pass
for path in glob.iglob("@efiSysMountPoint@/EFI/Linux/*"):
if not path in known_paths and not os.path.isdir(path):
os.unlink(path)
def get_profiles() -> List[str]:
if os.path.isdir("/nix/var/nix/profiles/system-profiles/"):
return [x
for x in os.listdir("/nix/var/nix/profiles/system-profiles/")
if not x.endswith("-link")]
else:
return []
def main() -> None:
parser = argparse.ArgumentParser(description='Update NixOS-related systemd-boot files')
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help='The default NixOS config to boot')
args = parser.parse_args()
try:
with open("/etc/machine-id") as machine_file:
machine_id = machine_file.readlines()[0]
except IOError as e:
if e.errno != errno.ENOENT:
raise
# Since systemd version 232 a machine ID is required and it might not
# be there on newly installed systems, so let's generate one so that
# bootctl can find it and we can also pass it to write_entry() later.
cmd = ["@systemd@/bin/systemd-machine-id-setup", "--print"]
machine_id = subprocess.run(
cmd, text=True, check=True, stdout=subprocess.PIPE
).stdout.rstrip()
if os.getenv("NIXOS_INSTALL_GRUB") == "1":
warnings.warn("NIXOS_INSTALL_GRUB env var deprecated, use NIXOS_INSTALL_BOOTLOADER", DeprecationWarning)
os.environ["NIXOS_INSTALL_BOOTLOADER"] = "1"
if os.getenv("NIXOS_INSTALL_BOOTLOADER") == "1":
# bootctl uses fopen() with modes "wxe" and fails if the file exists.
if os.path.exists("@efiSysMountPoint@/loader/loader.conf"):
os.unlink("@efiSysMountPoint@/loader/loader.conf")
if "@canTouchEfiVariables@" == "1":
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"])
else:
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"])
else:
# Update bootloader to latest if needed
systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1]
sdboot_status = subprocess.check_output(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True)
# See status_binaries() in systemd bootctl.c for code which generates this
m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot ([\d.]+[^)]*)\)$",
sdboot_status, re.IGNORECASE | re.MULTILINE)
if m is None:
print("could not find any previously installed systemd-boot")
else:
sdboot_version = m.group(2)
if systemd_version > sdboot_version:
print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version))
subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"])
install_signed_if_required(lambda: "@systemd@/lib/systemd/boot/efi/systemd-bootx64.efi", "@efiSysMountPoint@/EFI/BOOT/BOOTX64.efi")
install_signed_if_required(lambda: "@systemd@/lib/systemd/boot/efi/systemd-bootx64.efi", "@efiSysMountPoint@/EFI/systemd/systemd-bootx64.efi")
mkdir_p("@efiSysMountPoint@/EFI/Linux")
mkdir_p("@efiSysMountPoint@/loader/entries")
gens = get_generations()
for profile in get_profiles():
gens += get_generations(profile)
remove_old_entries(gens)
for gen in gens:
try:
write_entry(*gen)
if os.readlink(system_dir(*gen)) == args.default_config:
write_loader_conf(*gen)
except OSError as e:
print("ignoring profile '{}' in the list of boot entries because of the following error:\n{}".format(profile, e), file=sys.stderr)
memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
if os.path.exists(memtest_entry_file):
os.unlink(memtest_entry_file)
shutil.rmtree("@efiSysMountPoint@/efi/memtest86", ignore_errors=True)
if "@memtest86@" != "":
mkdir_p("@efiSysMountPoint@/efi/memtest86")
for path in glob.iglob("@memtest86@/*"):
if os.path.isdir(path):
shutil.copytree(path, os.path.join("@efiSysMountPoint@/efi/memtest86", os.path.basename(path)))
else:
shutil.copy(path, "@efiSysMountPoint@/efi/memtest86/")
memtest_entry_file = "@efiSysMountPoint@/loader/entries/memtest86.conf"
memtest_entry_file_tmp_path = "%s.tmp" % memtest_entry_file
with open(memtest_entry_file_tmp_path, 'w') as f:
f.write(MEMTEST_BOOT_ENTRY)
os.rename(memtest_entry_file_tmp_path, memtest_entry_file)
# Since fat32 provides little recovery facilities after a crash,
# it can leave the system in an unbootable state, when a crash/outage
# happens shortly after an update. To decrease the likelihood of this
# event sync the efi filesystem after each update.
rc = libc.syncfs(os.open("@efiSysMountPoint@", os.O_RDONLY))
if rc != 0:
print("could not sync @efiSysMountPoint@: {}".format(os.strerror(rc)), file=sys.stderr)
if __name__ == '__main__':
main()

View file

@ -38,8 +38,6 @@ email:
password:
root: ENC[AES256_GCM,data:edK/dud41KmbX6v8Mxn1vVcaCwG0x4YhGjqLTw3oAigmwixTovz+4yUDrkjTQLb3/eMClqQJnjcJsRBv4chSu+UuNorKIsPM0IX9mkTmVH2soGmdPB21HXOXmisGu33oOyhyojbvlaWlFw==,iv:GiXRuhJVPgkAAp7OYufzXtHusnSPOfAP0ztdAtn14GE=,tag:nIOus2VvzE6d+r/aJOLCBw==,type:str]
darkkirb: ENC[AES256_GCM,data:vmI8B7PWeoKTwOywaGmJmD9gWb09eDcmchx241XrfNvT9QseuSElDTb3OajHornt/OFBPh7EtNi/y1BHF1+DZq0i1tmhYuJy24BLuCPH9VpCb5s5xZZCVtOC6w3qUGqIlLQHYN0Fp1Ap5A==,iv:KkcLQDJSDqeFr3gDByb66MOx8/PbpKpvM9Ym+KMB3jc=,tag:wLLOU4RhWnS+DDSOQLrLHA==,type:str]
secureboot:
DB.key: ENC[AES256_GCM,data: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,iv:mOxU05DF5Li/w80yDKM59D6quvnGl/6QdyWwszAJIOA=,tag:F1CqIiJm0kSAmVUKBO8w4A==,type:str]
sops:
kms: []
gcp_kms: []
@ -55,8 +53,8 @@ sops:
WnV3QWxtalIzWFdoQmpDTmJsNGdNOW8K++rFGXy0G6Gcu2gQwSP6xfXInQ/y5nh5
2oGp8sfOLFWnNI4SWL0ChP47K3C/9ysUHwQnUYPbRafZ/4X6cN40ZQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2023-04-18T18:46:22Z"
mac: ENC[AES256_GCM,data:io5AXt9wcCytbum4nzLAeoA+WcJwNKPMobJtEvo66efKMrk+Vow+y6aNls2YJJxnRjXq287k1BnAQdrQZdPxXBrQu3vDkt1CFyKthGnUjO4ac+me2mA843e7wZJ8HP0gGNNS6VRLeOmPbYOderQf060oyj6DSX4p+g2YTMEnCa4=,iv:6SdAGYRuxNgCrtFKo1w1eoga9oJQFS7qbG+7pi4SNKA=,tag:NUfYiC9X+ecuMtaH6L94RQ==,type:str]
lastmodified: "2023-05-25T07:33:13Z"
mac: ENC[AES256_GCM,data:L5jnCDJ1GQyJ3/Seakowpzkdp7RXlVc1OGFO+eTzRakENj4ZJR/3UCWTE9y8zzMxYocFjVSqhm983zobYmn2mA78bH9hzDTqz/rBqb7pqtkcbwmKRvbsST7t2bp08AFUJ+1zBbXteF0x9GPDuKgNXRVCgpnYNdn59mSzNl2H3XA=,iv:b/v9bgFWJEjjI21SrP145vEtZ4IVgYQmYDw0J7tdrMk=,tag:95vQA/6kJpclDQgTs6VZ/A==,type:str]
pgp:
- created_at: "2022-04-24T10:34:20Z"
enc: |

View file

@ -12,8 +12,6 @@ password:
darkkirb: ENC[AES256_GCM,data:wBaK3uue/ZRKuPm/zl1C8LiXh7wu327iPeOROhocJBLeDDzUwDHRVxi/X90hvvFhJTjZ6jR+7wexEvSE/bA1Dt2Q+Cwq0RChitBjjMcF2ZRuUObr/eP6fTZLLMWqvQR5rkQrSR4ssdynnQ==,iv:fgOXGZlwDI/Im2NOXbYp37kbNxVqdXLS5PcwMQsKFVg=,tag:TIMvyKmsGba/fVVrf9jMSQ==,type:str]
services:
woodpecker-runner: ENC[AES256_GCM,data:v7kvtZfbFATyEZ/rDnzP1EZvRKMBaXJf46xyIWu5La/hZnp7HTVxkHGw/fxMmwdwK11MAYW0dFMmUqHuKWGKCH02TwoE3UY+agOpK+ZmMKznWwgdJss+/5U=,iv:aU8WX+9/OAPQkDOnk5OUE/Xnjs6S3nUv/Dp0mTxq/8Q=,tag:+ED+PdIAOx6r5sRM3aipbw==,type:str]
secureboot:
DB.key: ENC[AES256_GCM,data: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,iv:fc/aXv6ilzKXo3GSuWYCwZld11BCOZJZvvSFYbS6wNo=,tag:rXlfw08GCsp6QEQeNY4Yyw==,type:str]
sops:
kms: []
gcp_kms: []
@ -29,8 +27,8 @@ sops:
WUpOUFNtcy9Id0NqN3ZwVzJmZW13NncKldw45j86wcwZghpPSL5frJBRAyrbh5bA
xoqHNpr4JflU9JavVDk4Q+nnVfOQIIu1McxwMzPpoCkcf6QX8BLstw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2023-04-08T08:29:12Z"
mac: ENC[AES256_GCM,data:/N30jdSBM1w45G5920vWjJWrSuFHg1NDDmpITNYzx2ghxIJ0cXMtjr0xgXKOJEeN0luz4BIHG2B3IrBC7YBlITjvtuCgsg9jc1i0xpowVCw1Yp8MZQZKjdrAXVfCi0JAkaCigkQ1ZNsJK/gPU+8+b2PhxGXjDOiSdbO89xOq2qk=,iv:856BRgnOmLTklKrtkj8h4s+Fc2s43ftQKjBElVWIBig=,tag:JdLgClllhIAsD7GcCjAsnQ==,type:str]
lastmodified: "2023-05-25T07:32:48Z"
mac: ENC[AES256_GCM,data:mDVjudo9nLPZ2tZVa2wt+MJD3JOkPCNL7dbZdgDpOZLTQM5zLrFKQmYxuBbwZsyJXdoj+fm8+P2+yABj7oXDE8HP5sPSU6+/zx8pZ24Jurv0XjQYA8305WIWNdVEtgWNi9n2TiJ83w+HyIR1zGb0n1XFErvdJ3rbFYFNpvygNS4=,iv:WOghx+QutGA4XCQFdsMQ8iGTjmoZFLX6WIAoS6myvgQ=,tag:sLsG4jbgmStOZyINMkIhBQ==,type:str]
pgp:
- created_at: "2023-02-18T08:55:29Z"
enc: |