# Wazuh Agent Management - Enrollment and Configuration

> Complete guide to Wazuh 4.14 agent management - enrollment methods, groups, centralized configuration, upgrades, mass deployment, and troubleshooting

Source: https://opennix.org/en/docs/wazuh/infrastructure/wazuh-agent-management/


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
                                                        |
                                                     Removed
```

### Checking agent status

Through the API:

```bash
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:

```bash
/var/ossec/bin/agent_control -l

# Detailed information about a specific agent
/var/ossec/bin/agent_control -i 001
```

Through the state file on the agent:

```bash
cat /var/ossec/var/run/wazuh-agentd.state
```

### Configuring disconnection time

By default, an agent is considered disconnected after 600 seconds (10 minutes). To change this in `ossec.conf` on the manager:

```xml
<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:

```xml
<!-- /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):

```powershell
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:

```bash
echo "MySecurePassword" > /var/ossec/etc/authd.pass
chmod 640 /var/ossec/etc/authd.pass
chown root:wazuh /var/ossec/etc/authd.pass
```

Enable password authentication in `ossec.conf`:

```xml
<ossec_config>
  <auth>
    <use_password>yes</use_password>
  </auth>
</ossec_config>
```

On the agent, specify the password:

```xml
<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:

```xml
<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:

```xml
<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.

```bash
# 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-agent
```

### Enrollment via authd

The authd daemon automatically handles enrollment requests. It is enabled by default and listens on port 1515/TCP.

```bash
# 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:

```bash
/var/ossec/bin/agent_groups -a -g web-servers -q
```

Through the API:

```bash
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

```bash
# 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

```bash
# 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.

```bash
# 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

```bash
# 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

```xml
<!-- /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

```xml
<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

```xml
<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

```bash
# 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 001
```

### Configuration 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:

```bash
# 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

```bash
curl -sk -H "Authorization: Bearer $TOKEN" \
  "https://localhost:55000/agents/upgrade_result" | jq '.data.affected_items'
```

### Upgrading through Dashboard

1. Navigate to Agents management
2. Select agents for upgrade
3. Click Upgrade
4. Confirm the version and start the process

### Staged upgrades

To minimize impact on production systems, upgrade agents in batches:

```bash
# 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:

```bash
# 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`:

```xml
<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`:

```xml
<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:

```xml
<labels>
  <label key="_internal.ticket">JIRA-12345</label>
</labels>
```

### Using labels in queries

```json
GET wazuh-alerts-*/_search
{
  "query": {
    "term": { "agent.labels.environment": "production" }
  }
}
```

## Key Management

### Exporting an agent key

```bash
/var/ossec/bin/manage_agents -e 001
```

### Importing a key on the agent

```bash
/var/ossec/bin/manage_agents -i "<KEY_STRING>"
```

### Listing registered agents

```bash
/var/ossec/bin/manage_agents -l
```

### Removing an agent

```bash
# 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

```yaml
# 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: yes
```

### GPO with MSI (Windows)

For mass deployment on Windows through Group Policy:

1. Download the MSI package: `wazuh-agent-4.14.4-1.msi`
2. Place it in a network share accessible to domain computers
3. Create a GPO for Software Installation:
   - Computer Configuration - Policies - Software Settings - Software Installation
   - Add the MSI package
4. 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=MySecurePassword
```

### cloud-init

```yaml
#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-agent
```

### Docker

```dockerfile
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:

```bash
# 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:

```bash
# /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:

```bash
# 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 1515
```

Diagnostics on the manager:

```bash
# 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 1514
```

Solutions:

- 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-authd` on the manager

### Key mismatch

**Symptom**: `Invalid key` or `Agent key mismatch` messages in the logs.

```bash
# 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-agent
```

### Version 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.

```bash
# 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 VERSION
```

### Duplicate agents

**Symptom**: a single host is registered multiple times with different IDs.

```bash
# 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:

```xml
<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.

```bash
# 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-agent
```

Ensure that `agent.conf` is valid XML - malformed XML blocks synchronization entirely.

## Additional Resources

- [Wazuh Agent Installation](/docs/wazuh/installation/wazuh-agent-installation/) - installing agents on various operating systems
- [Wazuh Dashboard Configuration](/docs/wazuh/infrastructure/wazuh-dashboard-configuration/) - monitoring agents through the web interface
- [Wazuh Indexer API](/docs/wazuh/infrastructure/wazuh-indexer-api/) - querying agent data
- [Log Data Collection](/docs/wazuh/capabilities/wazuh-log-data-collection/) - configuring data sources on agents

