fix(iam_policy_no_administrative_privileges): check attached policies and AWS-Managed (#2200)

Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
Sergio Garcia
2023-04-19 14:34:53 +02:00
committed by GitHub
parent 10d744704a
commit 7a00f79a56
40 changed files with 1025 additions and 361 deletions

View File

@@ -0,0 +1,165 @@
from re import search
from unittest import mock
from boto3 import client, session
from moto import mock_iam
from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_iam_aws_attached_policy_no_administrative_privileges_test:
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
session_config=None,
original_session=None,
audit_session=session.Session(
profile_name=None,
botocore_session=None,
),
audited_account=AWS_ACCOUNT_NUMBER,
audited_user_id=None,
audited_partition="aws",
audited_identity_arn=None,
profile=None,
profile_region=None,
credentials=None,
assumed_role_info=None,
audited_regions=["us-east-1", "eu-west-1"],
organizations_metadata=None,
audit_resources=None,
)
return audit_info
@mock_iam
def test_policy_with_administrative_privileges(self):
iam_client = client("iam")
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
iam_client.attach_role_policy(
PolicyArn="arn:aws:iam::aws:policy/AdministratorAccess", RoleName="my-role"
)
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges import (
iam_aws_attached_policy_no_administrative_privileges,
)
check = iam_aws_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "AdministratorAccess":
assert result.status == "FAIL"
assert (
result.resource_arn
== "arn:aws:iam::aws:policy/AdministratorAccess"
)
assert search(
"AWS policy AdministratorAccess is attached and allows ",
result.status_extended,
)
@mock_iam
def test_policy_non_administrative(self):
iam_client = client("iam")
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
iam_client.attach_role_policy(
PolicyArn="arn:aws:iam::aws:policy/IAMUserChangePassword",
RoleName="my-role",
)
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges import (
iam_aws_attached_policy_no_administrative_privileges,
)
check = iam_aws_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "IAMUserChangePassword":
assert result.status == "PASS"
assert (
result.resource_arn
== "arn:aws:iam::aws:policy/IAMUserChangePassword"
)
assert search(
"AWS policy IAMUserChangePassword is attached but does not allow",
result.status_extended,
)
@mock_iam
def test_policy_administrative_and_non_administrative(self):
iam_client = client("iam")
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
iam_client.attach_role_policy(
PolicyArn="arn:aws:iam::aws:policy/AdministratorAccess", RoleName="my-role"
)
iam_client.attach_role_policy(
PolicyArn="arn:aws:iam::aws:policy/IAMUserChangePassword",
RoleName="my-role",
)
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_aws_attached_policy_no_administrative_privileges.iam_aws_attached_policy_no_administrative_privileges import (
iam_aws_attached_policy_no_administrative_privileges,
)
check = iam_aws_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "IAMUserChangePassword":
assert result.status == "PASS"
assert (
result.resource_arn
== "arn:aws:iam::aws:policy/IAMUserChangePassword"
)
assert search(
"AWS policy IAMUserChangePassword is attached but does not allow ",
result.status_extended,
)
assert result.resource_id == "IAMUserChangePassword"
if result.resource_id == "AdministratorAccess":
assert result.status == "FAIL"
assert (
result.resource_arn
== "arn:aws:iam::aws:policy/AdministratorAccess"
)
assert search(
"AWS policy AdministratorAccess is attached and allows ",
result.status_extended,
)
assert result.resource_id == "AdministratorAccess"

View File

@@ -0,0 +1,185 @@
from json import dumps
from re import search
from unittest import mock
from boto3 import client, session
from moto import mock_iam
from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_iam_customer_attached_policy_no_administrative_privileges_test:
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
session_config=None,
original_session=None,
audit_session=session.Session(
profile_name=None,
botocore_session=None,
),
audited_account=AWS_ACCOUNT_NUMBER,
audited_user_id=None,
audited_partition="aws",
audited_identity_arn=None,
profile=None,
profile_region=None,
credentials=None,
assumed_role_info=None,
audited_regions=["us-east-1", "eu-west-1"],
organizations_metadata=None,
audit_resources=None,
)
return audit_info
@mock_iam
def test_policy_administrative(self):
iam_client = client("iam")
policy_name = "policy1"
policy_document = {
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "*", "Resource": "*"},
],
}
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
arn = iam_client.create_policy(
PolicyName=policy_name, PolicyDocument=dumps(policy_document)
)["Policy"]["Arn"]
iam_client.attach_role_policy(PolicyArn=arn, RoleName="my-role")
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges import (
iam_customer_attached_policy_no_administrative_privileges,
)
check = iam_customer_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "FAIL"
assert result.resource_arn == arn
assert search(
f"Custom policy {policy_name} is attached and allows ",
result.status_extended,
)
@mock_iam
def test_policy_non_administrative(self):
iam_client = client("iam")
policy_name = "policy1"
policy_document = {
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "*"},
],
}
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
arn = iam_client.create_policy(
PolicyName=policy_name, PolicyDocument=dumps(policy_document)
)["Policy"]["Arn"]
iam_client.attach_role_policy(PolicyArn=arn, RoleName="my-role")
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges import (
iam_customer_attached_policy_no_administrative_privileges,
)
check = iam_customer_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "PASS"
assert result.resource_arn == arn
assert search(
f"Custom policy {policy_name} is attached but does not allow",
result.status_extended,
)
@mock_iam
def test_policy_administrative_and_non_administrative(self):
iam_client = client("iam")
policy_name_non_administrative = "policy1"
policy_document_non_administrative = {
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "logs:*", "Resource": "*"},
],
}
policy_name_administrative = "policy2"
policy_document_administrative = {
"Version": "2012-10-17",
"Statement": [
{"Effect": "Allow", "Action": "*", "Resource": "*"},
],
}
arn_non_administrative = iam_client.create_policy(
PolicyName=policy_name_non_administrative,
PolicyDocument=dumps(policy_document_non_administrative),
)["Policy"]["Arn"]
arn_administrative = iam_client.create_policy(
PolicyName=policy_name_administrative,
PolicyDocument=dumps(policy_document_administrative),
)["Policy"]["Arn"]
iam_client.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}", Path="/my-path/"
)
iam_client.attach_role_policy(
PolicyArn=arn_non_administrative, RoleName="my-role"
)
iam_client.attach_role_policy(PolicyArn=arn_administrative, RoleName="my-role")
current_audit_info = self.set_mocked_audit_info()
from prowler.providers.aws.services.iam.iam_service import IAM
with mock.patch(
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_customer_attached_policy_no_administrative_privileges.iam_customer_attached_policy_no_administrative_privileges import (
iam_customer_attached_policy_no_administrative_privileges,
)
check = iam_customer_attached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "PASS"
assert result.resource_arn == arn_non_administrative
assert search(
f"Custom policy {policy_name_non_administrative} is attached but does not allow ",
result.status_extended,
)
assert result.resource_id == policy_name_non_administrative
if result.resource_id == "policy2":
assert result.status == "FAIL"
assert result.resource_arn == arn_administrative
assert search(
f"Custom policy {policy_name_administrative} is attached and allows ",
result.status_extended,
)
assert result.resource_id == policy_name_administrative

View File

@@ -10,7 +10,7 @@ from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_iam_policy_no_administrative_privileges_test:
class Test_iam_customer_unattached_policy_no_administrative_privileges_test:
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
session_config=None,
@@ -55,19 +55,23 @@ class Test_iam_policy_no_administrative_privileges_test:
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges.iam_client",
"prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges import (
iam_policy_no_administrative_privileges,
from prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges import (
iam_customer_unattached_policy_no_administrative_privileges,
)
check = iam_policy_no_administrative_privileges()
result = check.execute()
assert result[0].status == "FAIL"
assert result[0].resource_arn == arn
assert search(f"Policy {policy_name} allows ", result[0].status_extended)
assert result[0].resource_id == policy_name
check = iam_customer_unattached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "FAIL"
assert result.resource_arn == arn
assert search(
f"Custom policy {policy_name} is unattached and allows ",
result.status_extended,
)
@mock_iam
def test_policy_non_administrative(self):
@@ -90,21 +94,23 @@ class Test_iam_policy_no_administrative_privileges_test:
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges.iam_client",
"prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges import (
iam_policy_no_administrative_privileges,
from prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges import (
iam_customer_unattached_policy_no_administrative_privileges,
)
check = iam_policy_no_administrative_privileges()
result = check.execute()
assert result[0].status == "PASS"
assert result[0].resource_arn == arn
assert search(
f"Policy {policy_name} does not allow", result[0].status_extended
)
assert result[0].resource_id == policy_name
check = iam_customer_unattached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "PASS"
assert result.resource_arn == arn
assert search(
f"Custom policy {policy_name} is unattached and does not allow",
result.status_extended,
)
@mock_iam
def test_policy_administrative_and_non_administrative(self):
@@ -139,27 +145,29 @@ class Test_iam_policy_no_administrative_privileges_test:
"prowler.providers.aws.lib.audit_info.audit_info.current_audit_info",
new=current_audit_info,
), mock.patch(
"prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges.iam_client",
"prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges.iam_client",
new=IAM(current_audit_info),
):
from prowler.providers.aws.services.iam.iam_policy_no_administrative_privileges.iam_policy_no_administrative_privileges import (
iam_policy_no_administrative_privileges,
from prowler.providers.aws.services.iam.iam_customer_unattached_policy_no_administrative_privileges.iam_customer_unattached_policy_no_administrative_privileges import (
iam_customer_unattached_policy_no_administrative_privileges,
)
check = iam_policy_no_administrative_privileges()
result = check.execute()
assert len(result) == 2
assert result[0].status == "PASS"
assert result[0].resource_arn == arn_non_administrative
assert search(
f"Policy {policy_name_non_administrative} does not allow ",
result[0].status_extended,
)
assert result[0].resource_id == policy_name_non_administrative
assert result[1].status == "FAIL"
assert result[1].resource_arn == arn_administrative
assert search(
f"Policy {policy_name_administrative} allows ",
result[1].status_extended,
)
assert result[1].resource_id == policy_name_administrative
check = iam_customer_unattached_policy_no_administrative_privileges()
results = check.execute()
for result in results:
if result.resource_id == "policy1":
assert result.status == "PASS"
assert result.resource_arn == arn_non_administrative
assert search(
f"Custom policy {policy_name_non_administrative} is unattached and does not allow ",
result.status_extended,
)
assert result.resource_id == policy_name_non_administrative
if result.resource_id == "policy2":
assert result.status == "FAIL"
assert result.resource_arn == arn_administrative
assert search(
f"Custom policy {policy_name_administrative} is unattached and allows ",
result.status_extended,
)
assert result.resource_id == policy_name_administrative

View File

@@ -69,7 +69,7 @@ class Test_iam_policy_allows_privilege_escalation:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Customer Managed IAM Policy {policy_arn} allows for privilege escalation using the following actions: {{'sts:*'}}"
== f"Custom Policy {policy_arn} allows privilege escalation using the following actions: {{'sts:*'}}"
)
assert result[0].resource_id == policy_name
assert result[0].resource_arn == policy_arn
@@ -111,7 +111,7 @@ class Test_iam_policy_allows_privilege_escalation:
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Customer Managed IAM Policy {policy_arn} not allows for privilege escalation"
== f"Custom Policy {policy_arn} does not allow privilege escalation"
)
assert result[0].resource_id == policy_name
assert result[0].resource_arn == policy_arn
@@ -157,7 +157,7 @@ class Test_iam_policy_allows_privilege_escalation:
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Customer Managed IAM Policy {policy_arn} not allows for privilege escalation"
== f"Custom Policy {policy_arn} does not allow privilege escalation"
)
assert result[0].resource_id == policy_name
assert result[0].resource_arn == policy_arn
@@ -214,7 +214,7 @@ class Test_iam_policy_allows_privilege_escalation:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Customer Managed IAM Policy {policy_arn} allows for privilege escalation using the following actions: {{'dynamodb:PutItem'}}"
== f"Custom Policy {policy_arn} allows privilege escalation using the following actions: {{'dynamodb:PutItem'}}"
)
assert result[0].resource_id == policy_name
assert result[0].resource_arn == policy_arn

View File

@@ -9,7 +9,6 @@ from prowler.providers.aws.services.iam.iam_service import IAM
class Test_iam_policy_no_full_access_to_cloudtrail:
# Mocked Audit Info
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
@@ -66,7 +65,7 @@ class Test_iam_policy_no_full_access_to_cloudtrail:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Policy {policy_name} allows 'cloudtrail:*' privileges"
== f"Custom Policy {policy_name} allows 'cloudtrail:*' privileges"
)
assert result[0].resource_id == "policy_cloudtrail_full"
assert result[0].resource_arn == arn
@@ -105,7 +104,7 @@ class Test_iam_policy_no_full_access_to_cloudtrail:
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Policy {policy_name} does not allow 'cloudtrail:*' privileges"
== f"Custom Policy {policy_name} does not allow 'cloudtrail:*' privileges"
)
assert result[0].resource_id == "policy_no_cloudtrail_full"
assert result[0].resource_arn == arn
@@ -148,7 +147,7 @@ class Test_iam_policy_no_full_access_to_cloudtrail:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Policy {policy_name} allows 'cloudtrail:*' privileges"
== f"Custom Policy {policy_name} allows 'cloudtrail:*' privileges"
)
assert result[0].resource_id == "policy_mixed"
assert result[0].resource_arn == arn

View File

@@ -9,7 +9,6 @@ from prowler.providers.aws.services.iam.iam_service import IAM
class Test_iam_policy_no_full_access_to_kms:
# Mocked Audit Info
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
@@ -66,7 +65,7 @@ class Test_iam_policy_no_full_access_to_kms:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Policy {policy_name} allows 'kms:*' privileges"
== f"Custom Policy {policy_name} allows 'kms:*' privileges"
)
assert result[0].resource_id == "policy_kms_full"
assert result[0].resource_arn == arn
@@ -105,7 +104,7 @@ class Test_iam_policy_no_full_access_to_kms:
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Policy {policy_name} does not allow 'kms:*' privileges"
== f"Custom Policy {policy_name} does not allow 'kms:*' privileges"
)
assert result[0].resource_id == "policy_no_kms_full"
assert result[0].resource_arn == arn
@@ -144,7 +143,7 @@ class Test_iam_policy_no_full_access_to_kms:
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Policy {policy_name} allows 'kms:*' privileges"
== f"Custom Policy {policy_name} allows 'kms:*' privileges"
)
assert result[0].resource_id == "policy_mixed"
assert result[0].resource_arn == arn

View File

@@ -620,12 +620,23 @@ class Test_IAM_Service:
],
}
iam_client.create_policy(
PolicyName=policy_name, PolicyDocument=dumps(policy_document)
PolicyName=policy_name,
PolicyDocument=dumps(policy_document),
Tags=[
{"Key": "string", "Value": "string"},
],
)
audit_info = self.set_mocked_audit_info()
iam = IAM(audit_info)
assert len(iam.policies) == 1
assert iam.policies[0]["PolicyName"] == "policy1"
custom_policies = 0
for policy in iam.policies:
if policy.type == "Custom":
custom_policies += 1
assert policy.name == "policy1"
assert policy.tags == [
{"Key": "string", "Value": "string"},
]
assert custom_policies == 1
@mock_iam
def test__list_policies_version__(self):
@@ -643,10 +654,15 @@ class Test_IAM_Service:
audit_info = self.set_mocked_audit_info()
iam = IAM(audit_info)
assert len(iam.policies) == 1
assert iam.policies[0]["PolicyDocument"]["Statement"][0]["Effect"] == "Allow"
assert iam.policies[0]["PolicyDocument"]["Statement"][0]["Action"] == "*"
assert iam.policies[0]["PolicyDocument"]["Statement"][0]["Resource"] == "*"
custom_policies = 0
for policy in iam.policies:
if policy.type == "Custom":
custom_policies += 1
assert policy.name == "policy2"
assert policy.document["Statement"][0]["Effect"] == "Allow"
assert policy.document["Statement"][0]["Action"] == "*"
assert policy.document["Statement"][0]["Resource"] == "*"
assert custom_policies == 1
# Test IAM List SAML Providers
@mock_iam