How to use the parliament.misc.make_list function in parliament

To help you get started, we’ve selected a few parliament examples, based on popular ways it is used in public projects.

Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.

github duo-labs / parliament / parliament / statement.py View on Github external
for key in principal:
                if key == "AWS":
                    for aws_principal in make_list(principal[key]):
                        account_id_regex = re.compile("^\d{12}$")
                        arn_regex = re.compile("^arn:[-a-z\*]*:iam::(\d{12}|):.*$")

                        if aws_principal == "*":
                            pass
                        elif account_id_regex.match(aws_principal):
                            pass
                        elif arn_regex.match(aws_principal):
                            pass
                        else:
                            self.add_finding("UNKNOWN_PRINCIPAL", detail=aws_principal)
                elif key == "Federated":
                    for federation in make_list(principal[key]):
                        saml_regex = re.compile(
                            "^arn:[-a-z\*]*:iam::\d{12}:saml-provider/.*$"
                        )
                        if federation in [
                            "cognito-identity.amazonaws.com",
                            "www.amazon.com",
                            "graph.facebook.com",
                            "accounts.google.com",
                        ]:
                            pass
                        elif saml_regex.match(federation):
                            pass
                        else:
                            self.add_finding(
                                "UNKNOWN_FEDERATION_SOURCE", detail=federation
                            )
github duo-labs / parliament / parliament / statement.py View on Github external
def in_actions(self, privilege_prefix, privilege_name):
        """
        Given "s3" "GetObject", determine if the privilege is in this statement.
        This could happen either because the Action is ["s3:GetObject"] or ["s3:*", "ec2:*"]
        or because the action is not in the NotAction. For example, if we have an Allow on NotAction "ec2:*",
        then this, with "s3" "GetObject" returns True.
        """

        if "Action" in self.stmt:
            for action in make_list(self.stmt["Action"]):
                if action == "*" or action == "*:*":
                    return True

                expanded_actions = expand_action(action, raise_exceptions=False)

                for action_struct in expanded_actions:
                    if (
                        action_struct["service"] == privilege_prefix
                        and action_struct["action"] == privilege_name
                    ):
                        return True
            return False

        # Else, we're dealing with a NotAction
        for action in make_list(self.stmt["NotAction"]):
            if action == "*" or action == "*:*":
github duo-labs / parliament / parliament / statement.py View on Github external
if "Resource" in self.stmt:
            resources = make_list(self.stmt["Resource"])
        elif "NotResource" in self.stmt:
            resources = make_list(self.stmt["NotResource"])
        else:
            self.add_finding(
                "MALFORMED",
                detail="Statement contains neither Resource nor NotResource",
                location={"string": self.stmt},
            )
            return False

        # Check if a Condition element exists and if so save them for later
        if "Condition" in self.stmt:
            conditions = make_list(self.stmt["Condition"])
            if len(conditions) > 1:
                self.add_finding(
                    "MALFORMED",
                    detail="Condition formatted incorrectly",
                    location={"string": self.stmt},
                )
                return False

        # Expand the actions from s3:Get* to s3:GetObject and others
        expanded_actions = []
        for action in actions:
            # Handle special case where all actions are allowed
            if action == "*" or action == "*:*":
                # TODO Should ensure the resource is "*" with this action
                continue
github duo-labs / parliament / parliament / statement.py View on Github external
return False

        for key in condition_block:

            # Check for known bad pattern
            if operator.lower() == "bool":
                if key.lower() == "aws:MultiFactorAuthPresent".lower() and "false" in make_list(
                    condition_block[key]
                ):
                    self.add_finding(
                        "BAD_PATTERN_FOR_MFA",
                        detail='The condition {"Bool": {"aws:MultiFactorAuthPresent":"false"}} is bad because aws:MultiFactorAuthPresent may not exist so it does not enforce MFA. You likely want to use a Deny with BoolIfExists.',
                        location={"location": condition_block},
                    )
            elif operator.lower() == "null":
                if key.lower == "aws:MultiFactorAuthPresent".lower() and "false" in make_list(
                    condition_block[key]
                ):
                    self.add_finding(
                        "BAD_PATTERN_FOR_MFA",
                        detail='The condition {"Null": {"aws:MultiFactorAuthPresent":"false"}} is bad because aws:MultiFactorAuthPresent it does not enforce MFA, and only checks if the value exists. You likely want to use an Allow with {"Bool": {"aws:MultiFactorAuthPresent":"true"}}.',
                        location={"location": condition_block},
                    )
            
            if operator.lower() in ["null"]:
                # The following condition is valid:
                # "Condition": { "Null": { "aws:MultiFactorAuthAge": true }
                # If we check further we'll get a MISMATCHED_TYPE finding due to
                # aws:MultiFactorAuthAge being checked against a bool value instead of a date
                continue
            
            # The key here from the example is "s3:prefix"
github duo-labs / cloudmapper / parliament / statement.py View on Github external
privilege_info = get_privilege_info(privilege_prefix, privilege_name)

        # Iterate through the resources defined in the action definition
        for resource_type in privilege_info["resource_types"]:
            resource_type = resource_type["resource_type"]

            # Only check the required resources which have a "*" at the end
            if "*" not in resource_type:
                continue

            arn_format = get_arn_format(
                resource_type, privilege_info["service_resources"]
            )

            # At least one resource has to match the action's required resources
            for resource in make_list(self.stmt["Resource"]):
                if is_arn_match(resource_type, arn_format, resource):
                    affected_resources.append(resource)
                elif resource == "*":
                    affected_resources.append(resource)

        # Ensure we match on "*"
        for resource in make_list(self.stmt["Resource"]):
            if resource == "*":
                affected_resources.append(resource)

        return affected_resources
github duo-labs / parliament / parliament / statement.py View on Github external
)
            
            if operator.lower() in ["null"]:
                # The following condition is valid:
                # "Condition": { "Null": { "aws:MultiFactorAuthAge": true }
                # If we check further we'll get a MISMATCHED_TYPE finding due to
                # aws:MultiFactorAuthAge being checked against a bool value instead of a date
                continue
            
            # The key here from the example is "s3:prefix"
            condition_type = get_global_key_type(key)
            if condition_type:
                # This is a global key, like aws:CurrentTime
                # Check if the values match the type (ex. must all be Date values)
                if not is_value_in_correct_format_for_type(
                    condition_type, make_list(condition_block[key])
                ):
                    self.add_finding(
                        "MISMATCHED_TYPE",
                        detail="Type mismatch: {} requires a value of type {} but given {}".format(
                            key, condition_type, condition_block[key]
                        ),
                        location={"location": condition_block},
                    )
            else:
                # See if this is a service specific key
                for action_struct in expanded_actions:
                    privilege_info = get_privilege_info(
                        action_struct["service"], action_struct["action"]
                    )

                    # Ensure the condition_key exists
github duo-labs / parliament / parliament / cli.py View on Github external
def is_finding_filtered(finding, minimum_severity="LOW"):
    # Return True if the finding should not be displayed
    minimum_severity = minimum_severity.upper()
    severity_choices = ["MUTE", "INFO", "LOW", "MEDIUM", "HIGH", "CRITICAL"]
    if severity_choices.index(finding.severity) < severity_choices.index(
        minimum_severity
    ):
        return True

    if finding.ignore_locations:
        for location_type, locations_to_ignore in finding.ignore_locations.items():
            for location_to_ignore in make_list(locations_to_ignore):
                if (
                    location_to_ignore.lower()
                    in str(finding.location.get(location_type, "")).lower()
                ):
                    return True
    return False
github duo-labs / cloudmapper / parliament / statement.py View on Github external
"Null operation requires being matched against true or false but given {}".format(
                        condition_block
                    ),
                    severity.INVALID,
                    location={"location": condition_block},
                )
                return False

        for key in condition_block:
            # The key here from the example is "s3:prefix"
            condition_type = get_global_key_type(key)
            if condition_type:
                # This is a global key, like aws:CurrentTime
                # Check if the values match the type (ex. must all be Date values)
                if not is_value_in_correct_format_for_type(
                    condition_type, make_list(condition_block[key])
                ):
                    self.add_finding(
                        "Type mismatch: {} requires a value of type {} but given {}".format(
                            key, condition_type, condition_block[key]
                        ),
                        severity.INVALID,
                        location={"location": condition_block},
                    )
            else:
                # See if this is a service specific key
                for action_struct in expanded_actions:
                    privilege_info = get_privilege_info(
                        action_struct["service"], action_struct["action"]
                    )

                    # Ensure the condition_key exists
github duo-labs / cloudmapper / parliament / statement.py View on Github external
if "Resource" in self.stmt:
            resources = make_list(self.stmt["Resource"])
        elif "NotResource" in self.stmt:
            resources = make_list(self.stmt["NotResource"])
        else:
            self.add_finding(
                "Statement contains neither Resource nor NotResource",
                severity.MALFORMED,
                location={"string": self.stmt},
            )
            return False

        # Check if a Condition element exists and if so save them for later
        if "Condition" in self.stmt:
            conditions = make_list(self.stmt["Condition"])
            if len(conditions) > 1:
                self.add_finding(
                    "Condition formatted incorrectly",
                    severity.MALFORMED,
                    location={"string": self.stmt},
                )
                return False

        # Expand the actions from s3:Get* to s3:GetObject and others
        expanded_actions = []
        for action in actions:
            # Handle special case where all actions are allowed
            if action == "*" or action == "*:*":
                # TODO Should ensure the resource is "*" with this action
                continue
github duo-labs / parliament / parliament / statement.py View on Github external
if "Sid" in self.stmt and not re.fullmatch("[0-9A-Za-z]*", self.stmt["Sid"]):
            # The grammar is defined at https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_grammar.html
            self.add_finding("INVALID_SID", detail=self.stmt)
            return False

        # Check Action
        if "Action" in self.stmt and "NotAction" in self.stmt:
            self.add_finding(
                "MALFORMED",
                detail="Statement contains both Action and NotAction",
                location={"string": self.stmt},
            )
            return False

        if "Action" in self.stmt:
            actions = make_list(self.stmt["Action"])
        elif "NotAction" in self.stmt:
            actions = make_list(self.stmt["NotAction"])
        else:
            self.add_finding(
                "MALFORMED",
                detail="Statement contains neither Action nor NotAction",
                location={"string": self.stmt},
            )
            return False

        # Check Resource exists and save the list of resources for later
        if "Resource" in self.stmt and "NotResource" in self.stmt:
            self.add_finding(
                "MALFORMED",
                detail="Statement contains both Resource and NotResource",
                location={"string": self.stmt},