V9.14.024.2026.06.11

Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
2026-06-11 17:11:22 +01:00
parent 9ef535554a
commit 97596fbcba
63 changed files with 767 additions and 200 deletions
+59 -15
View File
@@ -76,7 +76,6 @@ guard_sourcing || return "${ERR_GUARD_SRCE}"
# ERR__SSH__PORT: on failure
#######################################
arg_parser() {
declare primordial_key_regex='^[A-Za-z0-9._@%+=:,~-]+$'
declare primordial_url_regex='^https://[A-Za-z0-9.-]+/[A-Za-z0-9._~/%+=:@,-]+\.git$'
while [[ $# -gt 0 ]]; do
@@ -109,6 +108,16 @@ arg_parser() {
shift 1
;;
-l | --logo)
if [[ -n "${2-}" && "${2}" != -* ]]; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --logo MUST NOT be followed by an argument.\e[0m\n" >&2
read -p -r $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_ARG_MSMTCH}"
fi
shift 1
;;
-v | --version)
if [[ -n "${2-}" && "${2}" != -* ]]; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
@@ -134,10 +143,9 @@ arg_parser() {
;;
--build-directory)
declare -gx VAR_HANDLER_BUILD_DIR="${2}"
if [[ ! "${VAR_HANDLER_BUILD_DIR}" =~ ^/ ]]; then
declare -gx VAR_HANDLER_BUILD_DIR="${2-}"
if ! validate_build_dir_argument "${VAR_HANDLER_BUILD_DIR}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --build-directory MUST be an absolute path. Got: '%s'\n" "${VAR_HANDLER_BUILD_DIR}" >&2
exit "${ERR_NOTABSPATH}"
fi
declare -gx VAR_BUILD_LOG="${VAR_HANDLER_BUILD_DIR}/cdlb_${VAR_ISO8601}_build.log"
@@ -266,18 +274,28 @@ arg_parser() {
;;
--key_age=*)
declare key_age="${1#*=}"
if ! validate_secret_filename "--key_age" "${key_age}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_AGE="true"
# shellcheck disable=SC2034
declare -gx VAR_AGE_KEY="${1#*=}"
declare -gx VAR_AGE_KEY="${key_age}"
shift 1
;;
--key_luks=*)
declare key_luks="${1#*=}"
if ! validate_secret_filename "--key_luks" "${key_luks}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_LUKS="true"
# shellcheck disable=SC2034
declare -gx VAR_LUKS_KEY="${1#*=}"
declare -gx VAR_LUKS_KEY="${key_luks}"
shift 1
;;
@@ -296,7 +314,7 @@ arg_parser() {
--primordial-key)
declare primordial_key="${2-}"
if [[ -n "${primordial_key}" && "${primordial_key}" != -* && "${primordial_key}" != "." && "${primordial_key}" != ".." && "${primordial_key}" != */* && "${primordial_key}" =~ ${primordial_key_regex} ]]; then
if validate_secret_filename "--primordial-key" "${primordial_key}"; then
# shellcheck disable=SC2034
declare -gx VAR_PRIMORDIAL_KEY="${primordial_key}"
@@ -315,7 +333,7 @@ arg_parser() {
--primordial-key=*)
declare primordial_key="${1#*=}"
if [[ -n "${primordial_key}" && "${primordial_key}" != "." && "${primordial_key}" != ".." && "${primordial_key}" != */* && "${primordial_key}" =~ ${primordial_key_regex} ]]; then
if validate_secret_filename "--primordial-key" "${primordial_key}"; then
# shellcheck disable=SC2034
declare -gx VAR_PRIMORDIAL_KEY="${primordial_key}"
@@ -461,7 +479,7 @@ arg_parser() {
;;
--root-password-file)
declare pw_file="${2}"
declare pw_file="${2-}"
if [[ -z "${pw_file}" ]]; then
@@ -473,10 +491,9 @@ arg_parser() {
fi
if [[ ! -f "${pw_file}" ]]; then
if ! validate_secret_absolute_file_basics "--root-password-file" "${pw_file}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
printf "\e[91m❌ Error: --root-password-file password file '%s' does not exist.\e[0m\n" "${pw_file}" >&2
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_MISS_PWD_F}"
@@ -507,6 +524,13 @@ arg_parser() {
}
fi
validate_secret_file_path "--root-password-file" "${pw_file}" || {
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
# shellcheck disable=SC2162
read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m'
exit "${ERR_RGHT_PWD_F}"
}
declare plaintext_pw
### No tracing for security reasons ----------------------------------------------------------------------------------
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x
@@ -606,16 +630,26 @@ arg_parser() {
;;
--signing_ca=*)
declare signing_ca="${1#*=}"
if ! validate_secret_filename "--signing_ca" "${signing_ca}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_SIGNING_CA="${1#*=}"
declare -gx VAR_SIGNING_CA="${signing_ca}"
shift 1
;;
--signing_key=*)
declare signing_key="${1#*=}"
if ! validate_secret_filename "--signing_key" "${signing_key}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_SIGNER="true"
# shellcheck disable=SC2034
declare -gx VAR_SIGNING_KEY="${1#*=}"
declare -gx VAR_SIGNING_KEY="${signing_key}"
shift 1
;;
@@ -626,8 +660,13 @@ arg_parser() {
;;
--signing_key_pass=*)
declare signing_key_pass="${1#*=}"
if ! validate_secret_filename "--signing_key_pass" "${signing_key_pass}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_SIGNING_KEY_PASS="${1#*=}"
declare -gx VAR_SIGNING_KEY_PASS="${signing_key_pass}"
shift 1
;;
@@ -694,8 +733,13 @@ arg_parser() {
;;
--ssh-pubkey)
declare ssh_pubkey="${2-}"
if ! validate_ssh_pubkey_directory "${ssh_pubkey}"; then
if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi
exit "${ERR_ARG_MSMTCH}"
fi
# shellcheck disable=SC2034
declare -gx VAR_SSHPUBKEY="${2}"
declare -gx VAR_SSHPUBKEY="${ssh_pubkey}"
shift 2
;;
+6 -2
View File
@@ -33,12 +33,16 @@ x_remove() {
shopt -s nullglob dotglob
### Collect exact currently available secret values before removing their source files.
### Log rewriting is intentionally deferred to the final trap after xtrace has been stopped.
collect_debug_secret_values || true
if [[ "${VAR_SIGNER}" == "true" ]]; then
# shellcheck disable=SC2312
find "${VAR_TMP_SECRET}" -xdev -type f \
! -path "${VAR_TMP_SECRET}/signing_key_pass.txt" \
! -path "${VAR_TMP_SECRET}/luks.txt" \
! -path "${VAR_TMP_SECRET}/${VAR_SIGNING_KEY_PASS:-signing_key_pass.txt}" \
! -path "${VAR_TMP_SECRET}/${VAR_LUKS_KEY:-luks.txt}" \
-print0 \
| xargs -0 --no-run-if-empty shred -fzu -n 5 --
+3 -1
View File
@@ -1,4 +1,5 @@
#!/bin/bash
# shellcheck disable=SC2154
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-11-12; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git
@@ -14,9 +15,10 @@ guard_sourcing || return "${ERR_GUARD_SRCE}"
#######################################
# Integrates and generates sha512sum and GPG signatures on CISS specific LIVE boot artifacts:
# - /root/.ciss/attestation/VAR_SIGNING_KEY_FPR.*
# - /root/.ciss/attestation/VAR_SIGNING_KEY_FPR.* legacy-signed public-key copy, not rootfs content attestation
# - /etc/initramfs-tools/files/unlock_wrapper.sh
# - /usr/lib/live/boot/0030-ciss-verify-checksums
# Rootfs content attestation for the final SquashFS payload is generated by zzzz_ciss_crypt_squash.hook.binary.
# Globals:
# BASH_SOURCE
# VAR_HANDLER_BUILD_DIR
+30 -15
View File
@@ -33,6 +33,7 @@ guard_sourcing || return "${ERR_GUARD_SRCE}"
#######################################
clean_up() {
declare clean_exit_code="$1" fs_type="" _old_nullglob="" _old_dotglob="" _old_failglob=""
declare build_dir_valid="false" includes_chroot=""
### Enable nullglob/dotglob, disable failglob for safe globbing.
_old_nullglob="$(shopt -p nullglob || true)"
@@ -52,10 +53,10 @@ clean_up() {
rm -f -- "${VAR_NOTES}"
### Release advisory lock on FD 127.
flock -u 127
flock -u 127 2>/dev/null || true
### Close file descriptor 127.
exec 127>&-
exec 127>&- 2>/dev/null || true
### Remove the lockfile artifact.
rm -f /run/lock/ciss_live_builder.lock
@@ -100,32 +101,46 @@ clean_up() {
### No tracing for security reasons ------------------------------------------------------------------------------------------
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x
### Removes secrets securely.
# shellcheck disable=SC2312
find "${VAR_TMP_SECRET}" -xdev -type f -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 --
find "${VAR_TMP_SECRET}" -xdev -depth -type d -empty -delete
### Stop xtrace before destructive cleanup and collect still-available exact secret values.
### The final log rewrite runs later from the trap after no further debug/error log writes are expected.
finalize_debug_xtrace_logging || true
collect_debug_secret_values || true
### Securely shred all regular files below ./includes.chroot, then remove empty dirs.
if [[ -d "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" ]]; then
### Removes secrets securely.
if [[ -n "${VAR_TMP_SECRET:-}" && -d "${VAR_TMP_SECRET}" && ! -L "${VAR_TMP_SECRET}" ]]; then
# shellcheck disable=SC2312
find "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" -xdev -type f -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 --
find "${VAR_TMP_SECRET}" -xdev -type f -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 -- || true
find "${VAR_TMP_SECRET}" -xdev -depth -type d -empty -delete || true
fi
if [[ -n "${VAR_HANDLER_BUILD_DIR:-}" && -d "${VAR_HANDLER_BUILD_DIR}" ]]; then
if require_builder_owned_build_dir "${VAR_HANDLER_BUILD_DIR}"; then
build_dir_valid="true"
fi
fi
### Securely shred all regular files below ./includes.chroot, then remove empty dirs.
includes_chroot="${VAR_HANDLER_BUILD_DIR:-}/config/includes.chroot"
if [[ "${build_dir_valid}" == "true" && -d "${includes_chroot}" ]] \
&& require_builder_owned_subpath "${VAR_HANDLER_BUILD_DIR}" "${includes_chroot}"; then
# shellcheck disable=SC2312
find "${includes_chroot}" -xdev -type f -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 -- || true
### Remove empty directories (bottom-up).
find "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" -depth -xdev -type d -empty -delete
find "${includes_chroot}" -depth -xdev -type d -empty -delete || true
fi
### Delete all files and directories below ./chroot.
if [[ -d "${VAR_HANDLER_BUILD_DIR}/chroot" ]]; then
if [[ "${build_dir_valid}" == "true" && -d "${VAR_HANDLER_BUILD_DIR}/chroot" ]]; then
rm -rf "${VAR_HANDLER_BUILD_DIR}/chroot"
safe_remove_builder_subpath "${VAR_HANDLER_BUILD_DIR}" "${VAR_HANDLER_BUILD_DIR}/chroot" || true
fi
### Turn on tracing again ----------------------------------------------------------------------------------------------------
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x
eval "${_old_nullglob}" 2>/dev/null || true
eval "${_old_dotglob}" 2>/dev/null || true
eval "${_old_failglob}" 2>/dev/null || true
+7 -1
View File
@@ -72,9 +72,15 @@ EOF
fi
### Use pubring as verification keyring reference.
### Use pubring as a verification keyring reference.
declare -grx VAR_VERIFY_KEYRING="${GNUPGHOME}/pubring.kbx"
validate_secret_file_in_root "--signing_key" "${VAR_SIGNING_KEY}" || return "${?}"
validate_secret_file_in_root "--signing_key_pass" "${VAR_SIGNING_KEY_PASS}" || return "${?}"
if [[ -n "${VAR_SIGNING_CA}" ]]; then
validate_secret_file_in_root "--signing_ca" "${VAR_SIGNING_CA}" || return "${?}"
fi
declare -grx VAR_SIGNING_KEY_PASSFILE="${VAR_TMP_SECRET}/${VAR_SIGNING_KEY_PASS}"
### No tracing for security reasons ------------------------------------------------------------------------------------------
+1
View File
@@ -182,6 +182,7 @@ hardening_ultra() {
printf "\e[95m🧪 Updating SSH Keys, Ports ... \e[0m\n"
### ./config/includes.chroot/root/.ssh ---------------------------------------------------------------------------------------
validate_ssh_pubkey_directory "${VAR_SSHPUBKEY}" || return "${?}"
install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
install -m 0600 -o root -g root "${VAR_SSHPUBKEY}/authorized_keys" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/"
+3 -5
View File
@@ -30,12 +30,14 @@ lb_config_start() {
mkdir -p "${VAR_HANDLER_BUILD_DIR}"
# shellcheck disable=SC2164
cd "${VAR_HANDLER_BUILD_DIR}"
ensure_builder_owned_build_dir "${VAR_HANDLER_BUILD_DIR}"
printf "\e[92m✅ '%s' created. \e[0m\n" "${VAR_HANDLER_BUILD_DIR}"
else
# shellcheck disable=SC2164
cd "${VAR_HANDLER_BUILD_DIR}"
ensure_builder_owned_build_dir "${VAR_HANDLER_BUILD_DIR}"
fi
@@ -48,11 +50,7 @@ lb_config_start() {
lb clean --binary --cache --purge --source
if [[ "${PWD}" == "${VAR_HANDLER_BUILD_DIR}" && "${PWD}" != "/" && -n "${PWD}" ]]; then
rm -rf -- ./* ./.??*
fi
safe_clean_build_dir_contents "${VAR_HANDLER_BUILD_DIR}"
printf "\e[92m✅ Deleting former config, binary and cache done.\e[0m\n"
+14
View File
@@ -84,6 +84,8 @@ init_primordial() {
### Check for SOPS AGE key integration ---------------------------------------------------------------------------------------
if [[ "${VAR_AGE,,}" == "true" ]]; then
validate_secret_file_in_root "--key_age" "${VAR_AGE_KEY}" || return "$?"
install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.config/sops/age"
install -m 0400 "${VAR_TMP_SECRET}/${VAR_AGE_KEY}" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.config/sops/age/keys.txt"
shred -fzu -n 5 -- "${VAR_TMP_SECRET}/${VAR_AGE_KEY}" 2>/dev/null || rm -f "${VAR_TMP_SECRET}/${VAR_AGE_KEY}"
@@ -93,6 +95,18 @@ init_primordial() {
### Check for SSH CISS and PhysNet Primordial-Workflow™ integration -------------------------------------------------------
if [[ "${VAR_SSHFP,,}" == "true" ]]; then
# shellcheck disable=SC2312
if find "${VAR_TMP_SECRET}" -xdev \( -name 'id*' -o -name 'ssh_host_*' \) -type l -print -quit | grep -q .; then
printf "\e[91m❌ ERROR: SSH identity and host key inputs MUST NOT be symlinks. \e[0m\n" >&2
return "${ERR_INVLD_CHAR}"
fi
# shellcheck disable=SC2312
if find "${VAR_TMP_SECRET}" -xdev \( -name 'id*' -o -name 'ssh_host_*' \) ! -type f -print -quit | grep -q .; then
printf "\e[91m❌ ERROR: SSH identity and host key inputs MUST be regular files. \e[0m\n" >&2
return "${ERR_INVLD_CHAR}"
fi
install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
install -m 0600 "${VAR_TMP_SECRET}/id"* "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/"
normalize_ssh_keys_in_dir "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh"
+4
View File
@@ -49,6 +49,8 @@ trap_on_exit() {
print_scr_exit "${errcode}"
sanitize_debug_logs || true
exit "${errcode}"
else
@@ -61,6 +63,8 @@ trap_on_exit() {
print_scr_exit_non_zero "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
sanitize_debug_logs || true
fi
exit "${errcode}"
+10 -6
View File
@@ -39,13 +39,13 @@ usage() {
# shellcheck disable=SC2155
declare var_header=$(center "CDLB(1) CISS.debian.live.builder CDLB(1)" "${var_cols}")
# shellcheck disable=SC2155
declare var_footer=$(center "V9.14.022.2026.06.10 2026-06-10 CDLB(1)" "${var_cols}")
declare var_footer=$(center "${VAR_VERSION} 2026-06-11 CDLB(1)" "${var_cols}")
{
echo -e "\e[1;97m${var_header}\e[0m"
echo
echo -e "\e[92mCISS.debian.live.builder from https://git.coresecret.dev/msw \e[0m"
echo -e "\e[92mMaster V9.14.022.2026.06.10\e[0m"
echo -e "\e[92mMaster ${VAR_VERSION}\e[0m"
echo -e "\e[92mA lightweight Shell Wrapper for building a hardened Debian Live ISO Image.\e[0m"
echo
echo -e "\e[97m(c) Marc S. Weidner, 2018 - 2026 \e[0m"
@@ -67,6 +67,7 @@ usage() {
echo
echo -e "\e[97m --build-directory </path/to/build_directory> \e[0m"
echo " Where the Debian Live Build Image should be generated. RECOMMENDED path: </opt/cdlb>"
echo " Cleanup is destructive inside the exact builder-owned path and requires '.ciss-live-builder-owned'."
echo " MUST be provided."
echo
echo -e "\e[97m --change-splash <STRING> one of <club | hexagon> \e[0m"
@@ -87,6 +88,7 @@ usage() {
echo -e "\e[97m --debug, -d \e[0m"
echo " Enables debug logging for the main program routine. Detailed logging information are written to:"
echo " </tmp/ciss_live_builder_$$.log>"
echo " After xtrace is stopped and its debug FD is closed, a final exact-value redaction pass sanitizes logs."
echo
echo -e "\e[97m --dhcp-centurion \e[0m"
echo " If a DHCP lease is provided, the provider's name server will be overridden and the hardened, privacy-focused "
@@ -108,12 +110,12 @@ usage() {
echo
echo -e "\e[97m --key_age=* \e[0m"
echo " The SOPS AGE private keyring for decryption operations. Change '*' to your desired SOPS AGE key file."
echo " File MUST be placed in:"
echo " This MUST be a filename only and MUST be placed in the root-owned tmpfs secret root:"
echo " </dev/shm/cdlb_secrets>"
echo
echo -e "\e[97m --key_luks=* \e[0m"
echo " The LUKS encryption / decryption passphrase for '/'-fs-encryption. Change '*' to your desired passphrase file."
echo " File MUST be placed in:"
echo " This MUST be a filename only and MUST be placed in the root-owned tmpfs secret root:"
echo " </dev/shm/cdlb_secrets>"
echo
echo -e "\e[97m --log-statistics-only \e[0m"
@@ -162,7 +164,8 @@ usage() {
echo -e "\e[97m --root-password-file </dev/shm/cdlb_secrets/password.txt>> \e[0m"
echo " Password file for 'root', if given, MUST be a string of 42 to 64 characters."
echo " If the argument is omitted, no further login authentication is required for the local console."
echo " MUST be placed in:"
echo " The path MUST be absolute, regular, non-symlink, root-owned, and mode 0400 after normalization."
echo " RECOMMENDED path:"
echo " </dev/shm/cdlb_secrets/password.txt>"
echo
echo -e "\e[97m --secure-boot-profile <STRING> one of <debian-shim | ciss-uki> \e[0m"
@@ -178,7 +181,7 @@ usage() {
echo " specified via '--signing_key=*'. If the keyring is protected, then provide the passphrase in its own file."
echo " Specify the fingerprint of the key to use via '--signing_key_fpr=*'."
echo " Optionally import an offline GPG CA signing public key via: '--signing_ca=*'."
echo " Change '*' to your desired files / fingerprint. Files MUST be placed in:"
echo " Change '*' to your desired filename-only files / fingerprint. Files MUST be placed in:"
echo " </dev/shm/cdlb_secrets>"
echo
echo -e "\e[97m --sops-version <STRING> \e[0m"
@@ -201,6 +204,7 @@ usage() {
echo
echo -e "\e[97m --ssh-pubkey </dev/shm/cdlb_secrets/> \e[0m"
echo " Imports the SSH Public Key from the file 'authorized_keys' into the Live ISO."
echo " Directory MUST be absolute, regular, non-symlink, root-owned, and not group/world-writable."
echo " Key file MUST be placed in:"
echo " </dev/shm/cdlb_secrets/authorized_keys>"
echo