ClassicLinkを設定していないEC2 Classicインスタンスを一覧する


tl;dr

EC2 Classic で稼働しているインスタンスについて、ClassicLinkを設定しないインスタンスを一覧する

背景

インクリメンツでは一部EC2 Classic環境のインスタンスが稼働しています。これらのClassicLinkの状況をチェックしたいのですが、以下の状況から1つのAPIで実現できず、AWS CLIでは厳しい。

  • DescribeInstances では、EC2 Classicで稼働しているインスタンスのみを取得するのができなさそう
    • filterでは実現できなさそうだし、queryでは結構つらい
    • ClassicLinkの状態は取得できない
  • DescribeClassicLinkInstances というAPIはありますが、これはClassicLink設定済みのインスタンスしか返却されない

ということでコードを書いた。
AWS Config の Custom Rule を作れば、新しくインスタンスが起動してきてもチェックすることができて安心。

EC2 Classicのインスタンスを列挙する

いくつか方法はありますが、VpcId の要素が無いのは Classic インスタンスです。

import boto3

ec2 = boto3.client('ec2')
paginator = ec2.get_paginator('describe_instances')
response_iterator = paginator.paginate()

for response in response_iterator:
    for reservations in response['Reservations']:
        for instance in reservations['Instances']:
            if instance.get('VpcId') is not None:
                continue

            instanceId = instance['InstanceId']
            imageId = instance['ImageId']
            state = instance['State']['Name']
            name = dict([[x['Key'], x['Value']] for x in instance.get('Tags')]).get('Name')

            print("\t".join([imageId, instanceId, state, name]))

タグの要素は [{Key: 'key', Value: 'value'}, ..] とリストの中に辞書が入っているのでリスト内包表記で [['key', 'value'], ...] の形式にしてdict()で辞書にした。

ClassicLink未設定のインスタンスを列挙

ClassicLinkが未設定のインスタンスは、EC2 Classicインスタンス一覧から、ClassicLinkインスタンス一覧を引いたもの。

import sys
import boto3

ec2 = boto3.client('ec2')

paginator = ec2.get_paginator('describe_instances')
response_iterator = paginator.paginate()

classicInstances = dict()

# fetch classic instances
for response in response_iterator:
    for reservations in response['Reservations']:

        for instance in reservations['Instances']:
            if instance.get('VpcId') is not None:
                continue

            instanceId = instance['InstanceId']
            imageId = instance['ImageId']
            state = instance['State']['Name']
            name = dict([[x['Key'], x['Value']] for x in instance.get('Tags')]).get('Name')

            classicInstances[instanceId] = {'imageId': imageId, 'state': state, 'name': name}

# fetch ClassicLink-ed instances
response = ec2.describe_classic_link_instances()

classicLinkInstances = dict()

for instance in response['Instances']:
    classicLinkInstances[instance['InstanceId']] = instance

# check ClassicLink not enabled instances
notActivatedInstanceIds = set(classicInstances.keys()) -  set(classicLinkInstances.keys())

print("# ClassicLink is not enabled")
for instanceId in notActivatedInstanceIds:
    print(classicInstances[instanceId])

describe_classic_link_instances には paginator が無いので、上のコードだとインスタンスが多い場合は駄目ですね。残念。

ClassicLinkが設定されているインスタンスの情報取得

これは、describe-classic-link-instances でいけるので、AWS CLIで。

aws ec2 describe-classic-link-instances \
--query 'Instances[].{InstanceId:InstanceId,VpcId:VpcId,Group:Groups[0].GroupId,Name:Tags[?Key==`Name`].Value|[0]}' \
--output table
aws ec2 describe-classic-link-instances --query 'Instances[].{InstanceId:InstanceId,VpcId:VpcId,Group:Groups[0].GroupId,Name:Tags[?Key==`Name`].Value|[0]}' --output table
---------------------------------------------------------------------------------------------------
|                                  DescribeClassicLinkInstances                                   |
+-------------+----------------------+-------------------------------------------+----------------+
|    Group    |     InstanceId       |                   Name                    |     VpcId      |
+-------------+----------------------+-------------------------------------------+----------------+
|  sg-c4effff|  i-04c1410db8deffff |  classic-foo-bar-baz                        |  vpc-16a2ffff  |

Nameタグを取ってくるのが面倒。