This guide provides a complete Ansible playbook to install Wazuh SIEM/XDR platform with indexer, dashboard, and manager components.
Current Wazuh version: 4.14.3
Create a file named wazuh.yml:
---
- name: Install and Configure Wazuh SIEM/XDR (All-in-One)
hosts: wazuh
become: true
vars:
wazuh_version: "4.14.3"
wazuh_manager_port: 1514
wazuh_agent_port: 1515
wazuh_api_port: 55000
indexer_port: 9200
dashboard_port: 443
admin_password: "SecretPassword" # Change this!
wazuh_config_dir: "/var/ossec"
tasks:
- name: Install prerequisites (Debian/Ubuntu)
apt:
name:
- apt-transport-https
- software-properties-common
- wget
- gnupg2
- curl
- unzip
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install prerequisites (RHEL/CentOS)
yum:
name:
- wget
- gnupg2
- curl
- unzip
state: present
when: ansible_os_family == "RedHat"
- name: Add Wazuh APT key (Debian/Ubuntu)
apt_key:
url: "https://packages.wazuh.com/key/GPG-KEY-WAZUH"
state: present
when: ansible_os_family == "Debian"
- name: Add Wazuh APT repository (Debian/Ubuntu)
apt_repository:
repo: "deb https://packages.wazuh.com/4.x/apt/ stable main"
state: present
filename: wazuh
when: ansible_os_family == "Debian"
- name: Add Wazuh YUM repository (RHEL/CentOS)
yum_repository:
name: wazuh
description: Wazuh Repository
baseurl: "https://packages.wazuh.com/4.x/yum/"
gpgcheck: true
gpgkey: "https://packages.wazuh.com/key/GPG-KEY-WAZUH"
enabled: true
when: ansible_os_family == "RedHat"
- name: Download Wazuh installation script
get_url:
url: "https://packages.wazuh.com/4.x/wazuh-install.sh"
dest: /tmp/wazuh-install.sh
mode: '0755'
- name: Download Wazuh configuration file
get_url:
url: "https://packages.wazuh.com/4.x/config.yml"
dest: /tmp/config.yml
mode: '0644'
- name: Configure Wazuh installation
lineinfile:
path: /tmp/config.yml
regexp: "^{{ item.key }}:"
line: "{{ item.key }}: {{ item.value }}"
loop:
- { key: 'admin_password', value: "'{{ admin_password }}'" }
- { key: 'wazuh_version', value: "'{{ wazuh_version }}'" }
- name: Run Wazuh all-in-one installation
shell: |
bash /tmp/wazuh-install.sh -a -i
args:
creates: /var/ossec/bin/wazuh-control
environment:
WAZUH_INSTALL_AIO: "true"
- name: Wait for Wazuh to start
wait_for:
port: "{{ wazuh_api_port }}"
delay: 10
timeout: 300
- name: Wait for Wazuh indexer
wait_for:
port: "{{ indexer_port }}"
delay: 5
timeout: 120
- name: Enable and start Wazuh manager
systemd:
name: wazuh-manager
enabled: true
state: started
- name: Enable and start Wazuh indexer
systemd:
name: wazuh-indexer
enabled: true
state: started
- name: Enable and start Wazuh dashboard
systemd:
name: wazuh-dashboard
enabled: true
state: started
- name: Configure firewall (UFW)
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
comment: "Wazuh"
loop:
- "{{ wazuh_manager_port }}"
- "{{ wazuh_agent_port }}"
- "{{ wazuh_api_port }}"
- "{{ indexer_port }}"
- "{{ dashboard_port }}"
when: ansible_os_family == "Debian"
failed_when: false
- name: Configure firewall (firewalld)
firewalld:
port: "{{ item }}/tcp"
permanent: true
immediate: true
state: enabled
loop:
- "{{ wazuh_manager_port }}"
- "{{ wazuh_agent_port }}"
- "{{ wazuh_api_port }}"
- "{{ indexer_port }}"
- "{{ dashboard_port }}"
when: ansible_os_family == "RedHat"
failed_when: false
- name: Get Wazuh API token
uri:
url: "https://localhost:{{ wazuh_api_port }}/security/user/authenticate"
method: POST
user: admin
password: "{{ admin_password }}"
force_basic_auth: true
validate_certs: false
return_content: true
register: api_token
retries: 5
delay: 3
until: api_token.status == 200
- name: Display Wazuh status
debug:
msg: |
Wazuh {{ wazuh_version }} installed successfully!
Dashboard: https://{{ ansible_default_ipv4.address | default(ansible_host) }}
Username: admin
Password: {{ admin_password }}
API Port: {{ wazuh_api_port }}
Manager Port: {{ wazuh_manager_port }}
Agent Port: {{ wazuh_agent_port }}
IMPORTANT: Change the default password after first login!
IMPORTANT: Wazuh uses self-signed SSL certificates. Accept the certificate in your browser.
---
wazuh:
hosts:
wazuh-server:
ansible_host: 192.168.1.107
ansible_user: ansible
ansible_become: true
# Test connectivity
ansible all -i inventory.yml -m ping
# Run the Wazuh playbook
ansible-playbook -i inventory.yml wazuh.yml
# Run with custom admin password
ansible-playbook -i inventory.yml wazuh.yml -e "admin_password=MySecureP@ssw0rd123"
# Check Wazuh manager status
ssh wazuh-server "sudo systemctl status wazuh-manager"
# Check Wazuh indexer status
ssh wazuh-server "sudo systemctl status wazuh-indexer"
# Check Wazuh dashboard status
ssh wazuh-server "sudo systemctl status wazuh-dashboard"
# Test API connection
curl -k -u admin:SecretPassword https://localhost:55000/agents
# Access web UI
# https://wazuh-server (accept self-signed certificate)
- name: Deploy Wazuh Agent to monitored hosts
hosts: monitored_hosts
become: true
vars:
wazuh_manager_ip: "192.168.1.107"
wazuh_version: "4.14.3"
tasks:
- name: Install prerequisites (Debian/Ubuntu)
apt:
name:
- apt-transport-https
- wget
- gnupg2
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Add Wazuh APT key (Debian/Ubuntu)
apt_key:
url: "https://packages.wazuh.com/key/GPG-KEY-WAZUH"
state: present
when: ansible_os_family == "Debian"
- name: Add Wazuh APT repository (Debian/Ubuntu)
apt_repository:
repo: "deb https://packages.wazuh.com/4.x/apt/ stable main"
state: present
filename: wazuh
when: ansible_os_family == "Debian"
- name: Install Wazuh agent (Debian/Ubuntu)
apt:
name: wazuh-agent
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install Wazuh agent (RHEL/CentOS)
yum:
name: wazuh-agent
state: present
when: ansible_os_family == "RedHat"
- name: Configure Wazuh agent
lineinfile:
path: /var/ossec/etc/ossec.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '<address>', line: ' <address>{{ wazuh_manager_ip }}</address>' }
- { regexp: '<port>', line: ' <port>1514</port>' }
- { regexp: '<protocol>', line: ' <protocol>tcp</protocol>' }
- name: Enable and start Wazuh agent
systemd:
name: wazuh-agent
enabled: true
state: started
- name: Configure firewall for agent
ufw:
rule: allow
port: 1514
proto: tcp
comment: "Wazuh agent"
when: ansible_os_family == "Debian"
failed_when: false
- name: Restart Wazuh agent
systemd:
name: wazuh-agent
state: restarted
- name: Configure File Integrity Monitoring
hosts: wazuh
become: true
vars:
wazuh_config_dir: "/var/ossec"
tasks:
- name: Add FIM rules for critical directories
lineinfile:
path: "{{ wazuh_config_dir }}/etc/ossec.conf"
insertafter: '<syscheck>'
line: " <directories check_all=\"yes\" realtime=\"yes\">/etc,/usr/bin,/usr/sbin,/bin,/sbin,/boot</directories>"
notify: Restart Wazuh manager
- name: Add FIM rules for web directories
lineinfile:
path: "{{ wazuh_config_dir }}/etc/ossec.conf"
insertafter: '<syscheck>'
line: " <directories check_all=\"yes\" realtime=\"yes\">/var/www,/srv/www</directories>"
notify: Restart Wazuh manager
- name: Restart Wazuh manager
systemd:
name: wazuh-manager
state: restarted
handlers:
- name: Restart Wazuh manager
systemd:
name: wazuh-manager
state: restarted
- name: Configure Active Response
hosts: wazuh
become: true
vars:
wazuh_config_dir: "/var/ossec"
tasks:
- name: Enable active response
lineinfile:
path: "{{ wazuh_config_dir }}/etc/ossec.conf"
regexp: "^ <active-response>"
line: " <active-response>"
notify: Restart Wazuh manager
- name: Configure active response for brute force
blockinfile:
path: "{{ wazuh_config_dir }}/etc/ossec.conf"
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
insertafter: '<active-response>'
block: |
<command>
<name>firewall-drop</name>
<executable>firewall-drop.sh</executable>
<timeout_allowed>yes</timeout_allowed>
</command>
<active-response>
<command>firewall-drop</command>
<location>local</location>
<rules_id>5710,5711,5712</rules_id>
<timeout>600</timeout>
</active-response>
notify: Restart Wazuh manager
handlers:
- name: Restart Wazuh manager
systemd:
name: wazuh-manager
state: restarted
- name: Configure email notifications
hosts: wazuh
become: true
vars:
wazuh_config_dir: "/var/ossec"
smtp_server: "smtp.example.com"
smtp_port: 587
smtp_user: "wazuh@example.com"
smtp_password: "smtp_password"
admin_email: "security@example.com"
tasks:
- name: Configure email settings
blockinfile:
path: "{{ wazuh_config_dir }}/etc/ossec.conf"
marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
insertafter: '<global>'
block: |
<email_notification>yes</email_notification>
<smtp_server>{{ smtp_server }}</smtp_server>
<email_from>wazuh@{{ ansible_fqdn | default(ansible_hostname) }}</email_from>
<email_to>{{ admin_email }}</email_to>
<email_maxperhour>12</email_maxperhour>
<email_log_source>alerts.log</email_log_source>
notify: Restart Wazuh manager
handlers:
- name: Restart Wazuh manager
systemd:
name: wazuh-manager
state: restarted
# Check logs
sudo tail -f /var/ossec/logs/ossec.log
sudo journalctl -u wazuh-manager -f
# Check configuration
sudo /var/ossec/bin/wazuh-logtest
# Check dashboard logs
sudo tail -f /var/log/wazuh-dashboard/wazuh-dashboard.log
# Check indexer connection
curl -k -u admin:SecretPassword https://localhost:9200/_cluster/health
# Check agent status
sudo /var/ossec/bin/wazuh-control status
# List connected agents
curl -k -u admin:SecretPassword https://localhost:55000/agents
# Check agent logs
sudo tail -f /var/ossec/logs/ossec.log
Beyond this playbook, we offer:
Contact our automation team: office@linux-server-admin.com