From 98abbd8d780b91b59889d9980f48f5a96a197e0c Mon Sep 17 00:00:00 2001 From: Antonio Date: Thu, 18 Apr 2024 16:06:49 +0200 Subject: [PATCH 01/13] enhancement(#5229): macOS tests added --- deployability/modules/generic/ansible.py | 10 +- .../modules/testing/tests/helpers/agent.py | 116 ++++++++------ .../modules/testing/tests/helpers/executor.py | 54 ++++--- .../modules/testing/tests/helpers/generic.py | 143 ++++++++++++++---- .../modules/testing/tests/helpers/utils.py | 69 ++++++--- .../testing/tests/test_agent/test_install.py | 11 +- .../tests/test_agent/test_registration.py | 4 +- .../testing/tests/test_agent/test_restart.py | 2 +- .../testing/tests/test_agent/test_stop.py | 3 +- .../tests/test_agent/test_uninstall.py | 8 +- 10 files changed, 288 insertions(+), 132 deletions(-) diff --git a/deployability/modules/generic/ansible.py b/deployability/modules/generic/ansible.py index 0829c84b3e..06ccb9072b 100755 --- a/deployability/modules/generic/ansible.py +++ b/deployability/modules/generic/ansible.py @@ -1,8 +1,10 @@ # Copyright (C) 2015, Wazuh Inc. # Created by Wazuh, Inc. . # 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 @@ -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: @@ -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 diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 7e60c5fbca..fdb1d2a869 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -23,6 +23,7 @@ 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) @@ -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 'x86_64' 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 /' ]) @@ -95,15 +96,23 @@ def register_agent(inventory_path, manager_path): manager_path = yaml.safe_load(yaml_file) host = manager_path.get('ansible_host') - internal_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host - - commands = [ - f"sed -i 's/
MANAGER_IP<\/address>/
{internal_ip}<\/address>/g' {WAZUH_CONF}", - "systemctl restart wazuh-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') + if 'linux' in inventory_path: + host_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host + commands = [ + f"sed -i 's/
MANAGER_IP<\/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') + + elif 'macos' in inventory_path: + host_ip = HostInformation.get_public_ip_from_aws_dns(host) if 'amazonaws' in host else host + commands = [ + f"sed -i '.bak' 's/
MANAGER_IP<\/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 @@ -190,41 +199,47 @@ def perform_action_and_scan(agent_params, action_callback) -> dict: os_name = HostInformation.get_os_name_from_inventory(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 'linux' in 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': [] + } + } + 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 'macos' in agent_params: + 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(): @@ -248,7 +263,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 @@ -264,11 +279,11 @@ 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. @@ -276,7 +291,10 @@ def assert_results(result) -> None: result (dict): result of comparison between pre and post action scan """ - categories = ['/root', '/usr/bin', '/usr/sbin', '/boot'] + if 'linux' in agent_params: + categories = ['/root', '/usr/bin', '/usr/sbin', '/boot'] + elif 'macos' in agent_params: + categories = ['/usr/bin', '/usr/sbin'] actions = ['added', 'modified', 'removed'] # Testing the results for category in categories: diff --git a/deployability/modules/testing/tests/helpers/executor.py b/deployability/modules/testing/tests/helpers/executor.py index 6d204d6ba8..f77c924c05 100644 --- a/deployability/modules/testing/tests/helpers/executor.py +++ b/deployability/modules/testing/tests/helpers/executor.py @@ -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 @@ -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 diff --git a/deployability/modules/testing/tests/helpers/generic.py b/deployability/modules/testing/tests/helpers/generic.py index 63e5140ec9..3d33cd0187 100644 --- a/deployability/modules/testing/tests/helpers/generic.py +++ b/deployability/modules/testing/tests/helpers/generic.py @@ -32,7 +32,11 @@ def dir_exists(inventory_path, dir_path) -> str: Returns: bool: True or False """ - return 'true' in Executor.execute_command(inventory_path, f'test -d {dir_path} && echo "true" || echo "false"') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return 'true' in Executor.execute_command(inventory_path, f'test -d {dir_path} && echo "true" || echo "false"') + elif os_type == 'macos': + return 'true' in Executor.execute_command(inventory_path, f'stat {dir_path} >/dev/null 2>&1 && echo "true" || echo "false"') @staticmethod @@ -47,7 +51,11 @@ def file_exists(inventory_path, file_path) -> bool: Returns: bool: True or False """ - return 'true' in Executor.execute_command(inventory_path, f'test -f {file_path} && echo "true" || echo "false"') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return 'true' in Executor.execute_command(inventory_path, f'test -f {file_path} && echo "true" || echo "false"') + elif os_type == 'macos': + return 'true' in Executor.execute_command(inventory_path, f'stat {file_path} >/dev/null 2>&1 && echo "true" || echo "false"') @staticmethod @@ -61,8 +69,16 @@ def get_os_type(inventory_path) -> str: Returns: str: type of host (windows, linux, macos) """ - system = Executor.execute_command(inventory_path, 'uname') - return system.lower() + if 'manager' in inventory_path: + pattern = r'manager-(\w+)-' + elif 'agent' in inventory_path: + pattern = r'agent-(\w+)-' + result = re.search(pattern, inventory_path) + if result: + return result.group(1) + else: + return None + @staticmethod @@ -115,9 +131,9 @@ def get_os_name_from_inventory(inventory_path) -> str: str: linux os name (debian, ubuntu, opensuse, amazon, centos, redhat) """ if 'manager' in inventory_path: - os_name = re.search(r'/manager-linux-([^-]+)-', inventory_path).group(1) + os_name = re.search(r'/manager-[^-]+-([^-]+)-', inventory_path).group(1) elif 'agent' in inventory_path: - os_name = re.search(r'/agent-linux-([^-]+)-', inventory_path).group(1) + os_name = re.search(r'/agent-[^-]+-([^-]+)-', inventory_path).group(1) return os_name @@ -133,9 +149,9 @@ def get_os_name_and_version_from_inventory(inventory_path) -> tuple: tuple: linux os name and version (e.g., ('ubuntu', '22.04')) """ if 'manager' in inventory_path: - match = re.search(r'/manager-linux-([^-]+)-([^-]+)-', inventory_path) + match = re.search(r'/manager-[^-]+-([^-]+)-([^-]+)-', inventory_path) elif 'agent' in inventory_path: - match = re.search(r'/agent-linux-([^-]+)-([^-]+)-', inventory_path) + match = re.search(r'/agent-[^-]+-([^-]+)-([^-]+)-', inventory_path) if match: os_name = match.group(1) version = match.group(2) @@ -158,7 +174,7 @@ def get_current_dir(inventory_path) -> str: return Executor.execute_command(inventory_path, 'pwd').replace("\n","") @staticmethod - def get_internal_ip_from_aws_dns(dns_name): + def get_internal_ip_from_aws_dns(dns_name) -> str: """ It returns the private AWS IP from dns_name @@ -176,6 +192,24 @@ def get_internal_ip_from_aws_dns(dns_name): else: return None + @staticmethod + def get_public_ip_from_aws_dns(dns_name) -> str: + """ + It returns the public AWS IP from dns_name + + Args: + dns_name (str): host's dns public dns name + + Returns: + str: public ip + """ + try: + ip_address = socket.gethostbyname(dns_name) + return ip_address + except socket.gaierror as e: + logger.error("Error obtaining IP address:", e) + return None + @staticmethod def get_client_keys(inventory_path) -> list[dict]: """ @@ -188,7 +222,11 @@ def get_client_keys(inventory_path) -> list[dict]: list: List of dictionaries with the client keys. """ clients = [] - client_key = Executor.execute_command(inventory_path, f'cat {CLIENT_KEYS}') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + client_key = Executor.execute_command(inventory_path, f'cat {CLIENT_KEYS}') + elif os_type == 'macos': + client_key = Executor.execute_command(inventory_path, f'cat /Library/Ossec/etc/client.keys') lines = client_key.split('\n')[:-1] for line in lines: _id, name, address, password = line.strip().split() @@ -227,14 +265,18 @@ def disable_firewall(inventory_path) -> None: inventory_path: host's inventory path """ - commands = ["sudo systemctl stop firewalld", "sudo systemctl disable firewalld"] - if GeneralComponentActions.isComponentActive(inventory_path, 'firewalld'): - Executor.execute_commands(inventory_path, commands) + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + commands = ["sudo systemctl stop firewalld", "sudo systemctl disable firewalld"] + if GeneralComponentActions.isComponentActive(inventory_path, 'firewalld'): + Executor.execute_commands(inventory_path, commands) + logger.info(f'Firewall disabled on {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') + else: + logger.info(f'No Firewall to disable on {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') + elif os_type == 'macos': logger.info(f'Firewall disabled on {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - else: - logger.info(f'No Firewall to disable on {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - + Executor.execute_command(inventory_path, 'sudo pfctl -d') def _extract_hosts(paths, is_aws): @@ -457,10 +499,12 @@ def _checkfiles(inventory_path, os_type, directory, filter= None, hash_algorithm Returns: Dict: dict of directories:hash """ - if 'linux' in os_type or 'macos' in os_type: + if 'linux' in os_type: command = f'sudo find {directory} -type f -exec sha256sum {{}} + {filter}' result = Executor.execute_command(inventory_path, command) - + elif 'macos' in os_type: + command = f'sudo find {directory} -type f -exec shasum -a 256 {{}} \; {filter}' + result = Executor.execute_command(inventory_path, command) elif 'windows' in os_type: command = 'dir /a-d /b /s | findstr /v /c:"\\.$" /c:"\\..$"| find /c ":"' else: @@ -504,9 +548,15 @@ def perform_action_and_scan(inventory_path, callback) -> dict: """ os_type = HostInformation.get_os_type(inventory_path) - directories = ['/boot', '/usr/bin', '/root', '/usr/sbin'] - filters_keywords = ['grep', 'tar', 'coreutils', 'sed', 'procps', 'gawk', 'lsof', 'curl', 'openssl', 'libcap', 'apt-transport-https', 'libcap2-bin', 'software-properties-common', 'gnupg', 'gpg'] - filters = f"| grep -v {filters_keywords[0]}" + if 'linux' in inventory_path: + directories = ['/boot', '/usr/bin', '/root', '/usr/sbin'] + filters_keywords = ['grep', 'tar', 'coreutils', 'sed', 'procps', 'gawk', 'lsof', 'curl', 'openssl', 'libcap', 'apt-transport-https', 'libcap2-bin', 'software-properties-common', 'gnupg', 'gpg'] + filters = f"| grep -v {filters_keywords[0]}" + + elif 'macos' in inventory_path: + directories = ['/usr/bin', '/usr/sbin'] + filters_keywords = ['grep'] + filters = f"| grep -v {filters_keywords[0]}" for filter_ in filters_keywords[1:]: filters+= f" | grep -v {filter_}" @@ -533,8 +583,11 @@ def get_component_status(inventory_path, host_role) -> str: str: Role status """ logger.info(f'Getting status of {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - - return Executor.execute_command(inventory_path, f'systemctl status {host_role}') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'systemctl status {host_role}') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control status | grep {host_role}') @staticmethod @@ -546,9 +599,12 @@ def component_stop(inventory_path, host_role) -> None: inventory_path: host's inventory path host_role: role of the component """ - logger.info(f'Stopping {host_role} in {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - Executor.execute_command(inventory_path, f'systemctl stop {host_role}') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'systemctl stop {host_role}') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control stop | grep {host_role}') @staticmethod @@ -562,7 +618,11 @@ def component_restart(inventory_path, host_role) -> None: """ logger.info(f'Restarting {host_role} in {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - Executor.execute_command(inventory_path, f'systemctl restart {host_role}') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'systemctl restart {host_role}') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control restart | grep {host_role}') @staticmethod @@ -576,7 +636,11 @@ def component_start(inventory_path, host_role) -> None: """ logger.info(f'Starting {host_role} in {HostInformation.get_os_name_and_version_from_inventory(inventory_path)}') - Executor.execute_command(inventory_path, f'systemctl restart {host_role}') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'systemctl start {host_role}') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control start | grep {host_role}') @staticmethod @@ -590,7 +654,11 @@ def get_component_version(inventory_path) -> str: Returns: str: version """ - return Executor.execute_command(inventory_path, f'{WAZUH_CONTROL} info -v') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'{WAZUH_CONTROL} info -v') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control info -v') @staticmethod @@ -604,7 +672,11 @@ def get_component_revision(inventory_path) -> str: Returns: str: revision number """ - return Executor.execute_command(inventory_path, f'{WAZUH_CONTROL} info -r') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return Executor.execute_command(inventory_path, f'{WAZUH_CONTROL} info -r') + elif os_type == 'macos': + return Executor.execute_command(inventory_path, f'/Library/Ossec/bin/wazuh-control info -r') @staticmethod @@ -618,7 +690,11 @@ def hasAgentClientKeys(inventory_path) -> bool: Returns: bool: True/False """ - return 'true' in Executor.execute_command(inventory_path, f'[ -f {CLIENT_KEYS} ] && echo true || echo false') + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return HostInformation.file_exists(inventory_path,{CLIENT_KEYS}) + elif os_type == 'macos': + return HostInformation.file_exists(inventory_path, '/Library/Ossec/etc/client.keys') @staticmethod @@ -633,7 +709,12 @@ def isComponentActive(inventory_path, host_role) -> bool: Returns: bool: True/False """ - return 'active' == Executor.execute_command(inventory_path, f'systemctl is-active {host_role}').replace("\n", "") + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': + return 'active' == Executor.execute_command(inventory_path, f'systemctl is-active {host_role}').replace("\n", "") + elif os_type == 'macos': + return f'com.{host_role.replace("-", ".")}' in Executor.execute_command(inventory_path, f'launchctl list | grep com.{host_role.replace("-", ".")}') + class Waits: diff --git a/deployability/modules/testing/tests/helpers/utils.py b/deployability/modules/testing/tests/helpers/utils.py index 211ee78b8f..5b7c4068fd 100644 --- a/deployability/modules/testing/tests/helpers/utils.py +++ b/deployability/modules/testing/tests/helpers/utils.py @@ -26,9 +26,9 @@ def extract_ansible_host(file_path) -> str: @staticmethod def check_inventory_connection(inventory_path, attempts=10, sleep=30) -> bool: if 'manager' in inventory_path: - match = re.search(r'/manager-linux-([^-]+)-([^-]+)-', inventory_path) + match = re.search(r'/manager-[^-]+-([^-]+)-([^-]+)-', inventory_path) elif 'agent' in inventory_path: - match = re.search(r'/agent-linux-([^-]+)-([^-]+)-', inventory_path) + match = re.search(r'/agent-[^-]+-([^-]+)-([^-]+)-', inventory_path) if match: os_name = match.group(1)+ '-' + match.group(2) logger.info(f'Checking connection to {os_name}') @@ -40,30 +40,55 @@ def check_inventory_connection(inventory_path, attempts=10, sleep=30) -> bool: except yaml.YAMLError: raise ValueError(logger.error(f'Invalid inventory information in {os_name}')) - 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 = paramiko.SSHClient() - ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - private_key = paramiko.RSAKey.from_private_key_file(private_key_path) + + 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') - for attempt in range(1, attempts + 1): ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) private_key = paramiko.RSAKey.from_private_key_file(private_key_path) - try: - ssh.connect(hostname=host, port=port, username=username, pkey=private_key) - logger.info(f'Connection established successfully in {os_name}') - ssh.close() - return True - except paramiko.AuthenticationException: - logger.error(f'Authentication error. Check SSH credentials in {os_name}') - return False - except Exception as e: - logger.warning(f'Error on attempt {attempt} of {attempts}: {e}') - time.sleep(sleep) + + for attempt in range(1, attempts + 1): + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + private_key = paramiko.RSAKey.from_private_key_file(private_key_path) + try: + ssh.connect(hostname=host, port=port, username=username, pkey=private_key) + logger.info(f'Connection established successfully in {os_name}') + ssh.close() + return True + except paramiko.AuthenticationException: + logger.error(f'Authentication error. Check SSH credentials in {os_name}') + return False + except Exception as e: + logger.warning(f'Error on attempt {attempt} of {attempts}: {e}') + time.sleep(sleep) + 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 = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + for attempt in range(1, attempts + 1): + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + ssh.connect(hostname=host, port=port, username=user, password=password) + logger.info(f'Connection established successfully in {os_name}') + ssh.close() + return True + except paramiko.AuthenticationException: + logger.error(f'Authentication error. Check SSH credentials in {os_name}') + return False + except Exception as e: + logger.warning(f'Error on attempt {attempt} of {attempts}: {e}') + time.sleep(sleep) logger.error(f'Connection attempts failed after {attempts} tries. Connection timeout in {os_name}') return False diff --git a/deployability/modules/testing/tests/test_agent/test_install.py b/deployability/modules/testing/tests/test_agent/test_install.py index 87fc6ac6c7..90ebec0363 100644 --- a/deployability/modules/testing/tests/test_agent/test_install.py +++ b/deployability/modules/testing/tests/test_agent/test_install.py @@ -54,6 +54,7 @@ def setup_test_environment(wazuh_params): updated_agents = {} for agent_name, agent_params in wazuh_params['agents'].items(): Utils.check_inventory_connection(agent_params) + if GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent') and GeneralComponentActions.hasAgentClientKeys(agent_params): if HostInformation.get_client_keys(agent_params) != []: client_name = HostInformation.get_client_keys(agent_params)[0]['name'] @@ -84,15 +85,19 @@ def test_installation(wazuh_params): for agent_names, agent_params in wazuh_params['agents'].items(): WazuhAgent.perform_install_and_scan_for_agent(agent_params, agent_names, wazuh_params) + # Testing installation directory - for agent in wazuh_params['agents'].values(): - assert HostInformation.dir_exists(agent, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in {HostInformation.get_os_name_and_version_from_inventory(agent)}') + for agent_names, agent_params in wazuh_params['agents'].items(): + if HostInformation.get_os_type(agent_params) == 'linux': + assert HostInformation.dir_exists(agent_params, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') + elif HostInformation.get_os_type(agent_params) == 'macos': + assert HostInformation.dir_exists(agent_params, '/Library/Ossec'), logger.error(f'The /Library/Ossec is not present in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') def test_status(wazuh_params): for agent in wazuh_params['agents'].values(): agent_status = GeneralComponentActions.get_component_status(agent, 'wazuh-agent') - assert 'loaded' in agent_status, logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} status is not loaded') + assert 'loaded' in agent_status or 'not running' in agent_status, logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} status is not loaded') def test_version(wazuh_params): diff --git a/deployability/modules/testing/tests/test_agent/test_registration.py b/deployability/modules/testing/tests/test_agent/test_registration.py index cc62fc7844..a1b4659e8a 100644 --- a/deployability/modules/testing/tests/test_agent/test_registration.py +++ b/deployability/modules/testing/tests/test_agent/test_registration.py @@ -69,7 +69,7 @@ def test_registration(wazuh_params): def test_status(wazuh_params): for agent in wazuh_params['agents'].values(): - assert 'active' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent'), logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} is not active') + assert 'active' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent') or 'is running' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent'), logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} is not active') def test_connection(wazuh_params): @@ -82,7 +82,7 @@ def test_connection(wazuh_params): def test_isActive(wazuh_params): wazuh_api = WazuhAPI(wazuh_params['master']) for agent_names, agent_params in wazuh_params['agents'].items(): - assert GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is not active by API') + assert GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is not active by command') expected_condition_func = lambda: 'active' == WazuhAgent.get_agent_status(wazuh_api, agent_names) Waits.dynamic_wait(expected_condition_func, cycles=20, waiting_time=30) diff --git a/deployability/modules/testing/tests/test_agent/test_restart.py b/deployability/modules/testing/tests/test_agent/test_restart.py index 3f876b9b4c..5585212c45 100644 --- a/deployability/modules/testing/tests/test_agent/test_restart.py +++ b/deployability/modules/testing/tests/test_agent/test_restart.py @@ -68,7 +68,7 @@ def test_restart(wazuh_params): def test_status(wazuh_params): for agent_names, agent_params in wazuh_params['agents'].items(): - assert 'active' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is not active by command') + assert 'active' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent') or 'is running' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is not active by command') def test_connection(wazuh_params): diff --git a/deployability/modules/testing/tests/test_agent/test_stop.py b/deployability/modules/testing/tests/test_agent/test_stop.py index 97808d5d24..320dd73008 100644 --- a/deployability/modules/testing/tests/test_agent/test_stop.py +++ b/deployability/modules/testing/tests/test_agent/test_stop.py @@ -71,8 +71,7 @@ def test_stop(wazuh_params): GeneralComponentActions.component_stop(agent_params, 'wazuh-agent') for agent_names, agent_params in wazuh_params['agents'].items(): - assert 'inactive' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is still active by command') - assert not GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is still active by command') + assert 'inactive' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent') or 'not running' in GeneralComponentActions.get_component_status(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is still active by command') expected_condition_func = lambda: 'disconnected' == WazuhAgent.get_agent_status(wazuh_api, agent_names) Waits.dynamic_wait(expected_condition_func, cycles=20, waiting_time=30) diff --git a/deployability/modules/testing/tests/test_agent/test_uninstall.py b/deployability/modules/testing/tests/test_agent/test_uninstall.py index ba9448a0f1..77c0b46515 100644 --- a/deployability/modules/testing/tests/test_agent/test_uninstall.py +++ b/deployability/modules/testing/tests/test_agent/test_uninstall.py @@ -66,12 +66,16 @@ def setup_test_environment(wazuh_params): def test_uninstall(wazuh_params): for agent_names, agent_params in wazuh_params['agents'].items(): assert GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent'), logger.error(f'{agent_names} is not Active before the installation') - assert HostInformation.dir_exists(agent_params, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in the host {agent_names}') + if 'linux' in agent_params: + assert HostInformation.dir_exists(agent_params, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in the host {agent_names}') + elif 'macos' in wazuh_params: + assert HostInformation.dir_exists(agent_params, '/Library/Ossec'), logger.error(f'The /Library/Ossec is not present in the host {agent_names}') - # Agent installation + # Agent uninstallation for agent_names, agent_params in wazuh_params['agents'].items(): WazuhAgent.perform_uninstall_and_scan_for_agent(agent_params,wazuh_params) + # Manager uninstallation status check for agent_names, agent_params in wazuh_params['agents'].items(): assert 'Disconnected' in WazuhManager.get_agent_control_info(wazuh_params['master']), logger.error(f'{agent_names} is still connected in the Manager') From 2c925fa95bb9aa0668a23b8f8aeb52ec7b7d1664 Mon Sep 17 00:00:00 2001 From: Antonio Date: Thu, 18 Apr 2024 16:21:27 +0200 Subject: [PATCH 02/13] enhancement(#5229): Enhancement of os validation --- .../modules/testing/tests/helpers/agent.py | 16 ++- .../modules/testing/tests/helpers/generic.py | 6 +- .../agent/vagrant/test-agent-complete.yaml | 110 ++++++++++++++++++ .../examples/agent/vagrant/test.yaml | 34 ++++++ 4 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml create mode 100755 deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index fdb1d2a869..5f6a24b78a 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -94,9 +94,11 @@ 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') - if 'linux' in inventory_path: + os_type = HostInformation.get_os_type(inventory_path) + if os_type == 'linux': host_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host commands = [ f"sed -i 's/
MANAGER_IP<\/address>/
{host_ip}<\/address>/g' {WAZUH_CONF}", @@ -105,7 +107,7 @@ def register_agent(inventory_path, manager_path): 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') - elif 'macos' in inventory_path: + elif os_type == 'macos': host_ip = HostInformation.get_public_ip_from_aws_dns(host) if 'amazonaws' in host else host commands = [ f"sed -i '.bak' 's/
MANAGER_IP<\/address>/
{host_ip}<\/address>/g' /Library/Ossec/etc/ossec.conf", @@ -199,7 +201,7 @@ def perform_action_and_scan(agent_params, action_callback) -> dict: os_name = HostInformation.get_os_name_from_inventory(agent_params) logger.info(f'Applying filters in checkfiles in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') - if 'linux' in agent_params: + if 'linux' == HostInformation.get_os_type(agent_params): if 'debian' in os_name: filter_data = { '/boot': {'added': [], 'removed': [], 'modified': ['grubenv']}, @@ -235,7 +237,7 @@ def perform_action_and_scan(agent_params, action_callback) -> dict: '/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []}, '/usr/sbin': {'added': [], 'removed': [], 'modified': []} } - elif 'macos' in agent_params: + elif 'macos' == HostInformation.get_os_type(agent_params): filter_data = { '/usr/bin': {'added': [], 'removed': [], 'modified': []}, '/usr/sbin': {'added': [], 'removed': [], 'modified': []} @@ -291,11 +293,13 @@ def assert_results(result, agent_params) -> None: result (dict): result of comparison between pre and post action scan """ - if 'linux' in agent_params: + os_name = HostInformation.get_os_name_from_inventory(agent_params) + if os_name == 'linux': categories = ['/root', '/usr/bin', '/usr/sbin', '/boot'] - elif 'macos' in agent_params: + elif os_name == 'macos': categories = ['/usr/bin', '/usr/sbin'] actions = ['added', 'modified', 'removed'] + # Testing the results for category in categories: for action in actions: diff --git a/deployability/modules/testing/tests/helpers/generic.py b/deployability/modules/testing/tests/helpers/generic.py index 3d33cd0187..316866aff1 100644 --- a/deployability/modules/testing/tests/helpers/generic.py +++ b/deployability/modules/testing/tests/helpers/generic.py @@ -499,13 +499,13 @@ def _checkfiles(inventory_path, os_type, directory, filter= None, hash_algorithm Returns: Dict: dict of directories:hash """ - if 'linux' in os_type: + if 'linux' == os_type: command = f'sudo find {directory} -type f -exec sha256sum {{}} + {filter}' result = Executor.execute_command(inventory_path, command) - elif 'macos' in os_type: + elif 'macos' == os_type: command = f'sudo find {directory} -type f -exec shasum -a 256 {{}} \; {filter}' result = Executor.execute_command(inventory_path, command) - elif 'windows' in os_type: + elif 'windows' == os_type: command = 'dir /a-d /b /s | findstr /v /c:"\\.$" /c:"\\..$"| find /c ":"' else: logger.info(f'Unsupported operating system') diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml new file mode 100644 index 0000000000..648ea9788d --- /dev/null +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml @@ -0,0 +1,110 @@ +version: 0.1 +description: This workflow is used to test agents' deployment for DDT1 PoC +variables: + agent-os: + - linux-oracle-9-amd64 + + manager-os: linux-ubuntu-22.04-amd64 + infra-provider: vagrant + working-dir: /tmp/dtt1-poc + +tasks: + # Unique manager allocate task + - task: "allocate-manager-{manager-os}" + description: "Allocate resources for the manager." + do: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: create + - provider: "{infra-provider}" + - size: large + - composite-name: "{manager-os}" + - inventory-output: "{working-dir}/manager-{manager-os}/inventory.yaml" + - track-output: "{working-dir}/manager-{manager-os}/track.yaml" + - label-termination-date: "1d" + - label-team: "qa" + on-error: "abort-all" + cleanup: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: delete + - track-output: "{working-dir}/manager-{manager-os}/track.yaml" + + # Unique agent allocate task + - task: "allocate-agent-{agent}" + description: "Allocate resources for the agent." + do: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: create + - provider: "{infra-provider}" + - size: small + - composite-name: "{agent}" + - inventory-output: "{working-dir}/agent-{agent}/inventory.yaml" + - track-output: "{working-dir}/agent-{agent}/track.yaml" + - label-termination-date: "1d" + - label-team: "qa" + foreach: + - variable: agent-os + as: agent + cleanup: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: delete + - track-output: "{working-dir}/agent-{agent}/track.yaml" + depends-on: + - "provision-manager-{manager-os}" + + # Unique manager provision task + - task: "provision-manager-{manager-os}" + description: "Provision the manager." + do: + this: process + with: + path: python3 + args: + - modules/provision/main.py + - inventory: "{working-dir}/manager-{manager-os}/inventory.yaml" + - install: + - component: wazuh-manager + type: assistant + version: 4.7.3 + live: True + depends-on: + - "allocate-manager-{manager-os}" + + + # Generic agent test task + - task: "run-agent-{agent}-tests" + description: "Run tests install for the agent {agent}." + do: + this: process + with: + path: python3 + args: + - modules/testing/main.py + - targets: + - wazuh-1: "{working-dir}/manager-{manager-os}/inventory.yaml" + - agent: "{working-dir}/agent-{agent}/inventory.yaml" + - tests: "install,registration,restart,stop,uninstall" + - component: "agent" + - wazuh-version: "4.7.3" + - wazuh-revision: "40714" + - live: "True" + foreach: + - variable: agent-os + as: agent + depends-on: + - "allocate-agent-{agent}" diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml new file mode 100755 index 0000000000..253016fae3 --- /dev/null +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml @@ -0,0 +1,34 @@ +version: 0.1 +description: Test agent restart with provisioning agents' with provision module +variables: + agent-os: + - macos-ventura-13.4.1-arm64 + manager-os: linux-ubuntu-18.04-amd64 + infra-provider: aws + working-dir: /tmp/dtt1-poc + +tasks: + + + + # Generic agent test task + - task: "run-agent-{agent}-tests" + description: "Run tests install for the agent {agent}." + do: + this: process + with: + path: python3 + args: + - modules/testing/main.py + - targets: + - wazuh-1: "{working-dir}/manager-{manager-os}/inventory.yaml" + - agent: "{working-dir}/agent-{agent}/inventory.yaml" + - tests: "install,registration,restart,stop,uninstall" + - component: "agent" + - wazuh-version: "4.7.3" + - wazuh-revision: "40714" + - live: "True" + foreach: + - variable: agent-os + as: agent + From 8aa767e4d2da811d0b836cec543ab77d7adb5907 Mon Sep 17 00:00:00 2001 From: Antonio Date: Thu, 18 Apr 2024 16:26:28 +0200 Subject: [PATCH 03/13] enhancement(#5229): logger fixes --- deployability/modules/testing/tests/helpers/agent.py | 7 ++++--- deployability/modules/testing/tests/helpers/manager.py | 2 +- deployability/modules/testing/tests/helpers/utils.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 5f6a24b78a..57fd67ff74 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -8,7 +8,7 @@ from .constants import WAZUH_CONF, WAZUH_ROOT from .executor import Executor, WazuhAPI from .generic import HostInformation, CheckFiles -from .logger.logger import logger +from modules.generic.logger import logger class WazuhAgent: @@ -199,9 +199,10 @@ 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 'linux' == HostInformation.get_os_type(agent_params): + if os_type == 'linux': if 'debian' in os_name: filter_data = { '/boot': {'added': [], 'removed': [], 'modified': ['grubenv']}, @@ -237,7 +238,7 @@ def perform_action_and_scan(agent_params, action_callback) -> dict: '/root': {'added': ['trustdb.gpg', 'lesshst'], 'removed': [], 'modified': []}, '/usr/sbin': {'added': [], 'removed': [], 'modified': []} } - elif 'macos' == HostInformation.get_os_type(agent_params): + elif os_type == 'macos': filter_data = { '/usr/bin': {'added': [], 'removed': [], 'modified': []}, '/usr/sbin': {'added': [], 'removed': [], 'modified': []} diff --git a/deployability/modules/testing/tests/helpers/manager.py b/deployability/modules/testing/tests/helpers/manager.py index 3611c7f5af..20b0d4e4c1 100644 --- a/deployability/modules/testing/tests/helpers/manager.py +++ b/deployability/modules/testing/tests/helpers/manager.py @@ -8,7 +8,7 @@ from .constants import CLUSTER_CONTROL, AGENT_CONTROL, WAZUH_CONF, WAZUH_ROOT from .executor import Executor, WazuhAPI from .generic import HostInformation, CheckFiles -from .logger.logger import logger +from modules.generic.logger import logger from .utils import Utils diff --git a/deployability/modules/testing/tests/helpers/utils.py b/deployability/modules/testing/tests/helpers/utils.py index 5b7c4068fd..78cf3a676f 100644 --- a/deployability/modules/testing/tests/helpers/utils.py +++ b/deployability/modules/testing/tests/helpers/utils.py @@ -8,7 +8,7 @@ import logging import time -from .logger.logger import logger +from modules.generic.logger import logger paramiko_logger = logging.getLogger("paramiko") From 684ea5d21e36c8b665e73937593e7fefeeb51f37 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 19 Apr 2024 12:30:09 +0200 Subject: [PATCH 04/13] enhancement(#5229): Improving get_os_type and arch --- .../modules/testing/tests/helpers/agent.py | 10 +-- .../modules/testing/tests/helpers/generic.py | 43 ++++++--- .../modules/testing/tests/helpers/manager.py | 2 +- .../modules/testing/tests/helpers/utils.py | 2 +- .../testing/tests/test_agent/test_install.py | 2 +- .../tests/test_agent/test_registration.py | 2 +- .../testing/tests/test_agent/test_restart.py | 2 +- .../testing/tests/test_agent/test_stop.py | 2 +- .../tests/test_agent/test_uninstall.py | 2 +- .../examples/agent/vagrant/test.yaml | 88 +++++++++++++++++-- 10 files changed, 124 insertions(+), 31 deletions(-) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 57fd67ff74..758eea6a2e 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -8,7 +8,7 @@ from .constants import WAZUH_CONF, WAZUH_ROOT from .executor import Executor, WazuhAPI from .generic import HostInformation, CheckFiles -from modules.generic.logger import logger +from modules.testing.utils import logger class WazuhAgent: @@ -29,19 +29,19 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv 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" ]) diff --git a/deployability/modules/testing/tests/helpers/generic.py b/deployability/modules/testing/tests/helpers/generic.py index 316866aff1..fd142fb3d8 100644 --- a/deployability/modules/testing/tests/helpers/generic.py +++ b/deployability/modules/testing/tests/helpers/generic.py @@ -14,7 +14,7 @@ from pathlib import Path from .constants import WAZUH_CONTROL, CLIENT_KEYS from .executor import Executor -from modules.generic.logger import logger +from modules.testing.utils import logger from .utils import Utils @@ -69,16 +69,19 @@ def get_os_type(inventory_path) -> str: Returns: str: type of host (windows, linux, macos) """ - if 'manager' in inventory_path: - pattern = r'manager-(\w+)-' - elif 'agent' in inventory_path: - pattern = r'agent-(\w+)-' - result = re.search(pattern, inventory_path) - if result: - return result.group(1) - else: - return None - + try: + with open(inventory_path.replace('inventory', 'track'), 'r') as file: + data = yaml.safe_load(file) + if 'platform' in data: + return data['platform'] + else: + raise KeyError("The 'platform' key was not found in the YAML file.") + except FileNotFoundError: + logger.error(f"The YAML file '{inventory_path}' was not found.") + except yaml.YAMLError as e: + logger.error(f"Error while loading the YAML file: {e}") + except Exception as e: + logger.error(f"An unexpected error occurred: {e}") @staticmethod @@ -90,9 +93,21 @@ def get_architecture(inventory_path) -> str: inventory_path: host's inventory path Returns: - str: architecture (aarch64, x86_64, intel, apple) + str: architecture (amd64, arm64, intel, apple) """ - return Executor.execute_command(inventory_path, 'uname -m') + try: + with open(inventory_path.replace('inventory', 'track'), 'r') as file: + data = yaml.safe_load(file) + if 'platform' in data: + return data['arch'] + else: + raise KeyError("The 'platform' key was not found in the YAML file.") + except FileNotFoundError: + logger.error(f"The YAML file '{inventory_path}' was not found.") + except yaml.YAMLError as e: + logger.error(f"Error while loading the YAML file: {e}") + except Exception as e: + logger.error(f"An unexpected error occurred: {e}") @staticmethod @@ -692,7 +707,7 @@ def hasAgentClientKeys(inventory_path) -> bool: """ os_type = HostInformation.get_os_type(inventory_path) if os_type == 'linux': - return HostInformation.file_exists(inventory_path,{CLIENT_KEYS}) + return HostInformation.file_exists(inventory_path, {CLIENT_KEYS}) elif os_type == 'macos': return HostInformation.file_exists(inventory_path, '/Library/Ossec/etc/client.keys') diff --git a/deployability/modules/testing/tests/helpers/manager.py b/deployability/modules/testing/tests/helpers/manager.py index 20b0d4e4c1..2ac8811ab7 100644 --- a/deployability/modules/testing/tests/helpers/manager.py +++ b/deployability/modules/testing/tests/helpers/manager.py @@ -8,7 +8,7 @@ from .constants import CLUSTER_CONTROL, AGENT_CONTROL, WAZUH_CONF, WAZUH_ROOT from .executor import Executor, WazuhAPI from .generic import HostInformation, CheckFiles -from modules.generic.logger import logger +from modules.testing.utils import logger from .utils import Utils diff --git a/deployability/modules/testing/tests/helpers/utils.py b/deployability/modules/testing/tests/helpers/utils.py index 78cf3a676f..24dd874c54 100644 --- a/deployability/modules/testing/tests/helpers/utils.py +++ b/deployability/modules/testing/tests/helpers/utils.py @@ -8,7 +8,7 @@ import logging import time -from modules.generic.logger import logger +from modules.testing.utils import logger paramiko_logger = logging.getLogger("paramiko") diff --git a/deployability/modules/testing/tests/test_agent/test_install.py b/deployability/modules/testing/tests/test_agent/test_install.py index 90ebec0363..bca54f2af7 100644 --- a/deployability/modules/testing/tests/test_agent/test_install.py +++ b/deployability/modules/testing/tests/test_agent/test_install.py @@ -8,7 +8,7 @@ from ..helpers.agent import WazuhAgent from ..helpers.constants import WAZUH_ROOT from ..helpers.generic import HostConfiguration, HostInformation, GeneralComponentActions -from modules.generic.logger import logger +from modules.testing.utils import logger from ..helpers.manager import WazuhManager from ..helpers.utils import Utils diff --git a/deployability/modules/testing/tests/test_agent/test_registration.py b/deployability/modules/testing/tests/test_agent/test_registration.py index a1b4659e8a..05231a1594 100644 --- a/deployability/modules/testing/tests/test_agent/test_registration.py +++ b/deployability/modules/testing/tests/test_agent/test_registration.py @@ -8,7 +8,7 @@ from ..helpers.agent import WazuhAgent, WazuhAPI from ..helpers.generic import HostInformation, GeneralComponentActions, Waits from ..helpers.manager import WazuhManager, WazuhAPI -from modules.generic.logger import logger +from modules.testing.utils import logger from ..helpers.utils import Utils @pytest.fixture(scope="module", autouse=True) diff --git a/deployability/modules/testing/tests/test_agent/test_restart.py b/deployability/modules/testing/tests/test_agent/test_restart.py index 5585212c45..b162cc9a7b 100644 --- a/deployability/modules/testing/tests/test_agent/test_restart.py +++ b/deployability/modules/testing/tests/test_agent/test_restart.py @@ -6,7 +6,7 @@ import re from ..helpers.generic import GeneralComponentActions, HostInformation -from modules.generic.logger import logger +from modules.testing.utils import logger from ..helpers.manager import WazuhManager from ..helpers.utils import Utils diff --git a/deployability/modules/testing/tests/test_agent/test_stop.py b/deployability/modules/testing/tests/test_agent/test_stop.py index 320dd73008..510ce26a76 100644 --- a/deployability/modules/testing/tests/test_agent/test_stop.py +++ b/deployability/modules/testing/tests/test_agent/test_stop.py @@ -7,7 +7,7 @@ from ..helpers.agent import WazuhAgent, WazuhAPI from ..helpers.generic import GeneralComponentActions, Waits, HostInformation -from modules.generic.logger import logger +from modules.testing.utils import logger from ..helpers.utils import Utils @pytest.fixture(scope="module", autouse=True) diff --git a/deployability/modules/testing/tests/test_agent/test_uninstall.py b/deployability/modules/testing/tests/test_agent/test_uninstall.py index 77c0b46515..e15daf6756 100644 --- a/deployability/modules/testing/tests/test_agent/test_uninstall.py +++ b/deployability/modules/testing/tests/test_agent/test_uninstall.py @@ -9,7 +9,7 @@ from ..helpers.constants import WAZUH_ROOT from ..helpers.generic import HostInformation, GeneralComponentActions, Waits from ..helpers.manager import WazuhManager, WazuhAPI -from modules.generic.logger import logger +from modules.testing.utils import logger from ..helpers.utils import Utils @pytest.fixture(scope="module", autouse=True) diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml index 253016fae3..9174420f15 100755 --- a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml @@ -1,14 +1,91 @@ version: 0.1 -description: Test agent restart with provisioning agents' with provision module +description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: - - macos-ventura-13.4.1-arm64 - manager-os: linux-ubuntu-18.04-amd64 - infra-provider: aws + - linux-ubuntu-18.04-amd64 + + manager-os: linux-ubuntu-22.04-amd64 + infra-provider: vagrant working-dir: /tmp/dtt1-poc tasks: + # Unique manager allocate task + - task: "allocate-manager-{manager-os}" + description: "Allocate resources for the manager." + do: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: create + - provider: "{infra-provider}" + - size: large + - composite-name: "{manager-os}" + - inventory-output: "{working-dir}/manager-{manager-os}/inventory.yaml" + - track-output: "{working-dir}/manager-{manager-os}/track.yaml" + - label-termination-date: "1d" + - label-team: "qa" + on-error: "abort-all" + cleanup: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: delete + - track-output: "{working-dir}/manager-{manager-os}/track.yaml" + # Unique agent allocate task + - task: "allocate-agent-{agent}" + description: "Allocate resources for the agent." + do: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: create + - provider: "{infra-provider}" + - size: small + - composite-name: "{agent}" + - inventory-output: "{working-dir}/agent-{agent}/inventory.yaml" + - track-output: "{working-dir}/agent-{agent}/track.yaml" + - label-termination-date: "1d" + - label-team: "qa" + on-error: "abort-all" + foreach: + - variable: agent-os + as: agent + cleanup: + this: process + with: + path: python3 + args: + - modules/allocation/main.py + - action: delete + - track-output: "{working-dir}/agent-{agent}/track.yaml" + depends-on: + - "provision-manager-{manager-os}" + + # Unique manager provision task + - task: "provision-manager-{manager-os}" + description: "Provision the manager." + do: + this: process + with: + path: python3 + args: + - modules/provision/main.py + - inventory: "{working-dir}/manager-{manager-os}/inventory.yaml" + - install: + - component: wazuh-manager + type: assistant + version: 4.7.3 + live: True + depends-on: + - "allocate-manager-{manager-os}" + on-error: "abort-all" # Generic agent test task @@ -31,4 +108,5 @@ tasks: foreach: - variable: agent-os as: agent - + depends-on: + - "allocate-agent-{agent}" From f9f548ef61b7d5cf315b2b9b9d35d77e2cb46293 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 19 Apr 2024 13:55:59 +0200 Subject: [PATCH 05/13] fix(#5229): Fixing clientkey checks --- deployability/modules/testing/tests/helpers/generic.py | 3 +-- .../modules/workflow_engine/examples/agent/vagrant/test.yaml | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deployability/modules/testing/tests/helpers/generic.py b/deployability/modules/testing/tests/helpers/generic.py index af8b18b7c6..fc3b6a6782 100644 --- a/deployability/modules/testing/tests/helpers/generic.py +++ b/deployability/modules/testing/tests/helpers/generic.py @@ -16,7 +16,6 @@ from .executor import Executor from modules.testing.utils import logger from .utils import Utils -from modules.testing.utils import logger class HostInformation: @@ -708,7 +707,7 @@ def hasAgentClientKeys(inventory_path) -> bool: """ os_type = HostInformation.get_os_type(inventory_path) if os_type == 'linux': - return HostInformation.file_exists(inventory_path, {CLIENT_KEYS}) + return HostInformation.file_exists(inventory_path, CLIENT_KEYS) elif os_type == 'macos': return HostInformation.file_exists(inventory_path, '/Library/Ossec/etc/client.keys') diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml index 9174420f15..88e0a753a0 100755 --- a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml @@ -2,8 +2,8 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: + - macos-sonoma-14.0-arm64 - linux-ubuntu-18.04-amd64 - manager-os: linux-ubuntu-22.04-amd64 infra-provider: vagrant working-dir: /tmp/dtt1-poc @@ -19,13 +19,14 @@ tasks: args: - modules/allocation/main.py - action: create - - provider: "{infra-provider}" + - provider: "aws" - size: large - composite-name: "{manager-os}" - inventory-output: "{working-dir}/manager-{manager-os}/inventory.yaml" - track-output: "{working-dir}/manager-{manager-os}/track.yaml" - label-termination-date: "1d" - label-team: "qa" + - ssh-key: "/home/akim/Desktop/personal/Ephemeral" on-error: "abort-all" cleanup: this: process From 1f80707ebca5dd5c0c5743ab9924912926c444c8 Mon Sep 17 00:00:00 2001 From: Antonio Date: Fri, 19 Apr 2024 17:05:56 +0200 Subject: [PATCH 06/13] fix(#5229): Adapting some validations --- .../modules/testing/tests/helpers/agent.py | 27 +++++++++++++++++-- .../tests/test_agent/test_connection.py | 2 +- .../testing/tests/test_agent/test_install.py | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 98e92d93be..bcabfb114d 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -65,7 +65,7 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv "NET STATUS WazuhSvc" ]) elif 'macos' in os_type: - if 'x86_64' 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 /' ]) @@ -117,6 +117,25 @@ def register_agent(inventory_path, manager_path): 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): + os_type = HostInformation.get_os_type(inventory_path) + if 'linux' in os_type: + commands = [ + f"sed -i 's/[^<]*<\/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>/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: os_type = HostInformation.get_os_type(inventory_path) @@ -328,7 +347,11 @@ def isAgent_port_open(agent_params): Returns: str: Os name. """ - return 'ESTAB' in Executor.execute_command(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB') + os_name = HostInformation.get_os_name_from_inventory(agent_params) + if os_name == 'linux': + return 'ESTAB' in Executor.execute_command(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB') + elif os_name == 'macos': + return 'ESTABLISHED' in Executor.execute_command(agent_params, 'netstat -an | grep ".1514 " | grep ESTABLISHED') def get_agents_information(wazuh_api: WazuhAPI) -> list: """ diff --git a/deployability/modules/testing/tests/test_agent/test_connection.py b/deployability/modules/testing/tests/test_agent/test_connection.py index 4a7297596a..6d2377dc6f 100644 --- a/deployability/modules/testing/tests/test_agent/test_connection.py +++ b/deployability/modules/testing/tests/test_agent/test_connection.py @@ -73,7 +73,7 @@ def test_connection(wazuh_params): def test_status(wazuh_params): for agent in wazuh_params['agents'].values(): - assert 'active' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent'), logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} is not active') + assert 'active' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent') or 'is running' in GeneralComponentActions.get_component_status(agent, 'wazuh-agent'), logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} is not active') def test_service(wazuh_params): diff --git a/deployability/modules/testing/tests/test_agent/test_install.py b/deployability/modules/testing/tests/test_agent/test_install.py index c922c0230a..043e290707 100644 --- a/deployability/modules/testing/tests/test_agent/test_install.py +++ b/deployability/modules/testing/tests/test_agent/test_install.py @@ -97,4 +97,4 @@ def test_installation(wazuh_params): def test_status(wazuh_params): for agent in wazuh_params['agents'].values(): agent_status = GeneralComponentActions.get_component_status(agent, 'wazuh-agent') - assert 'loaded' in agent_status, logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} status is not loaded') + assert 'loaded' in agent_status or 'not running' in agent_status, logger.error(f'The {HostInformation.get_os_name_and_version_from_inventory(agent)} status is not loaded') From 6d22b61d2fa44842d6afd33a6e21a6823d8caa56 Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 11:35:20 +0200 Subject: [PATCH 07/13] fix(#5229): Fixing connection check ostype --- .../modules/testing/tests/helpers/agent.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index bcabfb114d..79ea11044d 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -313,10 +313,10 @@ def assert_results(result, agent_params) -> None: result (dict): result of comparison between pre and post action scan """ - os_name = HostInformation.get_os_name_from_inventory(agent_params) - if os_name == 'linux': + os_type = HostInformation.get_os_type(agent_params) + if os_type == 'linux': categories = ['/root', '/usr/bin', '/usr/sbin', '/boot'] - elif os_name == 'macos': + elif os_type == 'macos': categories = ['/usr/bin', '/usr/sbin'] actions = ['added', 'modified', 'removed'] @@ -337,21 +337,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. """ - os_name = HostInformation.get_os_name_from_inventory(agent_params) - if os_name == 'linux': - return 'ESTAB' in Executor.execute_command(agent_params, 'ss -t -a -n | grep ":1514" | grep ESTAB') - elif os_name == 'macos': - return 'ESTABLISHED' in Executor.execute_command(agent_params, 'netstat -an | grep ".1514 " | grep ESTABLISHED') + 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: """ From 1e32d4dd086fe468247f12fd70871e3214a17a96 Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 13:25:28 +0200 Subject: [PATCH 08/13] fix(#5229): Fixing validations in basic_info --- deployability/modules/testing/tests/helpers/agent.py | 2 +- deployability/modules/testing/tests/helpers/generic.py | 4 ++-- .../modules/testing/tests/test_agent/test_basic_info.py | 6 +++++- .../examples/agent/{vagrant => aws}/test.yaml | 8 +++----- 4 files changed, 11 insertions(+), 9 deletions(-) rename deployability/modules/workflow_engine/examples/agent/{vagrant => aws}/test.yaml (93%) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 79ea11044d..87ff4d2ee6 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -108,7 +108,7 @@ def register_agent(inventory_path, manager_path): 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') elif os_type == 'macos': - host_ip = HostInformation.get_public_ip_from_aws_dns(host) if 'amazonaws' in host else host + host_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else HostInformation.get_public_ip_from_aws_dns(host) commands = [ f"sed -i '.bak' 's/
MANAGER_IP<\/address>/
{host_ip}<\/address>/g' /Library/Ossec/etc/ossec.conf", "/Library/Ossec/bin/wazuh-control restart" diff --git a/deployability/modules/testing/tests/helpers/generic.py b/deployability/modules/testing/tests/helpers/generic.py index b55ecc75a0..eaeee50211 100644 --- a/deployability/modules/testing/tests/helpers/generic.py +++ b/deployability/modules/testing/tests/helpers/generic.py @@ -177,9 +177,9 @@ def get_os_name_and_version_from_inventory(inventory_path) -> tuple: @staticmethod def get_os_version_from_inventory(inventory_path) -> str: if 'manager' in inventory_path: - os_version = re.search(r".*?/manager-linux-.*?-(.*?)-.*?/inventory.yaml", inventory_path).group(1) + os_version = re.search(r".*?/manager-.*?-.*?-(.*?)-.*?/inventory.yaml", inventory_path).group(1) elif 'agent' in inventory_path: - os_version = re.search(r".*?/agent-linux-.*?-(.*?)-.*?/inventory.yaml", inventory_path).group(1) + os_version = re.search(r".*?/agent-.*?-.*?-(.*?)-.*?/inventory.yaml", inventory_path).group(1) return os_version else: return None diff --git a/deployability/modules/testing/tests/test_agent/test_basic_info.py b/deployability/modules/testing/tests/test_agent/test_basic_info.py index 3b81a0765f..b2f2b46dd7 100644 --- a/deployability/modules/testing/tests/test_agent/test_basic_info.py +++ b/deployability/modules/testing/tests/test_agent/test_basic_info.py @@ -67,7 +67,11 @@ def setup_test_environment(wazuh_params): def test_wazuh_os_version(wazuh_params): wazuh_api = WazuhAPI(wazuh_params['master']) for agent_names, agent_params in wazuh_params['agents'].items(): - assert HostInformation.dir_exists(agent_params, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') + if HostInformation.get_os_type(agent_params) == 'linux': + assert HostInformation.dir_exists(agent_params, WAZUH_ROOT), logger.error(f'The {WAZUH_ROOT} is not present in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') + elif HostInformation.get_os_type(agent_params) == 'macos': + assert HostInformation.dir_exists(agent_params, '/Library/Ossec'), logger.error(f'The /Library/Ossec is not present in {HostInformation.get_os_name_and_version_from_inventory(agent_params)}') + expected_condition_func = lambda: 'active' == WazuhAgent.get_agent_status(wazuh_api, agent_names) Waits.dynamic_wait(expected_condition_func, cycles=20, waiting_time=30) assert HostInformation.get_os_version_from_inventory(agent_params) in WazuhAgent.get_agent_os_version_by_name(wazuh_api, agent_names), logger.error('There is a mismatch between the OS version and the OS version of the installed agent') diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml b/deployability/modules/workflow_engine/examples/agent/aws/test.yaml similarity index 93% rename from deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml rename to deployability/modules/workflow_engine/examples/agent/aws/test.yaml index 88e0a753a0..dca534b7f0 100755 --- a/deployability/modules/workflow_engine/examples/agent/vagrant/test.yaml +++ b/deployability/modules/workflow_engine/examples/agent/aws/test.yaml @@ -2,10 +2,9 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: - - macos-sonoma-14.0-arm64 - - linux-ubuntu-18.04-amd64 + - macos-sonoma-14.3-arm64 manager-os: linux-ubuntu-22.04-amd64 - infra-provider: vagrant + infra-provider: aws working-dir: /tmp/dtt1-poc tasks: @@ -26,7 +25,6 @@ tasks: - track-output: "{working-dir}/manager-{manager-os}/track.yaml" - label-termination-date: "1d" - label-team: "qa" - - ssh-key: "/home/akim/Desktop/personal/Ephemeral" on-error: "abort-all" cleanup: this: process @@ -101,7 +99,7 @@ tasks: - targets: - wazuh-1: "{working-dir}/manager-{manager-os}/inventory.yaml" - agent: "{working-dir}/agent-{agent}/inventory.yaml" - - tests: "install,registration,restart,stop,uninstall" + - tests: "install,registration,basic_info,connection,restart,stop,uninstall" - component: "agent" - wazuh-version: "4.7.3" - wazuh-revision: "40714" From 0062465dc9714d82f7c0c63066d66d5ffd75ae2f Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 13:26:21 +0200 Subject: [PATCH 09/13] fix(#5229): Renaming test file --- .../examples/agent/aws/{test.yaml => test-agent-macOs.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deployability/modules/workflow_engine/examples/agent/aws/{test.yaml => test-agent-macOs.yaml} (100%) diff --git a/deployability/modules/workflow_engine/examples/agent/aws/test.yaml b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-macOs.yaml similarity index 100% rename from deployability/modules/workflow_engine/examples/agent/aws/test.yaml rename to deployability/modules/workflow_engine/examples/agent/aws/test-agent-macOs.yaml From ddd25c48984b6125a1a8d93b489fc22c823865df Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 18:21:01 +0200 Subject: [PATCH 10/13] fix(#5229): Fixes around install validation and test yamls --- .../modules/testing/tests/helpers/agent.py | 14 ++++++++++---- .../testing/tests/test_agent/test_basic_info.py | 5 ++++- .../testing/tests/test_agent/test_install.py | 2 -- .../test-agent-complete-macOs.yaml} | 12 +++++++++--- .../examples/agent/aws/test-agent-suse.yaml | 2 +- .../test-agent-complete-macOS.yaml} | 7 +++++-- 6 files changed, 29 insertions(+), 13 deletions(-) rename deployability/modules/workflow_engine/examples/agent/{vagrant/test-agent-complete.yaml => aws/test-agent-complete-macOs.yaml} (89%) mode change 100644 => 100755 rename deployability/modules/workflow_engine/examples/agent/{aws/test-agent-macOs.yaml => vagrant/test-agent-complete-macOS.yaml} (95%) diff --git a/deployability/modules/testing/tests/helpers/agent.py b/deployability/modules/testing/tests/helpers/agent.py index 87ff4d2ee6..857174117d 100644 --- a/deployability/modules/testing/tests/helpers/agent.py +++ b/deployability/modules/testing/tests/helpers/agent.py @@ -93,13 +93,16 @@ 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) + manager_path_yaml = yaml.safe_load(yaml_file) + manager_host = manager_path_yaml.get('ansible_host') - host = manager_path.get('ansible_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') os_type = HostInformation.get_os_type(inventory_path) if os_type == 'linux': - host_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host + host_ip = HostInformation.get_internal_ip_from_aws_dns(manager_host) if 'amazonaws' in manager_host else manager_host commands = [ f"sed -i 's/
MANAGER_IP<\/address>/
{host_ip}<\/address>/g' {WAZUH_CONF}", "systemctl restart wazuh-agent" @@ -108,7 +111,10 @@ def register_agent(inventory_path, manager_path): 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') elif os_type == 'macos': - host_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else HostInformation.get_public_ip_from_aws_dns(host) + 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/
MANAGER_IP<\/address>/
{host_ip}<\/address>/g' /Library/Ossec/etc/ossec.conf", "/Library/Ossec/bin/wazuh-control restart" diff --git a/deployability/modules/testing/tests/test_agent/test_basic_info.py b/deployability/modules/testing/tests/test_agent/test_basic_info.py index b2f2b46dd7..1caa6c8cce 100644 --- a/deployability/modules/testing/tests/test_agent/test_basic_info.py +++ b/deployability/modules/testing/tests/test_agent/test_basic_info.py @@ -75,7 +75,10 @@ def test_wazuh_os_version(wazuh_params): expected_condition_func = lambda: 'active' == WazuhAgent.get_agent_status(wazuh_api, agent_names) Waits.dynamic_wait(expected_condition_func, cycles=20, waiting_time=30) assert HostInformation.get_os_version_from_inventory(agent_params) in WazuhAgent.get_agent_os_version_by_name(wazuh_api, agent_names), logger.error('There is a mismatch between the OS version and the OS version of the installed agent') - assert HostInformation.get_os_name_from_inventory(agent_params) in WazuhAgent.get_agent_os_name_by_name(wazuh_api, agent_names).replace(' ', ''), logger.error('There is a mismatch between the OS name and the OS name of the installed agent') + if HostInformation.get_os_type(agent_params) == 'linux': + assert HostInformation.get_os_name_from_inventory(agent_params) in WazuhAgent.get_agent_os_name_by_name(wazuh_api, agent_names).replace(' ', ''), logger.error('There is a mismatch between the OS name and the OS name of the installed agent') + elif HostInformation.get_os_type(agent_params) == 'macos': + assert 'macos' in WazuhAgent.get_agent_os_name_by_name(wazuh_api, agent_names).replace(' ', ''), logger.error('There is a mismatch between the OS name and the OS name of the installed agent') def test_wazuh_version(wazuh_params): diff --git a/deployability/modules/testing/tests/test_agent/test_install.py b/deployability/modules/testing/tests/test_agent/test_install.py index 043e290707..b06c00b668 100644 --- a/deployability/modules/testing/tests/test_agent/test_install.py +++ b/deployability/modules/testing/tests/test_agent/test_install.py @@ -54,7 +54,6 @@ def setup_test_environment(wazuh_params): updated_agents = {} for agent_name, agent_params in wazuh_params['agents'].items(): Utils.check_inventory_connection(agent_params) - if GeneralComponentActions.isComponentActive(agent_params, 'wazuh-agent') and GeneralComponentActions.hasAgentClientKeys(agent_params): if HostInformation.get_client_keys(agent_params) != []: client_name = HostInformation.get_client_keys(agent_params)[0]['name'] @@ -85,7 +84,6 @@ def test_installation(wazuh_params): for agent_names, agent_params in wazuh_params['agents'].items(): WazuhAgent.perform_install_and_scan_for_agent(agent_params, agent_names, wazuh_params) - # Testing installation directory for agent_names, agent_params in wazuh_params['agents'].items(): if HostInformation.get_os_type(agent_params) == 'linux': diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml old mode 100644 new mode 100755 similarity index 89% rename from deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml rename to deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml index 648ea9788d..3a87f0527c --- a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete.yaml +++ b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml @@ -2,10 +2,14 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: - - linux-oracle-9-amd64 + - macos-sonoma-14.3-arm64 + # Run one at a time as there are limitations on the number of hosts + #- macos-ventura-13.6.4-arm64 + #- macos-sonoma-14.3-amd64 + #- macos-ventura-13.6.4-amd64 manager-os: linux-ubuntu-22.04-amd64 - infra-provider: vagrant + infra-provider: aws working-dir: /tmp/dtt1-poc tasks: @@ -53,6 +57,7 @@ tasks: - track-output: "{working-dir}/agent-{agent}/track.yaml" - label-termination-date: "1d" - label-team: "qa" + on-error: "abort-all" foreach: - variable: agent-os as: agent @@ -84,6 +89,7 @@ tasks: live: True depends-on: - "allocate-manager-{manager-os}" + on-error: "abort-all" # Generic agent test task @@ -98,7 +104,7 @@ tasks: - targets: - wazuh-1: "{working-dir}/manager-{manager-os}/inventory.yaml" - agent: "{working-dir}/agent-{agent}/inventory.yaml" - - tests: "install,registration,restart,stop,uninstall" + - tests: "install,registration,basic_info,connection,restart,stop,uninstall" - component: "agent" - wazuh-version: "4.7.3" - wazuh-revision: "40714" diff --git a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-suse.yaml b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-suse.yaml index e97b123b8b..5f2c1e1047 100644 --- a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-suse.yaml +++ b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-suse.yaml @@ -122,7 +122,7 @@ tasks: - targets: - wazuh-1: "{working-dir}/manager-{manager-os}/inventory.yaml" - agent: "{working-dir}/agent-{agent}/inventory.yaml" - - tests: "install,registration,restart,stop,uninstall" + - tests: "install,registration,basic_info,connection,restart,stop,uninstall" - component: "agent" - wazuh-version: "4.7.3" - wazuh-revision: "40714" diff --git a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-macOs.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOS.yaml similarity index 95% rename from deployability/modules/workflow_engine/examples/agent/aws/test-agent-macOs.yaml rename to deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOS.yaml index dca534b7f0..bba60dedd8 100755 --- a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-macOs.yaml +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOS.yaml @@ -2,9 +2,12 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: - - macos-sonoma-14.3-arm64 + - macos-sonoma-14.0-arm64 + + # Run one at a time as there are limitations on the number of hosts + #- macos-ventura-13.4.1-arm64 manager-os: linux-ubuntu-22.04-amd64 - infra-provider: aws + infra-provider: vagrant working-dir: /tmp/dtt1-poc tasks: From 6b5cc1bd29bfa3ab6a439d3fc5ac271d9210595f Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 18:40:53 +0200 Subject: [PATCH 11/13] fix(#5229): Fixes around test yamls --- ...t-agent-complete-macOS.yaml => test-agent-complete-macOs.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename deployability/modules/workflow_engine/examples/agent/vagrant/{test-agent-complete-macOS.yaml => test-agent-complete-macOs.yaml} (100%) diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOS.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml similarity index 100% rename from deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOS.yaml rename to deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml From 26def58c092bfc81769203a19eae03072d00c45f Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 22:26:32 +0200 Subject: [PATCH 12/13] fix(#5229): AWS test comment --- .../examples/agent/aws/test-agent-complete-macOs.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml index 3a87f0527c..2ae2d26e5f 100755 --- a/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml +++ b/deployability/modules/workflow_engine/examples/agent/aws/test-agent-complete-macOs.yaml @@ -2,9 +2,8 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: + # Run one at a time as there are limitations on the number of hosts (Inform @dev-devops-team about your usage, dedicated hosts) - macos-sonoma-14.3-arm64 - - # Run one at a time as there are limitations on the number of hosts #- macos-ventura-13.6.4-arm64 #- macos-sonoma-14.3-amd64 #- macos-ventura-13.6.4-amd64 From 333a6b7ac09b93dbd9e59b2eca5c5f2a7e69ba32 Mon Sep 17 00:00:00 2001 From: Antonio Date: Mon, 22 Apr 2024 23:38:30 +0200 Subject: [PATCH 13/13] fix(#5229): Vagrant test comment --- .../examples/agent/vagrant/test-agent-complete-macOs.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml index bba60dedd8..d1e35d3e71 100755 --- a/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml +++ b/deployability/modules/workflow_engine/examples/agent/vagrant/test-agent-complete-macOs.yaml @@ -2,9 +2,8 @@ version: 0.1 description: This workflow is used to test agents' deployment for DDT1 PoC variables: agent-os: - - macos-sonoma-14.0-arm64 - # Run one at a time as there are limitations on the number of hosts + - macos-sonoma-14.0-arm64 #- macos-ventura-13.4.1-arm64 manager-os: linux-ubuntu-22.04-amd64 infra-provider: vagrant