Skip to content

feat(aws): add Resource Control Policies (RCP) support #7415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"Provider": "aws",
"CheckID": "organizations_rcps_enforce_encryption",
"CheckTitle": "Check if Resource Control Policies enforce encryption for AWS resources",
"CheckType": [
"Data Protection",
"Encryption"
],
"ServiceName": "organizations",
"SubServiceName": "rcp",
"ResourceIdTemplate": "arn:partition:service::account-id:organization/organization-id",
"Severity": "high",
"ResourceType": "Other",
"Description": "Check if AWS Organization is using Resource Control Policies to enforce encryption requirements across various AWS services in alignment with NIST 800-53 SC-13 and SC-28 controls.",
"Risk": "Without enforced encryption requirements at the resource level, sensitive data may be stored unencrypted, leading to potential data breaches and compliance violations including NIST 800-53, which requires protection of information at rest and in transit.",
"RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html",
"Remediation": {
"Code": {
"CLI": "aws organizations create-policy --name 'EncryptionRCP' --description 'Resource Control Policy to enforce encryption across resources' --type RESOURCE_CONTROL_POLICY --content file://encryptionRCP.json",
"NativeIaC": "",
"Other": "Example RCP content:\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"RequireS3Encryption\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"s3:PutObject\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"Null\": {\n \"s3:x-amz-server-side-encryption\": \"true\"\n }\n }\n },\n {\n \"Sid\": \"RequireEBSEncryption\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"ec2:CreateVolume\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"Bool\": {\n \"ec2:Encrypted\": \"false\"\n }\n }\n }\n ]\n}",
"Terraform": ""
},
"Recommendation": {
"Text": "Create Resource Control Policies that enforce encryption requirements for data at rest and in transit across critical AWS services. This aligns with NIST 800-53 controls SC-13 (Cryptographic Protection) and SC-28 (Protection of Information at Rest).",
"Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html"
}
},
"Categories": [
"encryption"
],
"DependsOn": [],
"RelatedTo": [
"organizations_resource_control_policies_enabled"
],
"Notes": "This check specifically looks for RCPs that enforce encryption requirements in alignment with NIST 800-53 controls SC-13 and SC-28."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.organizations.organizations_client import (
organizations_client,
)


class organizations_rcps_enforce_encryption(Check):
def execute(self):
findings = []

if organizations_client.organization:
if organizations_client.organization.policies is not None:
report = Check_Report_AWS(
metadata=self.metadata(),
resource=organizations_client.organization,
)
report.resource_id = organizations_client.organization.id
report.resource_arn = organizations_client.organization.arn
report.region = organizations_client.region
report.status = "FAIL"
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} does not have Resource Control Policies enforcing encryption requirements."

# Check if Resource Control Policies are present
if (
"RESOURCE_CONTROL_POLICY"
in organizations_client.organization.policies
):
rcps = organizations_client.organization.policies.get(
"RESOURCE_CONTROL_POLICY", []
)

# Check for encryption-related RCPs
encryption_rcps = []
for policy in rcps:
# Check if policy enforces encryption
if self._policy_enforces_encryption(policy):
encryption_rcps.append(policy)

if encryption_rcps:
report.status = "PASS"
report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(encryption_rcps)} Resource Control Policies enforcing encryption requirements."

findings.append(report)

return findings

def _policy_enforces_encryption(self, policy):
"""Check if a policy enforces encryption requirements"""
# Get policy statements
statements = policy.content.get("Statement", [])
if not isinstance(statements, list):
statements = [statements]

# Keywords and conditions that indicate encryption enforcement
encryption_keywords = [
"encrypted",
"encryption",
"kms",
"sse",
"server-side-encryption",
"tls",
"ssl",
"https",
"secure-transport",
]

# Known encryption-related conditions
encryption_conditions = [
"s3:x-amz-server-side-encryption",
"ec2:Encrypted",
"kms:EncryptionContext",
"dynamodb:Encrypted",
"rds:StorageEncrypted",
"secretsmanager:SecretString",
"lambda:SecretString",
"sagemaker:VolumeKmsKey",
]

# Check statements for encryption enforcement
for statement in statements:
# If the statement denies actions when encryption is not enabled
if statement.get("Effect") == "Deny":
# Check conditions
condition = statement.get("Condition", {})
condition_str = str(condition).lower()

# Check for encryption-related conditions
for keyword in encryption_keywords:
if keyword in condition_str:
return True

# Check for known encryption conditions
for enc_condition in encryption_conditions:
if enc_condition in str(condition):
return True

# Check if any actions are related to encryption
actions = statement.get("Action", [])
if not isinstance(actions, list):
actions = [actions]

for action in actions:
action = action.lower() if isinstance(action, str) else ""
# Check if action involves encryption
if any(
keyword in action for keyword in ["encrypt", "decrypt", "kms"]
):
return True

# If no encryption enforcement found
return False
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "organizations_rcps_enforce_iam_controls",
"CheckTitle": "Check if Resource Control Policies enforce IAM security controls",
"CheckType": [
"IAM"
],
"ServiceName": "organizations",
"SubServiceName": "rcp",
"ResourceIdTemplate": "arn:partition:service::account-id:organization/organization-id",
"Severity": "high",
"ResourceType": "Other",
"Description": "Check if AWS Organization is using Resource Control Policies to enforce IAM security controls in alignment with NIST 800-53 AC-2, AC-3, AC-6, and IA-2 controls.",
"Risk": "Without enforced IAM security controls, organizations risk privilege escalation, excessive permissions, and inadequate access control. NIST 800-53 requires proper account management, access enforcement, least privilege implementation, and identification and authentication mechanisms.",
"RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html",
"Remediation": {
"Code": {
"CLI": "aws organizations create-policy --name 'IAMSecurityRCP' --description 'Resource Control Policy to enforce IAM security controls' --type RESOURCE_CONTROL_POLICY --content file://iamSecurityRCP.json",
"NativeIaC": "",
"Other": "Example RCP content:\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"RequireMFAForIAMUsers\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"iam:CreateLoginProfile\",\n \"iam:CreateAccessKey\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"Bool\": {\n \"aws:MultiFactorAuthPresent\": \"false\"\n }\n }\n },\n {\n \"Sid\": \"PreventPermissionEscalation\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"iam:AttachRolePolicy\",\n \"iam:PutRolePolicy\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"ArnNotLike\": {\n \"aws:PrincipalArn\": \"arn:aws:iam::*:role/ApprovedAdminRole\"\n }\n }\n }\n ]\n}",
"Terraform": ""
},
"Recommendation": {
"Text": "Create Resource Control Policies that enforce IAM security controls such as requiring MFA, preventing privilege escalation, enforcing password policies, and implementing least privilege. This aligns with NIST 800-53 controls AC-2 (Account Management), AC-3 (Access Enforcement), AC-6 (Least Privilege), and IA-2 (Identification and Authentication).",
"Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [
"organizations_resource_control_policies_enabled"
],
"Notes": "This check specifically looks for RCPs that enforce IAM security controls in alignment with NIST 800-53 AC-2, AC-3, AC-6, and IA-2 controls."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.organizations.organizations_client import (
organizations_client,
)


class organizations_rcps_enforce_iam_controls(Check):
def execute(self):
findings = []

if organizations_client.organization:
if organizations_client.organization.policies is not None:
report = Check_Report_AWS(
metadata=self.metadata(),
resource=organizations_client.organization,
)
report.resource_id = organizations_client.organization.id
report.resource_arn = organizations_client.organization.arn
report.region = organizations_client.region
report.status = "FAIL"
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} does not have Resource Control Policies enforcing IAM security controls."

# Check if Resource Control Policies are present
if (
"RESOURCE_CONTROL_POLICY"
in organizations_client.organization.policies
):
rcps = organizations_client.organization.policies.get(
"RESOURCE_CONTROL_POLICY", []
)

# Check for IAM security controls in RCPs
iam_security_rcps = []
for policy in rcps:
# Check if policy enforces IAM security controls
if self._policy_enforces_iam_controls(policy):
iam_security_rcps.append(policy)

if iam_security_rcps:
report.status = "PASS"
report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(iam_security_rcps)} Resource Control Policies enforcing IAM security controls."

findings.append(report)

return findings

def _policy_enforces_iam_controls(self, policy):
"""Check if a policy enforces IAM security controls"""
# Get policy statements
statements = policy.content.get("Statement", [])
if not isinstance(statements, list):
statements = [statements]

# IAM-related actions to look for
iam_actions = [
"iam:create",
"iam:delete",
"iam:update",
"iam:put",
"iam:attach",
"iam:detach",
"iam:add",
"iam:remove",
"iam:pass",
"iam:getuser",
"iam:addrole",
"iam:createuser",
"iam:createlogin",
"iam:createaccesskey",
]

# IAM-related conditions to look for
iam_conditions = [
"aws:multifactorauthpresent",
"aws:principalarn",
"aws:principaltype",
"aws:principaltag",
"aws:tokenissuedate",
"iam:permissionsboundary",
"iam:passedtoprincipalarn",
]

# Check statements for IAM security controls
for statement in statements:
# If the statement is a deny for IAM actions
if statement.get("Effect") == "Deny":
# Check actions
actions = statement.get("Action", [])
if not isinstance(actions, list):
actions = [actions]

# Check for IAM-related actions
for action in actions:
action = action.lower() if isinstance(action, str) else ""
if action.startswith("iam:") or any(
iam_action in action for iam_action in iam_actions
):
return True

# Check conditions for IAM-related conditions
condition = statement.get("Condition", {})
condition_str = str(condition).lower()

# Check for IAM-related conditions
for iam_condition in iam_conditions:
if iam_condition in condition_str:
return True

# Also check for permissions boundaries enforcement
if "Resource" in statement and "Condition" in statement:
resource = statement.get("Resource", "")
condition = statement.get("Condition", {})

# Check if resource includes IAM roles/users
if isinstance(resource, str) and (
"iam" in resource.lower()
or "role" in resource.lower()
or "user" in resource.lower()
):
# Check conditions for permissions boundaries
condition_str = str(condition).lower()
if (
"permissionsboundary" in condition_str
or "aws:principalarn" in condition_str
):
return True

# If no IAM security controls found
return False
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"Provider": "aws",
"CheckID": "organizations_rcps_enforce_logging_monitoring",
"CheckTitle": "Check if Resource Control Policies enforce logging and monitoring",
"CheckType": [
"Logging and Monitoring"
],
"ServiceName": "organizations",
"SubServiceName": "rcp",
"ResourceIdTemplate": "arn:partition:service::account-id:organization/organization-id",
"Severity": "medium",
"ResourceType": "Other",
"Description": "Check if AWS Organization is using Resource Control Policies to enforce logging and monitoring controls in alignment with NIST 800-53 AU-2, AU-3, AU-8, and AU-9 controls.",
"Risk": "Without enforced logging and monitoring controls, organizations risk inability to detect and respond to security incidents, unauthorized activities, and compliance violations. NIST 800-53 requires proper audit event selection, content, time stamps, and protection.",
"RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html",
"Remediation": {
"Code": {
"CLI": "aws organizations create-policy --name 'LoggingMonitoringRCP' --description 'Resource Control Policy to enforce logging and monitoring controls' --type RESOURCE_CONTROL_POLICY --content file://loggingMonitoringRCP.json",
"NativeIaC": "",
"Other": "Example RCP content:\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"RequireCloudTrailLogging\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"cloudtrail:StopLogging\",\n \"cloudtrail:DeleteTrail\",\n \"cloudtrail:UpdateTrail\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringEquals\": {\n \"aws:ResourceTag/Compliance\": \"Required\"\n }\n }\n },\n {\n \"Sid\": \"RequireS3BucketLogging\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"s3:PutBucketLogging\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"Null\": {\n \"s3:LoggingEnabled\": \"true\"\n }\n }\n }\n ]\n}",
"Terraform": ""
},
"Recommendation": {
"Text": "Create Resource Control Policies that enforce logging and monitoring controls such as preventing disablement of CloudTrail, requiring server access logging for S3 buckets, and requiring CloudWatch log groups. This aligns with NIST 800-53 controls AU-2 (Audit Events), AU-3 (Content of Audit Records), AU-8 (Time Stamps), and AU-9 (Protection of Audit Information).",
"Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html"
}
},
"Categories": [
"logging"
],
"DependsOn": [],
"RelatedTo": [
"organizations_resource_control_policies_enabled"
],
"Notes": "This check specifically looks for RCPs that enforce logging and monitoring controls in alignment with NIST 800-53 AU-2, AU-3, AU-8, and AU-9 controls."
}
Loading
Loading