Skip to content

install

Installation Manager for Suricata and its dependencies.

To import...

from dynamite_nsm.services.suricata import install as suricata_install

InstallManager

Manage Suricata installation process

__init__(self, configuration_directory, install_directory, log_directory, download_suricata_archive=True, skip_interface_validation=False, stdout=False, verbose=False) special

Install Suricata

Parameters:

Name Type Description Default
configuration_directory str

Path to the configuration directory (E.G /etc/dynamite/suricata)

required
install_directory str

Path to the install directory (E.G /opt/dynamite/suricata/)

required
log_directory str

Path to the log directory (E.G /var/log/dynamite/suricata/)

required
download_suricata_archive Optional[bool]

If True, download the Suricata archive from a mirror

True
skip_interface_validation Optional[bool]

If included we don't check if the interface is available on the system

False
stdout Optional[bool]

Print the output to console

False
verbose Optional[bool]

Include detailed debug messages

False
Source code in dynamite_nsm/services/suricata/install.py
def __init__(self, configuration_directory: str, install_directory: str, log_directory: str,
             download_suricata_archive: Optional[bool] = True, skip_interface_validation: Optional[bool] = False,
             stdout: Optional[bool] = False, verbose: Optional[bool] = False):
    """Install Suricata
    Args:
        configuration_directory: Path to the configuration directory (E.G /etc/dynamite/suricata)
        install_directory: Path to the install directory (E.G /opt/dynamite/suricata/)
        log_directory: Path to the log directory (E.G /var/log/dynamite/suricata/)
        download_suricata_archive: If True, download the Suricata archive from a mirror
        skip_interface_validation: If included we don't check if the interface is available on the system
        stdout: Print the output to console
        verbose: Include detailed debug messages
    """
    self.configuration_directory = configuration_directory
    self.install_directory = install_directory
    self.log_directory = log_directory
    self.download_suricata_archive = download_suricata_archive
    self.skip_interface_validation = skip_interface_validation
    self.stdout = stdout
    self.verbose = verbose
    install.BaseInstallManager.__init__(self, 'suricata.install', verbose=self.verbose, stdout=stdout)
    if download_suricata_archive:
        self.logger.info("Attempting to download Suricata archive.")
        _, archive_name, self.local_mirror_root = self.download_from_mirror(const.SURICATA_MIRRORS)
        self.logger.info(f'Attempting to extract Suricata archive ({archive_name}).')
        self.extract_archive(os.path.join(const.INSTALL_CACHE, archive_name))
        self.logger.info("Extraction completed.")
    else:
        _, _, self.local_mirror_root = self.get_mirror_info(const.SURICATA_MIRRORS)

configure_compile_suricata(self, parallel_threads=None)

Configure and build Suricata from source

Parameters:

Name Type Description Default
parallel_threads Optional[int]

Number of parallel threads to use during the compiling process

None

Returns:

Type Description
None

None

Source code in dynamite_nsm/services/suricata/install.py
def configure_compile_suricata(self, parallel_threads: Optional[int] = None) -> None:
    """Configure and build Suricata from source
    Args:
        parallel_threads: Number of parallel threads to use during the compiling process
    Returns:
        None
    """
    suricata_source_install_cache = os.path.join(const.INSTALL_CACHE, self.local_mirror_root)
    suricata_config_parent_directory = '/'.join(self.configuration_directory.split('/')[:-1])
    if self.configuration_directory.endswith('/'):
        suricata_config_parent_directory = '/'.join(self.configuration_directory.split('/')[:-2])

    configure_args = [f'--prefix={self.install_directory}',
                      f'--sysconfdir={suricata_config_parent_directory} ',
                      f'--localstatedir={const.STATE_PATH}/suricata']
    self.logger.debug(f'Configuring with: {configure_args}')
    self.configure_source_package(suricata_source_install_cache, configure_args=configure_args)
    time.sleep(1)
    self.compile_source_package(suricata_source_install_cache,
                                parallel_threads=parallel_threads,
                                expected_lines_printed=COMPILE_PROCESS_EXPECTED_LINE_COUNT)

copy_suricata_files_and_directories(self)

Copy the required Suricata files from the install cache to their respective directories

Returns:

Type Description
None

None

Source code in dynamite_nsm/services/suricata/install.py
def copy_suricata_files_and_directories(self) -> None:
    """Copy the required Suricata files from the install cache to their respective directories
    Returns:
        None
    """
    suricata_tarball_extracted = f'{const.INSTALL_CACHE}/{self.local_mirror_root}'
    config_paths = [
        'reference.config',
        'threshold.config',
        'rules/'
    ]
    for conf in config_paths:
        self.copy_file_or_directory_to_destination(f'{suricata_tarball_extracted}/{conf}',
                                                   self.configuration_directory)

create_update_suricata_environment_variables(self)

Creates all the required Suricata environmental variables

Returns:

Type Description
None

None

Source code in dynamite_nsm/services/suricata/install.py
def create_update_suricata_environment_variables(self) -> None:
    """Creates all the required Suricata environmental variables

    Returns:
        None
    """
    self.create_update_env_variable('SURICATA_HOME', self.install_directory)
    self.create_update_env_variable('SURICATA_CONFIG', self.configuration_directory)
    self.create_update_env_variable('SURICATA_LOGS', self.log_directory)

install_suricata_dependencies(self)

Install Suricata dependencies

Returns:

Type Description
None

None

Source code in dynamite_nsm/services/suricata/install.py
def install_suricata_dependencies(self) -> None:
    """Install Suricata dependencies

    Returns:
        None
    """
    apt_get_packages = ['automake', 'bison', 'cargo', 'cmake', 'flex', 'g++', 'gcc', 'libcap-ng-dev',
                        'libjansson-dev', 'libjemalloc-dev', 'liblz4-dev', 'libmagic-dev', 'libnspr4-dev',
                        'libnss3-dev', 'libpcap-dev', 'libpcre3-dev', 'libtool', 'libyaml-dev', 'make',
                        'pkg-config', 'rustc', 'tar', 'wget', 'zlib1g-dev']

    yum_packages = ['automake', 'bison', 'cargo', 'cmake', 'file-devel', 'flex', 'gcc', 'gcc-c++', 'jansson-devel',
                    'jemalloc-devel', 'libcap-ng-devel', 'libpcap-devel', 'libtool', 'libyaml-devel', 'lz4-devel',
                    'make', 'nspr-devel', 'nss-devel', 'pcre-devel', 'pkgconfig', 'rustc', 'tar',
                    'wget', 'zlib-devel']

    def install_powertools_rhel(pacman_type):
        """Install Zeek dependencies (And PowerTools repo if on redhat based distro)
        Args:

        Returns:
            None
        """
        if pacman_type != 'yum':
            self.logger.info('Skipping RHEL PowerTools install, as it is not needed on this distribution.')
            return
        self.install_dependencies(yum_packages=['dnf-plugins-core', 'epel-release'])
        enable_powertools_p = subprocess.Popen(['yum', 'config-manager', '--set-enabled', 'powertools'],
                                               stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        enable_powertools_p.communicate()
        if enable_powertools_p.returncode == 0:
            self.logger.info("Installed PowerTools.")

    super(InstallManager, self).install_dependencies(apt_get_packages=apt_get_packages, yum_packages=yum_packages,
                                                     pre_install_function=install_powertools_rhel)

setup(self, inspect_interfaces)

Install Suricata

Parameters:

Name Type Description Default
inspect_interfaces List[str]

A list of network interfaces to capture on (E.G ["mon0", "mon1"])

required

Returns:

Type Description

None

Source code in dynamite_nsm/services/suricata/install.py
def setup(self, inspect_interfaces: List[str]):
    """Install Suricata
    Args:
        inspect_interfaces: A list of network interfaces to capture on (E.G ["mon0", "mon1"])
    Returns:
        None
    """
    if not self.skip_interface_validation:
        if not self.validate_inspect_interfaces(inspect_interfaces):
            raise install.NetworkInterfaceNotFound(inspect_interfaces)
    sysctl = systemctl.SystemCtl()
    self.install_suricata_dependencies()
    self.create_update_suricata_environment_variables()
    self.logger.debug(f'Creating directory: {self.configuration_directory}')
    utilities.makedirs(self.configuration_directory)
    self.logger.debug(f'Creating directory: {self.install_directory}')
    utilities.makedirs(self.install_directory)
    self.logger.debug(f'Creating directory: {self.log_directory}')
    utilities.makedirs(self.log_directory)
    self.copy_suricata_files_and_directories()
    self.logger.info('Setting up Suricata from source. This can take a few minutes.')
    if self.stdout:
        utilities.print_coffee_art()
    self.configure_compile_suricata()

    self.copy_file_or_directory_to_destination(
        f'{const.DEFAULT_CONFIGS}/suricata/suricata.yaml',
        self.configuration_directory
    )

    suricata_config = config.ConfigManager(self.configuration_directory, stdout=self.stdout, verbose=self.verbose)
    suricata_config.default_log_directory = self.log_directory
    suricata_config.suricata_log_output_file = os.path.join(self.log_directory, 'suricata.log')
    suricata_config.default_rules_directory = os.path.join(self.configuration_directory, 'rules')
    suricata_config.reference_config_file = os.path.join(self.configuration_directory, 'reference.config')
    suricata_config.classification_file = os.path.join(self.configuration_directory, 'rules',
                                                       'classification.config')
    suricata_config.af_packet_interfaces = misc.AfPacketInterfaces()
    for interface in inspect_interfaces:
        suricata_config.af_packet_interfaces.add(
            misc.AfPacketInterface(
                interface_name=interface, threads='auto', cluster_id=random.randint(1, 50000),
                cluster_type='cluster_qm'
            )
        )

    suricata_config.threading = suricata_config.get_optimal_suricata_threading_config(
        tuple([i for i in range(0, utilities.get_cpu_core_count() - 1)]))

    suricata_config.commit()
    self.logger.info('Applying Suricata configuration.')
    self.logger.debug(suricata_config.af_packet_interfaces)
    suricata_config.commit()

    # Fix Permissions
    self.logger.info('Setting up file permissions.')
    utilities.set_ownership_of_file(self.configuration_directory, user='dynamite', group='dynamite')
    utilities.set_ownership_of_file(self.install_directory, user='dynamite', group='dynamite')
    utilities.set_ownership_of_file(self.log_directory, user='dynamite', group='dynamite')
    utilities.set_permissions_of_file(f'{self.configuration_directory}/suricata.yaml', 660)
    post_install_bootstrap_updater(self.install_directory, stdout=self.stdout, verbose=self.verbose)

    self.logger.info('Setting up Suricata capture rules for dynamite user.')
    set_caps.SetCapturePermissions(self.install_directory).invoke(shell=True)

    self.logger.info(f'Installing service -> {const.DEFAULT_CONFIGS}/systemd/suricata.service')
    sysctl.install_and_enable(os.path.join(const.DEFAULT_CONFIGS, 'systemd', 'suricata.service'))

UninstallManager

Uninstall Suricata process manager

__init__(self, purge_config=True, stdout=False, verbose=False) special

Uninstall Suricata

Parameters:

Name Type Description Default
purge_config Optional[bool]

If enabled, remove all the configuration files associated with this installation

True
stdout Optional[bool]

Print output to console

False
verbose Optional[bool]

Include detailed debug messages

False

Returns:

Type Description

None

Source code in dynamite_nsm/services/suricata/install.py
def __init__(self, purge_config: Optional[bool] = True, stdout: Optional[bool] = False,
             verbose: Optional[bool] = False):
    """Uninstall Suricata
    Args:
        purge_config: If enabled, remove all the configuration files associated with this installation
        stdout: Print output to console
        verbose: Include detailed debug messages
    Returns:
        None
    """
    from dynamite_nsm.services.suricata.process import ProcessManager

    env_vars = utilities.get_environment_file_dict()
    suricata_directories = [env_vars.get('SURICATA_HOME'), env_vars.get('SURICATA_LOGS')]
    if purge_config:
        suricata_directories.append(env_vars.get('SURICATA_CONFIG'))
    super().__init__('suricata.uninstall', directories=suricata_directories, sysctl_service_name='suricata.service',
                     environ_vars=['SURICATA_HOME', 'SURICATA_CONFIG', 'SURICATA_LOGS', 'OINKMASTER_HOME'],
                     process=ProcessManager(stdout=stdout, verbose=verbose), stdout=stdout, verbose=verbose)

post_install_bootstrap_updater(suricata_install_directory, stdout=False, verbose=False)

Perform Suricata rule setup and updating with Oinkmaster

Parameters:

Name Type Description Default
suricata_install_directory str

The location of the suricata root install directory (E.G /opt/dynamite/suricata)

required
stdout Optional[bool]

Print the output to console

False
verbose Optional[bool]

Include detailed debug messages

False

Returns:

Type Description
None

None

Source code in dynamite_nsm/services/suricata/install.py
def post_install_bootstrap_updater(suricata_install_directory: str, stdout: Optional[bool] = False,
                                   verbose: Optional[bool] = False) -> None:
    """Perform Suricata rule setup and updating with Oinkmaster
    Args:
        suricata_install_directory: The location of the suricata root install directory (E.G /opt/dynamite/suricata)
        stdout: Print the output to console
        verbose: Include detailed debug messages
    Returns:
        None
    """
    from dynamite_nsm.services.suricata import oinkmaster as suricata_rule_updater
    from dynamite_nsm.services.suricata.oinkmaster import install as suricata_rule_updater_install
    suricata_rule_updater_install.InstallManager(
        install_directory=f'{suricata_install_directory}/rule_updater',
        download_oinkmaster_archive=True,
        stdout=stdout,
        verbose=verbose
    ).setup()
    suricata_rule_updater.update_suricata_rules()