📌

特定日数すぎたリソースの削除 + おまけ

2023/03/04に公開

これは何

停止状態になってから特定日数すぎた EC2 を一括削除するスクリプト

対応している Security Hub のルール

Stopped EC2 instances should be removed after a specified time period

[EC2.4] This control checks whether any EC2 instances have been stopped for more than the allowed number of days. An EC2 instance fails this check if it is stopped for longer than the maximum allowed time period, which by default is 30 days

コード

削除する経過日数を指定して実行する

import boto3

not_run_days = 30  # 削除対象の経過日数

def lambda_handler(event, context):
    for region in boto3.session.Session().get_available_regions('ec2'):

        ec2c = boto3.client('ec2', region)

        # Delete EC2 instance stopped for target days.
	for reservation in ec2c.describe_instances()['Reservations']:
            for instance in reservation['Instances']:
                if(instance['State']['Name'] in ['stopped'] \
		    and (now - instance['LaunchTime'].replace(tzinfo=None)).days > not_run_days:
                    if(ec2c.describe_instance_attribute(Attribute='disableApiTermination',InstanceId=instance['InstanceId'])['DisableApiTermination']['Value']) == True:
		        ec2c.modify_instance_attribute(
                            DisableApiTermination={
                                'Value': False
                            },
                            InstanceId=instance['InstanceId']
                        )
                    list = [instance['InstanceId']]
                    ec2c.terminate_instances(InstanceIds=list)

おまけ(その他課金対象リソースの自動削除

EC2 のスナップショット

import boto3

snapshot_days = 30  # 削除対象の経過日数

def lambda_handler(event, context):
    for region in boto3.session.Session().get_available_regions('ec2'):

        ec2c = boto3.client('ec2', region)

        # Delete EC2 snapshot stopped for target days. exclude ami snapshot
        for snapshot in ec2c.describe_snapshots(OwnerIds=['self'])['Snapshots']:
            if ((now - snapshot['StartTime'].replace(tzinfo=None)).days > snapshot_days:
                x = snapshot['Description']
                m = re.search(r'ami.*', x, flags=re.DOTALL)
                y = m.group(0) if m else None
                z = repr(y)
                amiIDs = z[1:22]
                try:
                    ec2c.delete_snapshot(SnapshotId=snapshot['SnapshotId'])
                except:
                    print("This is AMi Snapshot")

RDS のスナップショット

import boto3

snapshot_days = 30  # 削除対象の経過日数

def lambda_handler(event, context):
    for region in boto3.session.Session().get_available_regions('rds'):

        rdsc = boto3.client('rds', region)

        # Delete RDS snapshot stopped for target days.
        for snapshot in rdsc.describe_db_snapshots()['DBSnapshots']:
            if ((now - snapshot['SnapshotCreateTime'].replace(tzinfo=None)).days > snapshot_days:
	        rdsc.delete_db_snapshot(DBSnapshotIdentifier=snapshot['DBSnapshotIdentifier'])

インスタンスにアタッチされていない EBS ボリューム

import boto3

def lambda_handler(event, context):
    for region in boto3.session.Session().get_available_regions('ec2'):

        ec2c = boto3.client('ec2', region)

        # Delete non attached EBS volumes
        for ebs in ec2c.describe_volumes()['Volumes']:
            if(len(ebs['Attachments']) == 0):
                ec2c.delete_volume(VolumeId=ebs['VolumeId'])

インスタンスまたは Nat Gateway にアタッチされていない Elastic IP

import boto3

def lambda_handler(event, context):
    for region in boto3.session.Session().get_available_regions('ec2'):

        ec2c = boto3.client('ec2', region)

        # Delete non attached EIP
        for eip in ec2c.describe_addresses()['Addresses']:
            if eip.get('AssociationId') is None:
                ec2c.release_address(AllocationId=eip['AllocationId'])

Discussion