Adam Pippin
4 years ago
commit
ea0e810c4b
2 changed files with 202 additions and 0 deletions
@ -0,0 +1,166 @@ |
|||
import json |
|||
import boto3 |
|||
import time |
|||
|
|||
# The account id sharing snapshots with you |
|||
SOURCE_ACCOUNT = "987698769876" |
|||
# The account id this is running in |
|||
TARGET_ACCOUNT = "123412341234" |
|||
# Mapping of KMS keys -- keys are the key arn in the source account, values |
|||
# are the key arn in this account. |
|||
KMS_KEYS = { |
|||
"arn:aws:kms:ca-central-1:987698769876:key/abcd-abcd-abcd": "arn:aws:kms:ca-central-1:123412341234:key/qrst-qrst-qrst" |
|||
} |
|||
# Configure retention period for deleted snapshots. If the string is present |
|||
# in the snapshot description, then the retention time will be the number of |
|||
# seconds given in the value. If multiple strings match, which one is chosen |
|||
# is undefined. |
|||
RETENTION = { |
|||
"hour_snapshot": 0, |
|||
"day_snapshot": 86400, |
|||
"week_snapshot": 259200, |
|||
"month_snapshot": 259200, |
|||
"year_snapshot": 259200 |
|||
} |
|||
# Name of the tag on the snapshots to store the source snapshot id in. |
|||
SOURCE_TAG = "SourceSnapshotId" |
|||
# Name of the tag on the snapshots to store the retention period in. |
|||
RETENTION_TAG = "RetentionPeriod" |
|||
# Region the source snapshots are in. |
|||
REGION = "ca-central-1" |
|||
|
|||
print("START") |
|||
ec2 = boto3.client('ec2') |
|||
|
|||
def lambda_handler(event, context): |
|||
print("Fetching snapshots for source account " + SOURCE_ACCOUNT) |
|||
source_snapshots = fetch_snapshots(SOURCE_ACCOUNT) |
|||
print("Fetching snapshots for target account: " + TARGET_ACCOUNT) |
|||
target_snapshots = fetch_snapshots(TARGET_ACCOUNT) |
|||
source_snapshot_index = {} |
|||
target_snapshot_index = {} |
|||
target_snapshots_mapped = {} |
|||
target_snapshots_orphaned = {} |
|||
|
|||
results = [] |
|||
|
|||
for snapshot in source_snapshots: |
|||
source_snapshot_index[snapshot['SnapshotId']] = snapshot |
|||
|
|||
for snapshot in target_snapshots: |
|||
target_snapshot_index[snapshot['SnapshotId']] = snapshot |
|||
|
|||
for tag in snapshot['Tags']: |
|||
if tag['Key'] == SOURCE_TAG: |
|||
source_snapshot_id = tag['Value'] |
|||
if source_snapshot_id in source_snapshot_index.keys(): |
|||
target_snapshots_mapped[source_snapshot_id] = snapshot |
|||
else: |
|||
target_snapshots_orphaned[snapshot['SnapshotId']] = snapshot |
|||
|
|||
for source_snapshot_id, source_snapshot in source_snapshot_index.items(): |
|||
if source_snapshot_id in target_snapshots_mapped.keys(): |
|||
results.append(handle_snapshot(source_snapshot, target_snapshots_mapped[source_snapshot_id])) |
|||
else: |
|||
results.append(handle_snapshot(source_snapshot, None)) |
|||
|
|||
for target_snapshot_id in target_snapshots_orphaned: |
|||
results.append(handle_snapshot(None, target_snapshots_orphaned[target_snapshot_id])) |
|||
|
|||
results = list(filter(None, results)) |
|||
|
|||
return { |
|||
'statusCode': 200, |
|||
'body': json.dumps(results) |
|||
} |
|||
|
|||
def fetch_snapshots(account_id): |
|||
return ec2.describe_snapshots( |
|||
Filters = [ |
|||
{ |
|||
'Name': 'owner-id', |
|||
'Values': [ account_id ] |
|||
} |
|||
] |
|||
)['Snapshots'] |
|||
|
|||
def handle_snapshot(source_snapshot, target_snapshot): |
|||
if source_snapshot is not None and target_snapshot is not None: |
|||
# Source and target exist, nothing to do! |
|||
pass |
|||
elif source_snapshot is not None and target_snapshot is None: |
|||
# Source exists, no target. Copy! |
|||
print(source_snapshot['SnapshotId'] + " copying") |
|||
|
|||
# Quick guard -- make sure the snapshot is complete first. |
|||
if source_snapshot['Progress'] != '100%': |
|||
return [source_snapshot['SnapshotId'], None, "Source snapshot incomplete. Doing nothing."] |
|||
|
|||
copy_response = ec2.copy_snapshot( |
|||
Description = '/'.join([ |
|||
source_snapshot['OwnerId'], |
|||
source_snapshot['VolumeId'], |
|||
str(source_snapshot['StartTime']), |
|||
source_snapshot['Description'] |
|||
]), |
|||
Encrypted = True, |
|||
KmsKeyId = KMS_KEYS[source_snapshot['KmsKeyId']], |
|||
SourceRegion = REGION, |
|||
SourceSnapshotId = source_snapshot['SnapshotId'], |
|||
TagSpecifications = [ |
|||
{ |
|||
'ResourceType': 'snapshot', |
|||
'Tags': [ |
|||
{ |
|||
"Key": SOURCE_TAG, |
|||
"Value": source_snapshot['SnapshotId'] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
) |
|||
|
|||
return [source_snapshot['SnapshotId'], copy_response['SnapshotId'], "Copied snapshot"] |
|||
|
|||
elif source_snapshot is None and target_snapshot is not None: |
|||
# Check if there's already a retention tag |
|||
|
|||
retention = None |
|||
|
|||
for tag in target_snapshot['Tags']: |
|||
if tag['Key'] == RETENTION_TAG: |
|||
retention = float(tag['Value']) |
|||
break |
|||
|
|||
if retention is None: |
|||
# Mark target with retention tag |
|||
print(target_snapshot['SnapshotId'] + ": marked for removal") |
|||
|
|||
retention = time.time() |
|||
description = target_snapshot['Description'] |
|||
for search_str, retention_seconds in RETENTION.items(): |
|||
if search_str in description: |
|||
retention = retention + retention_seconds |
|||
break |
|||
|
|||
ec2.create_tags( |
|||
Resources=[ |
|||
target_snapshot['SnapshotId'] |
|||
], |
|||
Tags=[ |
|||
{ |
|||
'Key': RETENTION_TAG, |
|||
'Value':str(retention) |
|||
} |
|||
] |
|||
) |
|||
|
|||
return [None, target_snapshot['SnapshotId'], "Source removed. Marking for deletion."] |
|||
|
|||
elif retention < time.time(): |
|||
print(target_snapshot['SnapshotId'] + ": retention time passed, removing") |
|||
ec2.delete_snapshot( |
|||
SnapshotId = target_snapshot['SnapshotId'] |
|||
) |
|||
return [None, target_snapshot['SnapshotId'], "Retention period passed. Deleted."] |
|||
|
@ -0,0 +1,36 @@ |
|||
import json |
|||
import boto3 |
|||
|
|||
VOLUME_ID = 'vol-123412341234' |
|||
TARGET_ACCOUNT = "123412341234" |
|||
|
|||
print("START") |
|||
|
|||
def lambda_handler(event, context): |
|||
ec2 = boto3.resource('ec2') |
|||
print("Fetching snapshots for volume " + VOLUME_ID) |
|||
volume = ec2.Volume(id=VOLUME_ID) |
|||
snapshots = volume.snapshots.all() |
|||
snapshot_ids = [] |
|||
|
|||
for snapshot in snapshots: |
|||
shared = snapshot.describe_attribute(Attribute='createVolumePermission') |
|||
already_shared = False |
|||
|
|||
for i in range(0, len(shared['CreateVolumePermissions'])): |
|||
if 'UserId' in shared['CreateVolumePermissions'][i] and shared['CreateVolumePermissions'][i]['UserId'] == TARGET_ACCOUNT: |
|||
already_shared = True |
|||
break |
|||
|
|||
if not already_shared: |
|||
print("Sharing " + snapshot.id) |
|||
snapshot_ids.append(snapshot.id) |
|||
snapshot.modify_attribute( |
|||
Attribute='createVolumePermission', |
|||
OperationType='add', |
|||
UserIds=[TARGET_ACCOUNT]) |
|||
|
|||
return { |
|||
'statusCode': 200, |
|||
'body': json.dumps(snapshot_ids) |
|||
} |
Loading…
Reference in new issue