feat(Organizations): New check organizations_tags_policies_enabled_and_attached (#2287)

Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
Gabriel Soltz
2023-04-28 16:14:08 +02:00
committed by GitHub
parent 93eca1dff2
commit 22e7d2a811
7 changed files with 226 additions and 13 deletions

View File

@@ -29,6 +29,10 @@ class organizations_scp_check_deny_regions(Check):
is_region_restricted_statement = False
for policy in org.policies:
# We only check SCP policies here
if policy.type != "SERVICE_CONTROL_POLICY":
continue
# Statements are not always list
statements = policy.content.get("Statement")
if type(policy.content["Statement"]) is not list:

View File

@@ -8,6 +8,13 @@ from prowler.lib.logger import logger
from prowler.lib.scan_filters.scan_filters import is_resource_filtered
from prowler.providers.aws.aws_provider import generate_regional_clients
available_organizations_policies = [
"SERVICE_CONTROL_POLICY",
"TAG_POLICY",
"BACKUP_POLICY",
"AISERVICES_OPT_OUT_POLICY",
]
################## Organizations
class Organizations:
@@ -36,13 +43,8 @@ class Organizations:
organization_arn = organization_desc.get("Arn")
organization_id = organization_desc.get("Id")
organization_master_id = organization_desc.get("MasterAccountId")
organization_available_policy_types = organization_desc.get(
"AvailablePolicyTypes"
)
# Fetch policies for organization:
organization_policies = self.__list_policies__(
organization_available_policy_types
)
organization_policies = self.__list_policies__()
# Fetch delegated administrators for organization:
organization_delegated_administrator = (
self.__list_delegated_administrators__()
@@ -95,19 +97,17 @@ class Organizations:
)
# I'm using list_policies instead of list_policies_for_target, because the last one only returns "Attached directly" policies but not "Inherited from..." policies.
def __list_policies__(self, enabled_policy_types):
def __list_policies__(self):
logger.info("Organizations - List policies...")
try:
list_policies_paginator = self.client.get_paginator("list_policies")
for policy_type in enabled_policy_types:
for policy_type in available_organizations_policies:
logger.info(
"Organizations - List policies... - Type: %s",
policy_type.get("Type"),
policy_type,
)
for page in list_policies_paginator.paginate(
Filter=policy_type.get("Type")
):
for page in list_policies_paginator.paginate(Filter=policy_type):
for policy in page["Policies"]:
policy_content = self.__describe_policy__(policy.get("Id"))
policy_targets = self.__list_targets_for_policy__(

View File

@@ -0,0 +1,30 @@
{
"Provider": "aws",
"CheckID": "organizations_tags_policies_enabled_and_attached",
"CheckTitle": "Check if an AWS Organization has tags policies enabled and attached.",
"CheckType": [],
"ServiceName": "organizations",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service::account-id:organization/organization-id",
"Severity": "medium",
"ResourceType": "Other",
"Description": "Check if an AWS Organization has tags policies enabled and attached.",
"Risk": "If an AWS Organization tags policies are not enabled and attached, it is not possible to enforce tags on AWS resources.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Enable and attach AWS Organizations tags policies.",
"Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_tag-policies.html"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}

View File

@@ -0,0 +1,37 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.organizations.organizations_client import (
organizations_client,
)
class organizations_tags_policies_enabled_and_attached(Check):
def execute(self):
findings = []
for org in organizations_client.organizations:
report = Check_Report_AWS(self.metadata())
report.resource_id = org.id
report.resource_arn = org.arn
report.region = organizations_client.region
report.status = "FAIL"
report.status_extended = (
"AWS Organizations is not in-use for this AWS Account"
)
if org.status == "ACTIVE":
if org.policies is None:
# Access Denied to list_policies
continue
for policy in org.policies:
# We only check SCP policies here
if policy.type != "TAG_POLICY":
continue
report.status_extended = f"AWS Organization {org.id} has tag policies enabled but not attached"
if policy.targets:
report.status = "PASS"
report.status_extended = f"AWS Organization {org.id} has tag policies enabled and attached to an AWS account"
findings.append(report)
return findings

View File

@@ -82,7 +82,6 @@ class Test_Organizations_Service:
audit_info = self.set_mocked_audit_info()
organizations = Organizations(audit_info)
# Tests
assert len(organizations.policies) == 2
for policy in organizations.policies:
if policy.arn == response["Policy"]["PolicySummary"]["Arn"]:
assert policy.type == "SERVICE_CONTROL_POLICY"

View File

@@ -0,0 +1,143 @@
from unittest import mock
from prowler.providers.aws.services.organizations.organizations_service import (
Organization,
Policy,
)
AWS_REGION = "us-east-1"
# Moto: NotImplementedError: The TAG_POLICY policy type has not been implemented
# Needs to Mock manually
class Test_organizations_tags_policies_enabled_and_attached:
def test_organization_no_organization(self):
organizations_client = mock.MagicMock
organizations_client.region = AWS_REGION
organizations_client.organizations = [
Organization(
arn="",
id="AWS Organization",
status="NOT_AVAILABLE",
master_id="",
)
]
with mock.patch(
"prowler.providers.aws.services.organizations.organizations_service.Organizations",
new=organizations_client,
):
# Test Check
from prowler.providers.aws.services.organizations.organizations_tags_policies_enabled_and_attached.organizations_tags_policies_enabled_and_attached import (
organizations_tags_policies_enabled_and_attached,
)
check = organizations_tags_policies_enabled_and_attached()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "AWS Organizations is not in-use for this AWS Account"
)
assert result[0].resource_id == "AWS Organization"
assert result[0].resource_arn == ""
assert result[0].region == AWS_REGION
def test_organization_with_tag_policies_not_attached(self):
organizations_client = mock.MagicMock
organizations_client.region = AWS_REGION
organizations_client.organizations = [
Organization(
id="o-1234567890",
arn="arn:aws:organizations::1234567890:organization/o-1234567890",
status="ACTIVE",
master_id="1234567890",
policies=[
Policy(
id="p-1234567890",
arn="arn:aws:organizations::1234567890:policy/o-1234567890/p-1234567890",
type="TAG_POLICY",
aws_managed=False,
content={"tags": {"Owner": {}}},
targets=[],
)
],
delegated_administrators=None,
)
]
with mock.patch(
"prowler.providers.aws.services.organizations.organizations_tags_policies_enabled_and_attached.organizations_tags_policies_enabled_and_attached.organizations_client",
new=organizations_client,
):
# Test Check
from prowler.providers.aws.services.organizations.organizations_tags_policies_enabled_and_attached.organizations_tags_policies_enabled_and_attached import (
organizations_tags_policies_enabled_and_attached,
)
check = organizations_tags_policies_enabled_and_attached()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "AWS Organization o-1234567890 has tag policies enabled but not attached"
)
assert result[0].resource_id == "o-1234567890"
assert (
result[0].resource_arn
== "arn:aws:organizations::1234567890:organization/o-1234567890"
)
assert result[0].region == AWS_REGION
def test_organization_with_tag_policies_attached(self):
organizations_client = mock.MagicMock
organizations_client.region = AWS_REGION
organizations_client.organizations = [
Organization(
id="o-1234567890",
arn="arn:aws:organizations::1234567890:organization/o-1234567890",
status="ACTIVE",
master_id="1234567890",
policies=[
Policy(
id="p-1234567890",
arn="arn:aws:organizations::1234567890:policy/o-1234567890/p-1234567890",
type="TAG_POLICY",
aws_managed=False,
content={"tags": {"Owner": {}}},
targets=["1234567890"],
)
],
delegated_administrators=None,
)
]
with mock.patch(
"prowler.providers.aws.services.organizations.organizations_tags_policies_enabled_and_attached.organizations_tags_policies_enabled_and_attached.organizations_client",
new=organizations_client,
):
# Test Check
from prowler.providers.aws.services.organizations.organizations_tags_policies_enabled_and_attached.organizations_tags_policies_enabled_and_attached import (
organizations_tags_policies_enabled_and_attached,
)
check = organizations_tags_policies_enabled_and_attached()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "AWS Organization o-1234567890 has tag policies enabled and attached to an AWS account"
)
assert result[0].resource_id == "o-1234567890"
assert (
result[0].resource_arn
== "arn:aws:organizations::1234567890:organization/o-1234567890"
)
assert result[0].region == AWS_REGION