diff --git a/setup/modules/FreeipaAnsible/ansible/ansipa-enforce-policies.sh b/setup/modules/FreeipaAnsible/ansible/ansipa-enforce-policies.sh index 41e515a..41c2fd1 100755 --- a/setup/modules/FreeipaAnsible/ansible/ansipa-enforce-policies.sh +++ b/setup/modules/FreeipaAnsible/ansible/ansipa-enforce-policies.sh @@ -103,7 +103,7 @@ set -euo pipefail # shellcheck source=lib/ansipa-policy.sh source /usr/local/lib/ansipa/policy.sh -HOST_FQDN=$(hostname -f 2>/dev/null || hostname) +HOST_FQDN=$(ansipa_fqdn) command -v ipa &>/dev/null || { warn "ipa not found — host not enrolled in FreeIPA. Exiting."; exit 0; } diff --git a/setup/modules/FreeipaAnsible/ansible/lib/ansipa-policy.sh b/setup/modules/FreeipaAnsible/ansible/lib/ansipa-policy.sh index fa19d20..3acd550 100644 --- a/setup/modules/FreeipaAnsible/ansible/lib/ansipa-policy.sh +++ b/setup/modules/FreeipaAnsible/ansible/lib/ansipa-policy.sh @@ -27,6 +27,28 @@ POLICY_DIR="/usr/local/lib/ansipa/policies.d" log() { echo "[$LOG_TAG] $*"; logger -t "$LOG_TAG" "$*" 2>/dev/null || true; } warn() { echo "[$LOG_TAG][WARN] $*" >&2; logger -t "$LOG_TAG" "WARN: $*" 2>/dev/null || true; } +# ── Hostname resolution ─────────────────────────────────────────────────────── +# The `hostname` binary (from inetutils) is NOT installed on a minimal Arch +# system, so `hostname -f` aborts the enforcer with "command not found". Resolve +# the FQDN without depending on it: prefer hostnamectl, then the FQDN via getent +# on the static hostname, then /etc/hostname, then the kernel hostname. Every +# enrolled host has an FQDN (ipa-client-install sets it), so this resolves. +ansipa_fqdn() { + local h="" + if command -v hostname &>/dev/null; then + h=$(hostname -f 2>/dev/null) || h="" + fi + [[ -z "$h" ]] && h=$(hostnamectl --static 2>/dev/null || true) + [[ -z "$h" ]] && h=$(cat /etc/hostname 2>/dev/null || true) + [[ -z "$h" ]] && h=$(cat /proc/sys/kernel/hostname 2>/dev/null || true) + # Upgrade a short name to the FQDN via NSS if resolvable. + if [[ "$h" != *.* ]] && command -v getent &>/dev/null; then + local fqdn; fqdn=$(getent hosts "$h" 2>/dev/null | awk '{for(i=2;i<=NF;i++) if($i ~ /\./){print $i; exit}}') + [[ -n "$fqdn" ]] && h="$fqdn" + fi + printf '%s' "$h" +} + # ── Group discovery ─────────────────────────────────────────────────────────── # Called once by the orchestrator. Sets all policy-state variables needed by # every policy file, using exactly two IPA queries (one host-show, one group-find). diff --git a/setup/modules/FreeipaAnsible/ansible/policies.d/dev_security-scan.sh b/setup/modules/FreeipaAnsible/ansible/policies.d/dev_security-scan.sh index cd1934d..18285f2 100644 --- a/setup/modules/FreeipaAnsible/ansible/policies.d/dev_security-scan.sh +++ b/setup/modules/FreeipaAnsible/ansible/policies.d/dev_security-scan.sh @@ -12,7 +12,10 @@ if [[ "$WANT_SECURITY_SCAN" == true ]]; then # ansipa-security-scan — daily ClamAV / rkhunter / chkrootkit run + SMB upload. # Managed by ansipa-enforce-policies — do not edit manually. LOG=/var/log/ansipa-security-scan.log -HOSTNAME=$(hostname -f 2>/dev/null || hostname) +# `hostname` (inetutils) may be absent on minimal Arch; resolve without it. +HOSTNAME=$( { command -v hostname >/dev/null 2>&1 && hostname -f 2>/dev/null; } \ + || hostnamectl --static 2>/dev/null || cat /etc/hostname 2>/dev/null \ + || cat /proc/sys/kernel/hostname 2>/dev/null ) DATE=$(date +%Y-%m-%d) { echo "=== ansipa-security-scan: $DATE $HOSTNAME ===" diff --git a/setup/modules/FreeipaAnsible/image/ansipa-checkmk-setup.sh b/setup/modules/FreeipaAnsible/image/ansipa-checkmk-setup.sh index a7f76a8..1a5b65c 100644 --- a/setup/modules/FreeipaAnsible/image/ansipa-checkmk-setup.sh +++ b/setup/modules/FreeipaAnsible/image/ansipa-checkmk-setup.sh @@ -27,8 +27,20 @@ warn() { echo "[$LOG_TAG][WARN] $*" >&2; } _write_push_requests() { [[ -d /cmk-creds ]] || return 0 local _hosts _h + # `ipa hostgroup-show` prints members on the SAME line as the label + # (" Member hosts: a.example, b.example") and wraps long lists onto + # indented continuation lines. Capture the label line's own value AND any + # continuation lines, stopping at the next " Key:" field. (The previous + # awk did `next` on the label line, discarding the very line that holds the + # hostnames, so no host was ever extracted and no push request written.) _hosts=$(ipa hostgroup-show dev_mon_base --all 2>/dev/null \ - | awk '/Member hosts:/{p=1; next} /^$/{p=0} p{print}' \ + | awk ' + /^ [A-Za-z][A-Za-z0-9 _-]*:/ { + if ($0 ~ /Member hosts:/) { sub(/.*Member hosts:[[:space:]]*/, ""); p=1; print; next } + else { p=0 } + } + p { print } + ' \ | grep -oE '[a-zA-Z0-9._-]+\.[a-zA-Z]{2,}' | sort -u || true) [[ -z "$_hosts" ]] && return 0 while IFS= read -r _h; do @@ -39,17 +51,12 @@ _write_push_requests() { done <<< "$_hosts" } -# Skip re-initialization but still run push-mode requests if already set up -if [[ -f "$DONE_FLAG" ]]; then - [[ -f /etc/ipa/default.conf ]] && \ - echo "$IPA_ADMIN_PASS" | kinit "admin@${IPA_REALM}" &>/dev/null && \ - _write_push_requests 2>/dev/null; \ - kdestroy &>/dev/null || true - log "Already configured (delete $DONE_FLAG to force re-initialization)" - exit 0 -fi - # ── Resolve configuration ────────────────────────────────────────────────────── +# Must run BEFORE the DONE_FLAG early-exit: that path calls _write_push_requests, +# which needs IPA_REALM + IPA_ADMIN_PASS to kinit. Previously these were resolved +# only after the early exit, so every rerun kinit'd with an empty password, failed +# silently, and never wrote push-mode requests — leaving NAT'd clients stuck in +# pull mode (unreachable) forever. # docker-env.service writes container env to /etc/container.env; source it. [[ -f /etc/container.env ]] && source /etc/container.env || true @@ -59,6 +66,17 @@ CMK_API="${CMK_URL}/${CMK_SITE}/check_mk/api/1.0" IPA_REALM="${IPA_REALM:-}" IPA_ADMIN_PASS="${IPA_ADMIN_PASSWORD:-}" +# Skip re-initialization but still run push-mode requests if already set up +if [[ -f "$DONE_FLAG" ]]; then + if [[ -f /etc/ipa/default.conf && -n "$IPA_ADMIN_PASS" && -n "$IPA_REALM" ]]; then + echo "$IPA_ADMIN_PASS" | kinit "admin@${IPA_REALM}" &>/dev/null \ + && _write_push_requests 2>/dev/null + kdestroy &>/dev/null || true + fi + log "Already configured (delete $DONE_FLAG to force re-initialization)" + exit 0 +fi + if [[ -z "$IPA_REALM" || -z "$IPA_ADMIN_PASS" ]]; then warn "IPA_REALM or IPA_ADMIN_PASSWORD not set — cannot configure IPA side" exit 1