Wazuh Agent Management - Enrollment and Configuration
Wazuh agents are installed on endpoints and handle log collection, file system monitoring, system inventory, and security assessments. Agent management encompasses the entire lifecycle - from enrollment and group assignment through centralized configuration, upgrades, and decommissioning. At scale, automating enrollment and configuration through Ansible, GPO, or cloud-init becomes critical. This guide covers all aspects of managing Wazuh 4.14 agents.
Agent Lifecycle
Every Wazuh agent progresses through defined states during operation.
Agent states
| State | Description |
|---|---|
| Pending | Agent is registered but has not yet connected to the manager |
| Active | Agent is connected and transmitting data |
| Disconnected | Agent has lost communication with the manager (default: 10 minutes without heartbeat) |
| Never connected | Agent is registered but has never established a connection |
Lifecycle diagram
Installation -> Enrollment -> Pending -> Active <-> Disconnected
|
RemovedChecking agent status
Through the API:
TOKEN=$(curl -sk -u wazuh-wui:$PASSWORD \
-X POST "https://localhost:55000/security/user/authenticate?raw=true")
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/agents?status=active&limit=10" | jq '.data.affected_items[] | {id,name,status,ip}'Through the CLI on the manager:
/var/ossec/bin/agent_control -l
# Detailed information about a specific agent
/var/ossec/bin/agent_control -i 001Through the state file on the agent:
cat /var/ossec/var/run/wazuh-agentd.stateConfiguring disconnection time
By default, an agent is considered disconnected after 600 seconds (10 minutes). To change this in ossec.conf on the manager:
<ossec_config>
<global>
<agents_disconnection_time>300</agents_disconnection_time>
<agents_disconnection_alert_time>60</agents_disconnection_alert_time>
</global>
</ossec_config>Enrollment Methods
Enrollment via agent configuration
The most common method. The agent registers automatically on its first connection to the manager.
On a Linux agent:
<!-- /var/ossec/etc/ossec.conf -->
<ossec_config>
<client>
<server>
<address>192.168.1.5</address>
<port>1514</port>
<protocol>tcp</protocol>
</server>
<enrollment>
<enabled>yes</enabled>
<manager_address>192.168.1.5</manager_address>
<port>1515</port>
<agent_name>web-server-01</agent_name>
<groups>linux,web-servers</groups>
</enrollment>
</client>
</ossec_config>On a Windows agent (during installation):
Invoke-WebRequest -Uri https://packages.wazuh.com/4.x/windows/wazuh-agent-4.14.4-1.msi -OutFile wazuh-agent.msi
msiexec.exe /i wazuh-agent.msi /q `
WAZUH_MANAGER="192.168.1.5" `
WAZUH_AGENT_NAME="win-server-01" `
WAZUH_AGENT_GROUP="windows,servers" `
WAZUH_REGISTRATION_SERVER="192.168.1.5"Password-based enrollment
To protect the enrollment process, you can configure password authentication.
On the manager, create a password file:
echo "MySecurePassword" > /var/ossec/etc/authd.pass
chmod 640 /var/ossec/etc/authd.pass
chown root:wazuh /var/ossec/etc/authd.passEnable password authentication in ossec.conf:
<ossec_config>
<auth>
<use_password>yes</use_password>
</auth>
</ossec_config>On the agent, specify the password:
<enrollment>
<enabled>yes</enabled>
<manager_address>192.168.1.5</manager_address>
<authorization_pass_path>/var/ossec/etc/authd.pass</authorization_pass_path>
</enrollment>Certificate-based enrollment
Certificate authentication provides mutual verification between agent and manager.
On the manager:
<ossec_config>
<auth>
<ssl_agent_ca>/var/ossec/etc/rootCA.pem</ssl_agent_ca>
<ssl_verify_host>yes</ssl_verify_host>
</auth>
</ossec_config>On the agent:
<enrollment>
<enabled>yes</enabled>
<manager_address>192.168.1.5</manager_address>
<agent_certificate_path>/var/ossec/etc/agent.cert</agent_certificate_path>
<agent_key_path>/var/ossec/etc/agent.key</agent_key_path>
<server_ca_path>/var/ossec/etc/rootCA.pem</server_ca_path>
</enrollment>API-based enrollment
A two-step process: request a key through the API and import it on the agent.
# Step 1: Obtain the key via API
TOKEN=$(curl -sk -u wazuh-wui:$PASSWORD \
-X POST "https://localhost:55000/security/user/authenticate?raw=true")
KEY=$(curl -sk -H "Authorization: Bearer $TOKEN" \
-X POST "https://localhost:55000/agents" \
-H "Content-Type: application/json" \
-d '{"name":"api-agent-01","ip":"any"}' | jq -r '.data.key')
# Step 2: Import the key on the agent
/var/ossec/bin/manage_agents -i "$KEY"
# Step 3: Start the agent
systemctl start wazuh-agentEnrollment via authd
The authd daemon automatically handles enrollment requests. It is enabled by default and listens on port 1515/TCP.
# On the agent - request enrollment
/var/ossec/bin/agent-auth -m 192.168.1.5
# With a custom name and group
/var/ossec/bin/agent-auth -m 192.168.1.5 -A "custom-agent-name" -G "linux,production"
# With password
/var/ossec/bin/agent-auth -m 192.168.1.5 -P "MySecurePassword"Agent Groups
Groups allow logical organization of agents and centralized configuration management.
Default group
All newly registered agents are automatically assigned to the default group. The group configuration is located at /var/ossec/etc/shared/default/agent.conf.
Creating a group
Through the CLI:
/var/ossec/bin/agent_groups -a -g web-servers -qThrough the API:
curl -sk -H "Authorization: Bearer $TOKEN" \
-X POST "https://localhost:55000/groups" \
-H "Content-Type: application/json" \
-d '{"group_id": "web-servers"}'Through the Dashboard: Agents management - Groups - Add new group.
Assigning an agent to a group
# Through CLI
/var/ossec/bin/agent_groups -a -i 001 -g web-servers -q
# Through API
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/001/group/web-servers"Assignment during enrollment
# Using agent-auth
/var/ossec/bin/agent-auth -m 192.168.1.5 -G "web-servers,linux"
# During Windows installation
msiexec.exe /i wazuh-agent.msi /q WAZUH_AGENT_GROUP="windows,production"Multi-group membership
An agent can belong to multiple groups simultaneously. When parameters conflict, the last assigned group takes precedence.
# Assign to multiple groups
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/001/group/web-servers"
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/001/group/production"Priority order (lowest to highest): default - web-servers - production. Configuration from the production group overrides conflicting parameters from web-servers and default.
Viewing agent groups
# Groups for a specific agent
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/agents/001/group" | jq '.data.affected_items'
# All agents in a group
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/groups/web-servers/agents" | jq '.data.affected_items[] | {id,name,status}'Centralized Configuration (agent.conf)
The agent.conf file enables centralized management of agent configuration through the manager. Each group has its own agent.conf at /var/ossec/etc/shared/<GROUP_NAME>/agent.conf.
Structure of agent.conf
<!-- /var/ossec/etc/shared/web-servers/agent.conf -->
<agent_config>
<!-- Web server log collection -->
<localfile>
<log_format>apache</log_format>
<location>/var/log/apache2/access.log</location>
</localfile>
<localfile>
<log_format>apache</log_format>
<location>/var/log/apache2/error.log</location>
</localfile>
<!-- File integrity monitoring -->
<syscheck>
<directories check_all="yes" realtime="yes">/var/www/html</directories>
<directories check_all="yes">/etc/apache2</directories>
</syscheck>
<!-- Active Response -->
<active-response>
<disabled>no</disabled>
</active-response>
</agent_config>OS-based filtering
<agent_config os="Linux">
<localfile>
<log_format>syslog</log_format>
<location>/var/log/auth.log</location>
</localfile>
</agent_config>
<agent_config os="Windows">
<localfile>
<log_format>eventchannel</log_format>
<location>Security</location>
<query>Event/System[EventID=4625 or EventID=4624]</query>
</localfile>
</agent_config>Profile-based filtering
<agent_config profile="database">
<localfile>
<log_format>syslog</log_format>
<location>/var/log/postgresql/postgresql-*.log</location>
</localfile>
</agent_config>Shared files
In addition to agent.conf, the group directory can contain supplementary files that are automatically synchronized to agents:
- CDB lists for rootcheck
- CIS Benchmark files
- Custom configuration files
# Place a file for the group
cp custom-rootcheck.txt /var/ossec/etc/shared/web-servers/
# Check synchronization status
/var/ossec/bin/agent_groups -S -i 001Configuration merging (merged.mg)
The manager automatically generates a merged.mg file that combines configurations from all groups assigned to an agent. This file is sent to the agent and determines the final working configuration.
Agent Upgrades
Upgrading via WPK
WPK (Wazuh Package) files are signed packages for remote agent upgrades.
Through the API:
# Upgrade a single agent
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/001/upgrade" | jq '.'
# Upgrade multiple agents
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/upgrade" \
-H "Content-Type: application/json" \
-d '{"agents_list": ["001", "002", "003"]}'Checking upgrade status
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/agents/upgrade_result" | jq '.data.affected_items'Upgrading through Dashboard
- Navigate to Agents management
- Select agents for upgrade
- Click Upgrade
- Confirm the version and start the process
Staged upgrades
To minimize impact on production systems, upgrade agents in batches:
# Upgrade agents in the staging group
AGENTS=$(curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/groups/staging/agents?limit=500" | \
jq -r '.data.affected_items[].id' | tr '\n' ',' | sed 's/,$//')
curl -sk -H "Authorization: Bearer $TOKEN" \
-X PUT "https://localhost:55000/agents/upgrade" \
-H "Content-Type: application/json" \
-d "{\"agents_list\": [\"${AGENTS}\"]}"Custom WPK packages
To build custom WPK packages:
# Download the build tools
git clone https://github.com/wazuh/wazuh.git
cd wazuh/src/wazuh_modules/agent_upgrade/
# Build a custom WPK (requires a GPG key for signing)Agent Labels
Labels allow attaching custom metadata to agents. Labels are included in every alert, simplifying filtering and routing.
Configuring labels
On the agent in ossec.conf:
<ossec_config>
<labels>
<label key="environment">production</label>
<label key="datacenter">us-east-1</label>
<label key="team">platform</label>
<label key="cost-center">CC-1234</label>
</labels>
</ossec_config>Through centralized configuration in agent.conf:
<agent_config>
<labels>
<label key="compliance">pci-dss</label>
<label key="tier">tier-1</label>
</labels>
</agent_config>Hidden labels
Labels prefixed with _ are not included in alerts but remain accessible through the API:
<labels>
<label key="_internal.ticket">JIRA-12345</label>
</labels>Using labels in queries
GET wazuh-alerts-*/_search
{
"query": {
"term": { "agent.labels.environment": "production" }
}
}Key Management
Exporting an agent key
/var/ossec/bin/manage_agents -e 001Importing a key on the agent
/var/ossec/bin/manage_agents -i "<KEY_STRING>"Listing registered agents
/var/ossec/bin/manage_agents -lRemoving an agent
# Through CLI
/var/ossec/bin/manage_agents -r 001
# Through API
curl -sk -H "Authorization: Bearer $TOKEN" \
-X DELETE "https://localhost:55000/agents?agents_list=001&status=all&older_than=0s"Mass Deployment Strategies
Ansible
# playbook.yml
---
- name: Deploy Wazuh agents
hosts: all
become: yes
vars:
wazuh_manager: "192.168.1.5"
wazuh_version: "4.14.4"
wazuh_group: "{{ group_names | join(',') }}"
tasks:
- name: Add Wazuh repository
apt_repository:
repo: "deb https://packages.wazuh.com/4.x/apt/ stable main"
state: present
when: ansible_os_family == "Debian"
- name: Install Wazuh agent
apt:
name: "wazuh-agent={{ wazuh_version }}-1"
state: present
when: ansible_os_family == "Debian"
- name: Configure agent
template:
src: ossec.conf.j2
dest: /var/ossec/etc/ossec.conf
owner: root
group: wazuh
mode: '0640'
- name: Start Wazuh agent
systemd:
name: wazuh-agent
state: started
enabled: yesGPO with MSI (Windows)
For mass deployment on Windows through Group Policy:
- Download the MSI package:
wazuh-agent-4.14.4-1.msi - Place it in a network share accessible to domain computers
- Create a GPO for Software Installation:
- Computer Configuration - Policies - Software Settings - Software Installation
- Add the MSI package
- Configure installation parameters through an MST (transform) file:
WAZUH_MANAGER=192.168.1.5
WAZUH_AGENT_GROUP=windows,production
WAZUH_REGISTRATION_SERVER=192.168.1.5
WAZUH_REGISTRATION_PASSWORD=MySecurePasswordcloud-init
#cloud-config
package_update: true
runcmd:
- curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | gpg --dearmor -o /usr/share/keyrings/wazuh.gpg
- echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" > /etc/apt/sources.list.d/wazuh.list
- apt-get update
- WAZUH_MANAGER="192.168.1.5" WAZUH_AGENT_GROUP="cloud,auto-provisioned" apt-get install -y wazuh-agent
- systemctl daemon-reload
- systemctl enable wazuh-agent
- systemctl start wazuh-agentDocker
FROM ubuntu:22.04
ENV WAZUH_MANAGER="192.168.1.5"
ENV WAZUH_AGENT_GROUP="docker,containers"
RUN apt-get update && \
apt-get install -y curl gnupg && \
curl -s https://packages.wazuh.com/key/GPG-KEY-WAZUH | \
gpg --dearmor -o /usr/share/keyrings/wazuh.gpg && \
echo "deb [signed-by=/usr/share/keyrings/wazuh.gpg] https://packages.wazuh.com/4.x/apt/ stable main" \
> /etc/apt/sources.list.d/wazuh.list && \
apt-get update && \
apt-get install -y wazuh-agent && \
apt-get clean
ENTRYPOINT ["/var/ossec/bin/wazuh-control", "start"]Auto-removal of Disconnected Agents
To automatically clean up agents that have been offline for an extended period:
# Remove agents disconnected for more than 30 days
curl -sk -H "Authorization: Bearer $TOKEN" \
-X DELETE "https://localhost:55000/agents?status=disconnected&older_than=30d" | jq '.'To automate this, add a cron job:
# /etc/cron.daily/wazuh-cleanup-agents
#!/bin/bash
TOKEN=$(curl -sk -u wazuh-wui:$PASSWORD \
-X POST "https://localhost:55000/security/user/authenticate?raw=true")
curl -sk -H "Authorization: Bearer $TOKEN" \
-X DELETE "https://localhost:55000/agents?status=disconnected&older_than=30d"Comparison with Other SIEM Platforms
| Feature | Wazuh Agent | Splunk Universal Forwarder | Elastic Agent (Fleet) | QRadar Log Sources |
|---|---|---|---|---|
| Deployment model | Agent per host | Forwarder per host | Agent per host | Agentless + WinCollect |
| Group management | Groups with agent.conf | Server classes | Policies | Log Source Groups |
| Centralized config | agent.conf via manager | Deployment apps | Fleet policies | None (per-source) |
| Remote upgrade | WPK via API | Deployment server | Fleet upgrade | WinCollect update |
| Built-in FIM | Yes | No (addon) | Yes (integration) | No (addon) |
| Vulnerability scan | Yes | No | Yes | No |
| Mass deployment | Ansible, GPO, cloud-init | Ansible, GPO, SCCM | Fleet enrollment tokens | WinCollect MSI |
| Licensing | Free | Per data volume | Per data volume | Per EPS |
Troubleshooting
Agent not connecting
Symptom: agent remains in never_connected or disconnected status.
Diagnostics on the agent:
# Check configuration
cat /var/ossec/etc/ossec.conf | grep -A5 "<server>"
# Check agent logs
tail -50 /var/ossec/logs/ossec.log
# Test network connectivity
nc -zv 192.168.1.5 1514
nc -zv 192.168.1.5 1515Diagnostics on the manager:
# Check enrollment logs
tail -50 /var/ossec/logs/ossec.log | grep -i "agent"
# Verify authd is listening
ss -tlnp | grep 1515
# Verify remoted is listening
ss -tlnp | grep 1514Solutions:
- Verify that ports 1514/TCP and 1515/TCP are open on the firewall
- Check that the manager address is correct in the agent configuration
- When using password enrollment, ensure the password matches on both sides
- Restart
wazuh-authdon the manager
Key mismatch
Symptom: Invalid key or Agent key mismatch messages in the logs.
# On the manager - export the key for the agent
/var/ossec/bin/manage_agents -e 001
# On the agent - remove the old key and import the new one
/var/ossec/bin/manage_agents -r
/var/ossec/bin/manage_agents -i "<NEW_KEY>"
# Restart the agent
systemctl restart wazuh-agentVersion incompatibility
Symptom: agent connects but functionality is limited or errors appear.
Wazuh supports backward compatibility within the major version. Agent 4.x can connect to manager 4.y where y >= x. Upgrade the agent to match the manager version for full compatibility.
# Check version on the agent
/var/ossec/bin/wazuh-control info | grep VERSION
# Check version on the manager
/var/ossec/bin/wazuh-control info | grep VERSIONDuplicate agents
Symptom: a single host is registered multiple times with different IDs.
# Search for duplicates by IP or name
curl -sk -H "Authorization: Bearer $TOKEN" \
"https://localhost:55000/agents?name=web-server-01" | jq '.data.affected_items[] | {id,name,ip,status}'
# Remove the duplicate agent
curl -sk -H "Authorization: Bearer $TOKEN" \
-X DELETE "https://localhost:55000/agents?agents_list=002&status=all&older_than=0s"Prevention: use force.enabled in the authd configuration:
<ossec_config>
<auth>
<force>
<enabled>yes</enabled>
<key_mismatch>yes</key_mismatch>
<disconnected_time enabled="yes">1h</disconnected_time>
<after_registration_time>1h</after_registration_time>
</force>
</auth>
</ossec_config>This allows an agent with the same IP or name to replace an existing registration if the old agent has been disconnected for more than 1 hour.
Agent not receiving group configuration
Symptom: changes to agent.conf are not applied on the agent.
# Check synchronization status
/var/ossec/bin/agent_groups -S -i 001
# Check the merged.mg file on the agent
cat /var/ossec/etc/shared/merged.mg
# Force synchronization - restart the agent
systemctl restart wazuh-agentEnsure that agent.conf is valid XML - malformed XML blocks synchronization entirely.
Additional Resources
- Wazuh Agent Installation - installing agents on various operating systems
- Wazuh Dashboard Configuration - monitoring agents through the web interface
- Wazuh Indexer API - querying agent data
- Log Data Collection - configuring data sources on agents