Ejemplo n.º 1
0
    def _get_binding_from_old_syntax(cls, rule_def):
        """Get a binding for configs set with the old syntax.

        Default fields to glob as default as that is what the fields used to be
        set.

        Args:
          rule_def (dict): raw rule definition.

        Returns:
          Binding: If an old style config field is set, returns a single binding
            with a single member.
        """
        keys = ['role', 'domain', 'group_email', 'user_email', 'special_group']
        for key in keys:
            if key in rule_def:
                return Binding(role=regular_exp.escape_and_globify(
                    rule_def.get('role', '*')),
                               members=[
                                   Member(
                                       regular_exp.escape_and_globify(
                                           rule_def.get('domain', '*')),
                                       regular_exp.escape_and_globify(
                                           rule_def.get('group_email', '*')),
                                       regular_exp.escape_and_globify(
                                           rule_def.get('user_email', '*')),
                                       regular_exp.escape_and_globify(
                                           rule_def.get('special_group', '*')),
                                   )
                               ])
        return None
Ejemplo n.º 2
0
def _parse_sink_rule_spec(sink_spec):
    """Validates and escapes a sink from a rule config.

    Args:
        sink_spec (dict): A sink definition from a LogSink rule definition.

    Returns:
        dict: A sink definition with fields escaped and globified, or None if
        sink_spec is invalid.
    """
    if not sink_spec:
        return None

    sink_destination = sink_spec.get('destination')
    sink_filter = sink_spec.get('filter')
    sink_include_children = sink_spec.get('include_children')
    # All fields are mandatory.
    if any(item is None
           for item in [sink_destination, sink_filter, sink_include_children]):
        return None

    # include_children will either match a boolean, or allow either.
    if sink_include_children.lower() not in ['*', 'true', 'false']:
        return None
    if sink_include_children != '*':
        sink_include_children = sink_include_children.lower() == 'true'
    return {
        'destination': escape_and_globify(sink_destination),
        'filter': escape_and_globify(sink_filter),
        'include_children': sink_include_children,
    }
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')

        for resource in resources:
            resource_ids = resource.get('resource_ids')

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            bucket = rule_def.get('bucket')
            entity = rule_def.get('entity')
            email = rule_def.get('email')
            domain = rule_def.get('domain')
            role = rule_def.get('role')

            if ((bucket is None) or (entity is None) or (email is None) or
                    (domain is None) or (role is None)):
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_def.get('name')))

            rule_def_resource = BucketAccessControls(
                project_id='',
                bucket=escape_and_globify(bucket),
                full_name='',
                entity=escape_and_globify(entity),
                email=escape_and_globify(email),
                domain=escape_and_globify(domain),
                role=escape_and_globify(role.upper()),
                raw_json=json.dumps(rule_def, sort_keys=True)
            )

            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        rules=rule_def_resource)

            resource_rules = self.resource_rules_map.get(rule_index)

            if not resource_rules:
                self.resource_rules_map[rule_index] = rule
Ejemplo n.º 4
0
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        resources = rule_def.get('resource')

        for resource in resources:
            resource_ids = resource.get('resource_ids')

            if not resource_ids or len(resource_ids) < 1:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing resource ids in rule {}'.format(rule_index))

            instance_name = rule_def.get('instance_name')
            authorized_networks = rule_def.get('authorized_networks')
            require_ssl = rule_def.get('ssl_enabled', '').lower() == 'true'

            if instance_name is None or authorized_networks is None:
                raise audit_errors.InvalidRulesSchemaError(
                    'Faulty rule {}'.format(rule_def.get('name')))

            rule_def_resource = CloudSqlAccessControl(
                project_id='',
                instance_name=escape_and_globify(instance_name),
                full_name='',
                ipv4_enabled=True,
                authorized_networks=escape_and_globify(authorized_networks),
                require_ssl=require_ssl,
                raw_json=json.dumps(rule_def, sort_keys=True)
            )

            rule = Rule(rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        rules=rule_def_resource)

            resource_rules = self.resource_rules_map.get(rule_index)

            if not resource_rules:
                self.resource_rules_map[rule_index] = rule
Ejemplo n.º 5
0
    def __init__(self, role_name, members=None):
        """Initialize.

        Args:
            role_name (str): The string name of the role.
            members (list): The role members of the policy binding.
        """
        if not role_name or not members:
            raise errors.InvalidIamPolicyBindingError(
                ('Invalid IAM policy binding: '
                 'role_name={}, members={}'.format(role_name, members)))
        self.role_name = role_name
        self.members = _get_iam_members(members)
        self.role_pattern = re.compile(escape_and_globify(role_name),
                                       flags=re.IGNORECASE)
Ejemplo n.º 6
0
    def __init__(self, member_type, member_name=None):
        """Initialize.

        Args:
            member_type (str): The string member type (see `member_types`).
            member_name (str): The string member name.
        """
        if not member_type or not self._member_type_exists(member_type):
            raise errors.InvalidIamPolicyMemberError(
                'Invalid policy member: {}'.format(member_type))
        self.type = member_type
        self.name = member_name
        self.name_pattern = None
        if member_name:
            self.name_pattern = re.compile(escape_and_globify(self.name),
                                           flags=re.IGNORECASE)
    def __init__(self, name, index, mode, applies_to, location_patterns):
        """Initialize.

        Args:
            name (str): Name of the loaded rule.
            index (int): The index of the rule from the rule definitions.
            mode (Mode): The mode of this rule.
            applies_to (List[str]): list of resource types that the rule applies
                to.
            location_patterns (List[str]): Forseti-style patterns for locations.
        """
        self.name = name
        self.index = index
        self.mode = mode
        self.applies_to = applies_to

        loc_re_str = '|'.join([
            regular_exp.escape_and_globify(loc_wildcard.lower())
            for loc_wildcard in location_patterns
        ])
        self.location_re = re.compile(loc_re_str)
Ejemplo n.º 8
0
    def _build_rule(cls, rule_def, rule_index):
        """Build a rule.

        Args:
            rule_def (dict): A dictionary containing rule definition
                properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.

        Returns:
            Rule: rule for the given definition.
        """
        dataset_ids = []
        for dataset_id in rule_def.get('dataset_ids', []):
            dataset_ids.append(regular_exp.escape_and_globify(dataset_id))

        # Check `dataset_id` for backwards compatibility.
        # TODO: stop supporting this.
        if 'dataset_id' in rule_def:
            dataset_ids.append(
                regular_exp.escape_and_globify(rule_def['dataset_id']))

        if not dataset_ids:
            raise audit_errors.InvalidRulesSchemaError(
                'Missing dataset_ids in rule {}'.format(rule_index))

        bindings = []

        # TODO: stop supporting this.
        binding = cls._get_binding_from_old_syntax(rule_def)
        if binding:
            bindings.append(binding)

        # Default mode to blacklist for backwards compatibility as that was
        # the behaviour before mode was configurable.
        # TODO: make mode required?
        mode = Mode(rule_def.get('mode', 'blacklist'))

        for raw_binding in rule_def.get('bindings', []):
            if 'role' not in raw_binding:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing role in binding in rule {}'.format(rule_index))
            role = regular_exp.escape_and_globify(raw_binding['role'])

            if 'members' not in raw_binding:
                raise audit_errors.InvalidRulesSchemaError(
                    'Missing members in binding in rule {}'.format(rule_index))

            members = []
            for raw_member in raw_binding['members']:
                fields = {
                    field:
                    regular_exp.escape_and_globify(raw_member.get(field))
                    for field in
                    ['domain', 'group_email', 'user_email', 'special_group']
                }

                # only one key should be set per member
                num_fields_set = sum(
                    [val is not None for val in list(fields.values())])
                if num_fields_set != 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'At most one member field may be set in rule {}'.
                        format(rule_index))
                members.append(Member(**fields))

            bindings.append(Binding(role, members))

        if not bindings:
            raise audit_errors.InvalidRulesSchemaError(
                'Missing bindings in rule {}'.format(rule_index))

        return Rule(rule_name=rule_def.get('name'),
                    rule_index=rule_index,
                    rule_reference=RuleReference(dataset_ids=dataset_ids,
                                                 bindings=bindings,
                                                 mode=mode))
    def add_rule(self, rule_def, rule_index):
        """Add a rule to the rule book.

        Add a rule to the rule book.

        The rule supplied to this method is the dictionary parsed from
        the rules definition file.

        For example, this rule...

        # rules yaml:
            rules:
          - name: all networks covered in whitelist
            project: '*'
            network: '*'
            is_external_network: True
            whitelist:
              master:
                - master-1
              network:
                - network-1
                - network-2
              default:
                - default-1

        ... gets parsed into:
        {
            "rules": [
                {
                    "name": "all networks covered in whitelist",
                    "project": "*",
                    "network": "*",
                    "is_external_network": true,
                    "whitelist": {
                        "master": [
                            "master-1"
                        ],
                        "network": [
                            "network-1",
                            "network-2"
                        ],
                        "default": [
                            "default-1"
                        ]
                    }
                }
            ]
        }

        Args:
            rule_def (dict): A dictionary containing rule definition properties.
            rule_index (int): The index of the rule from the rule definitions.
                Assigned automatically when the rule book is built.
        """
        project = rule_def.get('project')
        network = rule_def.get('network')
        whitelist = rule_def.get('whitelist')
        is_external_network = rule_def.get('is_external_network')

        if ((whitelist is None) or
                (project is None) or
                (network is None) or
                (is_external_network is None)):
            raise audit_errors.InvalidRulesSchemaError(
                'Faulty rule {}'.format(rule_def.get('name')))

        rule_def_resource = {'whitelist': whitelist,
                             'project': escape_and_globify(project),
                             'network': escape_and_globify(network),
                             'is_external_network': is_external_network}

        rule = Rule(rule_name=rule_def.get('name'),
                    rule_index=rule_index,
                    rules=rule_def_resource)

        resource_rules = self.resource_rules_map.get(rule_index)
        if not resource_rules:
            self.resource_rules_map[rule_index] = rule
Ejemplo n.º 10
0
    def add_rule(self, rule_def, rule_index):  # pylint: disable=too-many-locals
        """Add a rule to the rule book.

        Args:
            rule_def (dict): rule definition properties
            rule_index (int): index of the rule from the rule definitions,
                              assigned automatically when the rule book is built
        """
        self._rules_sema.acquire()

        try:
            for resource in rule_def.get('resource'):
                resource_ids = resource.get('resource_ids')
                resource_type = None
                try:
                    resource_type = resource_mod.ResourceType.verify(
                        resource.get('type'))
                except resource_errors.InvalidResourceTypeError:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource type in rule {}'.format(rule_index))

                if not resource_ids or len(resource_ids) < 1:
                    raise audit_errors.InvalidRulesSchemaError(
                        'Missing resource ids in rule {}'.format(rule_index))

                allowed_alternate_services = [
                    regular_exp.escape_and_globify(glob) for glob in
                    rule_def.get('allowed_alternate_services', '').split(',')
                    if glob
                ]
                allowed_direct_access_sources = [
                    regular_exp.escape_and_globify(glob)
                    for glob in rule_def.get('allowed_direct_access_sources',
                                             '').split(',') if glob
                ]
                allowed_iap_enabled = regular_exp.escape_and_globify(
                    rule_def.get('allowed_iap_enabled', '*'))

                # For each resource id associated with the rule, create a
                # mapping of resource => rules.
                for resource_id in resource_ids:
                    gcp_resource = resource_util.create_resource(
                        resource_id=resource_id, resource_type=resource_type)

                    rule = Rule(
                        rule_name=rule_def.get('name'),
                        rule_index=rule_index,
                        allowed_alternate_services=allowed_alternate_services,
                        allowed_direct_access_sources=(
                            allowed_direct_access_sources),
                        allowed_iap_enabled=allowed_iap_enabled)

                    rule_applies_to = resource.get('applies_to')
                    rule_key = (gcp_resource, rule_applies_to)

                    # See if we have a mapping of the resource and rule
                    resource_rules = self.resource_rules_map.get(rule_key)

                    # If no mapping exists, create it.
                    if not resource_rules:
                        resource_rules = ResourceRules(
                            resource=gcp_resource,
                            applies_to=rule_applies_to,
                            inherit_from_parents=rule_def.get(
                                'inherit_from_parents', False))
                        self.resource_rules_map[rule_key] = resource_rules

                    # If the rule isn't in the mapping, add it.
                    if rule not in resource_rules.rules:
                        resource_rules.rules.add(rule)
        finally:
            self._rules_sema.release()