commands.py 7.74 KB
Newer Older
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
import click
from akinaka.client.aws_client import AWS_Client
from akinaka.libs import helpers, scan_resources_storage
from akinaka.libs import helpers, kms_share
from time import gmtime, strftime
import logging

aws_client = AWS_Client()
helpers.set_logger()

@click.group()
@click.option("--region", required=True, help="Region your resources are located in")
@click.option("--source-role-arn", required=True, help="ARN of a role the account to back up _from_")
@click.option("--destination-role-arn", required=True, help="ARN of an assumable role in the account to back up _to_")
@click.option("--dry-run", is_flag=True, help="Don't back anything up, just list would be backed up")
@click.pass_context
def dr(ctx, region, source_role_arn, destination_role_arn, dry_run):
    """
    Disaster recovery subcommand. Does nothing by itself except pass the global options through to it's
    subcommands via ctx
    """

    ctx.obj = {
        'region': region,
        'source_role_arn': source_role_arn,
        'destination_role_arn': destination_role_arn,
        'dry_run': dry_run,
        'log_level': ctx.obj.get('log_level')
    }

    pass

def get_shared_kms_key(region, source_role_arn, source_account, destination_account):
    """
    Create and return shared KMS account between [source_account] and [destination_account]
    """

    kms_sharer = kms_share.KMSShare(
        region = region,
        assumable_role_arn = source_role_arn,
        share_from_account = source_account,
        share_to_account = destination_account
    )

    return kms_sharer.get_kms_key(source_account)

def create_kms_key(region, assumable_role_arn):
    """
    Search for a key name that should exists if this has been run before. If not found,
    create it. In both cases, return the key.
    """

    kms_client = aws_client.create_client('kms', region, assumable_role_arn)
    key_alias = "alias/Akinaka"

    try:
        kms_key = kms_client.describe_key(KeyId=key_alias)
        logging.info("Found key: {}".format(kms_key['KeyMetadata']['Arn']))
    except kms_client.exceptions.NotFoundException:
        kms_key = kms_client.create_key()
        logging.info("No existing key found, so we created one: {}".format(kms_key['KeyMetadata']['Arn']))

        kms_client.create_alias(
            AliasName=key_alias,
            TargetKeyId=kms_key['KeyMetadata']['Arn']
        )

    return kms_key


@dr.command()
@click.pass_context
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
73
@click.option("--take-snapshot", is_flag=True, help="Boolean, default false. Take a live snapshot now, or take the existing latest snapshot. Relevant only for RDS")
74
@click.option("--names", required=False, help="Comma separated list in quotes of DB/S3 names to transfer")
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
75
@click.option("--service", type=click.Choice(['rds', 'aurora', 's3']), required=False, help="The service to transfer backups for. Defaults to all (RDS, S3)")
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
76
@click.option("--retention", required=False, help="Number of days of backups to keep")
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
77
@click.option("--rotate", is_flag=True, required=False, help="Only rotate backups so [retention] number of days is kept, don't do any actual backups. Relevant for RDS only")
78 79
@click.option("--keep", required=False, help="Comma separated list in quotes. Do not delete these snapshot IDs as part of the rotation policy.")
def transfer(ctx, take_snapshot, names, service, retention, keep, rotate):
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
80
    """
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
81 82
    Creates and passes shared KMS keys to the subcommands which wish to tranfer data between eachother.

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    Backup [service] from owning account of [ctx.source_role_arn] to owning account
    of [ctx.destination_role_arn].
    """

    region = ctx.obj.get('region')
    source_role_arn = ctx.obj.get('source_role_arn')
    destination_role_arn = ctx.obj.get('destination_role_arn')
    dry_run = ctx.obj.get('dry_run')

    source_sts_client = aws_client.create_client('sts', region, source_role_arn)
    source_account = source_sts_client.get_caller_identity()['Account']
    destination_sts_client = aws_client.create_client('sts', region, destination_role_arn)
    destination_account = destination_sts_client.get_caller_identity()['Account']

    source_kms_key = get_shared_kms_key(region, source_role_arn, source_account, destination_account)
    destination_kms_key = create_kms_key(region, destination_role_arn)

    if service == 'rds':
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
101 102
        if names:
            db_names = [names.replace(' ','')]
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
103 104
        else:
            scanner = scan_resources_storage.ScanResources(region, source_role_arn)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
105
            db_names = scanner.scan_rds_instances()['db_names']
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
106

107 108 109
        if keep:
            keep = [keep.replace(' ','')]

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
110 111 112 113 114 115 116 117 118 119
        rds(
            dry_run,
            region,
            source_role_arn,
            destination_role_arn,
            take_snapshot,
            db_names,
            source_kms_key,
            destination_kms_key,
            source_account,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
120 121
            destination_account,
            retention,
122
            keep,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
123
            rotate)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
124 125

    if service == 'aurora':
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
126 127
        if names:
            db_names = [names.replace(' ','')]
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
128 129
        else:
            scanner = scan_resources_storage.ScanResources(region, source_role_arn)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
130
            db_names = scanner.scan_rds_aurora()['aurora_names']
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
131

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
132 133 134 135 136 137
        rds(
            dry_run,
            region,
            source_role_arn,
            destination_role_arn,
            take_snapshot,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
138
            db_names,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
139 140 141
            source_kms_key,
            destination_kms_key,
            source_account,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
142 143
            destination_account,
            retention,
144
            keep,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
145
            rotate)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
146

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
147
    if service == 's3':
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
        if names:
            names = [names.replace(' ','')]
        else:
            scanner = scan_resources_storage.ScanResources(region, source_role_arn)
            names = scanner.scan_s3()['s3_names']

        s3(
            dry_run,
            region,
            source_role_arn,
            destination_role_arn,
            names,
            source_kms_key,
            destination_kms_key,
            retention
        )

def s3(
        dry_run,
        region,
        source_role_arn,
        destination_role_arn,
        names,
        source_kms_key,
        destination_kms_key,
        retention):
    """ Call the S3 class to make backups of S3 buckets """

    logging.info("Will attempt to backup the following S3 buckets, unless this is a dry run:")
    logging.info(names)

    if dry_run:
        exit(0)

    retention = retention or 7

    from .s3 import transfer_s3
    s3 = transfer_s3.TransferS3(
        region=region,
        source_role_arn=source_role_arn,
        destination_role_arn=destination_role_arn,
        source_kms_key=source_kms_key,
        destination_kms_key=destination_kms_key,
        retention=retention
    )

    s3.main(names)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
195 196 197 198 199 200 201

def rds(
    dry_run,
    region,
    source_role_arn,
    destination_role_arn,
    take_snapshot,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
202
    db_names,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
203 204 205
    source_kms_key,
    destination_kms_key,
    source_account,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
206 207
    destination_account,
    retention,
208
    keep,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
209
    rotate):
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
210 211 212 213
    """
    Call the RDS class to transfer snapshots
    """

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
214
    logging.info("Will attempt to backup the data for following RDS instances, unless this is a dry run:")
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
215
    logging.info(db_names)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
216 217 218 219 220 221 222 223 224 225 226 227 228

    if dry_run:
        exit(0)

    from .rds import transfer_snapshot
    rds = transfer_snapshot.TransferSnapshot(
        region=region,
        source_role_arn=source_role_arn,
        destination_role_arn=destination_role_arn,
        source_kms_key=source_kms_key,
        destination_kms_key=destination_kms_key
    )

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
229 230 231 232
    retention = retention or 7

    if rotate:
        for db_name in db_names:
233
            rds.rotate_snapshots(retention, db_name, keep)
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
234 235
        exit()

Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
236 237
    rds.transfer_snapshot(
        take_snapshot=take_snapshot,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
238
        db_names=db_names,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
239
        source_account=source_account,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
240
        destination_account=destination_account,
241
        keep=keep,
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
242
        retention=retention
Afraz Ahmadzadeh's avatar
Afraz Ahmadzadeh committed
243
    )