Compare commits
2 Commits
5eadfa9b00
...
a9a7db7c6b
| Author | SHA256 | Date | |
|---|---|---|---|
|
a9a7db7c6b
|
|||
|
a2b1fcb457
|
@@ -13,14 +13,14 @@
|
||||
# This file contains configurations for the CISS.debian.installer
|
||||
# Master V8.00.000.2025.06.17
|
||||
# YAML specification: 1.2
|
||||
|
||||
#
|
||||
preseed:
|
||||
description: "Configuration values for automated installation of encrypted systems on this host via primordial-workflow™."
|
||||
created_at: "2025-10-23"
|
||||
created_for: "host_domain_tld"
|
||||
name: "CISS.debian.installer"
|
||||
version: "V8.00.000.2025.06.17"
|
||||
|
||||
#
|
||||
################################################################################################################################
|
||||
# APT settings
|
||||
################################################################################################################################
|
||||
|
||||
@@ -11,8 +11,8 @@ include_toc: true
|
||||
[](https://github.com/mvdan/sh)
|
||||
[](https://google.github.io/styleguide/shellguide.html)
|
||||
|
||||
[](https://docs.gitea.com/)
|
||||
[](https://www.jetbrains.com/store/?section=personal&billing=yearly)
|
||||
[](https://docs.gitea.com/)
|
||||
[](https://www.jetbrains.com/store/?section=personal&billing=yearly)
|
||||
[](https://keepassxc.org/)
|
||||
[](https://www.netcup.com/de)
|
||||
[](https://coresecret.eu/)
|
||||
|
||||
@@ -213,8 +213,8 @@ yaml_reader
|
||||
info_echo "1252_yaml_validator.sh"
|
||||
yaml_validator
|
||||
|
||||
#info_echo "1256_secret_parser.sh"
|
||||
#yaml_secret
|
||||
info_echo "1256_secret_parser.sh"
|
||||
yaml_secret
|
||||
|
||||
|
||||
### CDI_3200
|
||||
|
||||
@@ -44,28 +44,36 @@ yaml_parser() {
|
||||
|
||||
### Generate Arrays for [Grub Parameter], [Locales], [NTPSec Server FQDN], [Software Packages].
|
||||
while IFS='=' read -r var_key var_value; do
|
||||
|
||||
var_value=${var_value#\'}
|
||||
var_value=${var_value%\'}
|
||||
|
||||
# shellcheck disable=SC2034,SC2249
|
||||
case "${var_key}" in
|
||||
|
||||
grub_parameter_[0-9]*) ARY_BOOTPARAM+=("${var_value}") ;;
|
||||
locale_locale_[0-9]*) ARY_LOCALE+=("${var_value}") ;;
|
||||
ntp_server_[0-9]*) ARY_NTPSRVR+=("${var_value}") ;;
|
||||
ssh_allow_ipv4_[0-9]*) ARY_ALLOW_IPV4+=("${var_value}") ;;
|
||||
ssh_allow_ipv6_[0-9]*) ARY_ALLOW_IPV6+=("${var_value}") ;;
|
||||
software_[0-9]*) ARY_PACKAGES+=("${var_value}") ;;
|
||||
|
||||
esac
|
||||
|
||||
done < "${VAR_PRESEED}"
|
||||
|
||||
var_key=""
|
||||
|
||||
### Search all set variables for user_userN_name patterns.
|
||||
# shellcheck disable=SC2312
|
||||
while IFS='=' read -r var_key _; do
|
||||
|
||||
### Accept any of these keys: name, fullname, uid, gid, shell, password, sshpubkey, authentication_* and privileges_*
|
||||
if [[ "${var_key}" =~ ^user_user([0-9]+)_(name|fullname|uid|gid|shell|password|sshpubkey|authentication_[A-Za-z0-9_]+|privileges_[A-Za-z0-9_]+)$ ]]; then
|
||||
var_index=${BASH_REMATCH[1]}
|
||||
(( var_index > VAR_USER_MAX )) && VAR_USER_MAX=var_index
|
||||
fi
|
||||
|
||||
done < "${VAR_PRESEED}"
|
||||
|
||||
### If nothing matched, default to 0 (only user 0).
|
||||
|
||||
@@ -98,33 +98,74 @@ ciss_secret_varname_from_path() {
|
||||
readonly -f ciss_secret_varname_from_path
|
||||
|
||||
#######################################
|
||||
# Purpose:
|
||||
# High-performance parsing of only "*.value" keys from 'SECRETS.yaml' into Bash globals.
|
||||
# Wipes the specified file securely.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: File to wipe
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
ciss_secrets_wiper() {
|
||||
### Declare Arrays, HashMaps, and Variables.
|
||||
declare var_file="${1:-}"
|
||||
|
||||
if [[ -f "${var_file}" ]]; then
|
||||
: >| "${var_file}"
|
||||
shred -vfzu -n 5 "${var_file}" > /dev/null 2>&1 || rm -f -- "${var_file}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f ciss_secrets_wiper
|
||||
|
||||
#######################################
|
||||
# Parsing of only "*.value" keys from 'SECRETS.yaml' into Bash globals.
|
||||
# If the file contains SOPS markers, decrypt once (streaming) with sops/age, then yq parses in a single pass.
|
||||
# No base64, plain values preserved (including newlines). No repeated per-key decrypts or yq calls.
|
||||
# Conventions:
|
||||
# Variables: CISS_SECRET_<UPPER_SNAKE_CASE_PATH> (PATH excludes "secrets." and trailing ".value")
|
||||
# All with "declare -g" (no export).
|
||||
# Mapping: CISS_SECRETS_MAP["foo.bar"]=CISS_SECRET_FOO_BAR
|
||||
# Security:
|
||||
# No logging of values. No plaintext temp files. Streaming pipeline; no full-doc materialization.
|
||||
# Globals:
|
||||
# CISS_SECRETS_AGE
|
||||
# CISS_SECRETS_MAP
|
||||
# CISS_SECRETS_SOURCE
|
||||
# DIR_CNF
|
||||
# ERR_MISSING_AGE_KEY
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_DECRYPTION_SOPS: on failure
|
||||
# ERR_MISSING_AGE_BIN: on failure
|
||||
# ERR_MISSING_AGE_KEY: on failure
|
||||
#######################################
|
||||
yaml_secret() {
|
||||
### Declare Arrays, HashMaps, and Variables.
|
||||
declare -r SOPS_AGE_KEY_FILE="/root/.config/sops/age/keys.txt"
|
||||
declare secrets_encrypted="" secrets_yaml="${CISS_SECRETS_SOURCE}" \
|
||||
__path="" __path_wo_prefix="" __pipe_fd="" __umask="" __value="" __varname=""
|
||||
declare -r SOPS_AGE_KEY_FILE="${CISS_SECRETS_AGE}"
|
||||
declare -a __names=()
|
||||
declare secrets_encrypted="" secrets_if="${CISS_SECRETS_SOURCE}" secrets_of="${DIR_CNF}/SECRETS_DECRYPTED.yaml" \
|
||||
__SECRETS="${DIR_CNF}/SECRETS_BASH.var" \
|
||||
__base="" __name="" __umask="" __path_wo_prefix="" __val="" __varname=""
|
||||
|
||||
__umask=$(umask)
|
||||
umask 0077
|
||||
|
||||
# TODO: guard_trace on
|
||||
#guard_trace on
|
||||
|
||||
secrets_encrypted="$(yq -r '.secrets.x_files // false' -- "${secrets_if}")" || secrets_encrypted="false"
|
||||
do_log "debug" "file_only" "1256() 'secrets_encrypted' according to secrets.x_files: '${secrets_encrypted}'."
|
||||
|
||||
if grep -qE '(^|\s)sops:\s*$' -- "${secrets_if}" 2>/dev/null || grep -q 'ENC\[' -- "${secrets_if}" 2>/dev/null; then
|
||||
|
||||
secrets_encrypted="true"
|
||||
do_log "debug" "file_only" "1256() 'secrets_encrypted' according to heuristic mode: '${secrets_encrypted}'."
|
||||
|
||||
fi
|
||||
|
||||
secrets_encrypted="$(yq -r '.secrets.x_files // false' -- "${secrets_yaml}")" || secrets_encrypted="false"
|
||||
|
||||
if [[ "${secrets_encrypted}" == "true" ]]; then
|
||||
|
||||
@@ -137,67 +178,76 @@ yaml_secret() {
|
||||
|
||||
[[ -r "${SOPS_AGE_KEY_FILE}" ]] || return "${ERR_MISSING_AGE_KEY}"
|
||||
|
||||
fi
|
||||
sops -d --input-type=yaml --output-type=yaml -- "${secrets_if}" >| "${secrets_of}"
|
||||
|
||||
__umask=$(umask)
|
||||
umask 0077
|
||||
[[ -r "${secrets_of}" ]] || return "${ERR_DECRYPTION_SOPS}"
|
||||
|
||||
### Create the producer as a process substitution.
|
||||
if [[ "${secrets_encrypted}" == "true" ]]; then
|
||||
|
||||
### Decrypt once, stream into yq; avoid storing full doc in memory; emits '<path>\0<value>\0' for each 'secrets.*.value'
|
||||
# shellcheck disable=SC2016,SC2312
|
||||
exec {__pipe_fd}< <(
|
||||
sops -d --input-type=yaml --output-type=yaml -- "${secrets_yaml}" | yq -r -N -0 'leaf_paths as $p
|
||||
| select($p[0]=="secrets" and $p[-1]=="value")
|
||||
| ($p[0:-1] | join(".")), ((getpath($p)//"") | tostring)
|
||||
' -
|
||||
)
|
||||
|
||||
else
|
||||
|
||||
# shellcheck disable=SC2016,SC2312
|
||||
exec {__pipe_fd}< <( yq -r -N -0 'path(..) as $p | select($p[0]=="secrets" and $p[-1]=="value") | ($p[0:-1]|join("."))' -- "${secrets_yaml}" )
|
||||
ciss_secrets_wiper "${secrets_if}" && mv "${secrets_of}" "${secrets_if}"
|
||||
|
||||
fi
|
||||
|
||||
### Single consumer: read NUL-delimited pairs and assign variables.
|
||||
### Loop invariant: next read is PATH, then VALUE. Stop cleanly at EOF.
|
||||
while :; do
|
||||
yq -o=shell "${secrets_if}" >| "${__SECRETS}" && ciss_secrets_wiper "${secrets_if}"
|
||||
|
||||
### Read path (up to NUL); break on EOF.
|
||||
IFS= read -r -d '' __path <&"${__pipe_fd}" || break
|
||||
echo "${__path}"
|
||||
LC_ALL=C sed -n -E '
|
||||
/^[[:space:]]*(#|$)/b
|
||||
s/^[[:space:]]*export[[:space:]]+//
|
||||
/^[[:space:]]*[A-Za-z_][A-Za-z0-9_]*_value=/p
|
||||
' -- "${__SECRETS}" >| "${__SECRETS}.value_only"
|
||||
|
||||
### Read value (up to NUL); if missing (odd count), treat as empty
|
||||
IFS= read -r -d '' __value <&"${__pipe_fd}" || __value=""
|
||||
echo "${__value}"
|
||||
ciss_secrets_wiper "${__SECRETS}"
|
||||
|
||||
### Drop the leading 'secrets.' prefix for naming.
|
||||
__path_wo_prefix="${__path#secrets.}"
|
||||
mv -f -- "${__SECRETS}.value_only" "${__SECRETS}"
|
||||
|
||||
# shellcheck disable=SC1091 source=./${__SECRETS}
|
||||
source "${__SECRETS}"
|
||||
|
||||
### Iterate only variables ending in '_value'.
|
||||
# shellcheck disable=SC2312
|
||||
mapfile -t __names < <(compgen -A variable 'secrets_*_value')
|
||||
|
||||
for __name in "${__names[@]}"; do
|
||||
|
||||
### Value of the generated variable:
|
||||
__val="${!__name}"
|
||||
echo "${__val}"
|
||||
|
||||
### Strip suffix and leading namespace:
|
||||
# secrets_db_password_value -> base="secrets_db_password"
|
||||
__base="${__name%_value}"
|
||||
echo "${__base}"
|
||||
# secrets_db_password -> path_wo_prefix="db_password"
|
||||
__path_wo_prefix="${__base#secrets_}"
|
||||
echo "${__path_wo_prefix}"
|
||||
|
||||
### Canonical CISS name:
|
||||
__varname="$(ciss_secret_varname_from_path "${__path_wo_prefix}")"
|
||||
echo "${__varname}"
|
||||
|
||||
### Assign to a global variable, preserving content verbatim (including newlines).
|
||||
### Assign as global (verbatim, preserves newlines).
|
||||
unset -v "${__varname}"
|
||||
declare -g "${__varname}"
|
||||
printf -v "${__varname}" '%s' "${__value}"
|
||||
echo "declare -g ${__varname}"
|
||||
|
||||
printf -v "${__varname}" '%s' "${__val}"
|
||||
echo "printf -v ${__varname} ${__val}"
|
||||
|
||||
### Track in the map (without .value)
|
||||
CISS_SECRETS_MAP["${__path_wo_prefix}"]="${__varname}"
|
||||
|
||||
done
|
||||
|
||||
### Close the producer FD
|
||||
exec {__pipe_fd}<&-
|
||||
### Hygiene: remove the intermediate variables to reduce secret surface, e.g., unset 'secrets_*_value' after transfer.
|
||||
for __name in "${__names[@]}"; do
|
||||
unset -v "${__name}"
|
||||
done
|
||||
|
||||
umask "${__umask}"
|
||||
|
||||
echo "Inside 1256()"
|
||||
sleep 60
|
||||
|
||||
# TODO: guard_trace off
|
||||
#guard_trace off
|
||||
|
||||
guard_dir; return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
|
||||
@@ -60,6 +60,7 @@ declare -girx ERR_VERIFY_LOGROTATE=213 # Error verification by 'logrotate'.
|
||||
declare -girx ERR_READ_AUTH_FILE=212 # Error reading the Luks Backup auth token file.
|
||||
declare -girx ERR_ACCOUNT_CREATE=211 # Error creating user accounts.
|
||||
declare -girx ERR_LUKS_HEADER_ENC=210 # Error encrypting LUKS Header backup.
|
||||
declare -girx ERR_DECRYPTION_SOPS=132 # An error occurred while decrypting SECRETS.yaml.
|
||||
declare -girx ERR_MISSING_AGE_BIN=130 # SOPS binary for decryption SECRETS.yaml missing.
|
||||
declare -girx ERR_MISSING_AGE_KEY=129 # AGE key for decryption SECRETS.yaml values missing.
|
||||
declare -girx ERR_GUARD_SOURCE=128 # Module tried to load twice.
|
||||
|
||||
@@ -52,13 +52,11 @@ declare -grx VAR_SETUP_PART="${DIR_CNF}/partitioning.yaml"
|
||||
|
||||
### Initialize SECRETS.yaml variables.
|
||||
# shellcheck disable=SC2034
|
||||
declare -gA CISS_SECRETS_MAP=() # YAML path (w/o '.value' and without 'secrets.') -> varname.
|
||||
declare -gA CISS_SECRETS_MAP=() # YAML path (w/o '.value' and without 'secrets.') -> varname.
|
||||
# shellcheck disable=SC2034
|
||||
declare -g CISS_SECRETS_AGE="" # AGE PRIVATE Keyfile to decrypt SOPS encrypted values.
|
||||
declare -g CISS_SECRETS_AGE="/root/.config/sops/age/keys.txt" # AGE PRIVATE Keyfile to decrypt SOPS encrypted values.
|
||||
# shellcheck disable=SC2034
|
||||
declare -gr CISS_SECRETS_SOURCE="${DIR_CNF}/SECRETS.yaml" # Effective YAML source used (plain or decrypted stream)
|
||||
# shellcheck disable=SC2034
|
||||
declare -g CISS_SECRETS_XFILES="" # Derived from SOPS presence heuristic.
|
||||
declare -gr CISS_SECRETS_SOURCE="${DIR_CNF}/SECRETS.yaml" # Effective YAML source used (plain or decrypted stream).
|
||||
|
||||
### Base mount paths and variables for debootstrap.
|
||||
declare -grx TARGET="/target"
|
||||
|
||||
Reference in New Issue
Block a user