Skip to content

Commit

Permalink
enhancement(#4843): Changes to work with AWS
Browse files Browse the repository at this point in the history
  • Loading branch information
pro-akim committed Mar 21, 2024
1 parent a0ef700 commit d1837a3
Show file tree
Hide file tree
Showing 13 changed files with 384 additions and 243 deletions.
2 changes: 1 addition & 1 deletion deployability/modules/testing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .testing import Tester
from .models import InputPayload, ExtraVars
from .testing import Tester
12 changes: 0 additions & 12 deletions deployability/modules/testing/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,3 @@ def validate_tests(cls, value) -> list[str]:
value = value.split(',')

return value

@field_validator('targets', mode='before')
def validate_targets(cls, values) -> list:
"""Validate required fields."""

return values

@model_validator(mode='before')
def validate_dependencies(cls, values) -> list:
"""Validate required fields."""

return values
17 changes: 6 additions & 11 deletions deployability/modules/testing/playbooks/setup.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
- hosts: all
- hosts: localhost
become: true
become_user: "{{ current_user }}"
tasks:
- name: Clone tests into the endpoint
block:
- name: Create test directory
file:
path: "{{ working_dir }}"
state: directory
- name: Copy files to endpoints
copy:
src: "{{ local_path }}/"
dest: "{{ working_dir }}"
- name: Cleaning old key ssh-keygen registries
ansible.builtin.command:
cmd: "ssh-keygen -f /home/{{ current_user }}/.ssh/known_hosts -R '{{ item }}'"
loop: {{ hosts_ip }}
6 changes: 0 additions & 6 deletions deployability/modules/testing/playbooks/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
become: true
become_user: "{{ current_user }}"
tasks:

- name: Cleaning old key ssh-keygen registries
ansible.builtin.command:
cmd: "ssh-keygen -f /home/{{ current_user }}/.ssh/known_hosts -R '{{ item }}'"
loop: {{ hosts_ip }}

- name: Test {{ test }} for {{ component }}
command: "python3 -m pytest modules/testing/tests/test_{{component}}/test_{{ test }}.py -v --wazuh_version={{ wazuh_version }} --wazuh_revision={{ wazuh_revision }} --component={{ component }} --dependencies='{{ dependencies }}' --targets='{{ targets }}' --live={{ live }} -s"
args:
Expand Down
84 changes: 41 additions & 43 deletions deployability/modules/testing/testing.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import ast

from pathlib import Path
import json
import os

from modules.generic import Ansible, Inventory
from modules.generic.utils import Utils
from pathlib import Path
from .models import InputPayload, ExtraVars
from .utils import logger
import os
import json


class Tester:
_playbooks_dir = Path(__file__).parent / 'playbooks'
_setup_playbook = _playbooks_dir / 'setup.yml'
Expand All @@ -24,51 +24,49 @@ def run(cls, payload: InputPayload) -> None:
"""
payload = InputPayload(**dict(payload))
extra_vars = cls._get_extra_vars(payload).model_dump()
targets_paths = payload.targets
extra_vars['hosts_ip'] = []
for target_path in targets_paths:
path = ', '.join(list(eval(target_path).values()))
target = Inventory(**Utils.load_from_yaml((path)))
extra_vars['hosts_ip'].append(target.ansible_host)
logger.info(f"Running tests for {target.ansible_host}")
print(payload)

targets = {}
for item in targets_paths:
dictionary = eval(item)
targets.update(dictionary)
target_string = json.dumps(targets)
extra_vars['targets'] = target_string.replace('"',"")
dependencies_paths = payload.dependencies
for dependency_path in dependencies_paths:
path = ', '.join(list(eval(dependency_path).values()))
dependency = Inventory(**Utils.load_from_yaml((path)))
logger.info(f"Dependencies {dependency.ansible_host}")
dependencies = {}
for item in targets_paths:
dictionary = eval(item)
dependencies.update(dictionary)
target_string = json.dumps(dependencies)
extra_vars['dependencies'] = target_string.replace('"',"")
extra_vars['hosts_ip'] = []

# Process targets and dependencies
for path_type, paths_list in [("targets", payload.targets), ("dependencies", payload.dependencies)]:
for path in paths_list:
dictionary = eval(path)
inventory = Inventory(**Utils.load_from_yaml(', '.join(dictionary.values())))
extra_vars['hosts_ip'].extend([inventory.ansible_host] if path_type == "targets" else [])
logger.info(f"Running tests for {(inventory.ansible_host)}") if path_type == "targets" else logger.info(f"Dependencies {inventory.ansible_host}")
if path_type == "targets":
targets.update(dictionary)
else:
dependencies.update(dictionary)

extra_vars['targets'] = json.dumps(targets).replace('"', "")
extra_vars['dependencies'] = json.dumps(dependencies).replace('"', "")

# Set extra vars
extra_vars['local_host_path'] = str(Path(__file__).parent.parent.parent)
extra_vars['current_user'] = os.getlogin()

logger.debug(f"Using extra vars: {extra_vars}")
for target in targets_paths:
target_value = eval(target).values()
target_inventory = Inventory(**Utils.load_from_yaml(str(list(target_value)[0])))
ansible = Ansible(ansible_data=target_inventory.model_dump())
cls._setup(ansible, extra_vars['working_dir'])

target_inventory = Inventory(**Utils.load_from_yaml(str(list(eval(targets_paths[0]).values())[0])))
ansible = None

# Setup and run tests
target_inventory = Inventory(**Utils.load_from_yaml(str(list(eval(payload.targets[0]).values())[0])))
ansible = Ansible(ansible_data=target_inventory.model_dump())
cls._setup(ansible, extra_vars)
cls._run_tests(payload.tests, ansible, extra_vars)

for target in targets_paths:
target_value = eval(target).values()
target_inventory = Inventory(**Utils.load_from_yaml(str(list(target_value)[0])))
if payload.cleanup:
# Clean up if required
if payload.cleanup:
for target_path in payload.targets:
target_value = eval(target_path).values()
target_inventory = Inventory(**Utils.load_from_yaml(str(list(target_value)[0])))
logger.info("Cleaning up")
cls._cleanup(ansible, extra_vars['working_dir'])


@classmethod
def _get_extra_vars(cls, payload: InputPayload) -> ExtraVars:
"""
Expand Down Expand Up @@ -103,17 +101,17 @@ def _run_tests(cls, test_list: list[str], ansible: Ansible, extra_vars: ExtraVar
ansible.run_playbook(playbook, extra_vars)

@classmethod
def _setup(cls, ansible: Ansible, remote_working_dir: str = '/tmp') -> None:
def _setup(cls, ansible: Ansible, extra_vars: ExtraVars) -> None:
"""
Setup the environment for the tests.
Args:
ansible (Ansible): The Ansible object to run the setup.
remote_working_dir (str): The remote working directory.
extra_vars (str): The extra vars for the setup.
"""
extra_vars = {'local_path': str(Path(__file__).parent / 'tests'),
'working_dir': remote_working_dir}
playbook = str(cls._setup_playbook)
rendering_var = {**extra_vars}
template = str(cls._setup_playbook)
playbook = ansible.render_playbook(template, rendering_var)
ansible.run_playbook(playbook, extra_vars)

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions deployability/modules/testing/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from ..testing import Tester
from ..models import InputPayload, ExtraVars
124 changes: 115 additions & 9 deletions deployability/modules/testing/tests/helpers/agent.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import yaml
import requests
import socket
import yaml

from .executor import Executor, WazuhAPI
from .generic import HostInformation
from .constants import WAZUH_CONTROL, CLUSTER_CONTROL, AGENT_CONTROL, CLIENT_KEYS, WAZUH_CONF, WAZUH_ROOT
from typing import List, Optional
from .constants import WAZUH_CONF, WAZUH_ROOT
from .executor import Executor, WazuhAPI
from .generic import HostInformation, CheckFiles



class WazuhAgent:

Expand All @@ -28,7 +31,7 @@ def install_agent(inventory_path, agent_name, wazuh_version, wazuh_revision, liv
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' or distribution == 'opensuse-leap' or distribution == 'amzn' and 'aarch64' in architecture:
elif distribution == 'rpm' and 'aarch64' 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"
])
Expand Down Expand Up @@ -89,15 +92,16 @@ 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')


internal_ip = HostInformation.get_internal_ip_from_aws_dns(host) if 'amazonaws' in host else host

commands = [
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{host}<\/address>/g' {WAZUH_CONF}",
f"sed -i 's/<address>MANAGER_IP<\/address>/<address>{internal_ip}<\/address>/g' {WAZUH_CONF}",
"systemctl restart wazuh-agent"
]
]

Executor.execute_commands(inventory_path, commands)


@staticmethod
def uninstall_agent(inventory_path, wazuh_version=None, wazuh_revision=None) -> None:
os_type = HostInformation.get_os_type(inventory_path)
Expand Down Expand Up @@ -155,6 +159,108 @@ def uninstall_agents( inventories_paths=[], wazuh_version: Optional[List[str]]=N














@staticmethod
def install_agent_callback(wazuh_params, agent_name, agent_params):
WazuhAgent.install_agent(agent_params, agent_name, wazuh_params['wazuh_version'], wazuh_params['wazuh_revision'], wazuh_params['live'])


@staticmethod
def uninstall_agent_callback(wazuh_params, agent_params):
WazuhAgent.uninstall_agent(agent_params, wazuh_params['wazuh_version'], wazuh_params['wazuh_revision'])


@staticmethod
def perform_action_and_scan(agent_params, action_callback):
result = CheckFiles.perform_action_and_scan(agent_params, action_callback)
os_name = HostInformation.get_os_name_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'
],
'removed': [],
'modified': []
},
'/root': {'added': ['trustdb.gpg'], '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'], 'removed': [], 'modified': []},
'/usr/sbin': {'added': [], 'removed': [], 'modified': []}
}

# Use of filters
for directory, changes in result.items():
if directory in filter_data:
for change, files in changes.items():
if change in filter_data[directory]:
result[directory][change] = [file for file in files if file.split('/')[-1] not in filter_data[directory][change]]

return result

@staticmethod
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)
WazuhAgent.assert_results(result)


@staticmethod
def perform_uninstall_and_scan_for_agent(agent_params, wazuh_params):
action_callback = lambda: WazuhAgent.uninstall_agent_callback(wazuh_params, agent_params)
result = WazuhAgent.perform_action_and_scan(agent_params, action_callback)
WazuhAgent.assert_results(result)


@staticmethod
def assert_results(result):
categories = ['/root', '/usr/bin', '/usr/sbin', '/boot']
actions = ['added', 'modified', 'removed']
# Testing the results
for category in categories:
for action in actions:
assert result[category][action] == []










## ----------- api

def get_agents_information(wazuh_api: WazuhAPI) -> list:
Expand Down
Loading

0 comments on commit d1837a3

Please sign in to comment.