おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

AWS Configでリソースに紐付かないセキュリティグループを抽出

tl;dr

  • 使っていないセキュリティグループを列挙したい
  • セキュリティグループはENIに対して割り当て、ENIがEC2などのリソースにアタッチされている。使っていないセキュリティグループ = どのENIにも割り当てられていないセキュリティグループ、なのだが、取得するのはセキュリティグループを列挙し、ENIを列挙して、という作業が必要でEC2 API叩いて処理するの地味に面倒
  • AWS Configを有効にしているなら、クエリでいい感じにとれるし、リージョンもまたげるし、Aggregatorを使っているならマルチアカウントも一発

コード

import json

import boto3

client = boto3.client('config')

query = "SELECT resourceId, awsRegion, resourceName, " \
        "configuration.description, configuration.ipPermissions, " \
        "configuration.ipPermissionsEgress, relationships " \
        "WHERE resourceType = 'AWS::EC2::SecurityGroup'"

results = []

response = client.select_resource_config(Expression=query, 
                                         Limit=100)
results.extend(response['Results'])

while True:
    if 'NextToken' in response:
        response = client.select_resource_config(Expression=query,
                                                 NextToken=response['NextToken'], 
                                                 Limit=100)
        results.extend(response['Results'])
    else:
        break

for result in results:
    result = json.loads(result)

    for relationship in result['relationships']:
        if relationship['resourceType'] == 'AWS::EC2::NetworkInterface':
            #eni_id = relationship['resourceId']
            break
    else:
        # 関連するENIが無い = リソースに関連付けられていないセキュリティグループ
        print('\t'.join(
            [result['awsRegion'], result['resourceId'], result['resourceName'],
             result['configuration']['description']]))

マルチアカウント版コード

select_aggregate_resource_config() に差し替えるだけで、AWS Config Aggregatorに対してクエリを実行できます。便利。

import json

import boto3

client = boto3.client('config')

query = "SELECT accountId, resourceId, awsRegion, resourceName, " \
        "configuration.description, configuration.ipPermissions, " \
        "configuration.ipPermissionsEgress, relationships " \
        "WHERE resourceType = 'AWS::EC2::SecurityGroup'"

results = []

response = client.select_aggregate_resource_config(Expression=query, Limit=100,
                                                   ConfigurationAggregatorName='<aggregator name>')
results.extend(response['Results'])

while True:
    if 'NextToken' in response:
        response = client.select_aggregate_resource_config(Expression=query, 
                                                           NextToken=response['NextToken'], 
                                                           Limit=100,
                                                           ConfigurationAggregatorName='<aggregator name>')
        results.extend(response['Results'])
    else:
        break

for result in results:
    result = json.loads(result)

    for relationship in result['relationships']:
        if relationship['resourceType'] == 'AWS::EC2::NetworkInterface':
            #eni_id = relationship['resourceId']
            break
    else:
        # 関連するENIが無い = リソースに関連付けられていないセキュリティグループ
        print('\t'.join(
            ['"' + result['accountId'] + '"', result['awsRegion'], result['resourceId'], 
             result['resourceName'], result['configuration']['description']]))