mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
feat(Organizations): New check organizations_tags_policies_enabled_and_attached (#2287)
Co-authored-by: Pepe Fagoaga <pepe@verica.io>
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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__(
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user