Exemplo n.º 1
0
 def _check_policy_document(
     self, result: Result, logical_id: str, policy_document: PolicyDocument, policy_name: Optional[str], extras: Dict
 ):
     statements_to_review = policy_document.statements_with(REGEX_IS_STAR) + policy_document.statements_with(
         REGEX_WILDCARD_ARN
     )
     for statement in statements_to_review:
         self._check_statement(result, logical_id, policy_name, statement, extras=extras)
Exemplo n.º 2
0
def test_get_iam_actions():

    correct_list = [
        "IAM:DeleteAccountPasswordPolicy",
        "IAM:DeleteServiceLinkedRole",
        "IAM:DeleteRole",
        "IAM:DeleteOpenIDConnectProvider",
        "IAM:DeleteGroup",
        "IAM:DeleteRolePolicy",
        "IAM:DeleteSSHPublicKey",
        "IAM:DeleteLoginProfile",
        "IAM:DeleteServiceSpecificCredential",
        "IAM:DeleteUserPolicy",
        "IAM:DeleteVirtualMFADevice",
        "IAM:DeletePolicyVersion",
        "IAM:DeleteGroupPolicy",
        "IAM:DeleteAccountAlias",
        "IAM:DeleteSigningCertificate",
        "IAM:DeleteUser",
        "IAM:DeletePolicy",
        "IAM:DeleteSAMLProvider",
        "IAM:DeleteAccessKey",
        "IAM:DeleteServerCertificate",
        "IAM:DeleteInstanceProfile",
    ]

    pd = {
        "PolicyDocument": {
            "Statement": [
                {
                    "Action": [
                        "IAM:Delete*"
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                    "NotPrincipal": {
                        "AWS": [
                            "156460612806"
                        ]
                    }
                }
            ]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])

    actions = document.get_iam_actions()

    assert len(actions) == 21
    assert correct_list == actions
Exemplo n.º 3
0
def test_star_resource():
    pd = {
        "PolicyDocument": {
            "Statement": [{
                "Action": ["*"],
                "Effect": "Allow",
                "Resource": "*",
                "Principal": {
                    "AWS": ["156460612806"]
                }
            }]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.star_resource_statements()) == 1
Exemplo n.º 4
0
def test_not_principla():
    pd = {
        "PolicyDocument": {
            "Statement": [{
                "Action": ["*"],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                "NotPrincipal": {
                    "AWS": ["156460612806"]
                }
            }]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.allows_not_principal()) == 1
Exemplo n.º 5
0
def test_multi_statements():
    pd = {
        "doc": {
            "Version":
            "2012-10-17",
            "Statement": [{
                "Effect": "Allow",
                "Principal": {
                    "Service": ["ec2.amazonaws.com"],
                    "AWS": "arn:aws:iam::324320755747:root"
                },
                "Action": ["sts:AssumeRole"]
            }, {
                "Effect": "bar",
                "Principal": {
                    "Service": ["ec2.amazonaws.com"],
                    "AWS": "arn:aws:iam::324320755747:root"
                },
                "Action": ["sts:AssumeRole"]
            }]
        }
    }

    document = PolicyDocument(pd["doc"])
    statement1 = document.statements[0]
    assert statement1.effect == "Allow"
    statement2 = document.statements[1]
    assert statement2.effect == "bar"
Exemplo n.º 6
0
def policy_document_not_principal():
    return PolicyDocument(
        **{
            "Statement": [
                {
                    "Action": [
                        "iam:Delete*",
                        "s3:GetObject*",
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                    "NotPrincipal": {
                        "AWS": ["156460612806"]
                    },
                },
                {
                    "Action": [
                        "s3:List*",
                    ],
                    "Effect": "Deny",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                    "NotPrincipal": {
                        "AWS": ["156460612806"]
                    },
                },
            ]
        })
Exemplo n.º 7
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         for policy in resource.policy_documents:
             self._check_policy_document(result, logical_id,
                                         policy.policy_document,
                                         policy.name, extras)
         if isinstance(resource, IAMRole):
             self._check_policy_document(
                 result, logical_id,
                 resource.Properties.AssumeRolePolicyDocument, None, extras)
         elif isinstance(resource, KMSKey):
             self._check_policy_document(result, logical_id,
                                         resource.Properties.KeyPolicy,
                                         None, extras)
         elif isinstance(resource, GenericResource):
             if hasattr(resource, "Properties"):
                 policy_document = resource.Properties.get("PolicyDocument")
                 if policy_document:
                     self._check_policy_document(
                         result, logical_id,
                         PolicyDocument(**policy_document), None, extras)
     return result
Exemplo n.º 8
0
def test_wildcard_actions():
    pd = {
        "PolicyDocument": {
            "Statement": [{
                "Action": ["s3:*"],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::fakebucketfakebucket2/*",
                "Principal": {
                    "AWS": "*"
                }
            }]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.wildcard_allowed_actions()) == 1
    assert len(
        document.wildcard_allowed_actions(pattern=r"^(\w*:){0,1}\*$")) == 1
Exemplo n.º 9
0
 def _check_policy_document(self, result: Result, logical_id: str,
                            policy_document: PolicyDocument,
                            policy_name: Optional[str], extras: Dict):
     for statement in policy_document.statements_with(REGEX_IS_STAR):
         self._check_statement(result,
                               logical_id,
                               policy_name,
                               statement,
                               extras=extras)
Exemplo n.º 10
0
def test_get_iam_actions():

    correct_list = [
        "IAM:DeleteAccountPasswordPolicy",
        "IAM:DeleteServiceLinkedRole",
        "IAM:DeleteRole",
        "IAM:DeleteOpenIDConnectProvider",
        "IAM:DeleteGroup",
        "IAM:DeleteRolePolicy",
        "IAM:DeleteSSHPublicKey",
        "IAM:DeleteLoginProfile",
        "IAM:DeleteServiceSpecificCredential",
        "IAM:DeleteUserPolicy",
        "IAM:DeleteVirtualMFADevice",
        "IAM:DeletePolicyVersion",
        "IAM:DeleteGroupPolicy",
        "IAM:DeleteAccountAlias",
        "IAM:DeleteSigningCertificate",
        "IAM:DeleteUser",
        "IAM:DeletePolicy",
        "IAM:DeleteSAMLProvider",
        "IAM:DeleteAccessKey",
        "IAM:DeleteServerCertificate",
        "IAM:DeleteInstanceProfile",
    ]

    pd = {
        "PolicyDocument": {
            "Statement": [{
                "Action": ["IAM:Delete*"],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                "NotPrincipal": {
                    "AWS": ["156460612806"]
                }
            }]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])

    actions = document.get_iam_actions()

    assert len(actions) == 21
    assert correct_list == actions
Exemplo n.º 11
0
def policy_document_one_statement():
    return PolicyDocument(
        **{
            "Version": "2012-10-17",
            "Statement": {
                "Effect": "Allow",
                "Principal": {"Service": ["ec2.amazonaws.com"], "AWS": "arn:aws:iam::324320755747:root"},
                "Action": ["sts:AssumeRole"],
            },
        }
    )
Exemplo n.º 12
0
def policy_document_wildcard_actions():
    return PolicyDocument(
        **{
            "Statement": [{
                "Action": ["s3:*"],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::fakebucketfakebucket2/*",
                "Principal": {
                    "AWS": "*"
                },
            }]
        })
Exemplo n.º 13
0
def policy_document_star_resource():
    return PolicyDocument(
        **{
            "Statement": [{
                "Action": ["*"],
                "Effect": "Allow",
                "Resource": "*",
                "Principal": {
                    "AWS": ["156460612806"]
                }
            }]
        })
Exemplo n.º 14
0
def test_not_principla():
    pd = {
        "PolicyDocument": {
            "Statement": [
                {
                    "Action": [
                        "*"
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                    "NotPrincipal": {
                        "AWS": [
                            "156460612806"
                        ]
                    }
                }
            ]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.allows_not_principal()) == 1
Exemplo n.º 15
0
def policy_document_not_principal():
    return PolicyDocument(
        **{
            "Statement": [{
                "Action": ["IAM:Delete*"],
                "Effect": "Allow",
                "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                "NotPrincipal": {
                    "AWS": ["156460612806"]
                },
            }]
        })
Exemplo n.º 16
0
def test_wildcard_actions():
    pd = {
        "PolicyDocument": {
            "Statement": [
                {
                    "Action": [
                        "s3:*"
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket2/*",
                    "Principal": {
                        "AWS": "*"
                    }
                }
            ]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.wildcard_allowed_actions()) == 1
    assert len(document.wildcard_allowed_actions(
        pattern=r"^(\w*:){0,1}\*$")) == 1
Exemplo n.º 17
0
def test_star_resource():
    pd = {
        "PolicyDocument": {
            "Statement": [
                {
                    "Action": [
                        "*"
                    ],
                    "Effect": "Allow",
                    "Resource": "*",
                    "Principal": {
                        "AWS": [
                            "156460612806"
                        ]
                    }
                }
            ]
        }
    }
    document = PolicyDocument(pd["PolicyDocument"])
    assert len(document.star_resource_statements()) == 1
Exemplo n.º 18
0
    def resource_invoke(self,
                        resource: Resource,
                        logical_id: str,
                        extras: Optional[Dict] = None) -> Result:
        """
        Checks each policy of a given resource.
        If it's an IAMRole, it will check its AssumeRolePolicyDocument as well.
        There are some cases where GenericResource contains a property called PolicyDocument that can be a str and
        therefore, it's not being retrieved in the initial for loop.
        For those cases, we run another check transforming the str to a PolicyDocument.
        """
        result = Result()

        for policy in resource.policy_documents:
            self._check_policy_document(result,
                                        logical_id,
                                        policy.policy_document,
                                        policy.name,
                                        extras,
                                        resource_type=resource.Type)

        if isinstance(resource, IAMRole):
            self._check_policy_document(
                result,
                logical_id,
                resource.Properties.AssumeRolePolicyDocument,
                None,
                extras,
                resource_type=resource.Type,
            )
        elif isinstance(resource, GenericResource):
            policy_document = getattr(resource.Properties, "PolicyDocument",
                                      None)
            if policy_document:
                try:
                    formatted_policy_document = (
                        json.loads(policy_document) if isinstance(
                            policy_document, str) else policy_document)
                    self._check_policy_document(
                        result,
                        logical_id,
                        PolicyDocument(**formatted_policy_document),
                        None,
                        extras,
                        resource_type=resource.Type,
                    )
                except Exception:
                    logger.warning(
                        f"Could not process the PolicyDocument {policy_document} on {logical_id}",
                        stack_info=True)

        return result
Exemplo n.º 19
0
def policy_document_condition_with_source_vpce():
    return PolicyDocument(
        **{
            "Statement": [
                {
                    "Action": ["s3:ListBucket"],
                    "Condition": {"IpAddress": {"aws:SourceVpce": ["vpce-123456"]}},
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                },
            ],
        }
    )
Exemplo n.º 20
0
def policy_document_condition_with_source_ip():
    return PolicyDocument(
        **{
            "Statement": [
                {
                    "Action": ["s3:ListBucket"],
                    "Condition": {"IpAddress": {"aws:SourceIp": ["116.202.65.160", "116.202.68.32/27"]}},
                    "Effect": "Allow",
                    "Principal": {"AWS": "*"},
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                },
            ],
        }
    )
Exemplo n.º 21
0
def policy_document_not_action():
    return PolicyDocument(
        **{
            "Statement": [
                {
                    "NotAction": [
                        "rds:*",
                    ],
                    "Effect": "Allow",
                    "Resource": "arn:aws:s3:::fakebucketfakebucket/*",
                    "NotPrincipal": {"AWS": ["156460612806"]},
                },
            ]
        }
    )
Exemplo n.º 22
0
def test_can_obtain_policy_documents_from_inherited_method(valid_opensearch_domain_with_access_policies):
    assert len(valid_opensearch_domain_with_access_policies.policy_documents) == 1
    assert valid_opensearch_domain_with_access_policies.policy_documents == [
        OptionallyNamedPolicyDocument(
            policy_document=PolicyDocument(
                Statement=[
                    Statement(
                        Effect="Allow",
                        Action="es:*",
                        Resource="arn:aws:es:us-east-1:123456789012:domain/test/*",
                        Principal=Principal(AWS="arn:aws:iam::123456789012:user/opensearch-user"),
                    )
                ]
            ),
            name=None,
        ),
    ]
Exemplo n.º 23
0
 def invoke(self,
            cfmodel: CFModel,
            extras: Optional[Dict] = None) -> Result:
     result = Result()
     for logical_id, resource in cfmodel.Resources.items():
         if isinstance(resource, IAMPolicy):
             self._check_policy_document(result, logical_id,
                                         resource.Properties.PolicyDocument,
                                         resource.Properties.PolicyName,
                                         extras)
         elif isinstance(resource, (IAMManagedPolicy, S3BucketPolicy,
                                    SNSTopicPolicy, SQSQueuePolicy)):
             self._check_policy_document(result, logical_id,
                                         resource.Properties.PolicyDocument,
                                         None, extras)
         elif isinstance(resource, IAMRole):
             self._check_policy_document(
                 result, logical_id,
                 resource.Properties.AssumeRolePolicyDocument, None, extras)
             if resource.Properties.Policies:
                 for policy in resource.Properties.Policies:
                     self._check_policy_document(result, logical_id,
                                                 policy.PolicyDocument,
                                                 policy.PolicyName, extras)
         elif isinstance(
                 resource, IAMUser
         ) and resource.Properties and resource.Properties.Policies:
             for policy in resource.Properties.Policies:
                 self._check_policy_document(result, logical_id,
                                             policy.PolicyDocument,
                                             policy.PolicyName, extras)
         elif isinstance(resource, KMSKey):
             self._check_policy_document(result, logical_id,
                                         resource.Properties.KeyPolicy,
                                         None, extras)
         elif isinstance(resource, GenericResource):
             if hasattr(resource, "Properties"):
                 policy_document = resource.Properties.get("PolicyDocument")
                 if policy_document:
                     self._check_policy_document(
                         result, logical_id,
                         PolicyDocument(**policy_document), None, extras)
     return result
Exemplo n.º 24
0
    def check_for_wildcards(
        self,
        result: Result,
        logical_id: str,
        resource: PolicyDocument,
        resource_type: str,
        extras: Optional[Dict] = None,
    ):
        for statement in resource.statement_as_list():
            if statement.Effect == "Allow" and statement.principals_with(
                    self.FULL_REGEX):
                for principal in statement.get_principal_list():
                    account_id_match = self.IAM_PATTERN.match(
                        principal) or self.AWS_ACCOUNT_ID_PATTERN.match(
                            principal)
                    account_id = account_id_match.group(
                        1) if account_id_match else None

                    # Check if account ID is allowed. `self._get_allowed_from_config()` used here
                    # to reduce number of false negatives and only allow exemptions for accounts
                    # which belong to AWS Services (such as ELB and ElastiCache).
                    if account_id in self._get_allowed_from_config():
                        continue
                    if statement.Condition and statement.Condition.dict():
                        # Ignoring condition checks since they will get reviewed in other rules and future improvements
                        continue
                    else:
                        self.add_failure_to_result(
                            result,
                            self.REASON_WILDCARD_PRINCIPAL.format(
                                logical_id, principal),
                            resource_ids={logical_id},
                            resource_types={resource_type},
                            context={
                                "config": self._config,
                                "extras": extras,
                                "logical_id": logical_id,
                                "resource": resource,
                                "statement": statement,
                                "principal": principal,
                                "account_id": account_id,
                            },
                        )
Exemplo n.º 25
0
    def check_for_wildcards(self, result: Result, logical_id: str, resource: PolicyDocument):
        for statement in resource._statement_as_list():
            if statement.Effect == "Allow" and statement.principals_with(self.FULL_REGEX):
                for principal in statement.get_principal_list():
                    # Check if account ID is allowed
                    account_id_match = self.IAM_PATTERN.match(principal)
                    if account_id_match:
                        self.validate_account_id(result, logical_id, account_id_match.group(1))

                    if statement.Condition and statement.Condition.dict():
                        logger.warning(
                            f"Not adding {type(self).__name__} failure in {logical_id} because there are conditions: "
                            f"{statement.Condition}"
                        )
                    elif not self.resource_is_whitelisted(logical_id):
                        self.add_failure_to_result(
                            result,
                            self.REASON_WILCARD_PRINCIPAL.format(logical_id, principal),
                            resource_ids={logical_id},
                        )
Exemplo n.º 26
0
    def check_for_wildcards(
        self,
        result: Result,
        logical_id: str,
        resource: PolicyDocument,
        resource_type: str,
        extras: Optional[Dict] = None,
    ):
        for statement in resource.statement_as_list():
            filtered_principals = statement.principals_with(self.FULL_REGEX)
            if statement.Effect == "Allow" and filtered_principals:
                for principal in filtered_principals:
                    # if we can't find the account ID it might be a canonical ID
                    identifier = get_account_id_from_principal(
                        principal) or principal

                    # Check if account ID / canonical ID is allowed. `self._get_allowed_from_config()` used here
                    # to reduce number of false negatives and only allow exemptions for accounts
                    # which belong to AWS Services (such as ELB and ElastiCache).
                    if identifier in self._get_allowed_from_config():
                        continue
                    if statement.Condition and statement.Condition.dict():
                        # Ignoring condition checks since they will get reviewed in other rules and future improvements
                        continue
                    else:
                        self.add_failure_to_result(
                            result,
                            self.REASON_WILDCARD_PRINCIPAL.format(
                                logical_id, principal),
                            resource_ids={logical_id},
                            resource_types={resource_type},
                            context={
                                "config": self._config,
                                "extras": extras,
                                "logical_id": logical_id,
                                "resource": resource,
                                "statement": statement,
                                "principal": principal,
                                "account_id": identifier,
                            },
                        )
Exemplo n.º 27
0
    def check_for_wildcards(self,
                            result: Result,
                            logical_id: str,
                            resource: PolicyDocument,
                            extras: Optional[Dict] = None):
        for statement in resource._statement_as_list():
            if statement.Effect == "Allow" and statement.principals_with(
                    self.FULL_REGEX):
                for principal in statement.get_principal_list():
                    account_id_match = self.IAM_PATTERN.match(principal)
                    account_id = account_id_match.group(
                        1) if account_id_match else None

                    # Check if account ID is allowed. `self._get_allowed_from_config()` used here
                    # to reduce number of false negatives and only allow exemptions for accounts
                    # which belong to AWS Services (such as ELB and ElastiCache).
                    if account_id in self._get_allowed_from_config():
                        continue

                    if statement.Condition and statement.Condition.dict():
                        logger.warning(
                            f"Not adding {type(self).__name__} failure in {logical_id} because there are conditions: "
                            f"{statement.Condition}")
                    else:
                        self.add_failure_to_result(
                            result,
                            self.REASON_WILCARD_PRINCIPAL.format(
                                logical_id, principal),
                            resource_ids={logical_id},
                            context={
                                "config": self._config,
                                "extras": extras,
                                "logical_id": logical_id,
                                "resource": resource,
                                "statement": statement,
                                "principal": principal,
                                "account_id": account_id,
                            },
                        )
Exemplo n.º 28
0
                         "Statement": [{
                             "Effect": "Allow",
                             "Action": ["service:GetService"],
                             "Resource": "*",
                         }],
                     },
                 },
             }
         },
     },
     [
         OptionallyNamedPolicyDocument(
             policy_document=PolicyDocument(Statement=[
                 Statement(
                     Effect="Allow",
                     Action=["service:GetService"],
                     Resource="*",
                 )
             ]),
             name=None,
         )
     ],
     1,
 ),
 (
     {
         "AWSTemplateFormatVersion": "2010-09-09",
         "Description":
         "Test resolving a nonexistent resource to Resource class",
         "Resources": {
             "NonexistentResource": {
Exemplo n.º 29
0
def policy_document_kms_key():
    return PolicyDocument(
        **{
            "Version": "2012-10-17",
            "Id": "key-consolepolicy-2",
            "Statement": [
                {
                    "Sid": "Enable IAM policies",
                    "Effect": "Allow",
                    "Principal": {"AWS": "arn:aws:iam::111122223333:root"},
                    "Action": "kms:*",
                    "Resource": "*",
                },
                {
                    "Sid": "Allow access for Key Administrators",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [
                            "arn:aws:iam::111122223333:user/KMSAdminUser",
                            "arn:aws:iam::111122223333:role/KMSAdminRole",
                        ]
                    },
                    "Action": [
                        "kms:Create*",
                        "kms:Describe*",
                        "kms:Enable*",
                        "kms:List*",
                        "kms:Put*",
                        "kms:Update*",
                        "kms:Revoke*",
                        "kms:Disable*",
                        "kms:Get*",
                        "kms:Delete*",
                        "kms:TagResource",
                        "kms:UntagResource",
                        "kms:ScheduleKeyDeletion",
                        "kms:CancelKeyDeletion",
                    ],
                    "Resource": "*",
                },
                {
                    "Sid": "Allow use of the key",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [
                            "arn:aws:iam::111122223333:user/ExampleUser",
                            "arn:aws:iam::111122223333:role/ExampleRole",
                            "arn:aws:iam::444455556666:root",
                        ]
                    },
                    "Action": [
                        "kms:Encrypt",
                        "kms:Decrypt",
                        "kms:ReEncrypt*",
                        "kms:GenerateDataKey*",
                        "kms:DescribeKey",
                    ],
                    "Resource": "*",
                },
                {
                    "Sid": "Allow attachment of persistent resources",
                    "Effect": "Allow",
                    "Principal": {
                        "AWS": [
                            "arn:aws:iam::111122223333:user/ExampleUser",
                            "arn:aws:iam::111122223333:role/ExampleRole",
                            "arn:aws:iam::444455556666:root",
                        ]
                    },
                    "Action": ["kms:CreateGrant", "kms:ListGrants", "kms:RevokeGrant"],
                    "Resource": "*",
                    "Condition": {"Bool": {"kms:GrantIsForAWSResource": True}},
                },
            ],
        }
    )