V8.00.000.2025.06.17
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m30s
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m30s
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
@@ -58,10 +58,11 @@ accounts_setup() {
|
|||||||
|
|
||||||
### Update pam modules for 2fa.
|
### Update pam modules for 2fa.
|
||||||
mkdir -p "${var_target}/root/.ciss/cdi/backup/etc/pam.d"
|
mkdir -p "${var_target}/root/.ciss/cdi/backup/etc/pam.d"
|
||||||
write_pam_login "${var_target}"
|
write_pam_login "${var_target}"
|
||||||
write_pam_sshd "${var_target}"
|
write_pam_sshd "${var_target}"
|
||||||
write_pam_su "${var_target}"
|
write_pam_su "${var_target}"
|
||||||
write_pam_sudo "${var_target}"
|
write_pam_su-l "${var_target}"
|
||||||
|
write_pam_sudo-i "${var_target}"
|
||||||
|
|
||||||
### Prepare the '2fa'-seed variable.
|
### Prepare the '2fa'-seed variable.
|
||||||
read_totp_seed
|
read_totp_seed
|
||||||
@@ -1195,10 +1196,7 @@ write_pam_su() {
|
|||||||
auth sufficient pam_rootok.so
|
auth sufficient pam_rootok.so
|
||||||
|
|
||||||
# Hardening of '/bin/su': only members of the group 'sudo' can su to root.
|
# Hardening of '/bin/su': only members of the group 'sudo' can su to root.
|
||||||
auth required pam_wheel.so use_uid group=sudo
|
auth required pam_wheel.so group=sudo
|
||||||
|
|
||||||
# Reuse a recent successful su-auth within the TTL:
|
|
||||||
auth sufficient pam_timestamp.so
|
|
||||||
|
|
||||||
# Standard password for the target account (root or other):
|
# Standard password for the target account (root or other):
|
||||||
@include common-auth
|
@include common-auth
|
||||||
@@ -1220,8 +1218,6 @@ auth required pam_google_authenticator.so
|
|||||||
|
|
||||||
@include common-account
|
@include common-account
|
||||||
@include common-session
|
@include common-session
|
||||||
# Keep a ticket to avoid re-prompts during this shell session:
|
|
||||||
session optional pam_timestamp.so
|
|
||||||
|
|
||||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
||||||
EOF
|
EOF
|
||||||
@@ -1241,7 +1237,7 @@ EOF
|
|||||||
readonly -f write_pam_su
|
readonly -f write_pam_su
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Writes CISS Header for '/etc/pam.d/sudo'.
|
# Writes CISS Header for '/etc/pam.d/su-l'.
|
||||||
# Globals:
|
# Globals:
|
||||||
# None
|
# None
|
||||||
# Arguments:
|
# Arguments:
|
||||||
@@ -1249,15 +1245,81 @@ readonly -f write_pam_su
|
|||||||
# Returns:
|
# Returns:
|
||||||
# 0: on success
|
# 0: on success
|
||||||
#######################################
|
#######################################
|
||||||
write_pam_sudo() {
|
write_pam_su-l() {
|
||||||
### Declare Arrays, HashMaps, and Variables.
|
### Declare Arrays, HashMaps, and Variables.
|
||||||
declare -r var_target="$1"
|
declare -r var_target="$1"
|
||||||
|
|
||||||
mv "${var_target}/etc/pam.d/sudo" "${var_target}/root/.ciss/cdi/backup/etc/pam.d/sudo"
|
mv "${var_target}/etc/pam.d/su-l" "${var_target}/root/.ciss/cdi/backup/etc/pam.d/su-l"
|
||||||
|
|
||||||
insert_header "${var_target}/etc/pam.d/sudo"
|
insert_header "${var_target}/etc/pam.d/su-l"
|
||||||
insert_comments "${var_target}/etc/pam.d/sudo"
|
insert_comments "${var_target}/etc/pam.d/su-l"
|
||||||
cat << EOF >> "${var_target}/etc/pam.d/sudo"
|
cat << EOF >> "${var_target}/etc/pam.d/su-l"
|
||||||
|
#
|
||||||
|
# PAM configuration for the su-l service
|
||||||
|
#
|
||||||
|
|
||||||
|
# If caller is already root, allow quickly without further auth:
|
||||||
|
auth sufficient pam_rootok.so
|
||||||
|
|
||||||
|
# Hardening of '/bin/su': only members of the group 'sudo' can su to root.
|
||||||
|
auth required pam_wheel.so group=sudo
|
||||||
|
|
||||||
|
# Standard password for the target account (root or other):
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
|
||||||
|
# ===== CISS 2FA block ========
|
||||||
|
|
||||||
|
# If gate returns SUCCESS => skip next two lines (no TOTP).
|
||||||
|
auth [success=2 default=ignore] pam_exec.so quiet /usr/local/libexec/ciss_pam_2fa_gate.sh
|
||||||
|
|
||||||
|
# For listed users: enforce that the secret file exists, else deny without prompting.
|
||||||
|
# pam_google_authenticator will itself fail if the file is absent; we add a clear hint before it.
|
||||||
|
# No 'nullok' here: listed users MUST have a secret; missing -> hard fail.
|
||||||
|
auth required pam_echo.so file=/etc/ciss/pam_su_l_totp.prompt
|
||||||
|
auth required pam_google_authenticator.so
|
||||||
|
|
||||||
|
# ===== CISS 2FA block end =====
|
||||||
|
|
||||||
|
|
||||||
|
@include common-account
|
||||||
|
@include common-session
|
||||||
|
|
||||||
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
||||||
|
EOF
|
||||||
|
|
||||||
|
do_log "info" "file_only" "4520() Written: [/etc/pam.d/su-l]."
|
||||||
|
|
||||||
|
cat << 'EOF' >| "${var_target}/etc/ciss/pam_su_l_totp.prompt"
|
||||||
|
Please enter the 6-digit TOTP or 8-digit Backup code of the target user:
|
||||||
|
EOF
|
||||||
|
chmod 0444 "${var_target}/etc/ciss/pam_su_l_totp.prompt"
|
||||||
|
do_log "info" "file_only" "4520() Written: [/etc/ciss/pam_su_l_totp.prompt]."
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
### Prevents accidental 'unset -f'.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
readonly -f write_pam_su-l
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Writes CISS Header for '/etc/pam.d/sudo-i'.
|
||||||
|
# Globals:
|
||||||
|
# None
|
||||||
|
# Arguments:
|
||||||
|
# 1: TARGET
|
||||||
|
# Returns:
|
||||||
|
# 0: on success
|
||||||
|
#######################################
|
||||||
|
write_pam_sudo-i() {
|
||||||
|
### Declare Arrays, HashMaps, and Variables.
|
||||||
|
declare -r var_target="$1"
|
||||||
|
|
||||||
|
mv "${var_target}/etc/pam.d/sudo-i" "${var_target}/root/.ciss/cdi/backup/etc/pam.d/sudo-i"
|
||||||
|
|
||||||
|
insert_header "${var_target}/etc/pam.d/sudo-i"
|
||||||
|
insert_comments "${var_target}/etc/pam.d/sudo-i"
|
||||||
|
cat << EOF >> "${var_target}/etc/pam.d/sudo-i"
|
||||||
#
|
#
|
||||||
# PAM configuration for the sudo service
|
# PAM configuration for the sudo service
|
||||||
#
|
#
|
||||||
@@ -1277,7 +1339,7 @@ auth [success=2 default=ignore] pam_exec.so quiet /usr/local/libe
|
|||||||
# For listed users: enforce that the secret file exists, else deny without prompting.
|
# For listed users: enforce that the secret file exists, else deny without prompting.
|
||||||
# pam_google_authenticator will itself fail if the file is absent; we add a clear hint before it.
|
# pam_google_authenticator will itself fail if the file is absent; we add a clear hint before it.
|
||||||
# No 'nullok' here: listed users MUST have a secret; missing -> hard fail.
|
# No 'nullok' here: listed users MUST have a secret; missing -> hard fail.
|
||||||
auth required pam_echo.so file=/etc/ciss/pam_sudo_totp.prompt
|
auth required pam_echo.so file=/etc/ciss/pam_sudo_i_totp.prompt
|
||||||
auth required pam_google_authenticator.so
|
auth required pam_google_authenticator.so
|
||||||
|
|
||||||
# ===== CISS 2FA block end =====
|
# ===== CISS 2FA block end =====
|
||||||
@@ -1285,7 +1347,7 @@ auth required pam_google_authenticator.so
|
|||||||
|
|
||||||
# Accounts, sessions:
|
# Accounts, sessions:
|
||||||
@include common-account
|
@include common-account
|
||||||
@include common-session-noninteractive
|
@include common-session
|
||||||
|
|
||||||
# Maintain a pam_timestamp ticket on successful sudo to suppress re-prompts.
|
# Maintain a pam_timestamp ticket on successful sudo to suppress re-prompts.
|
||||||
session optional pam_timestamp.so
|
session optional pam_timestamp.so
|
||||||
@@ -1293,19 +1355,19 @@ session optional pam_timestamp.so
|
|||||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
do_log "info" "file_only" "4520() Written: [/etc/pam.d/sudo]."
|
do_log "info" "file_only" "4520() Written: [/etc/pam.d/sudo-i]."
|
||||||
|
|
||||||
cat << 'EOF' >| "${var_target}/etc/ciss/pam_sudo_totp.prompt"
|
cat << 'EOF' >| "${var_target}/etc/ciss/pam_sudo_i_totp.prompt"
|
||||||
Please enter your 6-digit TOTP or 8-digit Backup code:
|
Please enter your 6-digit TOTP or 8-digit Backup code:
|
||||||
EOF
|
EOF
|
||||||
chmod 0444 "${var_target}/etc/ciss/pam_sudo_totp.prompt"
|
chmod 0444 "${var_target}/etc/ciss/pam_sudo_i_totp.prompt"
|
||||||
do_log "info" "file_only" "4520() Written: [/etc/ciss/pam_sudo_totp.prompt]."
|
do_log "info" "file_only" "4520() Written: [/etc/ciss/pam_sudo_i_totp.prompt]."
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
### Prevents accidental 'unset -f'.
|
### Prevents accidental 'unset -f'.
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
readonly -f write_pam_sudo
|
readonly -f write_pam_sudo-i
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Use the official ohmyzsh-installer but force non-interactive behavior; do not run zsh; do not chsh.
|
# Use the official ohmyzsh-installer but force non-interactive behavior; do not run zsh; do not chsh.
|
||||||
|
|||||||
@@ -21,11 +21,61 @@ set -Ceuo pipefail
|
|||||||
### Declare Arrays, HashMaps, and Variables.
|
### Declare Arrays, HashMaps, and Variables.
|
||||||
declare -g VAR_MAP_FILE="/etc/ciss/2fa.map"
|
declare -g VAR_MAP_FILE="/etc/ciss/2fa.map"
|
||||||
declare -g VAR_POLICY="${CISS_POLICY:-strict}"
|
declare -g VAR_POLICY="${CISS_POLICY:-strict}"
|
||||||
|
declare -g VAR_BINDING="${CISS_SU_BINDING:-caller}"
|
||||||
|
declare -g VAR_U=""
|
||||||
|
|
||||||
### PAM variables provided by pam_exec:
|
### PAM variables provided by pam_exec:
|
||||||
declare -g VAR_U="${PAM_USER:-}"
|
|
||||||
declare -g VAR_S="${PAM_SERVICE:-}"
|
declare -g VAR_S="${PAM_SERVICE:-}"
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Which identity to check in the 2FA map per PAM service.
|
||||||
|
# - $PAM_USER = target user (su/sudo: usually "root")
|
||||||
|
# - $PAM_RUSER = calling user
|
||||||
|
# Globals:
|
||||||
|
# PAM_RUSER
|
||||||
|
# PAM_USER
|
||||||
|
# VAR_BINDING
|
||||||
|
# VAR_S
|
||||||
|
# Arguments:
|
||||||
|
# None
|
||||||
|
# Returns:
|
||||||
|
# 0: on success
|
||||||
|
#######################################
|
||||||
|
identify_subject() {
|
||||||
|
# shellcheck disable=SC2249
|
||||||
|
case "${VAR_S,,}" in
|
||||||
|
|
||||||
|
login|sshd)
|
||||||
|
echo "${PAM_USER:-}"
|
||||||
|
;;
|
||||||
|
|
||||||
|
sudo|sudo-i)
|
||||||
|
### Enforce 2FA policy by caller for sudo.
|
||||||
|
echo "${PAM_RUSER:-${PAM_USER:-}}"
|
||||||
|
;;
|
||||||
|
|
||||||
|
su|su-l)
|
||||||
|
### Default: Bind su policy to the caller. Set CISS_SU_BINDING="target" if you want policy bound to the target account.
|
||||||
|
case "${VAR_BINDING,,}" in
|
||||||
|
|
||||||
|
caller) echo "${PAM_RUSER:-${PAM_USER:-}}" ;;
|
||||||
|
target) echo "${PAM_USER:-}" ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "${PAM_USER:-}"
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
### Prevents accidental 'unset -f'.
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
readonly -f identify_subject
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Read flag for user and service (0/1), default: empty (not found).
|
# Read flag for user and service (0/1), default: empty (not found).
|
||||||
# Globals:
|
# Globals:
|
||||||
@@ -84,12 +134,14 @@ readonly -f read_flag
|
|||||||
map_service_to_col() {
|
map_service_to_col() {
|
||||||
declare -r var_s="${1}"
|
declare -r var_s="${1}"
|
||||||
case "${var_s}" in
|
case "${var_s}" in
|
||||||
login) echo 2 ;;
|
login) echo 2 ;;
|
||||||
sshd) echo 3 ;;
|
sshd) echo 3 ;;
|
||||||
su) echo 4 ;;
|
su|su-l) echo 4 ;;
|
||||||
sudo) echo 5 ;;
|
sudo|sudo-i) echo 5 ;;
|
||||||
*) echo 0 ;; # Unknown services => behave as "not enforced".
|
*) echo 0 ;; # Unknown services => behave as "not enforced".
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
### Prevents accidental 'unset -f'.
|
### Prevents accidental 'unset -f'.
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
@@ -109,6 +161,10 @@ readonly -f map_service_to_col
|
|||||||
# 1: on failure
|
# 1: on failure
|
||||||
#######################################
|
#######################################
|
||||||
main() {
|
main() {
|
||||||
|
VAR_U="$(identify_subject)"
|
||||||
|
### On missing User, behave like "not listed" (skip GA).
|
||||||
|
[[ -n "${VAR_U}" ]] || exit 0
|
||||||
|
|
||||||
### On missing map, behave like "not listed" (skip GA), analogous to onerr=ignore.
|
### On missing map, behave like "not listed" (skip GA), analogous to onerr=ignore.
|
||||||
if [[ ! -r "${VAR_MAP_FILE}" || -z "${VAR_U}" || -z "${VAR_S}" ]]; then
|
if [[ ! -r "${VAR_MAP_FILE}" || -z "${VAR_U}" || -z "${VAR_S}" ]]; then
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user