diff --git a/ciss_live_builder.sh b/ciss_live_builder.sh index 49a5fea..323ee2c 100644 --- a/ciss_live_builder.sh +++ b/ciss_live_builder.sh @@ -124,22 +124,28 @@ sleep 4 printf "\e[95m🧪 %s starting ... \e[0m\n" "${BASH_SOURCE[0]}" declare -grx VAR_SETUP="true" -### SECURING SECRETS ARTIFACTS. -test ! -L "${VAR_TMP_SECRET}" || { - . ./var/global.var.sh - printf "\e[91m❌ Refusing symlink: '%s'! Bye... \e[0m\n" "${VAR_TMP_SECRET}" >&2 - exit "${ERR_SECRETSSYM}" -} -find "${VAR_TMP_SECRET}" -type f -exec chmod 0400 {} + -find "${VAR_TMP_SECRET}" -type f -exec chown root:root {} + - ### SOURCING VARIABLES. [[ "${VAR_SETUP}" == true ]] && { source_guard "./var/color.var.sh" source_guard "./var/global.var.sh" } -### SOURCING LIBRARIES. +### SOURCE THE MINIMUM REQUIRED FOR EARLY EXIT CLEANUP COVERAGE. +[[ "${VAR_SETUP}" == true ]] && { + source_guard "./lib/lib_secret_validation.sh" + source_guard "./lib/lib_build_directory.sh" + source_guard "./lib/lib_debug_sanitizer.sh" + source_guard "./lib/lib_clean_up.sh" + source_guard "./lib/lib_trap_on_err.sh" + source_guard "./lib/lib_trap_on_exit.sh" +} + +trap 'trap_on_exit "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' EXIT + +### Validate the fixed tmpfs secret staging area without modifying operator-provided files. +validate_secret_staging_area + +### SOURCING REMAINING LIBRARIES. [[ "${VAR_SETUP}" == true ]] && { source_guard "./lib/lib_arg_parser.sh" source_guard "./lib/lib_arg_priority_check.sh" @@ -158,7 +164,6 @@ find "${VAR_TMP_SECRET}" -type f -exec chown root:root {} + source_guard "./lib/lib_ciss_upgrades_boot.sh" source_guard "./lib/lib_ciss_upgrades_build.sh" source_guard "./lib/lib_clean_screen.sh" - source_guard "./lib/lib_clean_up.sh" source_guard "./lib/lib_copy_integrity.sh" source_guard "./lib/lib_gnupg.sh" source_guard "./lib/lib_hardening_root_pw.sh" @@ -174,12 +179,13 @@ find "${VAR_TMP_SECRET}" -type f -exec chown root:root {} + source_guard "./lib/lib_run_analysis.sh" source_guard "./lib/lib_sanitizer.sh" source_guard "./lib/lib_secureboot_profile.sh" - source_guard "./lib/lib_trap_on_err.sh" - source_guard "./lib/lib_trap_on_exit.sh" source_guard "./lib/lib_update_microcode.sh" source_guard "./lib/lib_usage.sh" } +### Add ERR handling after all remaining libraries are available. +trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR + ### PRE-SCAN SECURE BOOT PROFILE FOR BUILD-HOST PACKAGE CHECKS. ### Formal validation still happens in arg_parser(). for ((idx=0; idx<${#ARY_PARAM_ARRAY[@]}; idx++)); do @@ -223,10 +229,6 @@ if ! ${VAR_HANDLER_AUTOBUILD}; then printf "XXX\nInitialization done ... \nXXX\n ### Updating Status of Dialog Gauge Bar. if ! ${VAR_HANDLER_AUTOBUILD}; then printf "XXX\nActivate traps ... \nXXX\n50\n" >&3; fi -### Following the CISS Bash naming and ordering scheme: -trap 'trap_on_exit "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' EXIT -trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR - ### Updating Status of Dialog Gauge Bar. if ! ${VAR_HANDLER_AUTOBUILD}; then printf "XXX\nSanitizing Arguments ... \nXXX\n75\n" >&3; fi arg_check "$@" diff --git a/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary b/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary index be5a0da..60ce34d 100644 --- a/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary +++ b/config/hooks/live/zzzz_ciss_crypt_squash.hook.binary @@ -66,6 +66,49 @@ readonly -f preallocate declare ROOTFS="${VAR_HANDLER_BUILD_DIR}/binary/live/filesystem.squashfs" declare LUKSFS="${VAR_HANDLER_BUILD_DIR}/binary/live/ciss_rootfs.crypt" declare KEYFD="" +declare LUKS_KEY_FILE="" +declare LUKS_KEY_FILENAME="${VAR_LUKS_KEY:-luks.txt}" +declare LUKS_KEY_LINK_COUNT="" +declare LUKS_KEY_MODE="" +declare LUKS_KEY_OWNER="" +declare SECRET_ROOT_FS="" +declare SECRET_ROOT_MODE="" +declare SECRET_ROOT_OWNER="" + +if [[ -L "${VAR_TMP_SECRET}" || ! -d "${VAR_TMP_SECRET}" ]]; then + printf "\e[91m❌ Unsafe secret root rejected. \e[0m\n" >&2 + exit 42 +fi + +SECRET_ROOT_OWNER="$(stat -c '%u' "${VAR_TMP_SECRET}")" +SECRET_ROOT_MODE="$(stat -c '%a' "${VAR_TMP_SECRET}")" +SECRET_ROOT_FS="$(stat -f -c '%T' "${VAR_TMP_SECRET}")" +if [[ "${SECRET_ROOT_OWNER}" != "${EUID}" || "${SECRET_ROOT_MODE}" != "700" \ + || ( "${SECRET_ROOT_FS}" != "tmpfs" && "${SECRET_ROOT_FS}" != "ramfs" ) ]]; then + printf "\e[91m❌ Unsafe secret-root ownership, permissions, or filesystem rejected. \e[0m\n" >&2 + exit 42 +fi + +if [[ -z "${LUKS_KEY_FILENAME}" || "${LUKS_KEY_FILENAME}" == "." || "${LUKS_KEY_FILENAME}" == ".." \ + || "${LUKS_KEY_FILENAME}" == */* || ! "${LUKS_KEY_FILENAME}" =~ ^[A-Za-z0-9._@%+=:,~-]+$ ]]; then + printf "\e[91m❌ Unsafe LUKS key filename rejected. \e[0m\n" >&2 + exit 42 +fi + +LUKS_KEY_FILE="${VAR_TMP_SECRET}/${LUKS_KEY_FILENAME}" +if [[ -L "${LUKS_KEY_FILE}" || ! -f "${LUKS_KEY_FILE}" ]]; then + printf "\e[91m❌ Unsafe LUKS key file rejected. \e[0m\n" >&2 + exit 42 +fi + +LUKS_KEY_OWNER="$(stat -c '%u' "${LUKS_KEY_FILE}")" +LUKS_KEY_MODE="$(stat -c '%a' "${LUKS_KEY_FILE}")" +LUKS_KEY_LINK_COUNT="$(stat -c '%h' "${LUKS_KEY_FILE}")" +if [[ "${LUKS_KEY_OWNER}" != "${EUID}" || "${LUKS_KEY_LINK_COUNT}" != "1" \ + || ( "${LUKS_KEY_MODE}" != "400" && "${LUKS_KEY_MODE}" != "600" ) ]]; then + printf "\e[91m❌ Unsafe LUKS key ownership, permissions, or link count rejected. \e[0m\n" >&2 + exit 42 +fi # shellcheck disable=SC2155 declare -i VAR_ROOTFS_SIZE=$(stat -c%s -- "${ROOTFS}") @@ -82,7 +125,7 @@ declare -i VAR_LUKSFS_SIZE=$(( ( (BASE_SIZE + ALIGN_BYTES - 1) / ALIGN_BYTES ) * preallocate "${LUKSFS}" "${VAR_LUKSFS_SIZE}" -exec {KEYFD}<"${VAR_TMP_SECRET}/luks.txt" +exec {KEYFD}<"${LUKS_KEY_FILE}" if [[ "${VAR_CDLB_INSIDE_RUNNER}" == "false" ]]; then @@ -146,7 +189,7 @@ cryptsetup close crypt_liveiso exec {KEYFD}<&- -shred -fzu -n 5 -- "${VAR_TMP_SECRET}/luks.txt" +shred -fzu -n 5 -- "${LUKS_KEY_FILE}" rm -f -- "${ROOTFS}" diff --git a/lib/lib_arg_parser.sh b/lib/lib_arg_parser.sh index 680957c..82d26d4 100644 --- a/lib/lib_arg_parser.sh +++ b/lib/lib_arg_parser.sh @@ -57,20 +57,17 @@ guard_sourcing || return "${ERR_GUARD_SRCE}" # None # Returns: # ERR_ARG_MSMTCH: on failure -# ERR_ARG_MSMTCH: on failure +# ERR_BUILD_PATH: on failure # ERR_CONTROL_CT: on failure # ERR_DROPBEAR_V: on failure -# ERR_MISS_PWD_F: on failure # ERR_MISS_PWD_P: on failure -# ERR_NOTABSPATH: on failure -# ERR_OWNS_PWD_F: on failure # ERR_PASS_LENGH: on failure # ERR_PASS_PLICY: on failure # ERR_REIONICE_P: on failure # ERR_REIO_C_VAL: on failure # ERR_REIO_P_VAL: on failure # ERR_RENICE_PRI: on failure -# ERR_RGHT_PWD_F: on failure +# ERR_SECRET_PATH: on failure # ERR_SPLASH_PNG: on failure # ERR__SOPS__VER: on failure # ERR__SSH__PORT: on failure @@ -134,12 +131,9 @@ arg_parser() { ;; --build-directory) - declare -gx VAR_HANDLER_BUILD_DIR="${2}" - if [[ ! "${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 build_directory="${2-}" + validate_build_directory_path "${build_directory}" build_directory || exit "${ERR_BUILD_PATH}" + declare -gx VAR_HANDLER_BUILD_DIR="${build_directory}" declare -gx VAR_BUILD_LOG="${VAR_HANDLER_BUILD_DIR}/cdlb_${VAR_ISO8601}_build.log" shift 2 ;; @@ -266,18 +260,22 @@ arg_parser() { ;; --key_age=*) + declare age_key="${1#*=}" + validate_secret_file_in_root "${age_key}" "SOPS Age key" || exit "${ERR_SECRET_PATH}" # shellcheck disable=SC2034 declare -gx VAR_AGE="true" # shellcheck disable=SC2034 - declare -gx VAR_AGE_KEY="${1#*=}" + declare -gx VAR_AGE_KEY="${age_key}" shift 1 ;; --key_luks=*) + declare luks_key="${1#*=}" + validate_secret_file_in_root "${luks_key}" "LUKS key file" || exit "${ERR_SECRET_PATH}" # shellcheck disable=SC2034 declare -gx VAR_LUKS="true" # shellcheck disable=SC2034 - declare -gx VAR_LUKS_KEY="${1#*=}" + declare -gx VAR_LUKS_KEY="${luks_key}" shift 1 ;; @@ -473,39 +471,7 @@ arg_parser() { fi - if [[ ! -f "${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}" - - fi - - declare owner - owner=$(stat -c '%U:%G' "${pw_file}") - if [[ "${owner}" != "root:root" ]]; then - chown root:root "${pw_file}" || { - if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi - printf "\e[91m❌ Error: --root-password-file failed to set owner root:root on '%s'.\e[0m\n" "${pw_file}" >&2 - # shellcheck disable=SC2162 - read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m' - exit "${ERR_OWNS_PWD_F}" - } - fi - - declare perms - perms=$(stat -c '%a' "${pw_file}") - if [[ "${perms}" -ne 400 ]]; then - chmod 0400 "${pw_file}" || { - if ! ${VAR_HANDLER_AUTOBUILD}; then boot_screen_cleaner; fi - printf "\e[91m❌ Error: --root-password-file failed to set permissions 0400 on '%s'.\e[0m\n" "${pw_file}" >&2 - # shellcheck disable=SC2162 - read -p $'\e[92m✅ Press \'ENTER\' to exit the script ... \e[0m' - exit "${ERR_RGHT_PWD_F}" - } - fi + validate_secret_absolute_file "${pw_file}" "root password file" || exit "${ERR_SECRET_PATH}" declare plaintext_pw ### No tracing for security reasons ---------------------------------------------------------------------------------- @@ -558,6 +524,7 @@ arg_parser() { [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x hash_temp=$(mkpasswd --method=sha-512 --salt="${salt}" --rounds=8388608 "${plaintext_pw}") + register_secret_value "${hash_temp}" ### Turn on tracing again -------------------------------------------------------------------------------------------- [[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x @@ -606,16 +573,20 @@ arg_parser() { ;; --signing_ca=*) + declare signing_ca="${1#*=}" + validate_secret_file_in_root "${signing_ca}" "signing CA file" || exit "${ERR_SECRET_PATH}" # shellcheck disable=SC2034 - declare -gx VAR_SIGNING_CA="${1#*=}" + declare -gx VAR_SIGNING_CA="${signing_ca}" shift 1 ;; --signing_key=*) + declare signing_key="${1#*=}" + validate_secret_file_in_root "${signing_key}" "signing key file" || exit "${ERR_SECRET_PATH}" # 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 +597,10 @@ arg_parser() { ;; --signing_key_pass=*) + declare signing_key_pass="${1#*=}" + validate_secret_file_in_root "${signing_key_pass}" "signing passphrase file" || exit "${ERR_SECRET_PATH}" # shellcheck disable=SC2034 - declare -gx VAR_SIGNING_KEY_PASS="${1#*=}" + declare -gx VAR_SIGNING_KEY_PASS="${signing_key_pass}" shift 1 ;; @@ -694,8 +667,11 @@ arg_parser() { ;; --ssh-pubkey) + declare ssh_pubkey_dir="${2-}" + validate_secret_absolute_directory "${ssh_pubkey_dir}" "SSH public-key directory" || exit "${ERR_SECRET_PATH}" + validate_secret_file "${ssh_pubkey_dir}/authorized_keys" "SSH authorized_keys file" || exit "${ERR_SECRET_PATH}" # shellcheck disable=SC2034 - declare -gx VAR_SSHPUBKEY="${2}" + declare -gx VAR_SSHPUBKEY="${ssh_pubkey_dir}" shift 2 ;; diff --git a/lib/lib_check_secrets.sh b/lib/lib_check_secrets.sh index e82448d..c1c2c5c 100644 --- a/lib/lib_check_secrets.sh +++ b/lib/lib_check_secrets.sh @@ -23,36 +23,26 @@ guard_sourcing || return "${ERR_GUARD_SRCE}" # 0: on success ####################################### x_remove() { + declare luks_key_filename="${VAR_LUKS_KEY:-luks.txt}" luks_key_path="" signing_pass_path="" + declare -a find_args=("${VAR_TMP_SECRET}" -xdev -type f) + printf "\e[95m🧪 %s starting ... \e[0m\n" "${BASH_SOURCE[0]}" - declare _old_nullglob="" _old_dotglob="" - - ### Enable nullglob/dotglob, disable failglob for safe globbing. - _old_nullglob="$(shopt -p nullglob || true)" - _old_dotglob="$( shopt -p dotglob || true)" - - shopt -s nullglob dotglob + validate_secret_staging_area || return "${ERR_SECRET_PATH}" 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" \ - -print0 \ - | xargs -0 --no-run-if-empty shred -fzu -n 5 -- - - else - - ### 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 - + validate_secret_file_in_root "${VAR_SIGNING_KEY_PASS}" "signing passphrase file" || return "${ERR_SECRET_PATH}" + signing_pass_path="${VAR_TMP_SECRET}/${VAR_SIGNING_KEY_PASS}" + find_args+=(! -path "${signing_pass_path}") fi - eval "${_old_nullglob}" 2>/dev/null || true - eval "${_old_dotglob}" 2>/dev/null || true + validate_secret_file_in_root "${luks_key_filename}" "LUKS key file" || return "${ERR_SECRET_PATH}" + luks_key_path="${VAR_TMP_SECRET}/${luks_key_filename}" + find_args+=(! -path "${luks_key_path}") + + # shellcheck disable=SC2312 + find "${find_args[@]}" -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 -- + find "${VAR_TMP_SECRET}" -xdev -depth -type d -empty -delete printf "\e[92m✅ %s successfully applied. \e[0m\n" "${BASH_SOURCE[0]}" diff --git a/lib/lib_clean_up.sh b/lib/lib_clean_up.sh index 3075257..3bca5bb 100644 --- a/lib/lib_clean_up.sh +++ b/lib/lib_clean_up.sh @@ -32,15 +32,7 @@ guard_sourcing || return "${ERR_GUARD_SRCE}" # 0: on success ####################################### clean_up() { - declare clean_exit_code="$1" fs_type="" _old_nullglob="" _old_dotglob="" _old_failglob="" - - ### Enable nullglob/dotglob, disable failglob for safe globbing. - _old_nullglob="$(shopt -p nullglob || true)" - _old_dotglob="$( shopt -p dotglob || true)" - _old_failglob="$(shopt -p failglob || true)" - - shopt -s nullglob dotglob - shopt -u failglob + declare chroot_directory="" clean_exit_code="$1" fs_type="" includes_directory="" if [[ -e /dev/mapper/crypt_liveiso ]]; then cryptsetup close crypt_liveiso || true @@ -52,10 +44,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,36 +92,41 @@ 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 - - ### 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 only after re-validating the fixed tmpfs staging area. + if validate_secret_staging_area "true"; 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 -- - - ### Remove empty directories (bottom-up). - find "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" -depth -xdev -type d -empty -delete - + 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 + else + printf "\e[93m⚠ Secret cleanup skipped because the staging area failed validation. \e[0m\n" >&2 fi - ### Delete all files and directories below ./chroot. - if [[ -d "${VAR_HANDLER_BUILD_DIR}/chroot" ]]; then - - rm -rf "${VAR_HANDLER_BUILD_DIR}/chroot" + ### Destructive build cleanup requires the exact builder-owned directory marker. + if [[ -n "${VAR_HANDLER_BUILD_DIR}" ]] && validate_build_directory_marker "${VAR_HANDLER_BUILD_DIR}" "true"; then + if [[ -e "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" || -L "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot" ]]; then + if validate_build_directory_subpath "${VAR_HANDLER_BUILD_DIR}" "config/includes.chroot" includes_directory "true"; then + # shellcheck disable=SC2312 + find "${includes_directory}" -xdev -type f -print0 | xargs -0 --no-run-if-empty shred -fzu -n 5 -- || true + find "${includes_directory}" -depth -xdev -type d -empty -delete || true + else + printf "\e[93m⚠ Build includes cleanup skipped because the exact subpath failed validation. \e[0m\n" >&2 + fi + fi + if [[ -e "${VAR_HANDLER_BUILD_DIR}/chroot" || -L "${VAR_HANDLER_BUILD_DIR}/chroot" ]]; then + if validate_build_directory_subpath "${VAR_HANDLER_BUILD_DIR}" "chroot" chroot_directory "true"; then + remove_build_paths "${chroot_directory}" || true + else + printf "\e[93m⚠ Build chroot cleanup skipped because the exact subpath failed validation. \e[0m\n" >&2 + fi + fi + elif [[ -n "${VAR_HANDLER_BUILD_DIR}" ]]; then + printf "\e[93m⚠ Build-directory cleanup skipped because the exact builder-owned marker failed validation. \e[0m\n" >&2 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 - return 0 } ### Prevents accidental 'unset -f'. diff --git a/lib/lib_gnupg.sh b/lib/lib_gnupg.sh index 1737789..4fc07af 100644 --- a/lib/lib_gnupg.sh +++ b/lib/lib_gnupg.sh @@ -41,6 +41,12 @@ init_gnupg() { if [[ "${VAR_SIGNER}" == "true" ]]; then + validate_secret_file_in_root "${VAR_SIGNING_KEY}" "signing key file" || return "${ERR_SECRET_PATH}" + validate_secret_file_in_root "${VAR_SIGNING_KEY_PASS}" "signing passphrase file" || return "${ERR_SECRET_PATH}" + if [[ -n "${VAR_SIGNING_CA}" ]]; then + validate_secret_file_in_root "${VAR_SIGNING_CA}" "signing CA file" || return "${ERR_SECRET_PATH}" + fi + __umask=$(umask) umask 0077 @@ -82,6 +88,7 @@ EOF declare __pw="" __pw="$(<"${VAR_SIGNING_KEY_PASSFILE}")"; __pw="${__pw%$'\r'}"; printf '%s' "${__pw}" >| "${VAR_SIGNING_KEY_PASSFILE}" + register_secret_value "${__pw}" __pw="" && unset __pw ### Turn on tracing again ---------------------------------------------------------------------------------------------------- diff --git a/lib/lib_hardening_ultra.sh b/lib/lib_hardening_ultra.sh index 6b89183..ea80ef6 100644 --- a/lib/lib_hardening_ultra.sh +++ b/lib/lib_hardening_ultra.sh @@ -182,6 +182,8 @@ hardening_ultra() { printf "\e[95m🧪 Updating SSH Keys, Ports ... \e[0m\n" ### ./config/includes.chroot/root/.ssh --------------------------------------------------------------------------------------- + validate_secret_absolute_directory "${VAR_SSHPUBKEY}" "SSH public-key directory" || return "${ERR_SECRET_PATH}" + validate_secret_file "${VAR_SSHPUBKEY}/authorized_keys" "SSH authorized_keys file" || return "${ERR_SECRET_PATH}" 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/" diff --git a/lib/lib_lb_config_start.sh b/lib/lib_lb_config_start.sh index d07f48e..246a521 100644 --- a/lib/lib_lb_config_start.sh +++ b/lib/lib_lb_config_start.sh @@ -23,36 +23,22 @@ guard_sourcing || return "${ERR_GUARD_SRCE}" # 0: on success ####################################### lb_config_start() { + declare canonical_build_dir="" + printf "\e[95m🧪 %s starting ... \e[0m\n" "${BASH_SOURCE[0]}" - if [[ ! -d ${VAR_HANDLER_BUILD_DIR} ]]; then - - mkdir -p "${VAR_HANDLER_BUILD_DIR}" - # shellcheck disable=SC2164 - cd "${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}" - - fi + initialize_build_directory "${VAR_HANDLER_BUILD_DIR}" canonical_build_dir || return "${ERR_BUILD_PATH}" + VAR_HANDLER_BUILD_DIR="${canonical_build_dir}" + cd "${VAR_HANDLER_BUILD_DIR}" || return "${ERR_BUILD_PATH}" if [[ -d "${VAR_HANDLER_BUILD_DIR}/.build" ]]; then - # shellcheck disable=SC2164 - cd "${VAR_HANDLER_BUILD_DIR}" + validate_build_directory_marker "${VAR_HANDLER_BUILD_DIR}" || return "${ERR_BUILD_PATH}" printf "\e[95m🧪 Deleting former config, binary and cache ... \e[0m\n" lb clean --binary --cache --purge --source - - if [[ "${PWD}" == "${VAR_HANDLER_BUILD_DIR}" && "${PWD}" != "/" && -n "${PWD}" ]]; then - - rm -rf -- ./* ./.??* - - fi + clean_build_directory_contents "${VAR_HANDLER_BUILD_DIR}" || return "${ERR_BUILD_PATH}" printf "\e[92m✅ Deleting former config, binary and cache done.\e[0m\n" diff --git a/lib/lib_primordial.sh b/lib/lib_primordial.sh index 105ef4e..6db9116 100644 --- a/lib/lib_primordial.sh +++ b/lib/lib_primordial.sh @@ -84,6 +84,7 @@ init_primordial() { ### Check for SOPS AGE key integration --------------------------------------------------------------------------------------- if [[ "${VAR_AGE,,}" == "true" ]]; then + validate_secret_file_in_root "${VAR_AGE_KEY}" "SOPS Age key" || return "${ERR_SECRET_PATH}" 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}" @@ -92,16 +93,35 @@ init_primordial() { ### Check for SSH CISS and PhysNet Primordial-Workflow™ integration ------------------------------------------------------- if [[ "${VAR_SSHFP,,}" == "true" ]]; then + declare secret_key_file="" + declare -a identity_files=() host_key_files=() + + validate_secret_directory "${VAR_TMP_SECRET}" "secret root" "true" || return "${ERR_SECRET_PATH}" + + while IFS= read -r -d '' secret_key_file; do + validate_secret_file "${secret_key_file}" "primordial SSH identity file" || return "${ERR_SECRET_PATH}" + identity_files+=("${secret_key_file}") + done < <(find "${VAR_TMP_SECRET}" -maxdepth 1 -type f -name 'id*' -print0) + + while IFS= read -r -d '' secret_key_file; do + validate_secret_file "${secret_key_file}" "primordial SSH host-key file" || return "${ERR_SECRET_PATH}" + host_key_files+=("${secret_key_file}") + done < <(find "${VAR_TMP_SECRET}" -maxdepth 1 -type f -name 'ssh_host_*' -print0) + + (( ${#identity_files[@]} > 0 && ${#host_key_files[@]} > 0 )) || { + secret_validation_error "required primordial SSH key files are missing" + return "${ERR_SECRET_PATH}" + } 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/" + install -m 0600 "${identity_files[@]}" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh/" normalize_ssh_keys_in_dir "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/.ssh" - shred -fzu -n 5 -- "${VAR_TMP_SECRET}/id"* 2>/dev/null || rm -f "${VAR_TMP_SECRET}/id"* + shred -fzu -n 5 -- "${identity_files[@]}" 2>/dev/null || rm -f "${identity_files[@]}" install -d -m 0700 "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh" - install -m 0600 "${VAR_TMP_SECRET}/ssh_host_"* "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh/" + install -m 0600 "${host_key_files[@]}" "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh/" normalize_ssh_keys_in_dir "${VAR_HANDLER_BUILD_DIR}/config/includes.chroot/root/ssh/" - shred -fzu -n 5 -- "${VAR_TMP_SECRET}/ssh_host_"* 2>/dev/null || rm -f "${VAR_TMP_SECRET}/ssh_host_"* + shred -fzu -n 5 -- "${host_key_files[@]}" 2>/dev/null || rm -f "${host_key_files[@]}" fi diff --git a/lib/lib_trap_on_exit.sh b/lib/lib_trap_on_exit.sh index 14a6bce..c49e01e 100644 --- a/lib/lib_trap_on_exit.sh +++ b/lib/lib_trap_on_exit.sh @@ -49,8 +49,6 @@ trap_on_exit() { print_scr_exit "${errcode}" - exit "${errcode}" - else if [[ "${ERRTRAP}" != "true" ]]; then @@ -63,9 +61,16 @@ trap_on_exit() { fi - exit "${errcode}" - fi + + if ! sanitize_debug_logs; then + printf "\e[93m⚠ Final debug-log sanitisation failed; preserving original exit status %s. \e[0m\n" "${errcode}" >&2 + if [[ -n "${LOG_ERROR:-}" && -f "${LOG_ERROR}" && ! -L "${LOG_ERROR}" ]]; then + printf "⚠ Final debug-log sanitisation failed; original exit status: %s.\n" "${errcode}" >> "${LOG_ERROR}" || true + fi + fi + + exit "${errcode}" } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034