diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/__init__.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.metadata.json b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.metadata.json new file mode 100644 index 0000000000..c1419b6e91 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.metadata.json @@ -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." +} diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.py new file mode 100644 index 0000000000..ba7dcfe4f1 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_encryption/organizations_rcps_enforce_encryption.py @@ -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 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/__init__.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.metadata.json b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.metadata.json new file mode 100644 index 0000000000..c3b442c00d --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.metadata.json @@ -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." +} diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.py new file mode 100644 index 0000000000..bdf8b1e65f --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_iam_controls/organizations_rcps_enforce_iam_controls.py @@ -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 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/__init__.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.metadata.json b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.metadata.json new file mode 100644 index 0000000000..ee7c19d7e5 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.metadata.json @@ -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." +} diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.py new file mode 100644 index 0000000000..8f65d025e9 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_logging_monitoring/organizations_rcps_enforce_logging_monitoring.py @@ -0,0 +1,156 @@ +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_logging_monitoring(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 logging and monitoring 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 logging and monitoring controls in RCPs + logging_monitoring_rcps = [] + for policy in rcps: + # Check if policy enforces logging and monitoring controls + if self._policy_enforces_logging_monitoring(policy): + logging_monitoring_rcps.append(policy) + + if logging_monitoring_rcps: + report.status = "PASS" + report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(logging_monitoring_rcps)} Resource Control Policies enforcing logging and monitoring controls." + + findings.append(report) + + return findings + + def _policy_enforces_logging_monitoring(self, policy): + """Check if a policy enforces logging and monitoring controls""" + # Get policy statements + statements = policy.content.get("Statement", []) + if not isinstance(statements, list): + statements = [statements] + + # Logging and monitoring related services + logging_services = [ + "cloudtrail", + "cloudwatch", + "logs", + "config", + "securityhub", + "guardduty", + "s3:logdelivery", + "logging", + "kinesisanalytics", + "kinesis", + "events", + "firehose", + "sns", + "eventbridge", + ] + + # Specific logging and monitoring related actions + logging_actions = [ + "stoplogging", + "deletetrail", + "updatetrail", + "deleteloggingconfiguration", + "disablelogs", + "putretentionpolicy", + "deletemetricfilter", + "putbucketlogging", + "deleteloggingpolicy", + "putloggingoptions", + "disableeventselection", + "deleteeventdatastore", + "disableall", + "deregister", + "deletealarm", + "disableimportfindings", + "disablelogging", + "deletesubscription", + ] + + # Logging and monitoring related conditions + logging_conditions = [ + "logging", + "log", + "trail", + "monitor", + "cloudtrail", + "cloudwatch", + "aws:loggingEnabled", + "s3:LoggingEnabled", + ] + + # Check statements for logging and monitoring controls + for statement in statements: + # Check if statement is about preventing logging disablement + if statement.get("Effect") == "Deny": + # Check actions + actions = statement.get("Action", []) + if not isinstance(actions, list): + actions = [actions] + + action_str = str(actions).lower() + + # Check for logging-related services in actions + for service in logging_services: + if service.lower() in action_str: + # Check for specific logging actions that should be denied + for logging_action in logging_actions: + if logging_action.lower() in action_str: + return True + + # Check conditions for logging-related conditions + condition = statement.get("Condition", {}) + condition_str = str(condition).lower() + + for log_condition in logging_conditions: + if log_condition.lower() in condition_str: + return True + + # Check if statement requires logging to be enabled + elif "Resource" in statement: + resource = statement.get("Resource", "") + # Check if resource includes logging-related resources + for service in logging_services: + if ( + isinstance(resource, str) + and service.lower() in resource.lower() + ): + # Check conditions for logging requirements + condition = statement.get("Condition", {}) + if condition: + condition_str = str(condition).lower() + for log_condition in logging_conditions: + if log_condition.lower() in condition_str: + return True + + # If no logging and monitoring controls found + return False diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/__init__.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.metadata.json b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.metadata.json new file mode 100644 index 0000000000..67a11e1009 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.metadata.json @@ -0,0 +1,34 @@ +{ + "Provider": "aws", + "CheckID": "organizations_rcps_enforce_network_security", + "CheckTitle": "Check if Resource Control Policies enforce network security controls", + "CheckType": [], + "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 network security controls in alignment with NIST 800-53 SC-7, SC-8, and SC-13 controls.", + "Risk": "Without enforced network security controls, organizations risk unauthorized network access, data exposure through insecure data transmission, and vulnerabilities from insecure network configurations. NIST 800-53 requires boundary protection, transmission confidentiality and integrity, and cryptographic protection.", + "RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html", + "Remediation": { + "Code": { + "CLI": "aws organizations create-policy --name 'NetworkSecurityRCP' --description 'Resource Control Policy to enforce network security controls' --type RESOURCE_CONTROL_POLICY --content file://networkSecurityRCP.json", + "NativeIaC": "", + "Other": "Example RCP content:\n{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"PreventPublicInternetAccess\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"ec2:AuthorizeSecurityGroupIngress\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringEquals\": {\n \"ec2:CidrIp\": \"0.0.0.0/0\"\n }\n }\n },\n {\n \"Sid\": \"RequireVPCEndpoints\",\n \"Effect\": \"Deny\",\n \"Action\": [\n \"s3:*\"\n ],\n \"Resource\": \"*\",\n \"Condition\": {\n \"StringNotEquals\": {\n \"aws:SourceVpce\": \"vpce-example\"\n }\n }\n }\n ]\n}", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create Resource Control Policies that enforce network security controls such as preventing public internet access, requiring VPC endpoints, enforcing secure TLS versions, and requiring WAF for public-facing resources. This aligns with NIST 800-53 controls SC-7 (Boundary Protection), SC-8 (Transmission Confidentiality and Integrity), and SC-13 (Cryptographic Protection).", + "Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html#example-rcp-enforce-ssl" + } + }, + "Categories": [ + "trustboundaries" + ], + "DependsOn": [], + "RelatedTo": [ + "organizations_resource_control_policies_enabled" + ], + "Notes": "This check specifically looks for RCPs that enforce network security controls in alignment with NIST 800-53 SC-7, SC-8, and SC-13 controls." +} diff --git a/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.py b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.py new file mode 100644 index 0000000000..63afcad9fb --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_rcps_enforce_network_security/organizations_rcps_enforce_network_security.py @@ -0,0 +1,205 @@ +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_network_security(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 network 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 network security controls in RCPs + network_security_rcps = [] + for policy in rcps: + # Check if policy enforces network security controls + if self._policy_enforces_network_security(policy): + network_security_rcps.append(policy) + + if network_security_rcps: + report.status = "PASS" + report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(network_security_rcps)} Resource Control Policies enforcing network security controls." + + findings.append(report) + + return findings + + def _policy_enforces_network_security(self, policy): + """Check if a policy enforces network security controls""" + # Get policy statements + statements = policy.content.get("Statement", []) + if not isinstance(statements, list): + statements = [statements] + + # Network security related services + network_services = [ + "ec2", + "vpc", + "vpn", + "directconnect", + "apigateway", + "elb", + "elbv2", + "cloudfront", + "route53", + "globalaccelerator", + "networkfirewall", + "waf", + "wafv2", + "shield", + "acm", + "networkmanager", + ] + + # Network security related actions + network_actions = [ + "createnetworkacl", + "createroute", + "createinternetgateway", + "attachinternetgateway", + "authorizesecuritygroupingress", + "authorizesecuritygroupegress", + "createsecuritygroup", + "modifyvpcattribute", + "createvpc", + "createsubnet", + "createnatgateway", + "createvpcendpoint", + "deletevpcendpoints", + "createloadbalancer", + "createlistener", + "createtargetgroup", + "createcache", + "createcluster", + "createdbinstance", + "modifysecuritygrouprules", + ] + + # Network security related conditions + network_conditions = [ + "sourcevpc", + "sourcevpce", + "sourceip", + "ipaddress", + "cidrrip", + "cidrip", + "toport", + "fromport", + "sourcetype", + "internetgateway", + "vpcendpoint", + "publicip", + "publiclyaccessible", + "subnetid", + "vpcid", + "awsvpcConfiguration", + "tlsversionforHttps", + ] + + # Check statements for network security controls + for statement in statements: + # Check if statement is about preventing insecure network configurations + if statement.get("Effect") == "Deny": + # Check actions + actions = statement.get("Action", []) + if not isinstance(actions, list): + actions = [actions] + + action_str = str(actions).lower() + + # Check for network-related services in actions + for service in network_services: + if service.lower() in action_str: + # Check for specific network actions that should be denied + for network_action in network_actions: + if network_action.lower() in action_str: + # Check conditions for network-related conditions + condition = statement.get("Condition", {}) + if condition: + condition_str = str(condition).lower() + # Check for network security conditions + for net_condition in network_conditions: + if net_condition.lower() in condition_str: + # This looks like a network security control + return True + + # Also check conditions directly for network security requirements + condition = statement.get("Condition", {}) + if condition: + condition_str = str(condition).lower() + # Conditions that specifically indicate network security controls + network_security_indicators = [ + "0.0.0.0/0", + "cidrip", + "ec2:cidrip", + "aws:sourcevpc", + "aws:sourcevpce", + "aws:sourceip", + "vpc-", + "vpce-", + "tls1.0", + "tls1.1", + "publiclyaccessible", + "ec2:isrestrictedmanagementport", + ] + + for indicator in network_security_indicators: + if indicator.lower() in condition_str: + return True + + # Also check if requiring specific security configurations + elif statement.get("Effect") == "Allow" and "Condition" in statement: + condition = statement.get("Condition", {}) + condition_str = str(condition).lower() + + # Look for conditions that enforce secure network configurations + secure_network_indicators = [ + "aws:securetransport", + "true", + "aws:vpce", + "aws:sourcevpc", + "ec2:requireimdsv2", + "true", + "ec2:isrestrictedmanagementport", + "tls1.2", + "tls1.3", + ] + + # Count how many secure network indicators are present + indicator_count = sum( + 1 + for indicator in secure_network_indicators + if indicator.lower() in condition_str + ) + + # If multiple indicators are present, it's likely enforcing network security + if indicator_count >= 2: + return True + + # If no network security controls found + return False diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/__init__.py b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.metadata.json b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.metadata.json new file mode 100644 index 0000000000..60c8c333ed --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "organizations_resource_control_policies_enabled", + "CheckTitle": "Check if AWS Organization is using Resource Control Policies", + "CheckType": [ + "IAM" + ], + "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 for resource governance and security.", + "Risk": "Without Resource Control Policies, organizations lack granular control over resources across accounts. This increases the risk of misconfigured resources, security vulnerabilities, and governance gaps at the resource level that can't be addressed by Service Control Policies alone.", + "RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html", + "Remediation": { + "Code": { + "CLI": "aws organizations create-policy --name 'MyResourceControlPolicy' --description 'Resource Control Policy to enforce security controls on resources' --type RESOURCE_CONTROL_POLICY --content file://rcpContent.json", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create Resource Control Policies to enforce security guardrails at the resource level across your organization. Consider implementing RCPs for critical resource types like S3 buckets, IAM roles, and Lambda functions.", + "Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "Resource Control Policies were introduced in 2023 and provide resource-level governance capabilities beyond what Service Control Policies can do." +} diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.py b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.py new file mode 100644 index 0000000000..c0e2f696d6 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_enabled/organizations_resource_control_policies_enabled.py @@ -0,0 +1,52 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.organizations.organizations_client import ( + organizations_client, +) + + +class organizations_resource_control_policies_enabled(Check): + def execute(self): + findings = [] + + if organizations_client.organization: + if ( + organizations_client.organization.policies is not None + ): # Access denied to list policies + 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 enabled." + + # Check if Resource Control Policies are present and attached to targets + if ( + "RESOURCE_CONTROL_POLICY" + in organizations_client.organization.policies + ): + rcps = organizations_client.organization.policies.get( + "RESOURCE_CONTROL_POLICY", [] + ) + if rcps: + # Check if any RCP is attached to targets + attached_rcps = [ + policy for policy in rcps if policy.targets + ] + if attached_rcps: + report.status = "PASS" + report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(attached_rcps)} Resource Control Policies attached to targets." + else: + report.status = "FAIL" + report.status_extended = f"AWS Organization {organizations_client.organization.id} has Resource Control Policies, but none are attached to targets." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/__init__.py b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.metadata.json b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.metadata.json new file mode 100644 index 0000000000..39c4eed16f --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.metadata.json @@ -0,0 +1,37 @@ +{ + "Provider": "aws", + "CheckID": "organizations_resource_control_policies_s3_security", + "CheckTitle": "Check if Resource Control Policies are enforcing S3 security settings", + "CheckType": [ + "Data Protection", + "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 critical S3 bucket security settings.", + "Risk": "Without Resource Control Policies enforcing S3 security settings, organizations are at higher risk of data breaches through misconfigured buckets. This can lead to data exposure, unauthorized access, and compliance violations across the organization.", + "RelatedUrl": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps.html", + "Remediation": { + "Code": { + "CLI": "aws organizations create-policy --name 'S3SecurityRCP' --description 'Resource Control Policy to enforce S3 bucket security settings' --type RESOURCE_CONTROL_POLICY --content file://s3SecurityRCP.json", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Create Resource Control Policies that enforce S3 security settings such as blocking public access, requiring encryption, enabling versioning, and requiring bucket logging.", + "Url": "https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_rcps_examples.html#example-rcp-consistent-bucket" + } + }, + "Categories": [ + "encryption" + ], + "DependsOn": [], + "RelatedTo": [ + "organizations_resource_control_policies_enabled" + ], + "Notes": "This check specifically looks for RCPs that enforce S3 security best practices." +} diff --git a/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.py b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.py new file mode 100644 index 0000000000..0f1b39e661 --- /dev/null +++ b/prowler/providers/aws/services/organizations/organizations_resource_control_policies_s3_security/organizations_resource_control_policies_s3_security.py @@ -0,0 +1,91 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.organizations.organizations_client import ( + organizations_client, +) + + +class organizations_resource_control_policies_s3_security(Check): + def execute(self): + findings = [] + + if organizations_client.organization: + if ( + organizations_client.organization.policies is not None + ): # Access denied to list policies + 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 S3 security settings." + + # 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 S3 security related RCPs + s3_security_rcps = [] + for policy in rcps: + # The content is already parsed as JSON in the service implementation + # Look for S3 specific statements in the policy + s3_policy = False + statements = policy.content.get("Statement", []) + # Ensure statements is a list + if not isinstance(statements, list): + statements = [statements] + + for statement in statements: + # Check if the policy applies to S3 buckets + resources = statement.get("Resource", "") + if not isinstance(resources, list): + resources = [resources] + + # Check if S3 is mentioned in the resources + for resource in resources: + if "s3" in resource.lower() or resource == "*": + s3_policy = True + break + + # Also check if it enforces specific S3 security settings + if ( + "Effect" in statement + and statement["Effect"] == "Deny" + ): + condition = statement.get("Condition", {}) + # Look for conditions related to S3 security settings + if any( + key in str(condition).lower() + for key in [ + "s3:publicaccess", + "s3:encryption", + "s3:versioning", + "s3:bucketlevel", + "s3:objectlockconfig", + ] + ): + s3_policy = True + break + + if s3_policy and policy.targets: + s3_security_rcps.append(policy) + + if s3_security_rcps: + report.status = "PASS" + report.status_extended = f"AWS Organization {organizations_client.organization.id} has {len(s3_security_rcps)} Resource Control Policies enforcing S3 security settings." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/organizations/organizations_service.py b/prowler/providers/aws/services/organizations/organizations_service.py index b3580fbebd..88652782b9 100644 --- a/prowler/providers/aws/services/organizations/organizations_service.py +++ b/prowler/providers/aws/services/organizations/organizations_service.py @@ -13,6 +13,7 @@ "TAG_POLICY", "BACKUP_POLICY", "AISERVICES_OPT_OUT_POLICY", + "RESOURCE_CONTROL_POLICY", ]