diff --git a/setup/modules/auto-enroll-ansible.sh b/setup/modules/auto-enroll-ansible.sh new file mode 100644 index 0000000..d7bf1bd --- /dev/null +++ b/setup/modules/auto-enroll-ansible.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +set -e + +if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +CONTROLLER_URL="$1" +API_TOKEN="$2" +INVENTORY_NAME="$3" + +# ----------------------------- +# Detect OS + environment +# ----------------------------- +echo "[INFO] Detecting OS and environment..." + +if [ -f /etc/os-release ]; then + . /etc/os-release + DISTRO=$ID + DISTRO_PRETTY=$PRETTY_NAME +else + DISTRO="unknown" + DISTRO_PRETTY="Unknown OS" +fi + +ARCH=$(uname -m) + +# ----------------------------- +# Detect virtualization (with hardware detection) +# ----------------------------- +RAW_VIRT=$(systemd-detect-virt 2>/dev/null || echo "unknown") + +case "$RAW_VIRT" in + none) + VIRT_TYPE="hardware" + ;; + docker|podman|lxc|container) + VIRT_TYPE="container" + ;; + kvm|qemu|vmware|xen|microsoft|oracle|hyperv) + VIRT_TYPE="$RAW_VIRT" + ;; + *) + VIRT_TYPE="unknown" + ;; +esac + +# ----------------------------- +# Detect cloud provider +# ----------------------------- +if curl -s --connect-timeout 1 http://169.254.169.254/latest/meta-data/ >/dev/null; then + CLOUD="aws" +elif curl -s --connect-timeout 1 -H Metadata:true http://169.254.169.254/metadata/instance?api-version=2021-02-01 >/dev/null; then + CLOUD="azure" +elif curl -s --connect-timeout 1 http://metadata.google.internal >/dev/null; then + CLOUD="gcp" +else + CLOUD="none" +fi + +IPA_HOSTNAME=$(hostname -f) + +echo "[INFO] Hostname: $IPA_HOSTNAME" +echo "[INFO] OS: $DISTRO_PRETTY" +echo "[INFO] Architecture: $ARCH" +echo "[INFO] Virtualization: $VIRT_TYPE" +echo "[INFO] Cloud provider: $CLOUD" + +# ----------------------------- +# Install Python +# ----------------------------- +install_python() { + case "$DISTRO" in + arch) + sudo pacman -Sy --noconfirm python + ;; + debian|ubuntu) + sudo apt update && sudo apt install -y python3 + ;; + rhel|centos|rocky|almalinux) + sudo yum install -y python3 || sudo dnf install -y python3 + ;; + fedora) + sudo dnf install -y python3 + ;; + opensuse*|sles) + sudo zypper install -y python3 + ;; + *) + echo "[WARN] Unknown distro, trying generic python3 install..." + sudo bash -c "apt install -y python3 || yum install -y python3 || dnf install -y python3 || pacman -Sy --noconfirm python" + ;; + esac +} + +if ! command -v python3 >/dev/null 2>&1; then + echo "[INFO] Installing Python..." + install_python +fi + +# ----------------------------- +# Ensure SSH + GSSAPI +# ----------------------------- +echo "[INFO] Ensuring SSH is running..." +sudo systemctl enable sshd --now 2>/dev/null || sudo systemctl enable ssh --now || true + +if ! grep -q "GSSAPIAuthentication yes" /etc/ssh/sshd_config; then + echo "GSSAPIAuthentication yes" | sudo tee -a /etc/ssh/sshd_config + sudo systemctl restart sshd || sudo systemctl restart ssh +fi + +# ----------------------------- +# Helper: API GET +# ----------------------------- +api_get() { + curl -s -H "Authorization: Bearer $API_TOKEN" "$CONTROLLER_URL$1" +} + +# ----------------------------- +# Helper: API POST +# ----------------------------- +api_post() { + curl -s -X POST -H "Authorization: Bearer $API_TOKEN" \ + -H "Content-Type: application/json" \ + -d "$2" "$CONTROLLER_URL$1" +} + +# ----------------------------- +# Ensure inventory exists +# ----------------------------- +echo "[INFO] Checking inventory '$INVENTORY_NAME'..." + +INVENTORY_ID=$(api_get "/api/v2/inventories/?name=$INVENTORY_NAME" \ + | python3 -c "import sys, json; d=json.load(sys.stdin); print(d['results'][0]['id'] if d['count'] else '')") + +if [ -z "$INVENTORY_ID" ]; then + echo "[INFO] Inventory not found. Creating..." + INVENTORY_ID=$(api_post "/api/v2/inventories/" \ + "{\"name\": \"$INVENTORY_NAME\", \"organization\": 1}" \ + | python3 -c "import sys, json; print(json.load(sys.stdin)['id'])") +else + echo "[INFO] Inventory exists with ID $INVENTORY_ID" +fi + +# ----------------------------- +# Ensure groups exist +# ----------------------------- +create_group_if_missing() { + local GROUP="$1" + local GROUP_ID=$(api_get "/api/v2/groups/?name=$GROUP&inventory=$INVENTORY_ID" \ + | python3 -c "import sys, json; d=json.load(sys.stdin); print(d['results'][0]['id'] if d['count'] else '')") + + if [ -z "$GROUP_ID" ]; then + echo "[INFO] Creating group: $GROUP" + GROUP_ID=$(api_post "/api/v2/groups/" \ + "{\"name\": \"$GROUP\", \"inventory\": $INVENTORY_ID}" \ + | python3 -c "import sys, json; print(json.load(sys.stdin)['id'])") + fi + + echo "$GROUP_ID" +} + +GROUP_OS=$(create_group_if_missing "$DISTRO") +GROUP_ARCH=$(create_group_if_missing "arch-$ARCH") +GROUP_VIRT=$(create_group_if_missing "virt-$VIRT_TYPE") +GROUP_CLOUD=$(create_group_if_missing "cloud-$CLOUD") + +# ----------------------------- +# Register host +# ----------------------------- +echo "[INFO] Registering host..." + +HOST_ID=$(api_post "/api/v2/hosts/" \ + "{\"name\": \"$IPA_HOSTNAME\", \"inventory\": $INVENTORY_ID, \"enabled\": true}" \ + | python3 -c "import sys, json; print(json.load(sys.stdin)['id'])") + +echo "[INFO] Host ID: $HOST_ID" + +# ----------------------------- +# Add host to groups +# ----------------------------- +for G in $GROUP_OS $GROUP_ARCH $GROUP_VIRT $GROUP_CLOUD; do + echo "[INFO] Adding host to group ID $G" + api_post "/api/v2/groups/$G/hosts/" "{\"id\": $HOST_ID}" >/dev/null +done + +echo "[SUCCESS] Host fully enrolled and auto‑classified."