mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
fix(aws): disallow child-accounts to overwrite policy for ai_services_opt_out (#6229)
Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
+4
-4
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"Provider": "aws",
|
||||
"CheckID": "organizations_opt_out_ai_services_policy",
|
||||
"CheckTitle": "Ensure that AWS Organizations opt-out of AI services policy is enabled.",
|
||||
"CheckTitle": "Ensure that AWS Organizations opt-out of AI services policy is enabled and disallow child-accounts to overwrite this policy.",
|
||||
"CheckType": [],
|
||||
"ServiceName": "organizations",
|
||||
"SubServiceName": "",
|
||||
"ResourceIdTemplate": "arn:partition:service::account-id:organization/organization-id",
|
||||
"Severity": "low",
|
||||
"ResourceType": "Other",
|
||||
"Description": "This control checks whether the AWS Organizations opt-out of AI services policy is enabled. The control fails if the policy is not enabled.",
|
||||
"Description": "This control checks whether the AWS Organizations opt-out of AI services policy is enabled and whether child-accounts are disallowed to overwrite this policy. The control fails if the policy is not enabled or if child-accounts are not disallowed to overwrite this policy.",
|
||||
"Risk": "By default, AWS may be using your data to train its AI models. This may include data from your AWS CloudTrail logs, AWS Config rules, and AWS GuardDuty findings. If you opt out of AI services, AWS will not use your data to train its AI models.",
|
||||
"RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_ai-opt-out_all.html",
|
||||
"Remediation": {
|
||||
"Code": {
|
||||
"CLI": "aws organizations enable-policy-type --root-id <root-id> --policy-type AI_SERVICES_OPT_OUT {'services': {'default': {'opt_out_policy': {'@@assign': 'optOut'}}}}",
|
||||
"CLI": "",
|
||||
"NativeIaC": "",
|
||||
"Other": "",
|
||||
"Terraform": ""
|
||||
},
|
||||
"Recommendation": {
|
||||
"Text": "Artificial Intelligence (AI) services opt-out policies enable you to control whether AWS AI services can store and use your content. Enable the AWS Organizations opt-out of AI services policy.",
|
||||
"Text": "Artificial Intelligence (AI) services opt-out policies enable you to control whether AWS AI services can store and use your content. Enable the AWS Organizations opt-out of AI services policy and disallow child-accounts to overwrite this policy.",
|
||||
"Url": "https://docs.aws.amazon.com/organizations/latest/userguide/disable-policy-type.html"
|
||||
}
|
||||
},
|
||||
|
||||
+33
-12
@@ -20,21 +20,42 @@ class organizations_opt_out_ai_services_policy(Check):
|
||||
report.status_extended = (
|
||||
"AWS Organizations is not in-use for this AWS Account."
|
||||
)
|
||||
|
||||
if organizations_client.organization.status == "ACTIVE":
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has not opted out of all AI services, granting consent for AWS to access its data."
|
||||
for policy in organizations_client.organization.policies.get(
|
||||
all_conditions_passed = False
|
||||
opt_out_policies = organizations_client.organization.policies.get(
|
||||
"AISERVICES_OPT_OUT_POLICY", []
|
||||
):
|
||||
if (
|
||||
policy.content.get("services", {})
|
||||
.get("default", {})
|
||||
.get("opt_out_policy", {})
|
||||
.get("@@assign")
|
||||
== "optOut"
|
||||
):
|
||||
)
|
||||
|
||||
if not opt_out_policies:
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has no opt-out policy for AI services."
|
||||
else:
|
||||
for policy in opt_out_policies:
|
||||
opt_out_policy = (
|
||||
policy.content.get("services", {})
|
||||
.get("default", {})
|
||||
.get("opt_out_policy", {})
|
||||
)
|
||||
|
||||
condition_1 = opt_out_policy.get("@@assign") == "optOut"
|
||||
condition_2 = opt_out_policy.get(
|
||||
"@@operators_allowed_for_child_policies"
|
||||
) == ["@@none"]
|
||||
|
||||
if condition_1 and condition_2:
|
||||
all_conditions_passed = True
|
||||
break
|
||||
|
||||
if not condition_1 and not condition_2:
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has not opted out of all AI services and it does not disallow child-accounts to overwrite the policy."
|
||||
elif not condition_1:
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has not opted out of all AI services."
|
||||
elif not condition_2:
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has opted out of all AI services but it does not disallow child-accounts to overwrite the policy."
|
||||
|
||||
if all_conditions_passed:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has opted out of all AI services, not granting consent for AWS to access its data."
|
||||
break
|
||||
report.status_extended = f"AWS Organization {organizations_client.organization.id} has opted out of all AI services and also disallows child-accounts to overwrite this policy."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
|
||||
+147
-11
@@ -87,7 +87,7 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS Organization o-1234567890 has not opted out of all AI services, granting consent for AWS to access its data."
|
||||
== "AWS Organization o-1234567890 has no opt-out policy for AI services."
|
||||
)
|
||||
assert result[0].resource_id == "o-1234567890"
|
||||
assert (
|
||||
@@ -96,7 +96,7 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
)
|
||||
assert result[0].region == AWS_REGION_EU_WEST_1
|
||||
|
||||
def test_organization_with_AI_optout_policy(self):
|
||||
def test_organization_with_AI_optout_policy_complete(self):
|
||||
organizations_client = mock.MagicMock
|
||||
organizations_client.region = AWS_REGION_EU_WEST_1
|
||||
organizations_client.audited_partition = "aws"
|
||||
@@ -118,7 +118,14 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
aws_managed=False,
|
||||
content={
|
||||
"services": {
|
||||
"default": {"opt_out_policy": {"@@assign": "optOut"}}
|
||||
"default": {
|
||||
"opt_out_policy": {
|
||||
"@@operators_allowed_for_child_policies": [
|
||||
"@@none"
|
||||
],
|
||||
"@@assign": "optOut",
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
targets=[],
|
||||
@@ -134,12 +141,15 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client",
|
||||
new=organizations_client,
|
||||
), mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client.get_unknown_arn",
|
||||
return_value="arn:aws:organizations:eu-west-1:0123456789012:unknown",
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client",
|
||||
new=organizations_client,
|
||||
),
|
||||
mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client.get_unknown_arn",
|
||||
return_value="arn:aws:organizations:eu-west-1:0123456789012:unknown",
|
||||
),
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy import (
|
||||
@@ -153,7 +163,7 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS Organization o-1234567890 has opted out of all AI services, not granting consent for AWS to access its data."
|
||||
== "AWS Organization o-1234567890 has opted out of all AI services and also disallows child-accounts to overwrite this policy."
|
||||
)
|
||||
assert result[0].resource_id == "o-1234567890"
|
||||
assert (
|
||||
@@ -209,7 +219,133 @@ class Test_organizations_tags_policies_enabled_and_attached:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS Organization o-1234567890 has not opted out of all AI services, granting consent for AWS to access its data."
|
||||
== "AWS Organization o-1234567890 has not opted out of all AI services and it does not disallow child-accounts to overwrite the policy."
|
||||
)
|
||||
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_EU_WEST_1
|
||||
|
||||
def test_organization_with_AI_optout_policy_no_disallow(self):
|
||||
organizations_client = mock.MagicMock
|
||||
organizations_client.region = AWS_REGION_EU_WEST_1
|
||||
organizations_client.audited_partition = "aws"
|
||||
organizations_client.audited_account = "0123456789012"
|
||||
organizations_client.organization = Organization(
|
||||
id="o-1234567890",
|
||||
arn="arn:aws:organizations::1234567890:organization/o-1234567890",
|
||||
status="ACTIVE",
|
||||
master_id="1234567890",
|
||||
policies={
|
||||
"AISERVICES_OPT_OUT_POLICY": [
|
||||
Policy(
|
||||
id="p-1234567890",
|
||||
arn="arn:aws:organizations::1234567890:policy/o-1234567890/p-1234567890",
|
||||
type="AISERVICES_OPT_OUT_POLICY",
|
||||
aws_managed=False,
|
||||
content={
|
||||
"services": {
|
||||
"default": {"opt_out_policy": {"@@assign": "optOut"}}
|
||||
}
|
||||
},
|
||||
targets=[],
|
||||
)
|
||||
]
|
||||
},
|
||||
delegated_administrators=None,
|
||||
)
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client",
|
||||
new=organizations_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy import (
|
||||
organizations_opt_out_ai_services_policy,
|
||||
)
|
||||
|
||||
check = organizations_opt_out_ai_services_policy()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS Organization o-1234567890 has opted out of all AI services but it does not disallow child-accounts to overwrite the policy."
|
||||
)
|
||||
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_EU_WEST_1
|
||||
|
||||
def test_organization_with_AI_optout_policy_no_opt_out(self):
|
||||
organizations_client = mock.MagicMock
|
||||
organizations_client.region = AWS_REGION_EU_WEST_1
|
||||
organizations_client.audited_partition = "aws"
|
||||
organizations_client.audited_account = "0123456789012"
|
||||
organizations_client.organization = Organization(
|
||||
id="o-1234567890",
|
||||
arn="arn:aws:organizations::1234567890:organization/o-1234567890",
|
||||
status="ACTIVE",
|
||||
master_id="1234567890",
|
||||
policies={
|
||||
"AISERVICES_OPT_OUT_POLICY": [
|
||||
Policy(
|
||||
id="p-1234567890",
|
||||
arn="arn:aws:organizations::1234567890:policy/o-1234567890/p-1234567890",
|
||||
type="AISERVICES_OPT_OUT_POLICY",
|
||||
aws_managed=False,
|
||||
content={
|
||||
"services": {
|
||||
"default": {
|
||||
"opt_out_policy": {
|
||||
"@@operators_allowed_for_child_policies": [
|
||||
"@@none"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
targets=[],
|
||||
)
|
||||
]
|
||||
},
|
||||
delegated_administrators=None,
|
||||
)
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1])
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
):
|
||||
with mock.patch(
|
||||
"prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy.organizations_client",
|
||||
new=organizations_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.organizations.organizations_opt_out_ai_services_policy.organizations_opt_out_ai_services_policy import (
|
||||
organizations_opt_out_ai_services_policy,
|
||||
)
|
||||
|
||||
check = organizations_opt_out_ai_services_policy()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "AWS Organization o-1234567890 has not opted out of all AI services."
|
||||
)
|
||||
assert result[0].resource_id == "o-1234567890"
|
||||
assert (
|
||||
|
||||
Reference in New Issue
Block a user