fix(rds): add ReadReplicaSourceDBInstanceIdentifier to db_instance (#3912)

Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
This commit is contained in:
ur
2024-05-08 15:54:51 +02:00
committed by GitHub
parent e226cb06e0
commit 73b7d76219
9 changed files with 317 additions and 158 deletions
+1 -1
View File
@@ -105,4 +105,4 @@ repos:
description: "Vulture finds unused code in Python programs."
entry: bash -c 'vulture --exclude "contrib" --min-confidence 100 .'
language: system
files: '.*\.py'
files: '.*\.py'
+7 -2
View File
@@ -39,6 +39,7 @@ The following list includes all the AWS checks with configurable variables that
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_entropy` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_minutes` | Integer |
| `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_actions` | List of Strings |
| `rds_instance_backup_enabled` | `check_rds_instance_replicas` | Boolean |
## Azure
### Configurable Checks
@@ -209,7 +210,7 @@ aws:
"UpdateFunctionCode",
"UpdateJob",
"UpdateLoginProfile",
]
]
# aws.cloudtrail_threat_detection_enumeration
threat_detection_enumeration_entropy: 0.7 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.7 (70%)
threat_detection_enumeration_minutes: 1440 # Past minutes to search from now for enumeration attacks, by default is 1440 minutes (24 hours)
@@ -304,7 +305,11 @@ aws:
"ListUsers",
"LookupEvents",
"Search",
]
]
# aws.rds_instance_backup_enabled
# Whether to check RDS instance replicas or not
check_rds_instance_replicas: False
# Azure Configuration
azure:
+150 -145
View File
@@ -100,154 +100,159 @@ aws:
# aws.cloudtrail_threat_detection_privilege_escalation
threat_detection_privilege_escalation_threshold: 0.1 # Percentage of actions found to decide if it is an privilege_escalation attack event, by default is 0.1 (10%)
threat_detection_privilege_escalation_minutes: 1440 # Past minutes to search from now for privilege_escalation attacks, by default is 1440 minutes (24 hours)
threat_detection_privilege_escalation_actions: [
"AddPermission",
"AddRoleToInstanceProfile",
"AddUserToGroup",
"AssociateAccessPolicy",
"AssumeRole",
"AttachGroupPolicy",
"AttachRolePolicy",
"AttachUserPolicy",
"ChangePassword",
"CreateAccessEntry",
"CreateAccessKey",
"CreateDevEndpoint",
"CreateEventSourceMapping",
"CreateFunction",
"CreateGroup",
"CreateJob",
"CreateKeyPair",
"CreateLoginProfile",
"CreatePipeline",
"CreatePolicyVersion",
"CreateRole",
"CreateStack",
"DeleteRolePermissionsBoundary",
"DeleteRolePolicy",
"DeleteUserPermissionsBoundary",
"DeleteUserPolicy",
"DetachRolePolicy",
"DetachUserPolicy",
"GetCredentialsForIdentity",
"GetId",
"GetPolicyVersion",
"GetUserPolicy",
"Invoke",
"ModifyInstanceAttribute",
"PassRole",
"PutGroupPolicy",
"PutPipelineDefinition",
"PutRolePermissionsBoundary",
"PutRolePolicy",
"PutUserPermissionsBoundary",
"PutUserPolicy",
"ReplaceIamInstanceProfileAssociation",
"RunInstances",
"SetDefaultPolicyVersion",
"UpdateAccessKey",
"UpdateAssumeRolePolicy",
"UpdateDevEndpoint",
"UpdateEventSourceMapping",
"UpdateFunctionCode",
"UpdateJob",
"UpdateLoginProfile",
]
threat_detection_privilege_escalation_actions:
[
"AddPermission",
"AddRoleToInstanceProfile",
"AddUserToGroup",
"AssociateAccessPolicy",
"AssumeRole",
"AttachGroupPolicy",
"AttachRolePolicy",
"AttachUserPolicy",
"ChangePassword",
"CreateAccessEntry",
"CreateAccessKey",
"CreateDevEndpoint",
"CreateEventSourceMapping",
"CreateFunction",
"CreateGroup",
"CreateJob",
"CreateKeyPair",
"CreateLoginProfile",
"CreatePipeline",
"CreatePolicyVersion",
"CreateRole",
"CreateStack",
"DeleteRolePermissionsBoundary",
"DeleteRolePolicy",
"DeleteUserPermissionsBoundary",
"DeleteUserPolicy",
"DetachRolePolicy",
"DetachUserPolicy",
"GetCredentialsForIdentity",
"GetId",
"GetPolicyVersion",
"GetUserPolicy",
"Invoke",
"ModifyInstanceAttribute",
"PassRole",
"PutGroupPolicy",
"PutPipelineDefinition",
"PutRolePermissionsBoundary",
"PutRolePolicy",
"PutUserPermissionsBoundary",
"PutUserPolicy",
"ReplaceIamInstanceProfileAssociation",
"RunInstances",
"SetDefaultPolicyVersion",
"UpdateAccessKey",
"UpdateAssumeRolePolicy",
"UpdateDevEndpoint",
"UpdateEventSourceMapping",
"UpdateFunctionCode",
"UpdateJob",
"UpdateLoginProfile",
]
# aws.cloudtrail_threat_detection_enumeration
threat_detection_enumeration_threshold: 0.1 # Percentage of actions found to decide if it is an enumeration attack event, by default is 0.1 (10%)
threat_detection_enumeration_minutes: 1440 # Past minutes to search from now for enumeration attacks, by default is 1440 minutes (24 hours)
threat_detection_enumeration_actions: [
"DescribeAccessEntry",
"DescribeAccountAttributes",
"DescribeAvailabilityZones",
"DescribeBundleTasks",
"DescribeCarrierGateways",
"DescribeClientVpnRoutes",
"DescribeCluster",
"DescribeDhcpOptions",
"DescribeFlowLogs",
"DescribeImages",
"DescribeInstanceAttribute",
"DescribeInstanceInformation",
"DescribeInstanceTypes",
"DescribeInstances",
"DescribeInstances",
"DescribeKeyPairs",
"DescribeLogGroups",
"DescribeLogStreams",
"DescribeOrganization",
"DescribeRegions",
"DescribeSecurityGroups",
"DescribeSnapshotAttribute",
"DescribeSnapshotTierStatus",
"DescribeSubscriptionFilters",
"DescribeTransitGatewayMulticastDomains",
"DescribeVolumes",
"DescribeVolumesModifications",
"DescribeVpcEndpointConnectionNotifications",
"DescribeVpcs",
"GetAccount",
"GetAccountAuthorizationDetails",
"GetAccountSendingEnabled",
"GetBucketAcl",
"GetBucketLogging",
"GetBucketPolicy",
"GetBucketReplication",
"GetBucketVersioning",
"GetCallerIdentity",
"GetCertificate",
"GetConsoleScreenshot",
"GetCostAndUsage",
"GetDetector",
"GetEbsDefaultKmsKeyId",
"GetEbsEncryptionByDefault",
"GetFindings",
"GetFlowLogsIntegrationTemplate",
"GetIdentityVerificationAttributes",
"GetInstances",
"GetIntrospectionSchema",
"GetLaunchTemplateData",
"GetLaunchTemplateData",
"GetLogRecord",
"GetParameters",
"GetPolicyVersion",
"GetPublicAccessBlock",
"GetQueryResults",
"GetRegions",
"GetSMSAttributes",
"GetSMSSandboxAccountStatus",
"GetSendQuota",
"GetTransitGatewayRouteTableAssociations",
"GetUserPolicy",
"HeadObject",
"ListAccessKeys",
"ListAccounts",
"ListAllMyBuckets",
"ListAssociatedAccessPolicies",
"ListAttachedUserPolicies",
"ListClusters",
"ListDetectors",
"ListDomains",
"ListFindings",
"ListHostedZones",
"ListIPSets",
"ListIdentities",
"ListInstanceProfiles",
"ListObjects",
"ListOrganizationalUnitsForParent",
"ListOriginationNumbers",
"ListPolicyVersions",
"ListRoles",
"ListRoles",
"ListRules",
"ListServiceQuotas",
"ListSubscriptions",
"ListTargetsByRule",
"ListTopics",
"ListUsers",
"LookupEvents",
"Search",
]
threat_detection_enumeration_actions:
[
"DescribeAccessEntry",
"DescribeAccountAttributes",
"DescribeAvailabilityZones",
"DescribeBundleTasks",
"DescribeCarrierGateways",
"DescribeClientVpnRoutes",
"DescribeCluster",
"DescribeDhcpOptions",
"DescribeFlowLogs",
"DescribeImages",
"DescribeInstanceAttribute",
"DescribeInstanceInformation",
"DescribeInstanceTypes",
"DescribeInstances",
"DescribeInstances",
"DescribeKeyPairs",
"DescribeLogGroups",
"DescribeLogStreams",
"DescribeOrganization",
"DescribeRegions",
"DescribeSecurityGroups",
"DescribeSnapshotAttribute",
"DescribeSnapshotTierStatus",
"DescribeSubscriptionFilters",
"DescribeTransitGatewayMulticastDomains",
"DescribeVolumes",
"DescribeVolumesModifications",
"DescribeVpcEndpointConnectionNotifications",
"DescribeVpcs",
"GetAccount",
"GetAccountAuthorizationDetails",
"GetAccountSendingEnabled",
"GetBucketAcl",
"GetBucketLogging",
"GetBucketPolicy",
"GetBucketReplication",
"GetBucketVersioning",
"GetCallerIdentity",
"GetCertificate",
"GetConsoleScreenshot",
"GetCostAndUsage",
"GetDetector",
"GetEbsDefaultKmsKeyId",
"GetEbsEncryptionByDefault",
"GetFindings",
"GetFlowLogsIntegrationTemplate",
"GetIdentityVerificationAttributes",
"GetInstances",
"GetIntrospectionSchema",
"GetLaunchTemplateData",
"GetLaunchTemplateData",
"GetLogRecord",
"GetParameters",
"GetPolicyVersion",
"GetPublicAccessBlock",
"GetQueryResults",
"GetRegions",
"GetSMSAttributes",
"GetSMSSandboxAccountStatus",
"GetSendQuota",
"GetTransitGatewayRouteTableAssociations",
"GetUserPolicy",
"HeadObject",
"ListAccessKeys",
"ListAccounts",
"ListAllMyBuckets",
"ListAssociatedAccessPolicies",
"ListAttachedUserPolicies",
"ListClusters",
"ListDetectors",
"ListDomains",
"ListFindings",
"ListHostedZones",
"ListIPSets",
"ListIdentities",
"ListInstanceProfiles",
"ListObjects",
"ListOrganizationalUnitsForParent",
"ListOriginationNumbers",
"ListPolicyVersions",
"ListRoles",
"ListRoles",
"ListRules",
"ListServiceQuotas",
"ListSubscriptions",
"ListTargetsByRule",
"ListTopics",
"ListUsers",
"LookupEvents",
"Search",
]
# aws.rds_instance_backup_enabled
# Whether to check RDS instance replicas or not
check_rds_instance_replicas: False
# Azure Configuration
azure:
@@ -20,6 +20,10 @@ class rds_instance_backup_enabled(Check):
f"RDS Instance {db_instance.id} does not have backup enabled."
)
if db_instance.replica_source and not rds_client.audit_config.get(
"check_rds_instance_replicas", False
):
continue
findings.append(report)
return findings
@@ -77,6 +77,9 @@ class RDS(AWSService):
cluster_arn=f"arn:{self.audited_partition}:rds:{regional_client.region}:{self.audited_account}:cluster:{instance.get('DBClusterIdentifier')}",
region=regional_client.region,
tags=instance.get("TagList", []),
replica_source=instance.get(
"ReadReplicaSourceDBInstanceIdentifier"
),
)
)
except Exception as error:
@@ -305,6 +308,7 @@ class DBInstance(BaseModel):
cluster_arn: Optional[str]
region: str
tags: Optional[list] = []
replica_source: Optional[str]
class DBCluster(BaseModel):
+1
View File
@@ -60,6 +60,7 @@ config_aws = {
],
"organizations_enabled_regions": [],
"organizations_trusted_delegated_administrators": [],
"check_rds_instance_replicas": False,
}
config_azure = {"shodan_api_key": None}
+4
View File
@@ -65,6 +65,10 @@ aws:
organizations_enabled_regions: []
organizations_trusted_delegated_administrators: []
# aws.rds_instance_backup_enabled
# Whether to check RDS instance replicas or not
check_rds_instance_replicas: False
# Azure Configuration
azure:
# Azure Network Configuration
+4
View File
@@ -60,3 +60,7 @@ obsolete_lambda_runtimes:
# ]
organizations_enabled_regions: []
organizations_trusted_delegated_administrators: []
# aws.rds_instance_backup_enabled
# Whether to check RDS instance replicas or not
check_rds_instance_replicas: False
@@ -1,4 +1,3 @@
from re import search
from unittest import mock
import botocore
@@ -58,8 +57,9 @@ class Test_rds_instance_backup_enabled:
@mock_aws
def test_rds_instance_no_backup(self):
conn = client("rds", region_name=AWS_REGION_US_EAST_1)
instance_id = "db-master-1"
conn.create_db_instance(
DBInstanceIdentifier="db-master-1",
DBInstanceIdentifier=instance_id,
AllocatedStorage=10,
Engine="postgres",
DBName="staging-postgres",
@@ -90,9 +90,9 @@ class Test_rds_instance_backup_enabled:
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"does not have backup enabled",
result[0].status_extended,
assert (
result[0].status_extended
== f"RDS Instance {instance_id} does not have backup enabled."
)
assert result[0].resource_id == "db-master-1"
assert result[0].region == AWS_REGION_US_EAST_1
@@ -105,13 +105,15 @@ class Test_rds_instance_backup_enabled:
@mock_aws
def test_rds_instance_with_backup(self):
conn = client("rds", region_name=AWS_REGION_US_EAST_1)
instance_id = "db-master-1"
retention_period = 10
conn.create_db_instance(
DBInstanceIdentifier="db-master-1",
DBInstanceIdentifier=instance_id,
AllocatedStorage=10,
Engine="postgres",
DBName="staging-postgres",
DBInstanceClass="db.m1.small",
BackupRetentionPeriod=10,
BackupRetentionPeriod=retention_period,
)
from prowler.providers.aws.services.rds.rds_service import RDS
@@ -135,9 +137,9 @@ class Test_rds_instance_backup_enabled:
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"has backup enabled",
result[0].status_extended,
assert (
result[0].status_extended
== f"RDS Instance {instance_id} has backup enabled with retention period {retention_period} days."
)
assert result[0].resource_id == "db-master-1"
assert result[0].region == AWS_REGION_US_EAST_1
@@ -146,3 +148,133 @@ class Test_rds_instance_backup_enabled:
== f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:db:db-master-1"
)
assert result[0].resource_tags == []
@mock_aws
def test_rds_instance_replica_with_backup_checking_replicas(self):
conn = client("rds", region_name=AWS_REGION_US_EAST_1)
instance_id = "db-master-1"
retention_period = 10
conn.create_db_instance(
DBInstanceIdentifier=instance_id,
AllocatedStorage=10,
Engine="postgres",
DBName="staging-postgres",
DBInstanceClass="db.m1.small",
BackupRetentionPeriod=retention_period,
)
replica_id = "db-replica-1"
conn.create_db_instance_read_replica(
DBInstanceIdentifier=replica_id,
SourceDBInstanceIdentifier="db-master-1",
DBInstanceClass="db.m1.small",
)
from prowler.providers.aws.services.rds.rds_service import RDS
aws_provider = set_mocked_aws_provider(
[AWS_REGION_US_EAST_1], audit_config={"check_rds_instance_replicas": True}
)
with mock.patch(
"prowler.providers.common.common.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled.rds_client",
new=RDS(aws_provider),
):
# Test Check
from prowler.providers.aws.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled import (
rds_instance_backup_enabled,
)
check = rds_instance_backup_enabled()
result = check.execute()
assert len(result) == 2
for finding in result:
if finding.resource_id == instance_id:
assert finding.status == "PASS"
assert (
finding.status_extended
== f"RDS Instance {instance_id} has backup enabled with retention period {retention_period} days."
)
assert finding.resource_id == instance_id
assert finding.region == AWS_REGION_US_EAST_1
assert (
finding.resource_arn
== f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:db:{instance_id}"
)
assert finding.resource_tags == []
if finding.resource_id == replica_id:
assert finding.status == "PASS"
assert (
finding.status_extended
== f"RDS Instance {replica_id} has backup enabled with retention period {retention_period} days."
)
assert finding.resource_id == replica_id
assert finding.region == AWS_REGION_US_EAST_1
assert (
finding.resource_arn
== f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:db:{replica_id}"
)
assert finding.resource_tags == []
@mock_aws
def test_rds_instance_replica_with_backup_default_config(self):
conn = client("rds", region_name=AWS_REGION_US_EAST_1)
instance_id = "db-master-1"
retention_period = 10
conn.create_db_instance(
DBInstanceIdentifier=instance_id,
AllocatedStorage=10,
Engine="postgres",
DBName="staging-postgres",
DBInstanceClass="db.m1.small",
BackupRetentionPeriod=retention_period,
)
replica_id = "db-replica-1"
conn.create_db_instance_read_replica(
DBInstanceIdentifier=replica_id,
SourceDBInstanceIdentifier=instance_id,
DBInstanceClass="db.m1.small",
)
from prowler.providers.aws.services.rds.rds_service import RDS
aws_provider = set_mocked_aws_provider(
[AWS_REGION_US_EAST_1],
)
with mock.patch(
"prowler.providers.common.common.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled.rds_client",
new=RDS(aws_provider),
):
# Test Check
from prowler.providers.aws.services.rds.rds_instance_backup_enabled.rds_instance_backup_enabled import (
rds_instance_backup_enabled,
)
check = rds_instance_backup_enabled()
result = check.execute()
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"RDS Instance {instance_id} has backup enabled with retention period {retention_period} days."
)
assert result[0].resource_id == instance_id
assert result[0].region == AWS_REGION_US_EAST_1
assert (
result[0].resource_arn
== f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:db:{instance_id}"
)
assert result[0].resource_tags == []