예제 #1
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
예제 #2
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
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
예제 #5
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
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
예제 #7
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
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
예제 #9
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
예제 #10
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
예제 #11
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
예제 #12
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
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
예제 #14
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
예제 #15
0
    def eval(self, record):
        """Evaluate firewall rules to check for insecurely exposed ports.

        Arguments:
            record (dict): A firewall rule record.

        Yields:
            dict: An event record representing an insecurely exposed port.

        """
        # If 'com' bucket is missing, we have a malformed record. Log a
        # warning and ignore it.
        com = record.get('com')
        if com is None:
            _log.warning('Firewall rule record is missing com key: %r', record)
            return

        # This plugin understands firewall rule records only, so ignore
        # any other record types.
        common_record_type = com.get('record_type')
        if common_record_type != 'firewall_rule':
            return

        # Ignore disabled firewall rule.
        if not com.get('enabled'):
            return

        # If the rule is not an ingress/inbound rule, ignore it.
        if com.get('direction') != 'in':
            return

        # If the rule is not an allow rule, ignore it.
        if com.get('access') != 'allow':
            return

        # If the rule is not a TCP port rule, ignore it.
        if com.get('protocol') not in ('tcp', 'all'):
            return

        # If the rule does not expose ports to the entire Internet,
        # ignore it.
        if '0.0.0.0/0' not in com.get('source_addresses'):
            return

        # Find the set of ports in self._ports that are exposed by the
        # firewall rule record.
        port_ranges = com.get('destination_ports')
        expanded_ports = util.expand_port_ranges(port_ranges)
        exposed_ports = self._ports.intersection(expanded_ports)

        # If there are no insecurely exposed ports, we do not need to
        # generate an event.
        if exposed_ports == set():
            return

        # Convert the set of ports to a sorted list of ports.
        exposed_ports = sorted(list(exposed_ports))

        # Human-friendly plain English description of the event along
        # with a recommendation.
        friendly_cloud_type = util.friendly_string(com.get('cloud_type'))
        port_label = util.pluralize(len(exposed_ports), 'port')
        friendly_exposed_ports = util.friendly_list(exposed_ports)
        reference = com.get('reference')
        description = (
            '{} firewall rule {} exposes {} {} to the entire Internet.'.format(
                friendly_cloud_type, reference, port_label,
                friendly_exposed_ports))
        recommendation = (
            'Check {} firewall rule {} and update rules to restrict '
            'access to {} {}.'.format(friendly_cloud_type, reference,
                                      port_label, friendly_exposed_ports))

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

        # Set the extended record type.
        event_record['ext']['record_type'] = 'firewall_rule_event'

        _log.info('Generating firewall_rule_event; %r', event_record)
        yield event_record
예제 #16
0
 def test_friendly_string_missing(self):
     s = util.friendly_string('foo')
     self.assertEqual(s, 'foo')
예제 #17
0
 def test_friendly_string_present(self):
     s = util.friendly_string('azure')
     self.assertEqual(s, 'Azure')