Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS test added #5264

Merged
merged 16 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions deployability/modules/generic/ansible.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Copyright (C) 2015, Wazuh Inc.
# Created by Wazuh, Inc. <[email protected]>.
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2

import ansible_runner
import jinja2
from typing import Optional
import yaml

from pathlib import Path
Expand All @@ -16,7 +18,8 @@ class Inventory(BaseModel):
ansible_host: str | IPvAnyAddress
ansible_user: str
ansible_port: int
ansible_ssh_private_key_file: str
ansible_ssh_private_key_file: Optional[str] = None
ansible_password: Optional[str] = None


class Ansible:
Expand Down Expand Up @@ -118,10 +121,13 @@ def generate_inventory(self) -> dict:
self.ansible_data.ansible_host: {
'ansible_port': self.ansible_data.ansible_port,
'ansible_user': self.ansible_data.ansible_user,
'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file
**({'ansible_ssh_private_key_file': self.ansible_data.ansible_ssh_private_key_file}
if hasattr(self.ansible_data, 'ansible_ssh_private_key_file')
else {'ansible_password': self.ansible_data.ansible_password})
}
}
}
}


return inventory_data
169 changes: 105 additions & 64 deletions deployability/modules/testing/tests/helpers/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,25 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv
release = 'pre-release'

os_type = HostInformation.get_os_type(inventory_path)
architecture = HostInformation.get_architecture(inventory_path)
commands = []
if 'linux' in os_type:
distribution = HostInformation.get_linux_distribution(inventory_path)
architecture = HostInformation.get_architecture(inventory_path)

if distribution == 'rpm' and 'x86_64' in architecture:
if distribution == 'rpm' and 'amd64' in architecture:
commands.extend([
f"curl -o wazuh-agent-{wazuh_version}-1.x86_64.rpm https://{s3_url}.wazuh.com/{release}/yum/wazuh-agent-{wazuh_version}-1.x86_64.rpm && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' rpm -ihv wazuh-agent-{wazuh_version}-1.x86_64.rpm"
])
elif distribution == 'rpm' and 'aarch64' in architecture:
elif distribution == 'rpm' and 'arm64' in architecture:
commands.extend([
f"curl -o wazuh-agent-{wazuh_version}-1aarch64.rpm https://{s3_url}.wazuh.com/{release}/yum/wazuh-agent-{wazuh_version}-1.aarch64.rpm && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' rpm -ihv wazuh-agent-{wazuh_version}-1.aarch64.rpm"
])
elif distribution == 'deb' and 'x86_64' in architecture:
elif distribution == 'deb' and 'amd64' in architecture:
commands.extend([
f"wget https://{s3_url}.wazuh.com/{release}/apt/pool/main/w/wazuh-agent/wazuh-agent_{wazuh_version}-1_amd64.deb && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' dpkg -i ./wazuh-agent_{wazuh_version}-1_amd64.deb"
])
elif distribution == 'deb' and 'aarch64' in architecture:
elif distribution == 'deb' and 'arm64' in architecture:
commands.extend([
f"wget https://{s3_url}.wazuh.com/{release}/apt/pool/main/w/wazuh-agent/wazuh-agent_{wazuh_version}-1_arm64.deb && sudo WAZUH_MANAGER='MANAGER_IP' WAZUH_AGENT_NAME='{agent_name}' dpkg -i ./wazuh-agent_{wazuh_version}-1arm64.deb"
])
Expand All @@ -64,11 +65,11 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv
"NET STATUS WazuhSvc"
])
elif 'macos' in os_type:
if 'intel' in architecture:
if 'amd64' in architecture:
commands.extend([
f'curl -so wazuh-agent.pkg https://{s3_url}.wazuh.com/{release}/macos/wazuh-agent-{wazuh_version}-1.intel64.pkg && echo "WAZUH_MANAGER=\'MANAGER_IP\' && WAZUH_AGENT_NAME=\'{agent_name}\'" > /tmp/wazuh_envs && sudo installer -pkg ./wazuh-agent.pkg -target /'
])
elif 'apple' in architecture:
elif 'arm64' in architecture:
commands.extend([
f'curl -so wazuh-agent.pkg https://{s3_url}.wazuh.com/{release}/macos/wazuh-agent-{wazuh_version}-1.arm64.pkg && echo "WAZUH_MANAGER=\'MANAGER_IP\' && WAZUH_AGENT_NAME=\'{agent_name}\'" > /tmp/wazuh_envs && sudo installer -pkg ./wazuh-agent.pkg -target /'
])
Expand All @@ -92,30 +93,54 @@ def install_agents(inventories_paths=[], wazuh_versions=[], wazuh_revisions=[],
def register_agent(inventory_path, manager_path):

with open(manager_path, 'r') as yaml_file:
manager_path = yaml.safe_load(yaml_file)
host = manager_path.get('ansible_host')
manager_path_yaml = yaml.safe_load(yaml_file)
manager_host = manager_path_yaml.get('ansible_host')

internal_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host
with open(inventory_path, 'r') as yaml_file:
inventory_path_yaml = yaml.safe_load(yaml_file)
agent_host = inventory_path_yaml.get('ansible_host')

commands = [
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{internal_ip}<\/address>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
os_type = HostInformation.get_os_type(inventory_path)
if os_type == 'linux':
host_ip = HostInformation.get_internal_ip_from_aws_dns(manager_host) if 'amazonaws' in manager_host else manager_host
commands = [
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{host_ip}<\/address>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
Executor.execute_commands(inventory_path, commands)
assert host_ip in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the Manager IP ({host_ip}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')

Executor.execute_commands(inventory_path, commands)
assert internal_ip in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the Manager IP ({internal_ip}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')
elif os_type == 'macos':
if 'amazonaws' in manager_host and 'amazonaws' in agent_host:
host_ip = HostInformation.get_internal_ip_from_aws_dns(manager_host)
else:
host_ip = HostInformation.get_public_ip_from_aws_dns(manager_host)
commands = [
f"sed -i '.bak' 's/<address>MANAGER_IP<\/address>/<address>{host_ip}<\/address>/g' /Library/Ossec/etc/ossec.conf",
"/Library/Ossec/bin/wazuh-control restart"
]
Executor.execute_commands(inventory_path, commands)
assert host_ip in Executor.execute_command(inventory_path, f'cat /Library/Ossec/etc/ossec.conf'), logger.error(f'Error configuring the Manager IP ({host_ip}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')


@staticmethod
def set_protocol_agent_connection(inventory_path, protocol):
commands = [
f"sed -i 's/<protocol>[^<]*<\/protocol>/<protocol>{protocol}<\/protocol>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]

Executor.execute_commands(inventory_path, commands)
assert protocol in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')

os_type = HostInformation.get_os_type(inventory_path)
if 'linux' in os_type:
commands = [
f"sed -i 's/<protocol>[^<]*<\/protocol>/<protocol>{protocol}<\/protocol>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
Executor.execute_commands(inventory_path, commands)
assert protocol in Executor.execute_command(inventory_path, f'cat {WAZUH_CONF}'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')
elif 'macos' in os_type:
commands = [
f"sed -i '' 's/<protocol>[^<]*<\/protocol>/<protocol>{protocol}<\/protocol>/g' /Library/Ossec/etc/ossec.conf",
"/Library/Ossec/bin/wazuh-control restart"
]
Executor.execute_commands(inventory_path, commands)
assert protocol in Executor.execute_command(inventory_path, f'cat /Library/Ossec/etc/ossec.conf'), logger.error(f'Error configuring the protocol ({protocol}) in: {HostInformation.get_os_name_and_version_from_inventory(inventory_path)} agent')


@staticmethod
def uninstall_agent(inventory_path, wazuh_version=None, wazuh_revision=None) -> None:
Expand Down Expand Up @@ -199,43 +224,50 @@ def perform_action_and_scan(agent_params, action_callback) -> dict:
"""
result = CheckFiles.perform_action_and_scan(agent_params, action_callback)
os_name = HostInformation.get_os_name_from_inventory(agent_params)
os_type = HostInformation.get_os_type(agent_params)
logger.info(f'Applying filters in checkfiles in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}')

if 'debian' in os_name:
filter_data = {
'/boot': {'added': [], 'removed': [], 'modified': ['grubenv']},
'/usr/bin': {
'added': [
'unattended-upgrade', 'gapplication', 'add-apt-repository', 'gpg-wks-server', 'pkexec', 'gpgsplit',
'watchgnupg', 'pinentry-curses', 'gpg-zip', 'gsettings', 'gpg-agent', 'gresource', 'gdbus',
'gpg-connect-agent', 'gpgconf', 'gpgparsemail', 'lspgpot', 'pkaction', 'pkttyagent', 'pkmon',
'dirmngr', 'kbxutil', 'migrate-pubring-from-classic-gpg', 'gpgcompose', 'pkcheck', 'gpgsm', 'gio',
'pkcon', 'gpgtar', 'dirmngr-client', 'gpg', 'filebeat', 'gawk', 'curl', 'update-mime-database',
'dh_installxmlcatalogs', 'appstreamcli', 'lspgpot', 'symcryptrun'
],
'removed': [],
'modified': []
},
'/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []},
'/usr/sbin': {
'added': [
'update-catalog', 'applygnupgdefaults', 'addgnupghome', 'install-sgmlcatalog', 'update-xmlcatalog'
],
'removed': [],
'modified': []
if os_type == 'linux':
if 'debian' in os_name:
filter_data = {
'/boot': {'added': [], 'removed': [], 'modified': ['grubenv']},
'/usr/bin': {
'added': [
'unattended-upgrade', 'gapplication', 'add-apt-repository', 'gpg-wks-server', 'pkexec', 'gpgsplit',
'watchgnupg', 'pinentry-curses', 'gpg-zip', 'gsettings', 'gpg-agent', 'gresource', 'gdbus',
'gpg-connect-agent', 'gpgconf', 'gpgparsemail', 'lspgpot', 'pkaction', 'pkttyagent', 'pkmon',
'dirmngr', 'kbxutil', 'migrate-pubring-from-classic-gpg', 'gpgcompose', 'pkcheck', 'gpgsm', 'gio',
'pkcon', 'gpgtar', 'dirmngr-client', 'gpg', 'filebeat', 'gawk', 'curl', 'update-mime-database',
'dh_installxmlcatalogs', 'appstreamcli', 'lspgpot', 'symcryptrun'
],
'removed': [],
'modified': []
},
'/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []},
'/usr/sbin': {
'added': [
'update-catalog', 'applygnupgdefaults', 'addgnupghome', 'install-sgmlcatalog', 'update-xmlcatalog'
],
'removed': [],
'modified': []
}
}
else:
filter_data = {
'/boot': {
'added': ['grub2', 'loader', 'vmlinuz', 'System.map', 'config-', 'initramfs'],
'removed': [],
'modified': ['grubenv']
},
'/usr/bin': {'added': ['filebeat'], 'removed': [], 'modified': []},
'/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []},
'/usr/sbin': {'added': [], 'removed': [], 'modified': []}
}
elif os_type == 'macos':
filter_data = {
'/usr/bin': {'added': [], 'removed': [], 'modified': []},
'/usr/sbin': {'added': [], 'removed': [], 'modified': []}
}
}
else:
filter_data = {
'/boot': {
'added': ['grub2', 'loader', 'vmlinuz', 'System.map', 'config-', 'initramfs'],
'removed': [],
'modified': ['grubenv']
},
'/usr/bin': {'added': ['filebeat'], 'removed': [], 'modified': []},
'/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []},
'/usr/sbin': {'added': [], 'removed': [], 'modified': []}
}

# Use of filters
for directory, changes in result.items():
Expand All @@ -259,7 +291,7 @@ def perform_install_and_scan_for_agent(agent_params, agent_name, wazuh_params) -
action_callback = lambda: WazuhAgent._install_agent_callback(wazuh_params, agent_name, agent_params)
result = WazuhAgent.perform_action_and_scan(agent_params, action_callback)
logger.info(f'Pre and post install checkfile comparison in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}: {result}')
WazuhAgent.assert_results(result)
WazuhAgent.assert_results(result, agent_params)


@staticmethod
Expand All @@ -275,20 +307,25 @@ def perform_uninstall_and_scan_for_agent(agent_params, wazuh_params) -> None:
action_callback = lambda: WazuhAgent._uninstall_agent_callback(wazuh_params, agent_params)
result = WazuhAgent.perform_action_and_scan(agent_params, action_callback)
logger.info(f'Pre and post uninstall checkfile comparison in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}: {result}')
WazuhAgent.assert_results(result)
WazuhAgent.assert_results(result, agent_params)


@staticmethod
def assert_results(result) -> None:
def assert_results(result, agent_params) -> None:
"""
Gets the status of an agent given its name.

Args:
result (dict): result of comparison between pre and post action scan

"""
categories = ['/root', '/usr/bin', '/usr/sbin', '/boot']
os_type = HostInformation.get_os_type(agent_params)
if os_type == 'linux':
categories = ['/root', '/usr/bin', '/usr/sbin', '/boot']
elif os_type == 'macos':
categories = ['/usr/bin', '/usr/sbin']
actions = ['added', 'modified', 'removed']

# Testing the results
for category in categories:
for action in actions:
Expand All @@ -306,17 +343,21 @@ def areAgent_processes_active(agent_params):
"""
return bool([int(numero) for numero in Executor.execute_command(agent_params, 'pgrep wazuh').splitlines()])

def isAgent_port_open(agent_params):
def isAgent_port_open(inventory_path):
"""
Check if agent port is open

Args:
agent_name (str): Agent name.
inventory_path (str): Agent inventory path.

Returns:
str: Os name.
"""
return 'ESTAB' in Executor.execute_command(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB')
os_type = HostInformation.get_os_type(inventory_path)
if os_type == 'linux':
return 'ESTAB' in Executor.execute_command(inventory_path, 'ss -t -a -n | grep ":1514" | grep ESTAB')
elif os_type == 'macos':
return 'ESTABLISHED' in Executor.execute_command(inventory_path, 'netstat -an | grep ".1514 " | grep ESTABLISHED')

def get_agents_information(wazuh_api: WazuhAPI) -> list:
"""
Expand Down
54 changes: 36 additions & 18 deletions deployability/modules/testing/tests/helpers/executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# This program is a free software; you can redistribute it and/or modify it under the terms of GPLv2

import json
import paramiko
import requests
import subprocess
import urllib3
Expand All @@ -19,24 +20,41 @@ def execute_command(inventory_path, command) -> str:
with open(inventory_path, 'r') as yaml_file:
inventory_data = yaml.safe_load(yaml_file)

host = inventory_data.get('ansible_host')
port = inventory_data.get('ansible_port')
private_key_path = inventory_data.get('ansible_ssh_private_key_file')
username = inventory_data.get('ansible_user')

ssh_command = [
"ssh",
"-i", private_key_path,
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-p", str(port),
f"{username}@{host}",
"sudo",
command
]
result = subprocess.run(ssh_command, stdout=subprocess.PIPE, text=True)

return result.stdout
if 'ansible_ssh_private_key_file' in inventory_data:
host = inventory_data.get('ansible_host')
port = inventory_data.get('ansible_port')
private_key_path = inventory_data.get('ansible_ssh_private_key_file')
username = inventory_data.get('ansible_user')

ssh_command = [
"ssh",
"-i", private_key_path,
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null",
"-p", str(port),
f"{username}@{host}",
"sudo",
command
]
result = subprocess.run(ssh_command, stdout=subprocess.PIPE, text=True)

return result.stdout
else:
host = inventory_data.get('ansible_host', None)
port = inventory_data.get('ansible_port', 22)
user = inventory_data.get('ansible_user', None)
password = inventory_data.get('ansible_password', None)

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname=host, port=port, username=user, password=password)
stdin, stdout, stderr = ssh_client.exec_command(f"sudo {command}")

result = ''.join(stdout.readlines())

ssh_client.close()

return result


@staticmethod
Expand Down
Loading