#!/usr/bin/env bash
#
# Enrol a Wazuh 5.0 agent through the manager API and print the client key.
#
# Every request below is taken from the Wazuh 5.0-beta enrolment pages:
#   https://documentation.wazuh.com/5.0-beta/user-manual/agent/agent-enrollment/enrollment-methods/via-manager-API/requesting-the-key.html
#   https://documentation.wazuh.com/5.0-beta/user-manual/agent/agent-management/grouping-agents.html
#
# Use this route when the endpoint should never hold the enrolment password,
# or when you need the key before the endpoint exists.
#
# Lesson: https://maheshtata.com/wazuh/wazuh-agent-enrollment/

set -euo pipefail

# ----------------------------------------------------------------------------
# Settings
# ----------------------------------------------------------------------------
MANAGER="${MANAGER:?set MANAGER to the manager IP or FQDN}"
API_PORT="${API_PORT:-55000}"
API_USER="${API_USER:-wazuh}"                 # default manager API user
API_PASSWORD="${API_PASSWORD:?set API_PASSWORD}"

AGENT_NAME="${AGENT_NAME:?set AGENT_NAME (must be unique across the deployment)}"

# Optional. If set, the script creates the group when missing and assigns the
# agent to it AFTER enrolment. The documented POST /agents body carries only
# the agent name, so the group is a separate call.
AGENT_GROUP="${AGENT_GROUP:-}"

# -k skips certificate verification. Drop it once the manager API presents a
# certificate this host trusts; leaving it on is a lab convenience, not a
# production setting.
CURL_OPTS=(-k -s)

BASE="https://${MANAGER}:${API_PORT}"

# ----------------------------------------------------------------------------
# 1. Authenticate. The token is a JWT; the manager API issues it from basic auth.
# ----------------------------------------------------------------------------
TOKEN=$(curl "${CURL_OPTS[@]}" -u "${API_USER}:${API_PASSWORD}" \
  -X POST "${BASE}/security/user/authenticate?raw=true")

if [ -z "${TOKEN}" ]; then
  echo "Authentication failed: no token returned." >&2
  exit 1
fi

auth=(-H "Authorization: Bearer ${TOKEN}")

# ----------------------------------------------------------------------------
# 2. Create the group if one was asked for.
#    A group that does not exist on the manager is the most common reason an
#    agent's own enrolment handshake is rejected, so create it up front even
#    when you assign it later.
# ----------------------------------------------------------------------------
if [ -n "${AGENT_GROUP}" ]; then
  echo "Ensuring group '${AGENT_GROUP}' exists..."
  curl "${CURL_OPTS[@]}" -X POST "${BASE}/groups?pretty=true" \
    -H "Content-Type: application/json" \
    -d "{\"group_id\": \"${AGENT_GROUP}\"}" \
    "${auth[@]}" || true
  # A group that already exists returns an error object, not a failure of this
  # script. Inspect the output above if the later assignment fails.
fi

# ----------------------------------------------------------------------------
# 3. Enrol the agent. The response carries the agent id and the client key.
# ----------------------------------------------------------------------------
echo "Enrolling '${AGENT_NAME}'..."
RESPONSE=$(curl "${CURL_OPTS[@]}" -X POST \
  -d "{\"name\":\"${AGENT_NAME}\"}" \
  "${BASE}/agents?pretty=true" \
  -H "Content-Type:application/json" \
  "${auth[@]}")

echo "${RESPONSE}"

# Extract id and key without assuming jq is installed.
AGENT_ID=$(printf '%s' "${RESPONSE}" | sed -n 's/.*"id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
AGENT_KEY=$(printf '%s' "${RESPONSE}" | sed -n 's/.*"key"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')

if [ -z "${AGENT_ID}" ] || [ -z "${AGENT_KEY}" ]; then
  echo "Enrolment did not return an id and key. See the response above." >&2
  exit 1
fi

# ----------------------------------------------------------------------------
# 4. Assign the group.
# ----------------------------------------------------------------------------
if [ -n "${AGENT_GROUP}" ]; then
  echo "Assigning agent ${AGENT_ID} to group '${AGENT_GROUP}'..."
  curl "${CURL_OPTS[@]}" -X PUT \
    "${BASE}/agents/${AGENT_ID}/group/${AGENT_GROUP}?pretty=true" \
    "${auth[@]}"
  echo
fi

# ----------------------------------------------------------------------------
# 5. Tell the operator what to do on the endpoint.
# ----------------------------------------------------------------------------
cat <<EOF

Agent ID : ${AGENT_ID}
Key      : ${AGENT_KEY}

On the endpoint, import the key:

  Linux   : /var/ossec/bin/manage_agents -i ${AGENT_KEY}
  macOS   : /Library/Ossec/bin/manage_agents -i ${AGENT_KEY}
  Windows : "C:\\Program Files (x86)\\ossec-agent\\manage_agents.exe" -i ${AGENT_KEY}

Then set the manager endpoint in the agent configuration file and restart:

  <ossec_config>
    <agent>
      <manager>
        <endpoint>${MANAGER}</endpoint>
      </manager>
    </agent>
  </ossec_config>

The key above is a credential. Do not leave it in shell history or a CI log.
EOF
