diff --git a/.gitignore b/.gitignore index 3e607236..52c1f543 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ result *.qcow2 *.fd .direnv +/efi/secret diff --git a/config/nutty-noon.nix b/config/nutty-noon.nix index 67916682..a404ea1b 100644 --- a/config/nutty-noon.nix +++ b/config/nutty-noon.nix @@ -9,6 +9,7 @@ #./services/tpm2.nix ./services/hydra.nix ./server.nix + ./secureboot.nix nixos-hardware.nixosModules.common-cpu-amd nixos-hardware.nixosModules.common-gpu-amd nixos-hardware.nixosModules.common-pc-ssd diff --git a/config/secureboot.nix b/config/secureboot.nix new file mode 100644 index 00000000..8a03c75e --- /dev/null +++ b/config/secureboot.nix @@ -0,0 +1,15 @@ +{ config, ... }: { + imports = [ + ../modules/systemd-secure-boot + ]; + + 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; + }; + }; +} diff --git a/efi/DB.auth b/efi/DB.auth new file mode 100644 index 00000000..c0d2cf6c Binary files /dev/null and b/efi/DB.auth differ diff --git a/efi/DB.cer b/efi/DB.cer new file mode 100644 index 00000000..76327c0b Binary files /dev/null and b/efi/DB.cer differ diff --git a/efi/DB.crt b/efi/DB.crt new file mode 100644 index 00000000..22ca76fc --- /dev/null +++ b/efi/DB.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFKzCCAxOgAwIBAgIUI3+y+fO534cN62xuXIJV9MFe9IkwDQYJKoZIhvcNAQEL +BQAwJTEjMCEGA1UEAwwaY2hpci5ycyBFRkkgU2VjdXJlIEJvb3QgREIwHhcNMjIw +NDIwMDcwNDU4WhcNMzIwNDE3MDcwNDU4WjAlMSMwIQYDVQQDDBpjaGlyLnJzIEVG +SSBTZWN1cmUgQm9vdCBEQjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AK68ldtCl7Wv9Np6+5TvrdxI3DYOk5U/GH0WEYT0JNN1PyNBnAUnGcv0Fll/Y1BV +VUcP6LnubHLqh6OuQHQpCyuUigTXPMk/84iMAqYbPCn82iym5bA6OtBcFtrY+ntu +UHBQvyerEFUHibYW112lw1VXNHS/o/PZP7CLMc9oFm9To+seavspGL0XpOOpcxn/ +psDGlSAuVK9/udvMVysCpXs7KO2a6/m3mGzC4wUzXMGClzEc9wY7FAgGJxk85Ndy +RRl3ivQg67I7x+dXz17JD1HZiWMzSdvoh2EgZcmq3VPIJIBkOOjJi6WBREeIxADM +M51anY4N1luD+7fxCEumaZY2oDX7RX9mtN2jD64PX8ERn5h1GOicsbj051QJc5Gf +moR2tXbnr7cZ9f3JpADSGwkleEL0E+STOCajnXlz+QGXetF8kuL7DmS+62SeusaE +lv016QH0Q1Onj0HzqZBtqPGkOX02heGyXez6BysZBTTYhuIoO06k0EG4uzqHCGVo +UmAK8EfYw2OJASP3zKY78Hjr5MSYqZUIS2RLIqw1ujb1cJCvuEbOeM8mBTRaJmAx +w+IX57+cABmSyCgR/qrmDOw7uh69/fAlPR5jjJNUIHGjuqJL856MaFo/OQPm85vI +tPZfhICVgAXqlj1/5yLKAZqBGx3w2CGoJnp+JpyIITM1AgMBAAGjUzBRMB0GA1Ud +DgQWBBTwqZ3TzsEKqqKzKGE0fCn67vB3lzAfBgNVHSMEGDAWgBTwqZ3TzsEKqqKz +KGE0fCn67vB3lzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCR +PE3EYnPmpGufxQEQqhDqkRVPp5pzVaBbVU1Vo9WF+kJAVnJlh0DpFCwMXEuzn/1u +rtnGCH46p96cxIWrJoIWnuwAuvcTLMvwrkKLHExpPisXJR3ufrYeVhEyBd39Lrl1 +FD9g6FDPMJshsRPhXZLhUKLli6IAbwji2TplCBH4SFDxHoaEezhl9J8tIlQZ6roY +L0A30qoLRQ8Z19DJ3Vhj18S5ibTgRWWcquq9pF3Swv/v4gS6cULPbGSqsnFwqVND +b3pzCdBmRKciGEXGK11nGhd++wcirxJN+U0brl8mHsP7vhX0ztBBxXkfyzo9q7cl +U3p/ae1pCzX0NyRPlYyYMZTs0ZSllDLoztrEGIp16bANOHmfh+f1xszAUYHImVl7 +Zq8J3js/UtnQJD5KZIEQCleXChMJaH6qbtJKpvgqO3RsHQRJDyunNgE7r6bPTfh4 +TP7DhL1QWAgTdfRPzm1qofRwnTRLitRovMDWI/95lLlPbbNL/zGkBqvur3T8fLKx +gE/X7BGHGbARc8tSDdQ81kVOchL8yvud7CMgPOdazP6dmJxcO52S9Q9KpFW/duJi +V9V33wKQe5MCbTV4jtbE6ot245vslGjB/fLt4eP6Hngth0YzbU14FhXXjJofhDq7 +hB0zS9HklS54OtQBvAd7EX732UfEWZi1jeR0LL6rhA== +-----END CERTIFICATE----- diff --git a/efi/DB.esl b/efi/DB.esl new file mode 100644 index 00000000..d5e14298 Binary files /dev/null and b/efi/DB.esl differ diff --git a/efi/KEK.auth b/efi/KEK.auth new file mode 100644 index 00000000..9870eb88 Binary files /dev/null and b/efi/KEK.auth differ diff --git a/efi/KEK.cer b/efi/KEK.cer new file mode 100644 index 00000000..246fa4bf Binary files /dev/null and b/efi/KEK.cer differ diff --git a/efi/KEK.crt b/efi/KEK.crt new file mode 100644 index 00000000..b4cc33bc --- /dev/null +++ b/efi/KEK.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFLTCCAxWgAwIBAgIUCg57ZgQLP349Iz6LjZfplKAh+ZQwDQYJKoZIhvcNAQEL +BQAwJjEkMCIGA1UEAwwbY2hpci5ycyBFRkkgU2VjdXJlIEJvb3QgS0VLMB4XDTIy +MDQyMDA3MDQ1OFoXDTMyMDQxNzA3MDQ1OFowJjEkMCIGA1UEAwwbY2hpci5ycyBF +RkkgU2VjdXJlIEJvb3QgS0VLMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEA7JvQgi2sXsEksXaCd6bQIISP9aBa0dsHUa4ZTCyyGqlOdb3GuZembdnKzjwT +AffWSoaSVUo+GeewHFOOhQNMsAEW/Vm6yNdsyOHKQxgd86WIs4AoD0ngwqx3f9yp +iwjiG6PCW6BroaVAnczOfXXwUdOWNPKCfpZd9YVZ4O6Eiq1rnuWiMtGrpNm20QMJ +oXw/ieTyJzE8GWRoQm3Sk0qfpO0ae8oVkAzeHd78yT+7ciStw+EgXFbwwjTQNovo +C0pAJABP+GFDGcv7mndMJO6Ln6tNZbuZfnboTPr34akxzgLWljplyRhn1l8e9gPy +LH1Yz3SwDq5Hm02k1ZxzF0R7S0gdcLRCmU31FISHE691SBWqMR0subDXfY3aW4Dx +oO9D+JEL1hECtPK4cEBXPIuEUnHofY3kVD820xM5DLVjJCLdyV18HoW/a3FG1fqu +SQvH1EcfLjLwJIY/OJrYiChLFM9wRDuRO7oOjOYIcNg82O7Z3tJi/fjnAXtm66Pm +rLJaMNtTKZj5GIMKQq1Opi38P9yxFhZJHk1CdV5D2L4VCz6EcFLqmoBsAF/njn9f +lQ+2No4o3sDlZEZTjJug7cgMvxqoAIIis7mRKbtUKK6Vk9wjuPLC39gRUNWkVaBs +R9OVgSVz6B1AXbbvfgc5UVVpisdAV2sKvree2Lo7TTb/k18CAwEAAaNTMFEwHQYD +VR0OBBYEFLa0KcdYrySJRfHROjG/1hCqQucZMB8GA1UdIwQYMBaAFLa0KcdYrySJ +RfHROjG/1hCqQucZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB +AKXBgO9HRvGqJZ83c9oOanlOM77bs9r6glfoCNRUpSzV4yqzbDUR+PToObk6RowF +hR4uHTBOYtCRAUwE/GlzlAE/pU4fteT8FsZMQq1NxfOYk6xBG8rc5hjtjlplfzZi +TW0xomOjIzzfR4CNKG9OQajGUCHquto1jAikDYSGXTWcaLYgMfqjU0WttIqRckRH +ebW1QOYQN388pirxXS2VTGir6NRNtGE+RWiXF52GveUG1zWKzEHRH3u0W3Wr25oZ +rHCEZLx69BqI/xdZJ9HM8G8U37HiZswbo2M8H6c3MrRVADksK/oTfoi9xvJl1Unr +5O4tIzSqKf0A+ZIxxa/Wg4bu+EVKds7IYb6V5hojIFznydeVWjdlHA++JsWsg2ff +XKhjRrc3TJRQ4FlQWWTXk0j+l3DVIP8UmhICeQwomj27bZ3nDhKwXZW3AliYPK2z +5jlpasnMvpyKuP2rIZlIamUsX0Fp0pjrxKPHiof0dVX1eEmM2OMVbhnjwNttDApJ +C4v/MIRfn0cPMLCXwW4FQqepPekTGUmOVzJKYFuTtdorfSSuvjtqI7iX7//MIey8 +bqxU6vOzY3R00WrLhzxtb/JJ6PQ/tCuoQ2UUEzOnnhqpCXVpfHtgn34pwpfQ+Shb +cBTrK6A68XlxHGudT59lOejkIgSeo30MFQTUGtFoJG+d +-----END CERTIFICATE----- diff --git a/efi/KEK.esl b/efi/KEK.esl new file mode 100644 index 00000000..58cc05db Binary files /dev/null and b/efi/KEK.esl differ diff --git a/efi/MS_UEFI_db.esl b/efi/MS_UEFI_db.esl new file mode 100644 index 00000000..37325b00 Binary files /dev/null and b/efi/MS_UEFI_db.esl differ diff --git a/efi/MS_Win_db.esl b/efi/MS_Win_db.esl new file mode 100644 index 00000000..58cb0a1b Binary files /dev/null and b/efi/MS_Win_db.esl differ diff --git a/efi/MS_db.esl b/efi/MS_db.esl new file mode 100644 index 00000000..0534fc02 Binary files /dev/null and b/efi/MS_db.esl differ diff --git a/efi/PK.auth b/efi/PK.auth new file mode 100644 index 00000000..0258825d Binary files /dev/null and b/efi/PK.auth differ diff --git a/efi/PK.cer b/efi/PK.cer new file mode 100644 index 00000000..8e3fe67c Binary files /dev/null and b/efi/PK.cer differ diff --git a/efi/PK.crt b/efi/PK.crt new file mode 100644 index 00000000..831e0d5f --- /dev/null +++ b/efi/PK.crt @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFKzCCAxOgAwIBAgIUShalNDCVi3u1Xuh2w5fUYRaCy7kwDQYJKoZIhvcNAQEL +BQAwJTEjMCEGA1UEAwwaY2hpci5ycyBFRkkgU2VjdXJlIEJvb3QgUEswHhcNMjIw +NDIwMDcwNDU3WhcNMzIwNDE3MDcwNDU3WjAlMSMwIQYDVQQDDBpjaGlyLnJzIEVG +SSBTZWN1cmUgQm9vdCBQSzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJovNh67rN+Kfj7jQ8TbguMQVwxxoHsznP0s/V07n8WCqAeiJiVJHcHC3Lb0QhVQ +oNRPbfVFG+ZxUyG+R8udnkUYGAxs6hFGFTiTlachJKah8cHl1Pj2EcAOOi31IjGV +4yxm4jxDWb5F4tBhtJSPeVida1YujjfGrbsdfvG3sK4vL9sfyhN27k08PQko313s +cB5OXgU2XJmd1yLHlHiBxQ2n6xZQ42V8Z3l5XRBHbd6p2vxPYQB/D42G99tkpTs/ +dMvrLPrWgSCOX/crU8ACM0LydCBOcEa66mG5x2/GcAtrapXe/PssIqhnJOPUYbgk +T/cYHnWVfb5yCrLWxdTIvnIyMzg8wVn4fOeWZxgaqjPIhtV/7x41r6zJc7UHvtGR +yhsEtc9hzibjmrnKBie4BDWUk7zR30fMz4YZv38oQKBpzknFosS3Uzerlhx33JgA +rYxJiiURiOaIPPN+C9WmYtQr50DLAMALj0yAzVNb1au+tmNqGQEvRdZxHhCtS0HR +S8T6tJW5cZ+Uf3X0akColgoYy8pe3QolNuB6j4kGfJLu6mmQoroMkFq0qyl8i6Pu +JhaUtMMd/F01cYpNYNJYIU/DK1G06a90NP7WHq+sU3+73fzb68od3gFyvs39CHCG +BiVhMt/BJnYLN62TMYj6HLVm/L5kAWFqjzCv/5JszXorAgMBAAGjUzBRMB0GA1Ud +DgQWBBTnW/GkNs3TfMLOo/tv5dTBQssnTDAfBgNVHSMEGDAWgBTnW/GkNs3TfMLO +o/tv5dTBQssnTDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBs +cw4zlwfLJCQAq44V7LoAYE8xuoQxiTeY90D2yAaaXlhX+UxmOXa39Vg3bB6ia3oP +kTuLmI55WMg8IkXiwNIpCJcmFqZ2wMjfzmdvn2zeDWDK/aGM80xcpytunhxDe5Fs +dy2CnBveUf1fdhyogV4bo+/CvLqJjH3oSSuDVC8SqTUHS2T/1GNgLsRIHHVpPzDq +7+vtTe2F7uEA003u+UhLy9zTwcb/kkRPeDRmzJioBcPuL5neH7wibbSQ2yLmZjGq +D9rjCjXy5iWR678wfW1c7eP3ZVBTRVbZPgNfeXNg8rVFrEC9eZGYrx0FONzBq8zc +d8BHfunjiKvLJYtA5llc+RE+CeRug9SRxfpyevU36nULKM0t1fJdKmaG7sC2LesI +4LdLen5q07Py1xfbDf35fODmw8GR0rCv6kJNqqOgjRJiuLFTySPR6QHz0P5D79Uk +T3tBurtyVNu7S+jwhUvEcpHK78hfjN0zqQD7q46n56JkaCfOA9IT0a4Qw3rzQuu4 +h5su9/to2hAe2W58kzO7SatLPT8fgx1L/3z5Ne+DvLeNy8Qa1lKo/2GRL3Md6pj8 +Q8sAI4WHuof8Fyj1TGLFqJeRelaiMaz+dyG0AICBrsQlNBbhV99ZgZ3GApS+y7wg +vqA7lksMrNOoB/59UIPs97u+OulNx4MXqtQTCGPaNQ== +-----END CERTIFICATE----- diff --git a/efi/PK.esl b/efi/PK.esl new file mode 100644 index 00000000..7412f975 Binary files /dev/null and b/efi/PK.esl differ diff --git a/efi/add_MS_db.auth b/efi/add_MS_db.auth new file mode 100644 index 00000000..dd557aaf Binary files /dev/null and b/efi/add_MS_db.auth differ diff --git a/efi/mkkeys.sh b/efi/mkkeys.sh new file mode 100755 index 00000000..2d30db4a --- /dev/null +++ b/efi/mkkeys.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Copyright (c) 2015 by Roderick W. Smith +# Licensed under the terms of the GPL v3 + +echo -n "Enter a Common Name to embed in the keys: " +read NAME + +openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME PK/" -keyout PK.key \ + -out PK.crt -days 3650 -nodes -sha256 +openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME KEK/" -keyout KEK.key \ + -out KEK.crt -days 3650 -nodes -sha256 +openssl req -new -x509 -newkey rsa:4096 -subj "/CN=$NAME DB/" -keyout DB.key \ + -out DB.crt -days 3650 -nodes -sha256 +openssl x509 -in PK.crt -out PK.cer -outform DER +openssl x509 -in KEK.crt -out KEK.cer -outform DER +openssl x509 -in DB.crt -out DB.cer -outform DER + +GUID=`python3 -c 'import uuid; print(str(uuid.uuid1()))'` +echo $GUID > myGUID.txt + +cert-to-efi-sig-list -g $GUID PK.crt PK.esl +cert-to-efi-sig-list -g $GUID KEK.crt KEK.esl +cert-to-efi-sig-list -g $GUID DB.crt DB.esl +rm -f noPK.esl +touch noPK.esl + +sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \ + -k PK.key -c PK.crt PK PK.esl PK.auth +sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \ + -k PK.key -c PK.crt PK noPK.esl noPK.auth +sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \ + -k PK.key -c PK.crt KEK KEK.esl KEK.auth +sign-efi-sig-list -t "$(date --date='1 second' +'%Y-%m-%d %H:%M:%S')" \ + -k KEK.key -c KEK.crt db DB.esl DB.auth + +chmod 0600 *.key + +echo "" +echo "" +echo "For use with KeyTool, copy the *.auth and *.esl files to a FAT USB" +echo "flash drive or to your EFI System Partition (ESP)." +echo "For use with most UEFIs' built-in key managers, copy the *.cer files;" +echo "but some UEFIs require the *.auth files." +echo "" diff --git a/efi/myGUID.txt b/efi/myGUID.txt new file mode 100644 index 00000000..7281d52d --- /dev/null +++ b/efi/myGUID.txt @@ -0,0 +1 @@ +30db5e21-c078-11ec-be5b-00d861d0de1e diff --git a/efi/noPK.auth b/efi/noPK.auth new file mode 100644 index 00000000..33dd13fb Binary files /dev/null and b/efi/noPK.auth differ diff --git a/efi/noPK.esl b/efi/noPK.esl new file mode 100644 index 00000000..e69de29b diff --git a/efi/old_KEK.esl b/efi/old_KEK.esl new file mode 100644 index 00000000..9fa0826b Binary files /dev/null and b/efi/old_KEK.esl differ diff --git a/efi/old_PK.esl b/efi/old_PK.esl new file mode 100644 index 00000000..4b9c2504 Binary files /dev/null and b/efi/old_PK.esl differ diff --git a/efi/old_db.esl b/efi/old_db.esl new file mode 100644 index 00000000..88d9baf7 Binary files /dev/null and b/efi/old_db.esl differ diff --git a/efi/old_dbx.esl b/efi/old_dbx.esl new file mode 100644 index 00000000..06e07fb5 Binary files /dev/null and b/efi/old_dbx.esl differ diff --git a/modules/systemd-secure-boot/README.md b/modules/systemd-secure-boot/README.md new file mode 100644 index 00000000..28f1fc3c --- /dev/null +++ b/modules/systemd-secure-boot/README.md @@ -0,0 +1,3 @@ +# Systemd Secure Boot + +Taken from https://github.com/frogamic/nix-machines/tree/main/modules/systemd-secure-boot diff --git a/modules/systemd-secure-boot/default.nix b/modules/systemd-secure-boot/default.nix new file mode 100644 index 00000000..bedec49a --- /dev/null +++ b/modules/systemd-secure-boot/default.nix @@ -0,0 +1,200 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.boot.loader.systemd-boot; + + efi = 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. + + null 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: + + + + "0": Standard UEFI 80x25 mode + + + "1": 80x50 mode, not supported by all devices + + + "2": The first non-standard mode provided by the device firmware, if any + + + "auto": Pick a suitable mode automatically using heuristics + + + "max": Pick the highest-numbered available mode + + + "keep": Keep the mode selected by firmware (the default) + + + ''; + }; + + 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 allowUnfree to be set to + true. + ''; + }; + }; + + 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 && isNull cfg.secureBoot.keyPath); + + message = "The secureboot signing key must be provided"; + } + { + assertion = !(cfg.secureBoot.enable && isNull cfg.secureBoot.certPath); + + 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") + ]; + }; + }; +} diff --git a/modules/systemd-secure-boot/systemd-boot-builder.py b/modules/systemd-secure-boot/systemd-boot-builder.py new file mode 100644 index 00000000..160e3be7 --- /dev/null +++ b/modules/systemd-secure-boot/systemd-boot-builder.py @@ -0,0 +1,300 @@ +#! @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() diff --git a/secrets/nutty-noon.yaml b/secrets/nutty-noon.yaml index ac8616e2..35a02325 100644 --- a/secrets/nutty-noon.yaml +++ b/secrets/nutty-noon.yaml @@ -1,26 +1,28 @@ network: wireguard: - privkey: ENC[AES256_GCM,data:y0yJd/IsKQIuYPnf/GKtQy8HXeS5PeiM0FMu1ZWqMOaO22LnJcWfQV9IZs8=,iv:nQNKSYgaQ+kgxiFRatMFGyJm3ui8iQ+xKIU9zOF2RiM=,tag:bDQE9cUrXAa8VuG0pMwf8g==,type:str] + privkey: ENC[AES256_GCM,data:szEM0VB3vTMs0PbquIbH/nLUOcntT0w5pggZzUEhTsUTQPbP2X20gROEK4w=,iv:T6xB0HKPtmVe/83p85y30Wwiq6bhflQCET/epa+E7PE=,tag:ThFxTCdcYXxql/bggNWIUQ==,type:str] services: nix-serve: - privkey: ENC[AES256_GCM,data:N2SpdR1ctfMDDQXhrQxQqGhpA7QkO3XumLFcBBUVi4MQ2VekG3NqzQfyfffxkfNB1/AJlb0KghDCde44baHCAJ6J5d3xFLluGPGp+uyLUA5qZFqqu9l6O41hOgkUu469pQ==,iv:5GZ6sPcdIdbEPMh60I5sgCqB9jhFqkwu6luxF9kpNVk=,tag:PeAJ1YEiHDFWuXYVsmGINw==,type:str] + privkey: ENC[AES256_GCM,data:H5bhEcGthmrPmnBx3npzBT4C6GXmxpedlsiG66m009Crca4Ho15SKUjUUVVRXPtcHO38zilJrh5tppWAkb34MSdLSYrVv0zHyeuJVG+LQmZ3SpUNTHHZwKFCfTYNXDxyqQ==,iv:w49+cYfTcz31jgMqTmFuRmIyybjrA6aDSdCZ+IovQVQ=,tag:7vYRLrZF7JFLhGXqAQOhiQ==,type:str] hydra: - gitea_token: ENC[AES256_GCM,data:MMDgCQSuRPBav6YhdW2tcE0p2s24yDzACgqdm6kBrdlpaNkXxBw8ZQ==,iv:q8ye1vW4SeHzwJjf3Mfbac76dtIYid6E61nBMWj5sUg=,tag:qskumtwySnkPKof95BvnGg==,type:str] - github_token: ENC[AES256_GCM,data:FRvWJ/FXNPjfvrGEVlieHENu7UmkDHobB/PwAVVI4nZxtzGLqwljPg==,iv:8supeS0aTTRiVh1e5X4RNs9zP2UAKNF9JNZjw1geMPY=,tag:1RutlYl8soA+raxEZJT3CA==,type:str] - aws_credentials: ENC[AES256_GCM,data:zztGMpBqCaPBuSehvF9MVGScGA/OlU2H/w+WVhacMkE8QxNjQsfI69Ztc8R/tktQTNn9+7vsvJlQIIDnA/SVm2PmeKsD0GVg8wEehCGz2WBWClUZ2X5tQZsmC9h1YogND7FN7vgSWjSMvMllzGa84Q==,iv:egFR0o650ZbWELL1e3hMvU5oYTNxZTY41Kn04QHlXk8=,tag:E/zMWzcTsPbPMCFy3l5LNg==,type:str] + gitea_token: ENC[AES256_GCM,data:3Ig/5LUJuG6kt4KPOFrACIYHPaHKd8Csb6tRoDG1V+5zEWWc1f4msA==,iv:PyLk/XPmibWC8gssbWR5ah+880ZkAML/aumwkZptlgI=,tag:JXZTLZPPbhC/6tGoFTLgng==,type:str] + github_token: ENC[AES256_GCM,data:8Hl1X5w7g4JsfsGohmGL2sWdEsP7HyaJKXxqNBG0VosSoLPrDNhNRw==,iv:cX1Wp9MHeGtdxkqvag7TCqju9Pq+6L5kJVQKHRszCdE=,tag:/x25BMa19jGQ7/Lf7gI7BQ==,type:str] + aws_credentials: ENC[AES256_GCM,data:jw2iHyAAgAWyDUj9SZX3l4qFnxfdA0rNtTi7AJhfJMnq40S3ca476c+jkHb6ETEqb85C3a1k2So7gbMhHMaWnV5te7pM0JBHDm6qau3u50PdkQUxbFZXhMjjnjhYOrxANICS/AEqv3Aiui3HLH+Xeg==,iv:DS12/Oy7yzleeOoOs4n0Ratbq7k9+8+Dti/Wk59GduA=,tag:fB8MDgrg221mdo9vztIvtg==,type:str] security: restic: - password: ENC[AES256_GCM,data:Mr8uOq7UtN7hdWWQQbyDfdC+jzI=,iv:Ey2Q0O+UPVhrb+z54l/w6sk3OQEAvAoMyP6TfJBRgmI=,tag:4z/NvwFpEE/QE7i/lSeexQ==,type:str] + password: ENC[AES256_GCM,data:h6gOInhL3WizolCbfcYM1mC1kqA=,iv:WeAGzefn1pZobi3Zw+PS5nAXTRWJ5Xj2bbtrleI92cQ=,tag:eG/xlHRL6U5G1ZtCtqGV1Q==,type:str] acme: - dns: ENC[AES256_GCM,data:vxGlQldRgsQErlZ5SzvjmDGth3Ozf3FIsREp7rPevzWEdeQzrX5U1f9enBed2Bdysa2SIdxtI5ZFl9Tql7YWBLFGURvjjeWEFE5FjoOznlYGqKDMUcnnoWcMa99fXpQAdYP1ThgRPZ69DAeLOopndHAl0KFQgwJFrRDlSDfj19orcJ4pXxGmw1dEY0SpiU71SfmS3oLyvdWNmnPklC46qcK4q/D+SON1Nk2J4O0rTDi6OgZv37fVz4I17P66L5XVzepwZGppGIJDd+IdIm/I55Q99kjeRj2VVw==,iv:WkGdSldoBepdtoIouIRTCfWVHmp9wYkYqUonzWo4H+o=,tag:/l7NAQxYzr8dfflsKhEUcw==,type:str] - dns2: ENC[AES256_GCM,data:j5Lmr1T1BfPKJmdf+Z9MYx7L9z/PqDTHTxYZo/osln7/wx+vlGf/1zWKq0m2AUObqIGRDqytKuOIwiGw+Q32OviEF2TwJkyLg0Dxjp5u9un8ha6FAa7YgfbHCw6W/FS8xWP/CE6ZOxgDd6e6NgPB8WcPltlsNMKtQ9gjQ6IZm4mdzfCcsjIerI6ZTkHjJHGZJSadJ8zFLeFaHosAIneDQC8ODRyDE8lSZuscIMCVhR+ynvsncSGOu7Vkh5mLPmseZjURiKrpNmxB/xkFvfdkwNnEUUJs4Da79w==,iv:yjA/yp8wOAA++hSKETPbXXOuAN0pozdgMDOFh0nNvq0=,tag:oAiiN/ol76kVEunoruAliQ==,type:str] - cloudflare: ENC[AES256_GCM,data:WfSxl91cv+1ztYN7AGLyNAX8tkF1OjAF5sndqVvZHpbWmq8IfeuVe1Xu/FNdZVUeSinyDCuf0uMBMlaE+frIdHbm/MrvnlVQ7oBmtmDKsj40P19TqLD77KqRfccX8tDsEeTsasFT/7fWab9zchHzmb7UMcb7372LwmAtGgtEW6AfF8RKKt7fEPJGWx8pcxKdUhFvrn6C0Wvg+yh0v0NpX3DNz8psx4zkd/BU9CGHBP+O5SIRbdSHYU8=,iv:5gPdKrlPCxKyq2hQqM/PzTgaT+xDpo6Czdf1BUpxlbI=,tag:S+A5XRHNDzSu2NuqR0id1A==,type:str] + dns: ENC[AES256_GCM,data:5VC6oBXZcfg3w4tX98hmvZO/Z2LK0wsHczJ4gtWGoJEu9vzMuwkLkcXkwBffL35HBXcV5NEK4X9/7TAlcM2vWNYjxBnHY3gT2763zQs9WUwQlVYLCXD3dptROUO9u0wU+Ekj/+xYY74V7WGrolzPnbrJo5/QyOcqc05N5yUu8oLCgTG9TlN7kVKUiEFBklZIolM9hoqBtYSoCQmnzigR1uc5UdLxVhAmThoJOmC9MnWym0smMqB6cTVyd27fMU4731yQSsO0Uji0BP/3LZN+S9e2/cIHI9migg==,iv:BjvU+s2mv36S89OMYGPN/c9LQEGdEIq0SMDHQys7XXU=,tag:ljhUMj8BHjRTvWYig21lgA==,type:str] + dns2: ENC[AES256_GCM,data:g1t7Eq800gSfqZkqGb36PxTqtV+Ah4R4Jitv29Be110kcRVTdfdKHELpCp/YelHbyjhf8w4JdoSOXqb2nXKGdpXQINidjOBHAYusZHJaRiGJWKqswSqnvUiWw0j0tyIaR7jn9Il25IjlQ4PhlpAV0fk/Ezm+COVKC8GlY03bscPCHFSpQCLdGzKv7Yl9Fz+K3excZGm1OZMOnjCoZnHsi/oT0TFeymXw+Lkm2v6/B8PVoOpe8N5woH92sFgbuIvAZIyeTIaRH8e9K4ZvOYAQMqY6SANnqL1Q0w==,iv:XRjXqZbcC80KnpoWUIDBinoVsJBCzM3tJ6v4qPcJYiw=,tag:VUgl3efofNwhFP/VcH1hLw==,type:str] + cloudflare: ENC[AES256_GCM,data:ONvtdegXFZuPSa/vQDZSDmQ4x8H1Qz08/i6NE6p7eJQav3c1rM1ai0oMdRMKZ1kfHGW99hkEGCacnIO0Lbg9iJbCQeR+Co/CM6G4UUeLgt3EOAI+J0aBpgMAjAbU7wPZVvG4mUarcwDkwx61tyKj/8gPhBMvArjnnUMyU3Xn+iuHHG5TeBRhX6KnlEwmcRDLWnYObmLcVzU37nque9NBrvyPT9iNANjF9WjtOnQU63EhFnTp4HUwcW8=,iv:DpQOKpdXOrTvxsWHJoIeEPc/rZJQmG3NprhEVqGpOgw=,tag:N47EaTXcFOAer2oL6wsDhQ==,type:str] email: - lotte@chir.rs: ENC[AES256_GCM,data:02v6qsTC30thvqQ4yDpYhfyNVg==,iv:rdz3HHlAyyt1TR7iUXpokIlBC8VEdS0GLoCkItBc3HY=,tag:/aNoPNoMeVGCWRT3j+F+ew==,type:str] - mdelenk@hs-mittweida.de: ENC[AES256_GCM,data:rXwwhdX2STqJjO2UMqW9YeXc8JtJ2DXLptZvVN9552ldRgZU7OoNiPxbYg/Kr7ZOkl/8HIg0yFa1uQIbvQxuoQ==,iv:ThZzE7m05FS1NPH/mvWF/vflxC4pmZCMX12iOUzKQfQ=,tag:qK0+ZA8486YgaW/I7BrfPQ==,type:str] + lotte@chir.rs: ENC[AES256_GCM,data:P6zZjE5iqqPifjwXxFtXwNFnKg==,iv:m9bCuByKC+ppg/+K97hwkuO29bdtID8bFW4Ie7hwAgA=,tag:2sNxBWery9H+Mu5hzJPELA==,type:str] + mdelenk@hs-mittweida.de: ENC[AES256_GCM,data:gxUiw3kGER3g6MLfy6xDWQhsWnkvvmn68bBYaXf7JTs7/KPSv25kQatziMvotjkkSDmjqP0/r5fqlVLI+QnPUQ==,iv:Ry4LhbEhgI6J61nQ6bGhu1Y8ZLSdAP3rEAMbI/h0j7c=,tag:woIMx78b8Fb2yvsBznwOZw==,type:str] password: - root: ENC[AES256_GCM,data:PioiMzGCro6vLXfCkJrmWN+SZkwdCSiHUXMmmtK3FLl2XRhtYFixeiDI+YFNT3SmdJ3clI4R+IrEV2pMjXX/jHejI80NnTzJU32Rp2/dYxwz6qk9vNwRC1OiyrsF67sg4VoSBVinbGMVuA==,iv:bIRfmXQqdv+PJDpHtnjR5RJUd5E5HC+Q+kN1ncRdUMU=,tag:6PAVQ1DPh5+5BrWkZrp4MQ==,type:str] - darkkirb: ENC[AES256_GCM,data:b1yBZSqsJh3Er8/U7dLa3L92uoe3/MH2xoOK+eOAjNYAL5kJD2yf+5ikTR9N+bRsVTjoGxfcpYfbx08WSK9NY8lP0u7zdQ32g9gyWSlpZiFjm9yQd3iwdxbnrtNYMd6fmSqTaPOAQqW9ww==,iv:Q1nuM+lmpqAJgiBKISjOKdLjTRJD3YFjaSDR6j1e43w=,tag:2O/3LY9hIvcixGtshWVDDg==,type:str] + root: ENC[AES256_GCM,data:EqOfup6j6v1rhfjN5/zKTgN/QuUVytSeed3F0Tj+lWRtPUCmP1CdXTt7dzU98LA88S48M9C4c2sQ3SsJnfoApvZ2VGfMeoMo40mdEaSJR4FJo5KxR+OYjsc2BD0CGnAWBUXL8OnXB6HfYA==,iv:gXqTmyCX7OBUSBAsjDee0qG+wwkENCNtZ7VU89WQQFI=,tag:aNNJI93+L4NxV1kyW6lqUw==,type:str] + darkkirb: ENC[AES256_GCM,data:iTWDpNIMlh6DMSBn981M5QTYk0uFutM1i7J2aiLWILIp8yqIJgufMTNndlNPeM0CMjxAaER392f9z9pyTpxQ27JdSBO79AOflqfk280NBICMkVSOUQSEdnGaA5JLfgS4TwNbO1cSCPNlxg==,iv:ItjvSYOm68ZjjkspgVF2s4J4saq7+TIBbEaIhlQpnaI=,tag:KBlXqLL2Fh6IrSQn4Fq0mQ==,type:str] +secureboot: + DB.key: ENC[AES256_GCM,data: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,iv:OFiuSu/Kh8mf4BxwtbpT4TH4oDS+YXu0GFK5/Zy+C/w=,tag:Fu4WeWJhWwQGFLB1c3qyXg==,type:str] sops: kms: [] gcp_kms: [] @@ -30,24 +32,24 @@ sops: - recipient: age1wfftrnyngg7nxcwvt7m590fwx3w7p4kkrjn9uprjq0u3k3ym4s3qqzkmzm enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzcDBaa0FXM21xNGErS3RH - S0gzZjJ1ZEFNTTFUZElMVFErVU0vbmVqQ0N3ClNpODB6djJ1bCtHNkVyQXFXWEpN - MkVabkJEUDJ4enVIRHFmcGlBRmsxcjgKLS0tIDBsTllyYXdsK0NLSDRKTkFRbk9P - U0JxSTR3WEFvZjVoMjJsV3NYNVFpYTAKxCpvEDbEjh3sNR+2X7AsReYPxi9n3bpP - g+IVnv+EX9CkqBNbpAHiwqzekVXNqM7SxMmgSasZ4IGRK1Wcf5NU0w== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUTnNSMC9lMmN0eVh6ck1i + Z0piR3ZnVTZNSTZCZTdGZld1b084L1RlWm40Ck9RNk0zWVVVWE5MeVo5S20ycW5W + c1J5T0JiRlNvU2t1MVlwU0FGbjRqV0EKLS0tIE9FZnVvQzEycjVnVGNJbVA1Q0li + eEtjUkdQek1peEdhbXpnSDJ6ZWlQQ00K+wUZi9x5ja1832ov4DYxCH5fbfZFkXv1 + 8U5idFtpxkQQH1mYKfBASC/3WbpH/xv3SCpIpqisqEVc7lL/2xD9cQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2022-04-13T14:30:15Z" - mac: ENC[AES256_GCM,data:jYbhAoFF6giESwzrWh1lpORjERoDl1sAOViYuaffslyBMc/RAH4i6LTCdtaMbqckciuxjppQeVvSXNU/TgjrASNHQNCgG4UDGZD91vx4tdLeABCCq/b65eTjUi9pNdFm5GzGaySvYzztcPxcVnqhaIY3z5N1fBQKYWu4LAJbqRM=,iv:ZqPomgoGoge/wPRdO0BEXt5Zh6VSTr2mS/iStUvLcbE=,tag:/EByxD3yAZ9MP1u+/hXo8A==,type:str] + lastmodified: "2022-04-20T07:17:38Z" + mac: ENC[AES256_GCM,data:ESjkNG8vQXJY9L2M8R/tuFtgjIR3UTIibwqTXKnU0/dxxdrr+y8jCdn2h4Yqm6BuZOCF6S4NRUsqLd1GoTORMyEENjpyhglhvld+bArZWQs/S3DDApgU5H9/gppDSVNN0XQTifsk9Wabm/ZPlfeBWKoGTbSQBKnMrX+LHiiwN/Q=,iv:5FURepA8YIps+nJMczarLdt27BQC2moSvG6qoz2+Z/o=,tag:2ikHAzF3lAiEB+uQozMOww==,type:str] pgp: - - created_at: "2022-04-02T06:17:40Z" + - created_at: "2022-04-20T07:17:37Z" enc: | -----BEGIN PGP MESSAGE----- - hF4DAAAAAAAAAAASAQdACVlYZwj9xdlHrbQ/yMc8jx0Ls3LSAyWGqJiIaj1ksRsw - XvU2dbAYhSLrpJSkTU+lSmjXFmPrq7GnkNKy+bPFWu7bmghKItXpO//6AcU7IB9m - 0l4BOrloU1EedUf6rJUewUtQP7nNXsJ+iqWOMpN5Y6GX4UWeXMZ8AgSEqpHni9QV - KFa5VdU73/ms2+zatFxqj1bix4ZZqsxwapWreyKgo2jwIOVLZyHAu9TyoN7rLyLP - =x+Y/ + hF4DAAAAAAAAAAASAQdAxefXUpTNr2aKPMHYv7vh1VygwqEGmUF/jLnmUvhY+Akw + okJvyJqVK2Fe2t/FOxBVfmfktMQ0K7GN6aoIGrRl6BLu1hUzRHyURYquKqOpDAPt + 0l4BOoRh/9iRaDICkEh0dG3OSgL7xG3L/QcNXB0K6H/tYBzfIJ0oCmCqwaG9khm8 + 5dqZtQ9x0Oxfdp6LfSwRk4C18n/fzDz4DydPH4IbURhXDVUu34p/Alg6kjwGYFyM + =xlEM -----END PGP MESSAGE----- fp: 46C6A7E14BC7812E86C2700737FE303AAC2D06CD unencrypted_suffix: _unencrypted