"""Lambda find-databases-to-back-up function module.""" import json import logging import sys import boto3 import sentry_sdk from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration import config if config.SENTRY_DSN: sentry_sdk.init( dsn=config.SENTRY_DSN, environment=config.ENVIRONMENT, integrations=[AwsLambdaIntegration(timeout_warning=True)] ) logger = logging.getLogger() logger.setLevel(config.LOGGER_LEVEL) stream_handler = logging.StreamHandler(sys.stdout) stream_handler.setLevel(logging.DEBUG) logger.handlers = [stream_handler] def assume_source_account_role(account_id): """ Assume IAM role in source account. Args: account_id (str): AWS account ID Returns: dict: dict of AWS credentials """ client = boto3.client('sts') assume_role_response = client.assume_role( RoleArn=f'arn:aws:iam::{account_id}:role/{config.CROSS_ACCOUNT_BACKUP_ROLE_NAME}', # noqa RoleSessionName=config.SERVICE_NAME, ExternalId=config.EXTERNAL_ID, DurationSeconds=3600 ) credentials = assume_role_response['Credentials'] return credentials def find_production_databases(client): """ Find production databases for a given account. Args: client (obj): a boto3 client Returns: dict: matching RDS database names and types """ clusters = client.describe_db_clusters()['DBClusters'] prod_clusters = { cluster['DBClusterIdentifier']: 'cluster' for cluster in clusters if [True for tag in cluster['TagList'] if ( (tag['Key'].lower() == 'environment' and tag['Value'] in ['prod', 'shared']))]} # noqa # Now find production instances = client.describe_db_instances()['DBInstances'] # Filter out cluster instances prod_instances = { instance['DBInstanceIdentifier']: 'standalone' for instance in instances if ( 'DBClusterIdentifier' not in instance and [ True for tag in instance['TagList'] if ( (tag['Key'].lower() == 'environment' and tag['Value'] in ['prod', 'shared']))] # noqa ) } return prod_clusters | prod_instances def handler(event, context): """Lambda entry point.""" for source_account_id in config.ACCOUNT_IDS_TO_BACKUP: credentials = assume_source_account_role(source_account_id) rds_client = boto3.client( 'rds', region_name=config.AWS_REGION, aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'] ) production_databases = find_production_databases(rds_client) logger.info('Databases to back up in account ' f'{source_account_id}: {production_databases.keys()}') for db_name, db_type in production_databases.items(): try: sfn_client = boto3.client('stepfunctions') sfn_input_dict = { 'source_account_id': source_account_id, 'db_name': db_name, 'db_type': db_type, } response = sfn_client.start_execution( stateMachineArn=config.STATE_MACHINE_ARN, input=json.dumps(sfn_input_dict) ) execution_arn = response['executionArn'] logger.info( f'Started state machine execution: {execution_arn}') except Exception as error: logger.exception(str(error)) raise error