Fix hostname collision and resume interrupted Tailscale enrollment
This commit is contained in:
+42
-21
@@ -13,15 +13,17 @@ secret() {
|
||||
printf '\n' >&2
|
||||
}
|
||||
installed_label() { if [[ $1 == 1 ]]; then printf 'vorhanden'; else printf 'fehlt'; fi; }
|
||||
choice_hint() { if [[ $1 == 1 ]]; then printf '[J/n]'; else printf '[j/N]'; fi; }
|
||||
|
||||
LIST=0; DRY=0; MANAGER=''; VERSION=''; LOGIN_SERVER=''; SELECTION=''; VERSION_EXPLICIT=0
|
||||
SSH_ENABLED=1; SSH_USER=''; SSH_SUDO=0; SSH_NOPASSWD=0; SAVE_SETTINGS=1
|
||||
TS_ACCEPT_DNS=0; DNS_SAVED=0
|
||||
TS_ACCEPT_DNS=0; DNS_SAVED=0; RESUME_TS=0
|
||||
VARS_FILE=/etc/lxc-enroll/.vars
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--list) LIST=1; shift ;;
|
||||
--dry-run) DRY=1; shift ;;
|
||||
--resume-tailscale) RESUME_TS=1; shift ;;
|
||||
--manager|--agent-version|--login-server|--select)
|
||||
[[ $# -ge 2 && -n $2 ]] || fail "Wert fehlt: $1"
|
||||
case "$1" in
|
||||
@@ -36,7 +38,9 @@ Auf dem Proxmox-Host als root starten:
|
||||
bash lxc-enroll.sh --list
|
||||
bash lxc-enroll.sh --dry-run --select '106 107'
|
||||
Optionen: --manager IP/NAME --agent-version VERSION --login-server HTTPS-URL
|
||||
--select 'CTID CTID' --list --dry-run
|
||||
--select 'CTID CTID' --list --dry-run --resume-tailscale
|
||||
--resume-tailscale: Bereits installiertes Tailscale nur bei NeedsLogin/NoState
|
||||
anmelden. Bestehende Registrierungen werden nicht ersetzt.
|
||||
Nur laufende Debian-/Ubuntu-LXCs mit systemd. Vorhandene Tailscale-/Wazuh-
|
||||
Registrierungen bleiben unveraendert. Optional Tailscale SSH/Nutzer/Sudo fuer die Auswahl.
|
||||
Lokale Einstellungen: /etc/lxc-enroll/.vars (JSON, ohne Geheimnisse).
|
||||
@@ -68,7 +72,7 @@ trap 'exit 143' TERM
|
||||
yes_no() {
|
||||
local prompt=$1 default=$2
|
||||
ask "$prompt"
|
||||
case "$REPLY" in '' ) REPLY=$default;; j|J|ja|Ja|y|Y|yes|Yes) REPLY=1;; n|N|nein|Nein|no|No) REPLY=0;; *) fail 'Bitte j oder n eingeben.';; esac
|
||||
case "$REPLY" in '' ) REPLY=$default;; 1|j|J|ja|Ja|y|Y|yes|Yes) REPLY=1;; 0|n|N|nein|Nein|no|No) REPLY=0;; *) fail 'Bitte j oder n eingeben (auch 1/0 moeglich).';; esac
|
||||
}
|
||||
|
||||
load_settings() {
|
||||
@@ -192,9 +196,10 @@ write_worker() {
|
||||
set -Eeuo pipefail
|
||||
set +x
|
||||
umask 077
|
||||
DIR=$1; MANAGER=$2; AGENT_VERSION=$3; LOGIN=$4; NAME=$5; WANT_TS=$6; WANT_WZ=$7
|
||||
DIR=$1; MANAGER=$2; AGENT_VERSION=$3; LOGIN=$4; CT_HOSTNAME=$5; WANT_TS=$6; WANT_WZ=$7
|
||||
SSH_ENABLED=$8; SSH_USER=$9; SSH_SUDO=${10}; SSH_NOPASSWD=${11}
|
||||
TS_ACCEPT_DNS=${12}
|
||||
RESUME_TS=${13}
|
||||
case "$TS_ACCEPT_DNS" in 1) DNS_FLAG=true;; 0) DNS_FLAG=false;; *) exit 1;; esac
|
||||
trap 'rm -f -- "$DIR/headscale.key" "$DIR/enrollment.pass" "$DIR/sudo.pass"' EXIT
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
@@ -208,30 +213,45 @@ if present wazuh-agent || present wazuh-manager || [[ -x /var/ossec/bin/wazuh-ag
|
||||
if [[ $WANT_WZ == 1 && -e /var/ossec/etc/ossec.conf ]]; then
|
||||
echo 'Wazuh-Konfiguration bereits vorhanden: bitte unvollstaendige Installation zuerst reparieren.' >&2; exit 1
|
||||
fi
|
||||
[[ $WANT_TS == 1 || $WANT_WZ == 1 || $SSH_ENABLED == 1 ]] || { echo 'Komponenten inzwischen vorhanden; nichts geaendert.'; exit 0; }
|
||||
JOIN_TS=$WANT_TS
|
||||
if [[ $WANT_TS == 0 && $RESUME_TS == 1 ]]; then
|
||||
systemctl enable --now tailscaled
|
||||
status_json=$(tailscale status --json) || true
|
||||
backend_state=$(printf '%s\n' "$status_json" | sed -n 's/.*"BackendState"[[:space:]]*:[[:space:]]*"\([A-Za-z]*\)".*/\1/p')
|
||||
case "$backend_state" in
|
||||
NeedsLogin|NoState) JOIN_TS=1;;
|
||||
Running) echo 'Tailscale bereits angemeldet; Registrierung bleibt erhalten.';;
|
||||
*) echo "Tailscale-Status ${backend_state:-unbekannt}: bitte zuerst pruefen; keine Neuregistrierung." >&2; exit 1;;
|
||||
esac
|
||||
fi
|
||||
[[ $JOIN_TS == 1 || $WANT_WZ == 1 || $SSH_ENABLED == 1 ]] || { echo 'Komponenten inzwischen vorhanden; nichts geaendert.'; exit 0; }
|
||||
|
||||
apt-get -o DPkg::Lock::Timeout=120 update
|
||||
apt-get -o DPkg::Lock::Timeout=120 install -y --no-install-recommends ca-certificates curl gnupg
|
||||
install -d -m 755 /usr/share/keyrings /etc/apt/sources.list.d
|
||||
|
||||
if [[ $WANT_TS == 1 ]]; then
|
||||
[[ -c /dev/net/tun && -s $DIR/headscale.key ]] || { echo 'TUN oder Headscale-Schluessel fehlt.' >&2; exit 1; }
|
||||
. /etc/os-release
|
||||
# Isolate distribution variables: os-release also defines NAME and VERSION.
|
||||
os_details=$( . /etc/os-release; printf '%s|%s' "$ID" "$VERSION_CODENAME")
|
||||
IFS='|' read -r DISTRO_ID DISTRO_CODENAME <<<"$os_details"
|
||||
if ! has_repo 'pkgs.tailscale.com'; then
|
||||
[[ ! -e /etc/apt/sources.list.d/tailscale.list ]] || { echo 'Vorhandene tailscale.list bitte zuerst pruefen.' >&2; exit 1; }
|
||||
download "https://pkgs.tailscale.com/stable/$ID/$VERSION_CODENAME.noarmor.gpg" "$DIR/tailscale.gpg"
|
||||
download "https://pkgs.tailscale.com/stable/$ID/$VERSION_CODENAME.tailscale-keyring.list" "$DIR/tailscale.list"
|
||||
download "https://pkgs.tailscale.com/stable/$DISTRO_ID/$DISTRO_CODENAME.noarmor.gpg" "$DIR/tailscale.gpg"
|
||||
download "https://pkgs.tailscale.com/stable/$DISTRO_ID/$DISTRO_CODENAME.tailscale-keyring.list" "$DIR/tailscale.list"
|
||||
install -m 644 "$DIR/tailscale.gpg" /usr/share/keyrings/tailscale-archive-keyring.gpg
|
||||
install -m 644 "$DIR/tailscale.list" /etc/apt/sources.list.d/tailscale.list
|
||||
fi
|
||||
apt-get -o DPkg::Lock::Timeout=120 update
|
||||
apt-get -o DPkg::Lock::Timeout=120 install -y --no-install-recommends tailscale
|
||||
systemctl enable --now tailscaled
|
||||
fi
|
||||
if [[ $JOIN_TS == 1 ]]; then
|
||||
[[ -c /dev/net/tun && -s $DIR/headscale.key ]] || { echo 'TUN oder Headscale-Schluessel fehlt.' >&2; exit 1; }
|
||||
# File reference keeps the key out of command arguments/history.
|
||||
timeout 90 tailscale up --login-server="$LOGIN" --auth-key="file:$DIR/headscale.key" --hostname="$NAME" --accept-dns="$DNS_FLAG" --timeout=60s
|
||||
timeout 90 tailscale up --login-server="$LOGIN" --auth-key="file:$DIR/headscale.key" --hostname="$CT_HOSTNAME" --accept-dns="$DNS_FLAG" --timeout=60s
|
||||
rm -f -- "$DIR/headscale.key"
|
||||
tailscale ip -4
|
||||
echo 'Tailscale installiert und angemeldet.'
|
||||
echo 'Tailscale angemeldet.'
|
||||
fi
|
||||
|
||||
# Explicitly accepted DNS settings may also enable MagicDNS on an existing client.
|
||||
@@ -257,7 +277,7 @@ if [[ $WANT_WZ == 1 ]]; then
|
||||
apt-cache madison wazuh-agent | awk '{print $3}' | grep -Fx "$AGENT_VERSION" >/dev/null || {
|
||||
echo "Wazuh-Version $AGENT_VERSION nicht verfuegbar; kein neuerer Agent wird installiert." >&2; exit 1;
|
||||
}
|
||||
export WAZUH_MANAGER="$MANAGER" WAZUH_REGISTRATION_SERVER="$MANAGER" WAZUH_AGENT_NAME="$NAME"
|
||||
export WAZUH_MANAGER="$MANAGER" WAZUH_REGISTRATION_SERVER="$MANAGER" WAZUH_AGENT_NAME="$CT_HOSTNAME"
|
||||
if [[ -s $DIR/enrollment.pass ]]; then export WAZUH_REGISTRATION_PASSWORD; WAZUH_REGISTRATION_PASSWORD=$(cat "$DIR/enrollment.pass"); fi
|
||||
apt-get -o DPkg::Lock::Timeout=120 install -y --no-install-recommends "wazuh-agent=$AGENT_VERSION"
|
||||
unset WAZUH_REGISTRATION_PASSWORD
|
||||
@@ -317,19 +337,19 @@ deploy_one() {
|
||||
[[ $(pct status "$id") == 'status: running' ]] || return 1
|
||||
if pct config "$id" | grep -q '^lock:'; then say "LXC $id inzwischen gesperrt."; return 1; fi
|
||||
ts=$((1-${TS[$id]})); wz=$((1-${WZ[$id]}))
|
||||
if [[ $ts == 1 && ${TUN[$id]} == 0 ]]; then ensure_tun "$id" || return 1; fi
|
||||
if [[ ( $ts == 1 || $RESUME_TS == 1 ) && ${TUN[$id]} == 0 ]]; then ensure_tun "$id" || return 1; fi
|
||||
dir=$(pct exec "$id" -- mktemp -d /run/lxc-enroll.XXXXXXXX) || return 1
|
||||
[[ $dir =~ ^/run/lxc-enroll\.[A-Za-z0-9]+$ ]] || return 1
|
||||
REMOTE_DIRS[$id]=$dir
|
||||
pct push "$id" "$TMP/worker.sh" "$dir/worker.sh" --user 0 --group 0 --perms 600 || return 1
|
||||
if [[ $ts == 1 ]]; then pct push "$id" "$TMP/headscale.key" "$dir/headscale.key" --user 0 --group 0 --perms 600 || return 1; fi
|
||||
if [[ $ts == 1 || $RESUME_TS == 1 ]]; then pct push "$id" "$TMP/headscale.key" "$dir/headscale.key" --user 0 --group 0 --perms 600 || return 1; fi
|
||||
if [[ $wz == 1 && -s $TMP/enrollment.pass ]]; then pct push "$id" "$TMP/enrollment.pass" "$dir/enrollment.pass" --user 0 --group 0 --perms 600 || return 1; fi
|
||||
if [[ $SSH_ENABLED == 1 ]]; then
|
||||
if [[ -s $TMP/sudo.pass ]]; then pct push "$id" "$TMP/sudo.pass" "$dir/sudo.pass" --user 0 --group 0 --perms 600 || return 1; fi
|
||||
fi
|
||||
# Credentials are files, never pct arguments. bash receives only non-secret settings.
|
||||
pct exec "$id" -- bash "$dir/worker.sh" "$dir" "$MANAGER" "$VERSION" "$LOGIN_SERVER" "${NAMES[$id]}" "$ts" "$wz" "$SSH_ENABLED" "$SSH_USER" "$SSH_SUDO" "$SSH_NOPASSWD" "$TS_ACCEPT_DNS" || return 1
|
||||
if [[ $ts == 1 ]]; then
|
||||
pct exec "$id" -- bash "$dir/worker.sh" "$dir" "$MANAGER" "$VERSION" "$LOGIN_SERVER" "${NAMES[$id]}" "$ts" "$wz" "$SSH_ENABLED" "$SSH_USER" "$SSH_SUDO" "$SSH_NOPASSWD" "$TS_ACCEPT_DNS" "$RESUME_TS" || return 1
|
||||
if [[ $ts == 1 || $RESUME_TS == 1 ]]; then
|
||||
pct exec "$id" -- tailscale status --json | python3 -c 'import json,sys; d=json.load(sys.stdin); sys.exit(0 if d.get("BackendState")=="Running" and d.get("Self",{}).get("Online") is True else 1)' || {
|
||||
say "LXC $id: Headscale-Verbindung nicht als online bestaetigt."; return 1;
|
||||
}
|
||||
@@ -345,15 +365,15 @@ main() {
|
||||
[[ ${#IDS[@]} -gt 0 ]] || { say 'Keine passenden LXCs gefunden.'; return 0; }
|
||||
exec 3<>/dev/tty || fail 'Interaktives Terminal fehlt. --list kann ohne Terminal laufen.'
|
||||
load_settings
|
||||
yes_no "Tailscale SSH fuer alle ausgewaehlten LXCs aktivieren? (Standard: $SSH_ENABLED; 1=Ja, 0=Nein) [j/n]" "$SSH_ENABLED"
|
||||
yes_no "Tailscale SSH fuer alle ausgewaehlten LXCs aktivieren? $(choice_hint "$SSH_ENABLED")" "$SSH_ENABLED"
|
||||
SSH_ENABLED=$REPLY
|
||||
if [[ $SSH_ENABLED == 1 ]]; then
|
||||
ask "SSH-Nutzername${SSH_USER:+ [$SSH_USER]}:"
|
||||
SSH_USER=${REPLY:-$SSH_USER}
|
||||
[[ $SSH_USER =~ ^[a-z_][a-z0-9_-]{0,30}$ && $SSH_USER != root ]] || fail 'Bitte einen normalen Linux-Nutzernamen verwenden.'
|
||||
yes_no "Nutzer zu sudo hinzufuegen? (Standard: $SSH_SUDO) [j/n]" "$SSH_SUDO"; SSH_SUDO=$REPLY
|
||||
yes_no "Nutzer zu sudo hinzufuegen? $(choice_hint "$SSH_SUDO")" "$SSH_SUDO"; SSH_SUDO=$REPLY
|
||||
if [[ $SSH_SUDO == 1 ]]; then
|
||||
yes_no "Sudo OHNE Passwort erlauben? (Standard: $SSH_NOPASSWD; 0=Passwort erforderlich) [j/n]" "$SSH_NOPASSWD"; SSH_NOPASSWD=$REPLY
|
||||
yes_no "Sudo OHNE Passwort erlauben? $(choice_hint "$SSH_NOPASSWD")" "$SSH_NOPASSWD"; SSH_NOPASSWD=$REPLY
|
||||
fi
|
||||
fi
|
||||
yes_no 'Einstellungen ohne Geheimnisse lokal in .vars speichern? [J/n]' 1; SAVE_SETTINGS=$REPLY
|
||||
@@ -373,12 +393,13 @@ main() {
|
||||
say ''; say 'Geplante Aenderungen:'
|
||||
for id in "${SELECTED[@]}"; do
|
||||
say "LXC $id ${NAMES[$id]}: Tailscale $(installed_label "${TS[$id]}"), Wazuh $(installed_label "${WZ[$id]}")."
|
||||
if [[ ${TS[$id]} == 0 ]]; then
|
||||
if [[ ${TS[$id]} == 0 || $RESUME_TS == 1 ]]; then
|
||||
need_ts=1
|
||||
if [[ ${TUN[$id]} == 0 ]]; then restart_ids+=" $id"; fi
|
||||
fi
|
||||
[[ ${WZ[$id]} != 0 ]] || need_wz=1
|
||||
done
|
||||
if [[ $RESUME_TS == 1 ]]; then say 'Wiederaufnahme: vorhandenes Tailscale nur bei NeedsLogin/NoState anmelden; angemeldete Clients behalten ihre Registrierung.'; fi
|
||||
if [[ -n $restart_ids ]]; then say "TUN-Zugriff ergaenzen und sauber neu starten:$restart_ids"; fi
|
||||
if [[ $SSH_ENABLED == 1 ]]; then
|
||||
say "Tailscale SSH fuer die Auswahl: Nutzer $SSH_USER, Sudo=$SSH_SUDO, Sudo-ohne-Passwort=$SSH_NOPASSWD."
|
||||
@@ -447,7 +468,7 @@ main() {
|
||||
done
|
||||
say ''; say "Erfolgreich abgeschlossen:${ok:- keine}"
|
||||
say "Nicht abgeschlossen:${failed:- keine}"
|
||||
say 'Bereits vorhandene Komponenten wurden nicht umkonfiguriert; deren Verbindung bitte separat pruefen.'
|
||||
say 'Vorhandene Wazuh-Registrierungen bleiben erhalten. DNS/SSH wurden nur gemaess Auswahl geaendert.'
|
||||
say 'Enrollment richtet noch keine Discord-Regeln oder vollstaendige Schwachstellenabdeckung ein.'
|
||||
[[ -z $failed ]]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user