Ejemplo n.º 1
0
def _write_worker(audit_key, audit_version, plugin_key, plugin,
                  input_queue, worker_type):
    """Worker function for store and alert plugins.

    Arguments:
        audit_key (str): Audit key name in configuration
        audit_version (str): Audit version string.
        plugin_key (str): Plugin key name in configuration.
        plugin (object): Store plugin or alert plugin object.
        input_queue (multiprocessing.Queue): Queue to read records from.
        worker_type (str): Either ``'store'`` or ``'alert'``.
    """
    worker_name = audit_key + '_' + plugin_key
    _log.info('%s: Started', worker_name)
    while True:
        record = input_queue.get()
        if record is None:
            plugin.done()
            break

        record['com'] = util.merge_dicts(record.get('com', {}), {
            'audit_key': audit_key,
            'audit_version': audit_version,
            'target_key': plugin_key,
            'target_class': type(plugin).__name__,
            'target_worker': worker_name,
            'target_type': worker_type,
        })
        plugin.write(record)
    _log.info('%s: Stopped', worker_name)
Ejemplo n.º 2
0
def cloud_worker(audit_key, audit_version, plugin_key, plugin,
                 output_queues):
    """Worker function for cloud plugins.

    This function expects the ``plugin`` object to implement a ``read``
    method that yields records. This function calls this ``read`` method
    to retrieve records and puts each record into each queue in
    ``output_queues``.

    Arguments:
        audit_key (str): Audit key name in configuration.
        audit_version (str): Audit version string.
        plugin_key (str): Plugin key name in configuration.
        plugin (object): Cloud plugin object.
        output_queues (list): List of :class:`multiprocessing.Queue`
            objects to write records to.
    """
    worker_name = audit_key + '_' + plugin_key
    _log.info('%s: Started', worker_name)
    for record in plugin.read():
        record['com'] = util.merge_dicts(record.get('com', {}), {
            'audit_key': audit_key,
            'audit_version': audit_version,
            'origin_key': plugin_key,
            'origin_class': type(plugin).__name__,
            'origin_worker': worker_name,
            'origin_type': 'cloud',
        })
        for q in output_queues:
            q.put(record)

    plugin.done()
    _log.info('%s: Stopped', worker_name)
Ejemplo n.º 3
0
def _get_sql_db_tde_disabled_event(com, ext):
    """Generate SQL DB disabled TDE event.

    Arguments:
        com (dict): SQL DB record `com` bucket
        ext (dict): SQL DB record `ext` bucket
    Returns:
        dict: An event record representing SQL DB with disabled TDE

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = ('{} SQL DB {} has TDE disabled.'.format(
        friendly_cloud_type, reference))
    recommendation = ('Check {} SQL DB {} and enable TDE.'.format(
        friendly_cloud_type, reference))
    event_record = {
        # Preserve the extended properties from the virtual
        # machine record because they provide useful context to
        # locate the virtual machine that led to the event.
        'ext': util.merge_dicts(ext, {'record_type': 'sql_db_tde_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'sql_db_tde_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating sql_db_tde_event; %r', event_record)
    yield event_record
Ejemplo n.º 4
0
def _get_log_profile_missing_event(com, ext):
    """Create an event record for missing log profile.

    Arguments:
        com (dict): The `com` bucket of a ``log_profile_missing`` record.
        ext (dict): The `ext` bucket of a ``log_profile_missing`` record.

    Returns:
        dict: An event record representing log profile missing for a
        subscription.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = ('{} subscription {} has log profile missing.'.format(
        friendly_cloud_type, reference))
    recommendation = (
        'Check {} subscription {} and create a log profile.'.format(
            friendly_cloud_type, reference))
    event_record = {
        # Preserve the extended properties from the virtual
        # machine record because they provide useful context to
        # locate the virtual machine that led to the event.
        'ext': util.merge_dicts(ext, {'record_type': 'log_profile_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'log_profile_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating log_profile_event; %r', event_record)
    yield event_record
Ejemplo n.º 5
0
def _process_vm_instance_view(vm, vm_iv, vm_index, subscription_id):
    """Process virtual machine record and yeild them.

    Arguments:
        vm (VirtualMachine): Virtual Machine Descriptor
        vm_iv (VirtualMachineInstanceView): Virtual Machine Instance view
        subscription_id (str): Subscription ID.

    Yields:
        dict: An Azure record of type ``vm_instance_view``.

    """
    raw_record = vm.as_dict()
    raw_record['instance_view'] = vm_iv.as_dict()
    record = {
        'raw': raw_record,
        'ext': {
            'cloud_type': 'azure',
            'record_type': 'vm_instance_view',
            'subscription_id': subscription_id,
        },
        'com': {
            'cloud_type': 'azure',
            'record_type': 'compute',
            'reference': raw_record.get('id')
        }
    }
    record['ext'] = util.merge_dicts(
        record['ext'], _get_normalized_vm_statuses(vm_iv),
        _get_normalized_vm_disk_encryption_status(vm, vm_iv))
    _log.info('Found vm_instance_view #%d; subscription_id: %s; name: %s',
              vm_index, subscription_id, record['raw'].get('name'))
    yield record
Ejemplo n.º 6
0
    def _process_postgres_server_details(self, sub, server, configuration,
                                         derived_configurations):
        """Process Postgres server details and configuration and yield them.

        Arguments:
            server (dict): Raw Postgres server record.
            configuration (list): Raw Postgres server configuration.
            derived_configurations (dict): Derived Postgres server
                                           configuration.

        Yields:
            dict: An Azure record of type ``rdbms``.

        """
        server['configuration'] = configuration
        ssl_enforcement = server.get('raw', {}).get('ssl_enforcement')
        ssl_connection_enabled = (ssl_enforcement == 'Enabled')
        record = {
            'raw': server,
            'ext': {
                'cloud_type': 'azure',
                'record_type': 'postgresql_server',
                'subscription_id': sub.get('subscription_id'),
                'subscription_name': sub.get('display_name'),
                'subscription_state': sub.get('state'),
            },
            'com': {
                'cloud_type': 'azure',
                'record_type': 'rdbms',
                'reference': server.get('id'),
                'tls_enforced': ssl_connection_enabled,
            }
        }
        record['ext'] = util.merge_dicts(record['ext'], derived_configurations)
        yield record
Ejemplo n.º 7
0
 def test_merge_dicts_immutability_simple(self):
     a = {'a': 1}
     b = {'b': 2}
     c = util.merge_dicts(a, b)
     c['c'] = 3
     self.assertEqual(a, {'a': 1})
     self.assertEqual(b, {'b': 2})
Ejemplo n.º 8
0
 def test_merge_dicts_immutability_nested(self):
     a = {'a': [1, 2, 3]}
     b = {'a': [4, 5, 6]}
     c = util.merge_dicts(a, b)
     c['a'].append(7)
     self.assertEqual(a, {'a': [1, 2, 3]})
     self.assertEqual(b, {'a': [4, 5, 6]})
Ejemplo n.º 9
0
def event_worker(audit_key, audit_version, plugin_key, plugin, input_queue,
                 output_queues):
    """Worker function for event plugins.

    This function expects the ``plugin`` object to implement a ``eval``
    method that accepts a single record as a parameter and yields one or
    more records, and a ``done`` method to perform cleanup work in the
    end.

    This function gets records from ``input_queue`` and passes each
    record to the ``eval`` method of ``plugin``. Then it puts each
    record yielded by the ``eval`` method into each queue in
    ``output_queues``.

    When there are no more records in the ``input_queue``, i.e., once
    ``None`` is found in the ``input_queue``, this function calls the
    ``done`` method of the ``plugin`` to indicate that record
    processing is over.

    Arguments:
        audit_key (str): Audit key name in configuration.
        audit_version (str): Audit version string.
        plugin_key (str): Plugin key name in configuration.
        plugin (object): Store plugin object.
        input_queue (multiprocessing.Queue): Queue to read records from.
        output_queues (list): List of :class:`multiprocessing.Queue`
            objects to write records to.
    """
    worker_name = audit_key + '_' + plugin_key
    _log.info('%s: Started', worker_name)
    while True:
        record = input_queue.get()
        if record is None:
            try:
                plugin.done()
            except Exception as e:
                _log.exception('%s: Failed; done() error: %s: %s', worker_name,
                               type(e).__name__, e)
            break

        try:
            for event_record in plugin.eval(record):
                event_record['com'] = \
                    util.merge_dicts(event_record.get('com', {}), {
                        'audit_key': audit_key,
                        'audit_version': audit_version,
                        'origin_key': plugin_key,
                        'origin_class': type(plugin).__name__,
                        'origin_worker': worker_name,
                        'origin_type': 'event',
                    })
                for q in output_queues:
                    q.put(event_record)
        except Exception as e:
            _log.exception('%s: Failed; eval() error: %s: %s', worker_name,
                           type(e).__name__, e)

    _log.info('%s: Stopped', worker_name)
Ejemplo n.º 10
0
def _get_normalized_firewall_rule(firewall_record, rule_index, rule,
                                  project_index, project, key_file_path):
    """Create a normalized firewall rule record.

    Arguments:
        firewall_record (dict): Firewall record generated by this plugin.
        rule_index (int): Index of a firewall rule (for logging only).
        rule (dict): Raw allowed or denied rule in ``firewall``.
        project_index (int): Project index (for logging only).
        project (dict): GCP project object (for logging only).
        key_file_path (str): Path to key file (for logging only).

    Returns:
        dict: A normalized firewall rule record with ``com`` bucket
            populated with firewall rule properties in common notation.

    """
    raw_firewall = firewall_record.get('raw', {})
    record = {
        'raw':
        rule,

        # Preserve the extended properties from firewall record.
        'ext':
        util.merge_dicts(
            firewall_record.get('ext'),
            {

                # Set extended properties specific to a firewall rule.
                'record_type': 'firewall_rule',
                'firewall_id': raw_firewall.get('id'),
                'firewall_link': raw_firewall.get('selfLink'),
            }),
        'com': {
            'cloud_type': 'gcp',
            'record_type': 'firewall_rule',
            'reference': raw_firewall.get('selfLink'),
            'enabled': not raw_firewall.get('disabled'),
            'direction': _get_normalized_firewall_direction(raw_firewall),
            'source_addresses': raw_firewall.get('sourceRanges'),
            'protocol': _get_normalized_firewall_protocol(rule),

            # If the 'ports' key is missing in an allowed/denied rule,
            # it means all ports are allowed/denied.
            'destination_ports': rule.get('ports', ['0-65535'])
        }
    }

    _log.info(
        'Found firewall_rule #%d; %s, %s; %s', rule_index,
        raw_firewall.get('name'), rule.get('IPProtocol'),
        util.outline_gcp_project(project_index, project, None, key_file_path))
    return record
Ejemplo n.º 11
0
def _get_azure_vm_data_disk_encryption_event(com, ext, raw):
    """Evaluate Azure VM for unencrypted data disks.

    Arguments:
        com (dict): Virtual machine record `com` bucket
        ext (dict): Virtual machine record `ext` bucket
        raw (dict): Virtual machine record `raw` bucket
    Returns:
        dict: An event record representing unencrypted data disk

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    os_disk_name = raw.get('storage_profile').get('os_disk').get('name')
    instance_view = raw.get('instance_view')
    if instance_view is None:
        return
    for disk in instance_view.get('disks'):
        # If it is an OS disk skip and continue
        if disk.get('name') == os_disk_name:
            continue
        if disk.get('encryption_settings') is not None and \
                disk['encryption_settings'][0]['enabled']:
            continue
        reference = com.get('reference')
        description = (
            '{} virtual machine {} has unencrypted data disk {}'
            .format(friendly_cloud_type, reference, disk.get('name'))
        )
        recommendation = (
            'Check {} virtual machine {} and encrypt data disk {}'
            .format(friendly_cloud_type, reference, disk.get('name'))
        )

        event_record = {
            # Preserve the extended properties from the virtual
            # machine record because they provide useful context to
            # locate the virtual machine that led to the event.
            'ext': util.merge_dicts(ext, {
                'record_type': 'vm_data_disk_encryption_event'
            }),
            'com': {
                'cloud_type': com.get('cloud_type'),
                'record_type': 'vm_data_disk_encryption_event',
                'reference': reference,
                'description': description,
                'recommendation': recommendation,
            }
        }

        _log.info('Generating vm_data_disk_encryption_event; %r', event_record)
        yield event_record
Ejemplo n.º 12
0
def _write_worker(audit_key, audit_version, plugin_key, plugin_config,
                  input_queue, worker_type):
    """Worker function for store and alert plugins.

    Arguments:
        audit_key (str): Audit key name in configuration
        audit_version (str): Audit version string.
        plugin_key (str): Plugin key name in configuration.
        plugin_config (dict): Store or alert plugin config dictionary.
        input_queue (multiprocessing.Queue): Queue to read records from.
        worker_type (str): Either ``'store'`` or ``'alert'``.

    """
    worker_name = audit_key + '_' + plugin_key
    _log.info('%s_worker: %s: Started', worker_type, worker_name)

    try:
        plugin = util.load_plugin(plugin_config)
    except Exception as e:
        _log.exception('%s_worker: %s: Failed; error: %s: %s', worker_type,
                       worker_name,
                       type(e).__name__, e)
        _log.info('%s_worker: %s: Stopped', worker_type, worker_name)
        return

    while plugin is not None:
        try:
            record = input_queue.get()
            if record is None:
                _log.info('%s_worker: %s: Stopping', worker_type, worker_name)
                plugin.done()
                break

            record['com'] = util.merge_dicts(
                record.get('com', {}), {
                    'audit_key': audit_key,
                    'audit_version': audit_version,
                    'target_key': plugin_key,
                    'target_class': type(plugin).__name__,
                    'target_worker': worker_name,
                    'target_type': worker_type,
                })

            plugin.write(record)

        except Exception as e:
            _log.exception('%s_worker: %s: Failed; error: %s: %s', worker_type,
                           worker_name,
                           type(e).__name__, e)

    _log.info('%s_worker: %s: Stopped', worker_type, worker_name)
Ejemplo n.º 13
0
def _get_normalized_rdbms_record(rdbms_record):
    """Normalize records of type `rdbms`.

    Arguments:
        rdbms_record (dict): RDBMS record generated by this plugin.

    Yields:
        dict: A normalized rdbms record.

    """
    ssl_enforcement = rdbms_record.get('raw', {}).get('ssl_enforcement')
    ssl_connection_enabled = (ssl_enforcement == 'Enabled')
    normalized_rdbms_record = {
        'raw': rdbms_record.get('raw', {}),
        'ext': util.merge_dicts(rdbms_record.get('ext'), {
            'reference': rdbms_record.get('raw', {}).get('id'),
        }),
        'com': util.merge_dicts(rdbms_record.get('com'), {
            'reference': rdbms_record.get('raw', {}).get('id'),
            'tls_enforced': ssl_connection_enabled,
        }),

    }
    yield normalized_rdbms_record
Ejemplo n.º 14
0
    def eval(self, record):
        """Evaluate record to check for multiples of ``n``.

        If ``record['raw']['data']`` is a multiple of ``n`` (the
        parameter with which this plugin was initialized with), then
        generate an event record. Otherwise, do nothing.

        If ``record['raw']['data]`` is missing, i.e., the key named
        ``raw`` or ``data`` does not exist, then its record number is
        assumed to be ``1``.

        This is a mock example of a event plugin. In actual event
        plugins, this method would typically check for security issues
        in the ``record``.

        Arguments:
            record (dict): Record to evaluate.

        Yields:
            dict: Event record if evaluation rule matches the input
            record.

        """
        # If record data value is a multiple of self._n, generate an
        # event record.
        data = record.get('raw', {}).get('data', 1)
        description = '{} is a multiple of {}.'.format(data, self._n)
        recommendation = (
            'Divide {} by {} and confirm that the remainder is 0.'.format(
                data, self._n))
        if data % self._n == 0:
            yield {
                'ext':
                util.merge_dicts(record.get('ext', {}), {
                    'record_type': 'mock_event',
                    'data': data,
                    'n': self._n,
                }),
                'com': {
                    'record_type': 'mock_event',
                    'description': description,
                    'recommendation': recommendation,
                }
            }
def _get_az_storage_account_secure_transfer_event(com, ext):
    """Evaluate Azure storage account to check if insecure transfer enabled.

    Arguments:
        com (dict): Azure storage account record `com` bucket.
        ext (dict): Azure storage account record `ext` bucket.

    Returns:
        dict: An event record representing storage accounts with secure
        transfer enabled set to false.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')

    description = (
        '{} storage account {} does not require secure transfer.'
        .format(friendly_cloud_type, reference)
    )
    recommendation = (
        'Check {} storage account {} and ensure that it requires '
        'secure transfer.'.format(friendly_cloud_type, reference)
    )

    event_record = {
        # Preserve the  properties from the storage account
        # record because they provide useful context to
        # locate the storage account that led to the event.
        'ext': util.merge_dicts(ext, {
            'record_type': 'storage_account_secure_transfer_event'
        }),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'storage_account_secure_transfer_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating storage_account_secure_transfer_event; %r',
              event_record)
    yield event_record
Ejemplo n.º 16
0
def _get_normalized_firewall_rule(firewall_record, rule):
    """Create a normalized firewall rule record.

    Arguments:
        firewall_record (dict): Firewall record generated by this plugin.
        rule (dict): Raw allowed or denied rule in ``firewall``.

    Returns:
        dict: A normalized firewall rule record with ``com`` bucket
            populated with firewall rule properties in common notation.

    """
    raw_firewall = firewall_record.get('raw', {})
    record = {
        'raw':
        rule,

        # Preserve the extended properties from firewall record.
        'ext':
        util.merge_dicts(
            firewall_record.get('ext'),
            {

                # Set extended properties specific to a firewall rule.
                'record_type': 'firewall_rule',
                'firewall_id': raw_firewall.get('id'),
                'firewall_link': raw_firewall.get('selfLink'),
            }),
        'com': {
            'cloud_type': 'gcp',
            'record_type': 'firewall_rule',
            'reference': raw_firewall.get('selfLink'),
            'enabled': not raw_firewall.get('disabled'),
            'direction': _get_normalized_firewall_direction(raw_firewall),
            'source_addresses': raw_firewall.get('sourceRanges'),
            'protocol': _get_normalized_firewall_protocol(rule),

            # If the 'ports' key is missing in an allowed/denied rule,
            # it means all ports are allowed/denied.
            'destination_ports': rule.get('ports', ['0-65535'])
        }
    }
    return record
Ejemplo n.º 17
0
def _get_az_storage_account_default_network_access_event(com, ext):
    """Generate Azure storage account default network access event.

    Arguments:
        com (dict): Azure storage account record `com` bucket.
        ext (dict): Azure storage account record `ext` bucket.

    Returns:
        dict: An event record representing storage accounts with default
        network access set to allowed.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')

    description = (
        '{} storage account {} has default network access set to allowed.'.
        format(friendly_cloud_type, reference))
    recommendation = (
        'Check {} storage account {} and set default network access to deny.'.
        format(friendly_cloud_type, reference))

    event_record = {
        # Preserve the  properties from the storage account
        # record because they provide useful context to
        # locate the storage account that led to the event.
        'ext':
        util.merge_dicts(
            ext,
            {'record_type': 'storage_account_default_network_access_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'storage_account_default_network_access_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating storage_account_default_network_access_event; %r',
              event_record)
    yield event_record
Ejemplo n.º 18
0
def _process_vm_instance_view(vm, vm_iv, subscription_id):
    """Process virtual machine record and yeild them.

    Arguments:
        vm (VirtualMachine): Virtual Machine Descriptor
        vm_iv (VirtualMachineInstanceView): Virtual Machine Instance view
        subscription_id (str): Subscription ID.

    Yields:
        dict: An Azure record of type ``vm_instance_view``.

    """
    try:
        raw_record = vm.as_dict()
        raw_record['instance_view'] = vm_iv.as_dict()
        record = {
            'raw': raw_record,
            'ext': {
                'cloud_type': 'azure',
                'record_type': 'vm_instance_view',
                'subscription_id': subscription_id,
            },
            'com': {
                'cloud_type': 'azure',
                'record_type': None,
                'reference': raw_record.get('id')
            }
        }
        record['ext'] = util.merge_dicts(
            record['ext'],
            _get_normalized_vm_statuses(vm_iv),
            _get_normalized_vm_disk_encryption_status(vm, vm_iv)
            )
        _log.info('Found virtual_machine; subscription_id: %s; name: %s',
                  subscription_id,
                  record['raw'].get('name'))
        yield record

    except CloudError as e:
        _log.error('Failed to fetch details for virtual_machine; '
                   'subscription_id: %s; error: %s: %s',
                   subscription_id, type(e).__name__, e)
def _get_postgres_log_retention_days_event(com, ext, min_log_retention_days):
    """Generate event for Postgres log retention days set below minimum.

    Arguments:
        com (dict): Postgres record `com` bucket
        ext (dict): Postgres record `ext` bucket
        min_log_retention_days (int): Minimum log retention days
    Returns:
        dict: An event record representing Postgres server
        with log retention days set below desired minimum.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    friendly_rdbms_type = util.friendly_string(ext.get('record_type'))

    reference = com.get('reference')
    description = (
        '{} {} {} has log retention days set below desired minimum value.'.
        format(friendly_cloud_type, friendly_rdbms_type, reference))
    recommendation = (
        'Check {} {} {} and set log retention days to minimum of {} days.'.
        format(friendly_cloud_type, friendly_rdbms_type, reference,
               min_log_retention_days))

    event_record = {
        # Preserve the extended properties from the RDBMS
        # record because they provide useful context to
        # locate the RDBMS that led to the event.
        'ext':
        util.merge_dicts(ext,
                         {'record_type': 'postgres_log_retention_days_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'postgres_log_retention_days_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating postgres_log_retention_days_event; %r', event_record)
    yield event_record
def _get_postgres_log_disconnections_disabled_event(com, ext):
    """Generate event for Postgres log disconnections disabled.

    Arguments:
        com (dict): Postgres record `com` bucket
        ext (dict): Postgres record `ext` bucket
    Returns:
        dict: An event record representing Postgres server
        with log disconnections disabled

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    friendly_rdbms_type = util.friendly_string(ext.get('record_type'))

    reference = com.get('reference')
    description = (
        '{} {} {} has log disconnections disabled.'
        .format(friendly_cloud_type, friendly_rdbms_type, reference)
    )
    recommendation = (
        'Check {} {} {} and enable log disconnections.'
        .format(friendly_cloud_type, friendly_rdbms_type, reference)
    )

    event_record = {
        # Preserve the extended properties from the RDBMS
        # record because they provide useful context to
        # locate the RDBMS that led to the event.
        'ext': util.merge_dicts(ext, {
            'record_type': 'postgres_log_disconnections_event'
        }),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'postgres_log_disconnections_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating postgres_log_disconnections_event; %r', event_record)
    yield event_record
Ejemplo n.º 21
0
def _get_azure_vm_blacklisted_extension_event(com, ext, blacklisted):
    """Evaluate Azure VM for blacklisted extensions.

    Arguments:
        com (dict): Virtual machine record `com` bucket
        ext (dict): Virtual machine record `ext` bucket
        blacklisted (list): Added blacklisted extension list
    Returns:
        dict: An event record representing VM with blacklisted extenstions

    """
    if not blacklisted:
        return
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = (
        '{} virtual machine {} has blacklisted extensions {}'.format(
            friendly_cloud_type, reference, util.friendly_list(blacklisted)))
    recommendation = (
        'Check {} virtual machine {} and remove blacklisted extensions {}'.
        format(friendly_cloud_type, reference,
               util.friendly_list(blacklisted)))

    event_record = {
        # Preserve the extended properties from the virtual
        # machine record because they provide useful context to
        # locate the virtual machine that led to the event.
        'ext':
        util.merge_dicts(ext,
                         {'record_type': 'vm_blacklisted_extension_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'vm_blacklisted_extension_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating vm_blacklisted_extension_event; %r', event_record)
    yield event_record
def _get_log_profile_missing_location_event(com, ext, missing_locations):
    """Generate log profile missing category type event.

    Arguments:
        com (dict): Log profile record `com` bucket
        ext (dict): Log profile record `ext` bucket
        missing_locations (set): Missing location set
    Returns:
        dict: An event record representing log profile which is not enabled
        for all locations.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = ('{} log profile {} does not include locations {}.'.format(
        friendly_cloud_type, reference, util.friendly_list(missing_locations)))
    recommendation = (
        'Check {} log profile {} and enable locations {}.'.format(
            friendly_cloud_type, reference,
            util.friendly_list(missing_locations)))
    event_record = {
        # Preserve the extended properties from the log profile
        # record because they provide useful context to locate
        # the log profile that led to the event.
        'ext':
        util.merge_dicts(
            ext, {
                'record_type': 'log_profile_missing_location_event',
                'missing_locations': missing_locations
            }),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'log_profile_missing_location_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }
    _log.info('Generating log_profile_missing_location_event; %r',
              event_record)
    return event_record
Ejemplo n.º 23
0
def _get_azure_web_app_https_event(com, ext):
    """Generate Web App HTTPS event.

    Arguments:
        com (dict): Azure web app record `com` bucket.
        ext (dict): Azure web app record `ext` bucket.

    Returns:
        dict: An event record representing web apps not using
        HTTPS only traffic.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = (
        '{} web app {} has HTTPS only traffic disabled.'
        .format(friendly_cloud_type, reference)
    )
    recommendation = (
        'Check {} web app {} and enable HTTPS only traffic.'
        .format(friendly_cloud_type, reference)
    )

    event_record = {
        # Preserve the extended properties from the web app
        # record because they provide useful context to
        # locate the web app that led to the event.
        'ext': util.merge_dicts(ext, {
            'record_type': 'web_app_https_event'
        }),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'web_app_https_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }
    _log.info('Generating web_app_https_event; %r', event_record)
    yield event_record
Ejemplo n.º 24
0
def _get_azure_vm_os_disk_encryption_event(com, ext, raw):
    """Evaluate Azure VM for unencrypted OS disks.

    Arguments:
        com (dict): Virtual machine record `com` bucket
        ext (dict): Virtual machine record `ext` bucket
        raw (dict): Virtual machine record `raw` bucket
    Returns:
        dict: An event record representing unencrypted OS disk

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    os_disk_name = raw.get('storage_profile').get('os_disk').get('name')
    reference = com.get('reference')
    description = (
        '{} virtual machine {} has unencrypted OS disk {}'
        .format(friendly_cloud_type, reference, os_disk_name)
    )
    recommendation = (
        'Check {} virtual machine {} and encrypt OS disk {}'
        .format(friendly_cloud_type, reference, os_disk_name)
    )

    event_record = {
        # Preserve the extended properties from the virtual
        # machine record because they provide useful context to
        # locate the virtual machine that led to the event.
        'ext': util.merge_dicts(ext, {
            'record_type': 'vm_os_disk_encryption_event'
        }),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'vm_os_disk_encryption_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }
    _log.info('Generating vm_os_disk_encryption_event; %r', event_record)
    yield event_record
Ejemplo n.º 25
0
def _get_log_profile_retention_event(com, ext, min_retention_days):
    """Generate log profile retention event.

    Arguments:
        com (dict): Log profile record `com` bucket
        ext (dict): Log profile record `ext` bucket
        min_retention_days (int): Minimum required retention days.

    Returns:
        dict: An event record representing log profile with retention
             policy configured for less number of days than required.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = (
        '{} log profile {} has log retention set to less than {} days.'.format(
            friendly_cloud_type, reference, min_retention_days))
    recommendation = (
        'Check {} log profile {} and set log retention to more than {} days.'.
        format(friendly_cloud_type, reference, min_retention_days))
    event_record = {
        # Preserve the extended properties from the virtual
        # machine record because they provide useful context to
        # locate the virtual machine that led to the event.
        'ext':
        util.merge_dicts(ext, {'record_type': 'log_profile_retention_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'log_profile_retention_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating log_profile_retention_event; %r', event_record)
    yield event_record
Ejemplo n.º 26
0
def _process_vm_instance_view(vm_index, vm, vm_iv, sub_index, sub, tenant):
    """Process virtual machine record and yeild them.

    Arguments:
        vm_index (int): Virtual machine index (for logging only).
        vm (dict): Raw virtual machine record.
        vm_iv (dict): Raw virtual machine instance view record.
        sub_index (int): Subscription index (for logging only).
        sub (Subscription): Azure subscription object.
        tenant (str): Azure tenant ID.

    Yields:
        dict: An Azure record of type ``vm_instance_view``.

    """
    vm['instance_view'] = vm_iv
    record = {
        'raw': vm,
        'ext': {
            'cloud_type': 'azure',
            'record_type': 'vm_instance_view',
            'subscription_id': sub.get('subscription_id'),
            'subscription_name': sub.get('display_name'),
            'subscription_state': sub.get('state'),
        },
        'com': {
            'cloud_type': 'azure',
            'record_type': 'compute',
            'reference': vm.get('id')
        }
    }
    record['ext'] = util.merge_dicts(
        record['ext'], _get_normalized_vm_statuses(vm_iv),
        _get_normalized_vm_disk_encryption_status(vm, vm_iv),
        _get_vm_extension_list(vm_iv))
    _log.info('Found vm_instance_view #%d: %s; %s', vm_index, vm.get('name'),
              util.outline_az_sub(sub_index, sub, tenant))
    return record
def _get_key_vault_secret_no_expiry_event(com, ext):
    """Generate Key Vault secret expiry event.

    Arguments:
        com (dict): Key Vault secret record `com` bucket.
        ext (dict): Key Vault secret record `ext` bucket.

    Returns:
        dict: An event record representing Key Vault secret with no expiry
        set.

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = (
        '{} Key Vault secret {} has has no expiration date set.'.format(
            friendly_cloud_type, reference))
    recommendation = (
        'Check {} Key Vault secret {} and set expiration date.'.format(
            friendly_cloud_type, reference))
    event_record = {
        # Preserve the extended properties from the key vault
        # secret record because they provide useful context to
        # locate the key vault secret that led to the event.
        'ext':
        util.merge_dicts(ext,
                         {'record_type': 'key_vault_secret_no_expiry_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'key_vault_secret_no_expiry_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }

    _log.info('Generating key_vault_secret_no_expiry_event; %r', event_record)
    yield event_record
Ejemplo n.º 28
0
def _get_azure_web_app_tls_event(com, ext, min_tls_version):
    """Evaluate Azure web app config for insecure min TLS version.

    Arguments:
        com (dict): Azure web app record `com` bucket
        ext (dict): Azure web app record `ext` bucket
        min_tls_version (float): Minimum required TLS version

    Returns:
        dict: An event record representing web apps not using a minimum
        TLS version

    """
    friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
    reference = com.get('reference')
    description = ('{} web app {} has insecure minimum TLS version.'.format(
        friendly_cloud_type, reference))
    recommendation = (
        'Check {} web app {} and ensure the minimum TLS version is set to {}.'.
        format(friendly_cloud_type, reference, str(min_tls_version)))

    event_record = {
        # Preserve the extended properties from the web app
        # record because they provide useful context to
        # locate the web app that led to the event.
        'ext': util.merge_dicts(ext, {'record_type': 'web_app_tls_event'}),
        'com': {
            'cloud_type': com.get('cloud_type'),
            'record_type': 'web_app_tls_event',
            'reference': reference,
            'description': description,
            'recommendation': recommendation,
        }
    }
    _log.info('Generating web_app_tls_event; %r', event_record)
    yield event_record
Ejemplo n.º 29
0
 def test_merge_second_dict_empty(self):
     a = {'a': 1}
     b = {}
     c = util.merge_dicts(a, b)
     self.assertEqual(c, {'a': 1})
Ejemplo n.º 30
0
 def test_merge_dicts_nested(self):
     a = {'a': 1, 'b': {'c': 2, 'd': 3}}
     b = {'a': 1, 'b': {'d': 4, 'e': 5}}
     c = util.merge_dicts(a, b)
     self.assertEqual(c, {'a': 1, 'b': {'c': 2, 'd': 4, 'e': 5}})