Securing Publicly Accessible AWS RDS Instances

This runbook is essential to prevent unauthorized access and data breaches. This entails configuring RDS instances to be private, thereby making them accessible only within the specified Virtual Private Cloud (VPC). Initially, all RDS instances are scanned to identify those marked as publicly accessible. This status is then altered to private, or within the AWS network, enhancing the security of the data stored. It is crucial to monitor the security groups and network access control lists (NACLs) associated with the instances to enforce this restricted access effectively. These preventive measures safeguard sensitive data and are a fundamental aspect of AWS security best practices.

  1. 1

    This task involves enumerating and displaying all AWS RDS (Amazon Relational Database Service) instances within an AWS account. This task is essential for management and auditing purposes, providing a clear view of all RDS instances. During this process, the script communicates with AWS services to retrieve information about each RDS instance, including their identifiers, status, and any other relevant details. This information is crucial for administrators to understand their AWS infrastructure's state, aiding in further actions like modification, deletion, or analysis of the RDS instances.

    import boto3 from botocore.exceptions import BotoCoreError, ClientError reg=None # Runs for specific region if provided otherwise runs for all regions if None/nothing is provided. creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def list_all_rds_instances(region=None): try: if region: regions = [region] else: # If region is None, list instances in all available regions ec2 = boto3.client('ec2', aws_access_key_id=access_key,aws_secret_access_key=secret_key,region_name='us-east-1') regions = [region['RegionName'] for region in ec2.describe_regions()['Regions']] all_instances = [] for region in regions: #print(f"Listing RDS instances in region {region}:") client = boto3.client('rds', aws_access_key_id=access_key,aws_secret_access_key=secret_key,region_name=region) try: db_instances = client.describe_db_instances() region_instances = [instance['DBInstanceIdentifier'] for instance in db_instances['DBInstances']] if region_instances: print(f"Found {len(region_instances)} RDS instances in region {region}:") for instance in region_instances: print(instance) all_instances.append({"region": region, "instance": instance}) else: #print(f"No RDS instances found in region {region}.") p=1 # dummy line to end the conditional block properly except ClientError as e: print(f"Client error in region {region}: {e}") except BotoCoreError as e: print(f"BotoCoreError in region {region}: {e}") except Exception as e: print(f"Unexpected error in region {region}: {e}") return all_instances except Exception as e: print(f"Unexpected error: {e}") instances = list_all_rds_instances(reg) # reg is initialized in input parameters. Runs for specific region if provided otherwise runs for all regions if None/nothing is provided. #print(instances)
    copied
    1
  2. 2

    This task is essential for identifying databases that are exposed to the internet, potentially posing security risks. This process involves scanning through all active AWS RDS instances in a given AWS account and pinpointing those configured to be publicly accessible. Publicly accessible in this context means that the RDS instance is reachable from the internet and not just within a private network or Virtual Private Cloud (VPC). By isolating these instances, administrators can take necessary actions to secure sensitive data, either by modifying the accessibility settings or implementing additional security measures. This task is crucial for maintaining a secure and compliant cloud environment, as it helps prevent unauthorized access and data breaches.

    import boto3 from botocore.exceptions import BotoCoreError, ClientError creds = _get_creds(cred_label)['creds'] access_key = creds['username'] secret_key = creds['password'] def filter_public_rds_instances(all_instances): public_instances = [] try: for instance_info in all_instances: region = instance_info['region'] instance = instance_info['instance'] print(f"Checking for public accessibility of RDS instance {instance} in region {region}:") client = boto3.client('rds', aws_access_key_id=access_key,aws_secret_access_key=secret_key,region_name=region) try: instance_details = client.describe_db_instances(DBInstanceIdentifier=instance) if instance_details['DBInstances'][0]['PubliclyAccessible']: public_instances.append({"region": region, "instance": instance}) print(f"{instance} in region {region} is publicly accessible.") except ClientError as e: print(f"Client error with instance {instance} in region {region}: {e}") except BotoCoreError as e: print(f"BotoCoreError with instance {instance} in region {region}: {e}") except Exception as e: print(f"Unexpected error with instance {instance} in region {region}: {e}") if not public_instances: print("No publicly accessible RDS instances found in the provided list.") except Exception as e: print(f"Unexpected error: {e}") return public_instances # Example list of all RDS instances and regions. Replace this with the actual data from your AWS account. # all_instances = [{'region': 'us-east-1', 'instance': 'database-1'},{'region': 'us-west-1', 'instance': 'database-1'}] # Example data # instances passed down from parent task all_instances = instances public_instances = filter_public_rds_instances(all_instances) #print(public_instances) context.proceed = False
    copied
    2
  3. 3

    This task modifies AWS RDS instances to be private and is aimed at enhancing the security of your database instances. Some RDS instances may be configured to be publicly accessible over the internet, exposing them to potential security vulnerabilities. Making an AWS RDS instance private means adjusting its accessibility settings so that it is no longer reachable from the open internet. This modification helps to shield your data from unauthorized access, providing an additional layer of security to your databases. It's a crucial measure for organizations that handle sensitive information, ensuring that their data storage complies with best security practices and regulatory standards.

    import boto3 from botocore.exceptions import BotoCoreError, ClientError def modify_rds_to_private(db_instance_info_list): try: for db_info in db_instance_info_list: region = db_info['region'] identifier = db_info['instance'] client = boto3.client('rds', region_name=region) try: # Retrieve the DB instance information instance_info = client.describe_db_instances(DBInstanceIdentifier=identifier) instance = instance_info['DBInstances'][0] instance_status = instance['DBInstanceStatus'] publicly_accessible = instance['PubliclyAccessible'] # Check if the instance is already private if not publicly_accessible: print(f"Instance {identifier} in region {region} is already private. Skipping modification.") continue # Check if the instance is in the 'available' state if instance_status != 'available': print(f"Instance {identifier} in region {region} is not in 'available' state. Currently in '{instance_status}' state. Skipping modification.") continue # Skip to the next iteration for other instances # If instance is available and public, proceed with modification client.modify_db_instance( DBInstanceIdentifier=identifier, PubliclyAccessible=False ) print(f"Modified {identifier} in region {region} to be private.") except ClientError as e: print(f"Client error with instance {identifier} in region {region}: {e}") except BotoCoreError as e: print(f"BotoCoreError with instance {identifier} in region {region}: {e}") except Exception as e: print(f"Unexpected error with instance {identifier} in region {region}: {e}") except Exception as e: print(f"Unexpected error: {e}") # Example input list of dictionaries. Replace this with your actual data. # db_instance_info_list = [{'region': 'us-east-1', 'instance': 'database-1'},{'region': 'us-west-1', 'instance': 'database-1'}] # Example data # public_instances passed down from parent task db_instance_info_list = public_instances if db_instance_info_list: modify_rds_to_private(db_instance_info_list) else: print("No RDS Instances provided for modification.")
    copied
    3