Compare commits

...

2 Commits

Author SHA256 Message Date
93fe56e837 Merge remote-tracking branch 'origin/master'
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 53s
2025-09-10 18:36:19 +02:00
257187bf41 V8.00.000.2025.06.17
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
2025-09-10 18:36:00 +02:00

View File

@@ -17,8 +17,13 @@ guard_sourcing
# Globals:
# TARGET
# VAR_SETUP_PATH
# VAR_TEMP_PLAIN_MFA_SEED
# VAR_USER_MAX
# user_root_authentication_2fa_ssh
# user_root_authentication_2fa_tty
# user_root_authentication_access_ssh
# user_root_authentication_access_tty
# user_root_authentication_password
# user_root_password
# user_root_shell
# user_root_sshpubkey
@@ -32,10 +37,10 @@ accounts_setup() {
declare -r var_logfile="/root/.ciss/cdi/log/4520_accounts_setup.log"
declare -i i=0
declare tmp_username="" tmp_fullname="" tmp_uid="" tmp_gid="" tmp_shell="" tmp_password="" tmp_sshpubkey="" \
tmp_access_ssh="" tmp_access_tty="" tmp_auth_pwd="" tmp_2fa_ssh="" tmp_2fa_tty="" tmp_sudo="" tmp_restricted=""
tmp_access_tty="" tmp_auth_pwd="" tmp_2fa_ssh="" tmp_2fa_tty="" tmp_sudo="" tmp_restricted=""
declare var_username="" var_fullname="" var_uid="" var_gid="" var_shell="" var_password="" var_sshpubkey="" \
var_access_ssh="" var_access_tty="" var_auth_pwd="" var_2fa_ssh="" var_2fa_tty="" var_sudo="" var_restricted=""
declare var_chpasswd="" var_sshdir="" var_pam_login="/etc/pam.d/login"
var_access_tty="" var_auth_pwd="" var_2fa_ssh="" var_2fa_tty="" var_sudo="" var_restricted=""
declare var_chpasswd="" var_pam_login="/etc/pam.d/login"
chroot_logger "${TARGET}${var_logfile}"
@@ -91,10 +96,10 @@ accounts_setup() {
### 3) Check tty access capabilities.
case "${user_root_authentication_access_tty}" in
false)
### 1) Ensure the 'pam_access' line is not activated in '/etc/pam.d/login' and '/etc/pam.d/sshd' in parallel.
### 3) A) 1) Ensure the 'pam_access' line is not activated in '/etc/pam.d/login' and '/etc/pam.d/sshd' in parallel.
pam_access_sync_login_sshd
### 2) Ensure 'pam_securetty' in the auth phase; requisite causes immediate fail for disallowed ttys.
### 3) A) 2) Ensure 'pam_securetty' in the auth phase; requisite causes immediate fail for disallowed ttys.
if ! grep -qE '^\s*auth\s+requisite\s+pam_securetty\.so' "${var_pam_login}"; then
### Insert pam_securetty before pam_unix to fail early.
awk '
@@ -110,10 +115,10 @@ accounts_setup() {
' "${var_pam_login}" >| "${var_pam_login}.new" && mv -f "${var_pam_login}.new" "${var_pam_login}"
fi
### 3) Disallow all local access for root in '/etc/security/access.conf'.
### 3) A) 3) Disallow all local access for root in '/etc/security/access.conf'.
printf "-: root:ALL \n" >> "${TARGET}/etc/security/access.conf"
### 4) Empty "/etc/securetty".
### 3) A) 4) Empty "/etc/securetty".
cat << 'EOF' >| "${TARGET}/etc/securetty"
EOF
@@ -121,10 +126,10 @@ EOF
;;
true)
### 1) Allow local access for 'root' only on 'tty1' in '/etc/security/access.conf'.
### 3) B) 1) Allow local access for 'root' only on 'tty1' in '/etc/security/access.conf'.
printf "+: root:tty1 \n" >> "${TARGET}/etc/security/access.conf"
### 2) Allow local access for 'root' only on 'tty1' in '/etc/securetty'.
### 3) B) 2) Allow local access for 'root' only on 'tty1' in '/etc/securetty'.
cat << 'EOF' >| "${TARGET}/etc/securetty"
tty1
EOF
@@ -132,7 +137,7 @@ EOF
;;
esac
### Check the password policy for the 'root' account.
### 4) Check the password policy for the 'root' account.
case "${user_root_authentication_password}" in
false)
chroot_script "${TARGET}" "passwd -l root"
@@ -146,13 +151,13 @@ EOF
;;
esac
### Update the 'root' SSH pubkey, if provided via 'preseed.yaml'.
### 5) Update the 'root' SSH pubkey, if provided via 'preseed.yaml'.
if [[ -n "${user_root_sshpubkey:-}" ]]; then
printf "%s\n" "${user_root_sshpubkey}" >| "${TARGET}/root/.ssh/authorized_keys"
do_log "info" "file_only" "4520() User: 'root' SSH public key: inserted."
fi
### Update the 'root' 'totp'-policy and write the '.google_authenticator'-file.
### 6) Update the 'root' 'totp'-policy and write the '.google_authenticator'-file.
[[ "${user_root_authentication_2fa_ssh}" == "true" || "${user_root_authentication_2fa_tty}" == "true" ]] && \
write_google_authenticator_file "root"
@@ -160,7 +165,7 @@ EOF
[[ "${user_root_authentication_2fa_tty}" == "true" ]] && pam_access_totp_enable "root" "login"
### 7) Final status logging.
do_log "info" "file_only" "User: 'root' updated."
@@ -174,8 +179,7 @@ EOF
tmp_shell="user_user${i}_shell"
tmp_password="user_user${i}_password"
tmp_sshpubkey="user_user${i}_sshpubkey"
tmp_access_ssh="user_user${i}authentication_access_ssh"
tmp_access_tty="user_user${i}authentication_access_ssh"
tmp_access_tty="user_user${i}authentication_access_tty"
tmp_auth_pwd="user_user${i}authentication_password"
tmp_2fa_ssh="user_user${i}authentication_2fa_ssh"
tmp_2fa_tty="user_user${i}authentication_2fa_tty"
@@ -189,7 +193,6 @@ EOF
var_shell="${!tmp_shell}"
var_password="${!tmp_password}"
var_sshpubkey="${!tmp_sshpubkey}"
var_access_ssh"${!tmp_access_ssh}"
var_access_tty"${!tmp_access_tty}"
var_auth_pwd"${!tmp_auth_pwd}"
var_2fa_ssh"${!tmp_2fa_ssh}"
@@ -254,124 +257,79 @@ EOF
do_log "info" "file_only" "4520() Skeleton: '${var_username}' successfully generated."
### 2) Check SSH access capabilities.
# Nothing to do here as per user SSH capabilities are already handled in '4330_installation_ssh.sh'
### Nothing to do here as per-user SSH capabilities are already handled in '4330_installation_ssh.sh'.
### 3) Check tty access capabilities.
case "${var_access_tty}" in
false)
### 1) Ensure the 'pam_access' line is not activated in '/etc/pam.d/login' and '/etc/pam.d/sshd' in parallel.
### 3) A) 1) Ensure the 'pam_access' line is not activated in '/etc/pam.d/login' and '/etc/pam.d/sshd' in parallel.
pam_access_sync_login_sshd
### 2) This step is not required for user accounts.
### 3) A) 2) This step is not required for user accounts.
### 3) Disallow all local access for user in '/etc/security/access.conf'.
### 3) A) 3) Disallow all local access for user in '/etc/security/access.conf'.
printf "-: %s:ALL \n" "${var_username}" >> "${TARGET}/etc/security/access.conf"
### 4) This step is not required for user accounts.
### 3) A) 4) This step is not required for user accounts.
do_log "info" "file_only" "4520() User: '${var_username}' tty access: [false]"
;;
true)
### 1) Allow local access for 'user' only on 'tty1' in '/etc/security/access.conf'.
### 3) B) 1) Allow local access for 'user' only on 'tty1' in '/etc/security/access.conf'.
printf "+: %s:tty1 \n" "${var_username}" >> "${TARGET}/etc/security/access.conf"
### 2) Allow local access for 'root' only on 'tty1' in '/etc/securetty'.
cat << 'EOF' >| "${TARGET}/etc/securetty"
tty1
EOF
do_log "info" "file_only" "4520() User: 'root' tty access: [true]"
### 3) B) 2) This step is not required for user accounts.
do_log "info" "file_only" "4520() User: '${var_username}' tty access: [true]"
;;
esac
### 4) Check the password policy for the 'user' account.
case "${var_auth_pwd}" in
false)
chroot_script "${TARGET}" "passwd -l ${var_username}"
do_log "info" "file_only" "4520() User: '${var_username}' password access: [false]"
;;
true)
var_chpasswd="${var_username}:${var_password}"
chroot_script "${TARGET}" "echo \"${var_chpasswd}\" | chpasswd -e"
var_chpasswd=""
do_log "info" "file_only" "4520() User: '${var_username}' password access: [true]"
;;
esac
### 5) Update the 'user' SSH pubkey, if provided via 'preseed.yaml'.
if [[ -n "${var_sshpubkey:-}" ]]; then
printf "%s\n" "${var_sshpubkey}" >| "${TARGET}/home/${var_username}/.ssh/authorized_keys"
do_log "info" "file_only" "4520() User: '${var_username}' SSH public key: inserted."
fi
### 6) Update the 'root' 'totp'-policy and write the '.google_authenticator'-file.
[[ "${var_2fa_ssh}" == "true" || "${var_2fa_tty}" == "true" ]] && \
write_google_authenticator_file "${var_username}"
[[ "${var_2fa_ssh}" == "true" ]] && pam_access_totp_enable "${var_username}" "sshd"
[[ "${var_2fa_tty}" == "true" ]] && pam_access_totp_enable "${var_username}" "login"
var_chpasswd="${var_username}:${var_password}"
chroot_script "${TARGET}" "echo \"${var_chpasswd}\" | chpasswd -e"
var_chpasswd=""
### 7) Check sudo membership for user.
if [[ "${var_sudo}" == "true" ]]; then
chroot_exec "${TARGET}" usermod -aG sudo "${var_username}"
fi
if [[ -n "${var_sshpubkey}" ]]; then
var_sshdir="${TARGET}/home/${var_username}/.ssh"
install -d -m 0700 -o "${var_username}" -g "${var_username}" "${var_sshdir}"
install -m 0600 -o "${var_username}" -g "${var_username}" /dev/null "${var_sshdir}/authorized_keys"
grep -qxF "${var_sshpubkey}" "${var_sshdir}/authorized_keys" || \
printf "%s\n" "${var_sshpubkey}" >> "${var_sshdir}/authorized_keys"
fi
do_log "info" "file_only" "Created user: [${var_username}] UID: [${var_uid}], GID: [${var_gid}]"
### 8) Final status logging.
do_log "info" "file_only" "Created user: [${var_username}] UID: [${var_uid}] GID: [${var_gid}]"
done
unset VAR_TEMP_PLAIN_MFA_SEED
printf "-: ALL:ALL \n" >> "${TARGET}/etc/security/access.conf"
printf "# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf \n" >> "${TARGET}/etc/security/access.conf"
guard_dir && return 0
}
#######################################
# Writes '.google_authenticator'-file for the respective user.
# Globals:
# RANDOM
# TARGET
# Arguments:
# 1: Username
# Returns:
# 0: on success
#######################################
write_google_authenticator_file() {
### Declare Arrays, HashMaps, and Variables.
declare var_user="${1}" var_secret=""
case "${1}" in
root) declare var_base="${TARGET}/root" ;;
*) declare var_base="${TARGET}/home/${var_user}" ;;
esac
declare -i i=0
guard_trace on
var_secret="$(generate_totp_secret "${var_user}")"
umask 0077
{
printf '%s\n' "${var_secret}"
printf '"RATE_LIMIT 3 30"\n'
printf '"WINDOW 10"\n'
printf '"DISALLOW_REUSE"\n'
printf '"TOTP_AUTH"\n'
### Emergency Codes:
for i in {0..7}; do printf '%08d\n' "$(( RANDOM % 100000000 ))"; done
} >| "${var_base}/.google_authenticator"
chown "${var_user}:${var_user}" "${var_base}/.google_authenticator"
chmod 0600 "${var_base}/.google_authenticator"
{
printf '%s\n' "${var_user}"
printf '%s\n' "${var_secret}"
} >| "${DIR_TMP}/TOTP_${var_user}.secret"
chmod 0400 "${DIR_TMP}/TOTP_${var_user}.secret"
umask 0022
unset var_secret
guard_trace off
return 0
}
#######################################
# Generates a deterministic TOTP secret based on:
# Username, FQDN, MFA salt, MFA master seed
@@ -404,40 +362,6 @@ generate_totp_secret() {
printf '%s\n' "${var_secret}"
unset var_secret
guard_trace off
return 0
}
#######################################
# Reads a 256-bit seed from '${DIR_CNF}/mfa_master.txt' (64 hex chars) into VAR_TEMP_PLAIN_MFA_SEED.
# Globals:
# DIR_CNF
# VAR_TEMP_PLAIN_MFA_SEED
# Arguments:
# None
# Returns:
# 0: on success
# ERR_READ_SEED_FILE
#######################################
read_totp_seed(){
### Declare Arrays, HashMaps, and Variables.
declare -r var_mfa_seed_file="${DIR_CNF}/mfa_master.txt"
declare -g VAR_TEMP_PLAIN_MFA_SEED=""
guard_trace on
if ! read_password_file "${var_mfa_seed_file}" VAR_TEMP_PLAIN_MFA_SEED; then
return "${ERR_READ_SEED_FILE}"
fi
### Validate: exactly 64 hex.
[[ "${VAR_TEMP_PLAIN_MFA_SEED}" =~ ^[0-9a-fA-F]{64}$ ]] || return "${ERR_READ_SEED_FILE}"
guard_trace off
return 0
@@ -445,6 +369,8 @@ read_totp_seed(){
#######################################
# Ensure the 'pam_access' line is not activated in '/etc/pam.d/login' and '/etc/pam.d/sshd' in parallel.
# Globals:
# None
# Arguments:
# None
# Returns:
@@ -496,6 +422,8 @@ pam_access_sync_login_sshd() {
#######################################
# Enable per-user TOTP in a given PAM service (login, sshd, su, sudo).
# Globals:
# TARGET
# Arguments:
# 1: <username>
# 2: <pam_module>
@@ -563,4 +491,85 @@ pam_access_totp_enable() {
return 0
}
#######################################
# Reads a 256-bit seed from '${DIR_CNF}/mfa_master.txt' (64 hex chars) into VAR_TEMP_PLAIN_MFA_SEED.
# Globals:
# DIR_CNF
# VAR_TEMP_PLAIN_MFA_SEED
# Arguments:
# None
# Returns:
# 0: on success
# ERR_READ_SEED_FILE
#######################################
read_totp_seed(){
### Declare Arrays, HashMaps, and Variables.
declare -r var_mfa_seed_file="${DIR_CNF}/mfa_master.txt"
declare -g VAR_TEMP_PLAIN_MFA_SEED=""
guard_trace on
if ! read_password_file "${var_mfa_seed_file}" VAR_TEMP_PLAIN_MFA_SEED; then
return "${ERR_READ_SEED_FILE}"
fi
### Validate: exactly 64 hex.
[[ "${VAR_TEMP_PLAIN_MFA_SEED}" =~ ^[0-9a-fA-F]{64}$ ]] || return "${ERR_READ_SEED_FILE}"
guard_trace off
return 0
}
#######################################
# Writes '.google_authenticator'-file for the respective user.
# Globals:
# DIR_TMP
# RANDOM
# TARGET
# Arguments:
# 1: Username
# Returns:
# 0: on success
#######################################
write_google_authenticator_file() {
### Declare Arrays, HashMaps, and Variables.
declare var_user="${1}" var_secret=""
case "${1}" in
root) declare var_base="${TARGET}/root" ;;
*) declare var_base="${TARGET}/home/${var_user}" ;;
esac
declare -i i=0
guard_trace on
var_secret="$(generate_totp_secret "${var_user}")"
umask 0077
{
printf '%s\n' "${var_secret}"
printf '"RATE_LIMIT 3 30"\n'
printf '"WINDOW 10"\n'
printf '"DISALLOW_REUSE"\n'
printf '"TOTP_AUTH"\n'
### Emergency Codes:
for i in {0..7}; do printf '%08d\n' "$(( RANDOM % 100000000 ))"; done
} >| "${var_base}/.google_authenticator"
chown "${var_user}:${var_user}" "${var_base}/.google_authenticator"
chmod 0600 "${var_base}/.google_authenticator"
{
printf '%s\n' "${var_user}"
printf '%s\n' "${var_secret}"
} >| "${DIR_TMP}/TOTP_${var_user}.secret"
chmod 0400 "${DIR_TMP}/TOTP_${var_user}.secret"
umask 0022
guard_trace off
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh