How to deploy wazuh-agent with Ansible

Note: For windows ports 5986 and 1515 must be open along with configureansiblescript.ps(powershell script) must have been setup for ansible to be able to communicate and deploy the wazuh-agent to windows machines.

.

In order to deploy the wazuh-agent to a large group of servers that span windows, ubuntu, centos type distros with ansible. Some tweaks need to be made on the wazuh manager and ansible server

.

This is done on the wazuh-manager server

/var/ossec/etc/ossec.conf – inside this file the following need to be edited for registrations to have the proper ip of the hosts being registered

<auth>

<disabled>no</disabled>

<port>1515</port>

<use_source_ip>yes</use_source_ip>

<force_insert>yes</force_insert>

<force_time>0</force_time>

<purge>yes</purge>

    <use_password>yes</use_password>

<limit_maxagents>no</limit_maxagents>

    <ciphers>HIGH:!ADH:!EXP:!MD5:RC4:3DES:!CAMELLIA:@STRENGTH</ciphers>

    <!– <ssl_agent_ca></ssl_agent_ca> –>

<ssl_verify_host>no</ssl_verify_host>

<ssl_manager_cert>/var/ossec/etc/sslmanager.cert</ssl_manager_cert>

<ssl_manager_key>/var/ossec/etc/sslmanager.key</ssl_manager_key>

<ssl_auto_negotiate>yes</ssl_auto_negotiate>

</auth>

To enable authd on wazuh-manager

 /var/ossec/bin/ossec-control enable authd

Now on your ansible server

1.You need to download the git repository with ansible playbooks for wazuh
2.git clone https://github.com/wazuh/wazuh-ansible <–do this in home directory /home/nicktailor
3.Next you will see them setup as roles that you would call in your playbook

.

 drwxr-x— 7 root root 97 Sep 21 13:45 ansible-role-elasticsearch
 drwxr-x— 8 root root 110 Sep 21 13:45 ansible-role-filebeat
 drwxr-x— 7 root root 97 Sep 21 13:45 ansible-role-kibana
 drwxr-x— 7 root root 97 Sep 21 13:45 ansible-role-logstash
 drwxr-x— 8 root root 109 Sep 21 13:45 ansible-wazuh-agent this is the role one you want to copy to /etc/ansible/roles
 drwxr-x— 8 root root 167 Sep 21 13:45 ansible-wazuh-manager
 drwxr-x— 8 root root 163 Sep 21 13:45 .git
 -rw-r—– 1 root root 163 Sep 21 13:45 .gitignore
 drwxr-x— 2 root root 22 Sep 21 13:45 meta
 -rw-r—– 1 root root 1060 Sep 21 13:45 README.md
 -rw-r—– 1 root root 350 Sep 21 13:45 wazuh-agent.ymlthis is the playbook you want to copy to /etc/ansible/playbooks
 -rw-r—– 1 root root 460 Sep 21 13:45 wazuh-elastic_stack-distributed.yml
 -rw-r—– 1 root root 322 Sep 21 13:45 wazuh-elastic_stack-single.yml
 -rw-r—– 1 root root 121 Sep 21 13:45 wazuh-elastic.yml
 -rw-r—– 1 root root 107 Sep 21 13:45 wazuh-kibana.yml
 -rw-r—– 1 root root 106 Sep 21 13:45 wazuh-logstash.yml
 -rw-r—– 1 root root 159 Sep 21 13:45 wazuh-manager.yml
4.You need to copy the role over to your ansible roles directory
a.cp -r ansible-wazuh-manger /etc/ansible/roles
5.next copy the playbook to your playbook directory
b.cp wazuh-agent.yml /etc/ansible/playbooks
6.Next you need to update the following file with the ip address of the wazuh-manager
c./etc/ansible/roles/ansible-wazuh-agent/defaults# cat main.yml

wazuh_managers:

  – address: 10.79.240.160

port: 1514

protocol: tcp

    api_port: 55000

    api_proto: ‘http’

    api_user: null

wazuh_profile: null

wazuh_auto_restart: ‘yes’

wazuh_agent_authd:

  enable: true

port: 1515

Next section in main.yml

  openscap:

    disable: ‘no’

timeout: 1800

interval: ‘1d’

    scan_on_start: ‘yes’

7.Now you need to add the password you setup on the wazuh-manager for the api user to the ansible authd section:
d./etc/ansible/roles/ansible-wazuh-agent/vars# cat authd_pass.yml

# We recommend the use of Ansible Vault to protect Wazuh, api, agentless and authd credentials.

authd_pass: ‘password’

e.Save the file authd_pass.yml

.

8.Next you need to have the hosts listed in your hosts file in ansible /etc/ansible/hosts-whatever
f.Not that for windows machines you will need to ensure the are also listed in /etc/hosts. The reason is authd using Kerberos has issues sometimes with dns resolution when attempting open a connection via winrm on port 5986.
9.Next you must list your hosts in the ansible host file as such
g./etc/ansible/hosts-linux
i.[linux]
ii.Server1.nicktailor.com
iii.Server2.nicktailor.com
h./etc/ansible/hosts-windows
iv.[windows]
v.Server1-w.nicktailor.com
vi.Server2-2.nicktailor.com

.

Test communication to windows machines via ansible run the following from /etc/ansible

 ansible windows -i /etc/ansible/hosts-windows -m ping
 ansible gsdprdint -i /etc/ansible/hosts-prod-linux -m ping –vault-password-file /etc/ansible/vaultpw.txt -u ansiblenick -k -K

How to run he playbook on linux machines, run from /etc/ansible/playbook/

 ansible-playbook mars -i /etc/ansible/hosts-prod-linux /etc/ansible/playbooks/wazuh-agent.yml –vault-password-file /etc/ansible/vaultpw.txt -u ansiblenick -k -K

How to run playbook on windows

 ansible-playbook -i /etc/ansible/hosts-windows /etc/ansible/playbooks/wazuh-agent.yml –vault-password-file /etc/ansible/vaultpw.txt -u ansiblenickt -k -K

.

Ansible playbook-roles-tasks breakdown

:/etc/ansible/playbooks# cat wazuh-agent.ymlplaybook file

– hosts: all:!wazuh-manager

roles:

– ansible-wazuh-agentroles that is called

vars:

    wazuh_managers:

– address: 192.168.10.10

port: 1514

protocol: udp

        api_port: 55000

        api_proto: ‘http’

        api_user: ansible

    wazuh_agent_authd:

      enable: true

port: 1515

      ssl_agent_ca: null

      ssl_auto_negotiate: ‘no

.

Roles: ansible-wazuh-agent

:/etc/ansible/roles/ansible-wazuh-agent/tasks# cat Linux.yml

– import_tasks: “RedHat.yml”

when: ansible_os_family == “RedHat”

.

– import_tasks: “Debian.yml”

when: ansible_os_family == “Debian”

.

– name: Linux | Install wazuh-agent

  become: yes

package: name=wazuh-agent state=present

async: 90

poll: 15

tags:

– init

.

– name: Linux | Check if client.keys exists

  become: yes

stat: path=/var/ossec/etc/client.keys

register: check_keys

tags:

– config

.

This task I added. If the client.keys file exists the registration on linux simply skips over when the playbook runs. You may want to disable this later, however when deploying to new machines probably best to have it active

.

– name: empty client key file

  become: yes

command: rm -f /var/ossec/etc/client.keys

command: touch /var/ossec/etc/client.keys

.

.

– name: Linux | Agent registration via authd

block:

– name: Retrieving authd Credentials

      include_vars: authd_pass.yml

tags:

– config

– authd

.

– name: Copy CA, SSL key and cert for authd

copy:

        src: “{{ item }}”

        dest: “/var/ossec/etc/{{ item | basename }}”

mode: 0644

      with_items:

– “{{ wazuh_agent_authd.ssl_agent_ca }}”

– “{{ wazuh_agent_authd.ssl_agent_cert }}”

– “{{ wazuh_agent_authd.ssl_agent_key }}”

tags:

– config

– authd

when:

– wazuh_agent_authd.ssl_agent_ca is not none

.

This section below is the most important section as this what registers the machine to wazuh, if this section is skipped its usually due to client.keys file. I have made adjustments from the original git repository as I found it had some issues.

.

    – name: Linux | Register agent (via authd)

shell: >

/var/ossec/bin/agent-auth

-m {{ wazuh_managers.0.address }}

-p {{ wazuh_agent_authd.port }}

{% if authd_pass is defined %}-P {{ authd_pass }}{% endif %}

{% if wazuh_agent_authd.ssl_agent_ca is not none %}

-v “/var/ossec/etc/{{ wazuh_agent_authd.ssl_agent_ca | basename }}”

-x “/var/ossec/etc/{{ wazuh_agent_authd.ssl_agent_cert | basename }}”

-k “/var/ossec/etc/{{ wazuh_agent_authd.ssl_agent_key | basename }}”

{% endif %}

{% if wazuh_agent_authd.ssl_auto_negotiate == ‘yes’ %}-a{% endif %}

      become: yes

register: agent_auth_output

when:

– check_keys.stat.size == 0

– wazuh_managers.0.address is not none

tags:

– config

– authd

.

– name: Linux | Verify agent registration

shell: echo {{ agent_auth_output }} | grep “Valid key created”

when:

– check_keys.stat.size == 0

– wazuh_managers.0.address is not none

tags:

– config

– authd

.

when: wazuh_agent_authd.enable == true

.

– name: Linux | Agent registration via rest-API

block:

.

– name: Retrieving rest-API Credentials

      include_vars: api_pass.yml

tags:

– config

– api

.

– name: Linux | Create the agent key via rest-API

      uri:

url: “{{ wazuh_managers.0.api_proto }}://{{ wazuh_managers.0.address }}:{{ wazuh_managers.0.api_port }}/agents/”

        validate_certs: no

method: POST

body: {“name”:”{{ inventory_hostname }}”}

        body_format: json

        status_code: 200

    headers:

Content-Type: “application/json”

user: “{{ wazuh_managers.0.api_user }}”

password: “{{ api_pass }}”

register: newagent_api

      changed_when: newagent_api.json.error == 0

when:

– check_keys.stat.size == 0

– wazuh_managers.0.address is not none

      become: no

tags:

– config

– api

.

– name: Linux | Retieve new agent data via rest-API

      uri:

url: “{{ wazuh_managers.0.api_proto }}://{{ wazuh_managers.0.address }}:{{ wazuh_managers.0.api_port }}/agents/{{ newagent_api.json.data.id }}”

        validate_certs: no

method: GET

        return_content: yes

user: “{{ wazuh_managers.0.api_user }}”

password: “{{ api_pass }}”

when:

– check_keys.stat.size == 0

– wazuh_managers.0.address is not none

– newagent_api.json.error == 0

register: newagentdata_api

      delegate_to: localhost

      become: no

tags:

– config

– api

.

– name: Linux | Register agent (via rest-API)

command: /var/ossec/bin/manage_agents

environment:

OSSEC_ACTION: i

OSSEC_AGENT_NAME: ‘{{ newagentdata_api.json.data.name }}’

OSSEC_AGENT_IP: ‘{{ newagentdata_api.json.data.ip }}’

OSSEC_AGENT_ID: ‘{{ newagent_api.json.data.id }}’

OSSEC_AGENT_KEY: ‘{{ newagent_api.json.data.key }}’

OSSEC_ACTION_CONFIRMED: y

register: manage_agents_output

when:

– check_keys.stat.size == 0

– wazuh_managers.0.address is not none

– newagent_api.changed

tags:

– config

– api

      notify: restart wazuh-agent

.

when: wazuh_agent_authd.enable == false

.

– name: Linux | Vuls integration deploy (runs in background, can take a while)

command: /var/ossec/wodles/vuls/deploy_vuls.sh {{ ansible_distribution|lower }} {{ ansible_distribution_major_version|int }}

  args:

creates: /var/ossec/wodles/vuls/config.toml

async: 3600

poll: 0

when:

– wazuh_agent_config.vuls.disable != ‘yes’

– ansible_distribution == ‘Redhat’ or ansible_distribution == ‘CentOS’ or ansible_distribution == ‘Ubuntu’ or ansible_distribution == ‘Debian’ or ansible_distribution == ‘Oracle’

tags:

– init

.

– name: Linux | Installing agent configuration (ossec.conf)

  become: yes

template: src=var-ossec-etc-ossec-agent.conf.j2

            dest=/var/ossec/etc/ossec.conf

owner=root

group=ossec

mode=0644

  notify: restart wazuh-agent

  tags:

– init

– config

.

– name: Linux | Ensure Wazuh Agent service is restarted and enabled

  become: yes

service:

name: wazuh-agent

enabled: yes

state: restarted

.

– import_tasks: “RMRedHat.yml”

when: ansible_os_family == “RedHat”

.

– import_tasks: “RMDebian.yml”

when: ansible_os_family == “Debian”

.

Windows- tasks

Note: This section only works if your ansible is configured to communicate with Windows machines. It requires that port 5986 from ansible to windows is open and then port 1515 from the window machine to the wazuh-manager is open.

.

Problems: When using authd and Kerberos for windows ensure you have the host name listed in /etc/hosts on the ansible server to help alleviate agent deployment issues. Its script does not seem to handle well when you have more than 5 or 6 clients at a time at least in my experience.

.

Either I had to rejoint the windows machine to the domain or remove the client.keys file. I have updated this task to include the task to remove the client.keys file before it check to see if it exists. You do need to play with it a bit sometimes. I have also added a section that adds the wazuh-agent as a service and restarts it upon deployment as I found it sometimes skipped this entirely.

.

:/etc/ansible/roles/ansible-wazuh-agent/tasks# cat Windows.yml

– name: Windows | Get current installed version

  win_shell: “{{ wazuh_winagent_config.install_dir }}ossec-agent.exe -h”

  args:

removes: “{{ wazuh_winagent_config.install_dir }}ossec-agent.exe”

register: agent_version

  failed_when: False

  changed_when: False

.

– name: Windows | Check Wazuh agent version installed

  set_fact: correct_version=true

when:

– agent_version.stdout is defined

– wazuh_winagent_config.version in agent_version.stdout

.

– name: Windows | Downloading windows Wazuh agent installer

  win_get_url:

    dest: C:\wazuh-agent-installer.msi

url: “{{ wazuh_winagent_config.repo }}wazuh-agent-{{ wazuh_winagent_config.version }}-{{ wazuh_winagent_config.revision }}.msi”

when:

– correct_version is not defined

.

– name: Windows | Verify the downloaded Wazuh agent installer

  win_stat:

path: C:\wazuh-agent-installer.msi

    get_checksum: yes

    checksum_algorithm: md5

register: installer_md5

when:

– correct_version is not defined

  failed_when:

– installer_md5.stat.checksum != wazuh_winagent_config.md5

.

– name: Windows | Install Wazuh agent

  win_package:

path: C:\wazuh-agent-installer.msi

arguments: APPLICATIONFOLDER={{ wazuh_winagent_config.install_dir }}

when:

– correct_version is not defined

.

This section was added. If it was present registrations would skip

– name: Remove a file, if present

  win_file:

path: C:\wazuh-agent\client.keys

state: absent

.

This section was added for troubleshooting purposes

#- name: Touch a file (creates if not present, updates modification time if present)

# win_file:

# path: C:\wazuh-agent\client.keys

# state: touch

.

.

– name: Windows | Check if client.keys exists

  win_stat: path=”{{ wazuh_winagent_config.install_dir }}client.keys”

register: check_windows_key

  notify: restart wazuh-agent windows

tags:

– config

.

– name: Retrieving authd Credentials

  include_vars: authd_pass.yml

tags:

– config

.

– name: Windows | Register agent

  win_shell: >

    {{ wazuh_winagent_config.install_dir }}agent-auth.exe

-m {{ wazuh_managers.0.address }}

-p {{ wazuh_agent_authd.port }}

{% if authd_pass is defined %}-P {{ authd_pass }}{% endif %}

  args:

    chdir: “{{ wazuh_winagent_config.install_dir }}”

register: agent_auth_output

  notify: restart wazuh-agent windows

when:

– wazuh_agent_authd.enable == true

– check_windows_key.stat.exists == false

– wazuh_managers.0.address is not none

tags:

– config

.

– name: Windows | Installing agent configuration (ossec.conf)

  win_template:

    src: var-ossec-etc-ossec-agent.conf.j2

    dest: “{{ wazuh_winagent_config.install_dir }}ossec.conf”

  notify: restart wazuh-agent windows

tags:

– config

.

– name: Windows | Delete downloaded Wazuh agent installer file

  win_file:

path: C:\wazuh-agent-installer.msi

state: absent

.

These section was added as the service sometimes was not created and the agent was not restarted upon deployment which resulted in a non active client In kibana

– name: Create a new service

  win_service:

name: wazuh-agent

path: C:\wazuh-agent\ossec-agent.exe

.

– name: Windows | Wazuh-agent Restart

  win_service:

name: wazuh-agent

state: restarted

.

.

3 Comments to How to deploy wazuh-agent with Ansible

  1. Wow that was odd. I just wrote an incredibly long comment but after I clicked submit my comment didn’t appear. Grrrr… well I’m not writing all that over again. Anyways, just wanted to say wonderful blog!

  2. Wow that was strange. I just wrote an very long comment but after I clickedsubmit my comment didn’t show up. Grrrr…well I’m not writing all that over again. Regardless, justwanted to say superb blog!

Leave a Reply

Your email address will not be published. Required fields are marked *

0