160 lines
6.2 KiB
Bash
Executable File
160 lines
6.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# freeipa-client.sh — FreeIPA client enrollment
|
|
#
|
|
# Three modes:
|
|
# --answerfile FILE Read settings from a JSON file (jq required)
|
|
# --interactive Prompt for every setting
|
|
# [flags] Pass any flags directly to freeipa-enroll.sh
|
|
#
|
|
# All flags accepted by freeipa-enroll.sh work here too and override
|
|
# any values loaded from an answerfile or interactive prompts.
|
|
#
|
|
# JSON answerfile schema:
|
|
# {
|
|
# "domain": "freeipa.abdelbaki.eu",
|
|
# "realm": "FREEIPA.ABDELBAKI.EU",
|
|
# "server": "freeipa.abdelbaki.eu",
|
|
# "hostname": "", <- leave blank to use current hostname
|
|
# "principal": "admin",
|
|
# "password": "", <- will prompt if blank
|
|
# "mkhomedir": true,
|
|
# "sudo": true,
|
|
# "dns_update": true,
|
|
# "ntp_server": "",
|
|
# "fido2": false,
|
|
# "fido2_users": []
|
|
# }
|
|
|
|
set -euo pipefail
|
|
|
|
SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ENROLL="$SELF_DIR/freeipa-enroll.sh"
|
|
|
|
[[ ! -x "$ENROLL" ]] && { echo "Error: freeipa-enroll.sh not found at $ENROLL" >&2; exit 1; }
|
|
|
|
# Defaults (match freeipa-enroll.sh hardcoded values; freeipa-server.sh will
|
|
# sed-replace these when generating customized copies)
|
|
IPA_DOMAIN="freeipa.abdelbaki.eu"
|
|
IPA_REALM="FREEIPA.ABDELBAKI.EU"
|
|
IPA_SERVER="freeipa.abdelbaki.eu"
|
|
|
|
MODE=""
|
|
ANSWERFILE=""
|
|
PASSTHROUGH=()
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--answerfile) MODE="answerfile"; ANSWERFILE="$2"; shift 2 ;;
|
|
--interactive) MODE="interactive"; shift ;;
|
|
*) PASSTHROUGH+=("$1"); shift ;;
|
|
esac
|
|
done
|
|
|
|
# ─── Answerfile mode ──────────────────────────────────────────────────────────
|
|
if [[ "$MODE" == "answerfile" ]]; then
|
|
[[ ! -f "$ANSWERFILE" ]] && { echo "Error: answerfile not found: $ANSWERFILE" >&2; exit 1; }
|
|
command -v jq &>/dev/null || { echo "Error: jq is required for answerfile mode" >&2; exit 1; }
|
|
|
|
get() { jq -r "$1 // empty" "$ANSWERFILE"; }
|
|
get_bool() { jq -r "$1 // empty" "$ANSWERFILE"; }
|
|
|
|
AF_DOMAIN=$(get '.domain')
|
|
AF_REALM=$(get '.realm')
|
|
AF_SERVER=$(get '.server')
|
|
AF_HOSTNAME=$(get '.hostname')
|
|
AF_PRINCIPAL=$(get '.principal')
|
|
AF_PASSWORD=$(get '.password')
|
|
AF_NTP=$(get '.ntp_server')
|
|
AF_MKHOMEDIR=$(get_bool '.mkhomedir')
|
|
AF_SUDO=$(get_bool '.sudo')
|
|
AF_DNS_UPDATE=$(get_bool '.dns_update')
|
|
AF_FIDO2=$(get_bool '.fido2')
|
|
mapfile -t AF_FIDO2_USERS < <(jq -r '.fido2_users // [] | .[]' "$ANSWERFILE")
|
|
|
|
ARGS=()
|
|
[[ -n "$AF_DOMAIN" ]] && ARGS+=(--domain "$AF_DOMAIN")
|
|
[[ -n "$AF_REALM" ]] && ARGS+=(--realm "$AF_REALM")
|
|
[[ -n "$AF_SERVER" ]] && ARGS+=(--server "$AF_SERVER")
|
|
[[ -n "$AF_HOSTNAME" ]] && ARGS+=(--hostname "$AF_HOSTNAME")
|
|
[[ -n "$AF_PRINCIPAL" ]] && ARGS+=(--principal "$AF_PRINCIPAL")
|
|
[[ -n "$AF_NTP" ]] && ARGS+=(--ntp-server "$AF_NTP")
|
|
|
|
if [[ -z "$AF_PASSWORD" ]]; then
|
|
printf '[?] Password for %s@%s: ' "${AF_PRINCIPAL:-admin}" "${AF_REALM:-REALM}"
|
|
read -rs AF_PASSWORD; echo
|
|
fi
|
|
ARGS+=(--password "$AF_PASSWORD")
|
|
|
|
[[ "$AF_MKHOMEDIR" == "false" ]] && ARGS+=(--no-mkhomedir)
|
|
[[ "$AF_SUDO" == "false" ]] && ARGS+=(--no-sudo)
|
|
[[ "$AF_DNS_UPDATE" == "false" ]] && ARGS+=(--no-dns-update)
|
|
[[ "$AF_FIDO2" == "true" ]] && ARGS+=(--fido2)
|
|
for U in "${AF_FIDO2_USERS[@]}"; do
|
|
[[ -n "$U" ]] && ARGS+=(--fido2-user "$U")
|
|
done
|
|
|
|
exec "$ENROLL" "${ARGS[@]}" "${PASSTHROUGH[@]}"
|
|
fi
|
|
|
|
# ─── Interactive mode ─────────────────────────────────────────────────────────
|
|
if [[ "$MODE" == "interactive" ]]; then
|
|
p() { printf '\033[0;35m[?]\033[0m %s ' "$*"; }
|
|
|
|
p "IPA Domain [$IPA_DOMAIN]:"; read -r I; IPA_DOMAIN="${I:-$IPA_DOMAIN}"
|
|
IPA_REALM="${IPA_DOMAIN^^}"
|
|
p "Kerberos Realm [$IPA_REALM]:"; read -r I; IPA_REALM="${I:-$IPA_REALM}"
|
|
p "IPA Server [$IPA_SERVER]:"; read -r I; IPA_SERVER="${I:-$IPA_SERVER}"
|
|
|
|
CURRENT_HOST=$(hostname -f 2>/dev/null || hostname)
|
|
p "This host's FQDN [$CURRENT_HOST]:"; read -r I; CLIENT_HOSTNAME="${I:-$CURRENT_HOST}"
|
|
|
|
p "Admin principal [admin]:"; read -r PRINCIPAL; PRINCIPAL="${PRINCIPAL:-admin}"
|
|
p "Admin password (no echo):"; read -rs PASSWORD; echo
|
|
[[ -z "$PASSWORD" ]] && { echo "Error: password is required" >&2; exit 1; }
|
|
|
|
p "Enable home directory creation? [Y/n]:"; read -r I
|
|
MKHOMEDIR=true; [[ "${I,,}" == "n"* ]] && MKHOMEDIR=false
|
|
|
|
p "Configure sudo via SSSD? [Y/n]:"; read -r I
|
|
SUDO=true; [[ "${I,,}" == "n"* ]] && SUDO=false
|
|
|
|
p "Update DNS record? [Y/n]:"; read -r I
|
|
DNS_UPDATE=true; [[ "${I,,}" == "n"* ]] && DNS_UPDATE=false
|
|
|
|
p "NTP server (blank to skip):"; read -r NTP_SERVER
|
|
|
|
p "Enable FIDO2 authentication? [y/N]:"; read -r I
|
|
FIDO2=false; [[ "${I,,}" == "y"* ]] && FIDO2=true
|
|
|
|
FIDO2_USER_LIST=()
|
|
if [[ "$FIDO2" == true ]]; then
|
|
p "FIDO2 users (comma-separated, blank to skip):"; read -r I
|
|
if [[ -n "$I" ]]; then
|
|
IFS=',' read -ra FIDO2_USER_LIST <<< "$I"
|
|
fi
|
|
fi
|
|
|
|
ARGS=(
|
|
--domain "$IPA_DOMAIN"
|
|
--realm "$IPA_REALM"
|
|
--server "$IPA_SERVER"
|
|
--hostname "$CLIENT_HOSTNAME"
|
|
--principal "$PRINCIPAL"
|
|
--password "$PASSWORD"
|
|
)
|
|
[[ "$MKHOMEDIR" == false ]] && ARGS+=(--no-mkhomedir)
|
|
[[ "$SUDO" == false ]] && ARGS+=(--no-sudo)
|
|
[[ "$DNS_UPDATE" == false ]] && ARGS+=(--no-dns-update)
|
|
[[ "$FIDO2" == true ]] && ARGS+=(--fido2)
|
|
[[ -n "$NTP_SERVER" ]] && ARGS+=(--ntp-server "$NTP_SERVER")
|
|
for U in "${FIDO2_USER_LIST[@]}"; do
|
|
[[ -n "${U// /}" ]] && ARGS+=(--fido2-user "${U// /}")
|
|
done
|
|
|
|
exec "$ENROLL" "${ARGS[@]}" "${PASSTHROUGH[@]}"
|
|
fi
|
|
|
|
# ─── Direct passthrough ───────────────────────────────────────────────────────
|
|
# No --answerfile or --interactive: forward all args directly to freeipa-enroll.sh
|
|
exec "$ENROLL" "${PASSTHROUGH[@]}"
|