• 投稿者:
  • 投稿コメント:0件のコメント
  • 投稿カテゴリー:AWS
  • 投稿の最終変更日:2024年10月4日

AWSの使われていないセキュリティグループを一覧取得する方法

AWS(Amazon Web Services)では、セキュリティグループ(SG)はネットワークトラフィックを制御するための仮想ファイアウォールとして機能します。セキュリティグループは、EC2インスタンスや他のAWSリソースに関連付けられ、許可されたトラフィックを定義します。しかし、長期間使用されていないセキュリティグループが放置されることが多く、無駄なリソースとして管理が必要です。このブログ記事では、AWS CLIを使用して使われていないセキュリティグループを一覧取得し、使用中のセキュリティグループの関連情報も確認する方法を解説します。


用語解説

  • セキュリティグループ(SG): AWSリソースへのネットワークトラフィックを制御するための仮想ファイアウォール。インバウンド(受信)およびアウトバウンド(送信)のトラフィックルールを設定する。
  • EC2インスタンス: AWSのElastic Compute Cloudサービスを利用した仮想サーバー。
  • ENI(Elastic Network Interface): AWS VPC内でネットワークインターフェースを作成・管理するためのリソース。
  • RDS(Relational Database Service): AWSのマネージドリレーショナルデータベースサービス。
  • Redshift: AWSのデータウェアハウスサービス。
  • ElastiCache: AWSのインメモリデータストアサービス。
  • Lambda: サーバーレスコンピューティングを実現するAWSのサービス。

前提条件

この手順を実行するには、以下の前提条件が必要です。AWSのcloudshellを利用する場合は、すでにAWS CLI、認証情報が設定済みなので便利です。

  • AWS CLI: AWS CLIがインストールされていること。
  • AWS認証情報の設定: AWSアカウントにアクセスするための認証情報(アクセスキーとシークレットキー)が設定されていること。
スポンサーリンク

使われていないセキュリティグループの判断基準

使われていないセキュリティグループを特定するための基準は以下の通りです。

  1. EC2インスタンスで未使用: セキュリティグループがEC2インスタンスに関連付けられていない場合、そのセキュリティグループは未使用とみなされます。
  2. ENIで未使用: セキュリティグループがENIに関連付けられていない場合も、未使用と見なすことができます。
  3. RDSインスタンスで未使用: Amazon RDSでもセキュリティグループが使用されるため、関連付けられていないセキュリティグループは未使用とみなされます。
  4. 他のAWSサービスでの使用: Amazon RedshiftやElastiCache、Lambdaなどでも使用されるため、これらのリソースに関連付けられていないセキュリティグループも未使用です。

使われていないセキュリティグループの一覧取得手順

セキュリティグループの一覧取得

全てのセキュリティグループを取得するために、以下のAWS CLIコマンドを使用します。

aws ec2 describe-security-groups --query 'SecurityGroups[*].{ID:GroupId,Name:GroupName}' --output table

このコマンドを実行することで、セキュリティグループのIDと名前の一覧がテーブル形式で表示されます。


スポンサーリンク

使用中のセキュリティグループの確認

次に、使用中のセキュリティグループがどのリソースに関連付けられているかを確認します。以下のコマンドを実行します。

EC2インスタンスのセキュリティグループ取得

aws ec2 describe-instances --query 'Reservations[*].Instances[*].{ID:InstanceId,SecurityGroups:SecurityGroups[*].GroupId}' --output table

ENIのセキュリティグループ取得

aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].{ID:NetworkInterfaceId,Groups:Groups[*].GroupId}' --output table

RDSインスタンスのセキュリティグループ取得

aws rds describe-db-instances --query 'DBInstances[*].{ID:DBInstanceIdentifier,SecurityGroups:VpcSecurityGroups[*].VpcSecurityGroupId}' --output table

Redshiftクラスタのセキュリティグループ取得

aws redshift describe-clusters --query 'Clusters[*].{ID:ClusterIdentifier,SecurityGroups:VpcSecurityGroups[*].VpcSecurityGroupId}' --output table

ElastiCacheのセキュリティグループ取得

aws elasticache describe-cache-clusters --query 'CacheClusters[*].{ID:CacheClusterId,SecurityGroups:VpcSecurityGroupIds}' --output table

Lambdaのセキュリティグループ取得

aws lambda list-functions --query 'Functions[*].{Name:FunctionName,SecurityGroups:VpcConfig.SecurityGroupIds}' --output table

これらのコマンドを実行することで、各リソースに関連付けられているセキュリティグループの情報を得ることができます。

未使用のセキュリティグループの抽出

次に、全てのセキュリティグループと比較して未使用のセキュリティグループを特定します。以下のシェルスクリプトを使用して、未使用のセキュリティグループを一覧表示します。ただ、Auto Scalingなど一時的に使ってないセキュリティグループを削除しないようにご注意ください。

#!/bin/bash
# 引数からリージョンを取得、指定がなければデフォルトでap-northeast-1を使用
REGION="${1:-ap-northeast-1}"
# ログファイルの設定
LOG_FILE="security_groups_report.log"
echo "セキュリティグループレポート (リージョン: $REGION)" > "$LOG_FILE"
echo "=====================" >> "$LOG_FILE"
# セキュリティグループの一覧を取得
if ! SECURITY_GROUPS=$(aws ec2 describe-security-groups --region "$REGION" --query "SecurityGroups[*].[GroupId, GroupName]" --output text); then
    echo "エラー: セキュリティグループの取得に失敗しました。" | tee -a "$LOG_FILE"
    exit 1
fi
# 使用中のセキュリティグループを保存するための配列
declare -A USED_SECURITY_GROUPS
# 全セキュリティグループのカウント
TOTAL_SECURITY_GROUPS=$(echo "$SECURITY_GROUPS" | wc -l)
# 各セキュリティグループに関連付けられているリソースを取得
while read -r GROUP_ID GROUP_NAME; do
    echo "----------------------------------------" | tee -a "$LOG_FILE"
    echo "セキュリティグループ ID: $GROUP_ID, 名前: $GROUP_NAME" | tee -a "$LOG_FILE"
    
    # EC2インスタンスのリストを取得
    if EC2_INSTANCES=$(aws ec2 describe-instances --region "$REGION" --filters "Name=instance.group-id,Values=$GROUP_ID" --query "Reservations[*].Instances[*].[InstanceId, Tags[?Key=='Name'].Value | [0]]" --output text); then
        if [ -n "$EC2_INSTANCES" ]; then
            echo "  このセキュリティグループを使用しているEC2インスタンス:" | tee -a "$LOG_FILE"
            echo "$EC2_INSTANCES" | while read -r INSTANCE_ID INSTANCE_NAME; do
                echo "    インスタンス ID: $INSTANCE_ID, 名前: $INSTANCE_NAME" | tee -a "$LOG_FILE"
            done
            USED_SECURITY_GROUPS["$GROUP_ID"]=1  # 使用中のSGを記録
        else
            echo "  このセキュリティグループを使用しているEC2インスタンスはありません。" | tee -a "$LOG_FILE"
        fi
    else
        echo "  エラー: EC2インスタンスの取得に失敗しました。" | tee -a "$LOG_FILE"
    fi
    
    # ELBのリストを取得
    if LOAD_BALANCERS=$(aws elbv2 describe-load-balancers --region "$REGION" --query "LoadBalancers[?contains(SecurityGroups, \`$GROUP_ID\`)].[LoadBalancerName]" --output text); then
        if [ -n "$LOAD_BALANCERS" ]; then
            echo "  このセキュリティグループを使用しているELB:" | tee -a "$LOG_FILE"
            echo "$LOAD_BALANCERS" | while read -r LOAD_BALANCER_NAME; do
                echo "    ELB 名: $LOAD_BALANCER_NAME" | tee -a "$LOG_FILE"
            done
            USED_SECURITY_GROUPS["$GROUP_ID"]=1  # 使用中のSGを記録
        else
            echo "  このセキュリティグループを使用しているELBはありません。" | tee -a "$LOG_FILE"
        fi
    else
        echo "  エラー: ELBの取得に失敗しました。" | tee -a "$LOG_FILE"
    fi
    # RDSのリストを取得
    if RDS_INSTANCES=$(aws rds describe-db-instances --region "$REGION" --query "DBInstances[?contains(VpcSecurityGroups[*].VpcSecurityGroupId, \`$GROUP_ID\`)].[DBInstanceIdentifier, DBInstanceClass]" --output text); then
        if [ -n "$RDS_INSTANCES" ]; then
            echo "  このセキュリティグループを使用しているRDSインスタンス:" | tee -a "$LOG_FILE"
            echo "$RDS_INSTANCES" | while read -r DB_INSTANCE_IDENTIFIER DB_INSTANCE_CLASS; do
                echo "    RDS インスタンス ID: $DB_INSTANCE_IDENTIFIER, クラス: $DB_INSTANCE_CLASS" | tee -a "$LOG_FILE"
            done
            USED_SECURITY_GROUPS["$GROUP_ID"]=1  # 使用中のSGを記録
        else
            echo "  このセキュリティグループを使用しているRDSインスタンスはありません。" | tee -a "$LOG_FILE"
        fi
    else
        echo "  エラー: RDSインスタンスの取得に失敗しました。" | tee -a "$LOG_FILE"
    fi
    
    echo "" | tee -a "$LOG_FILE"
done <<< "$SECURITY_GROUPS"
# 全セキュリティグループのリストを表示
echo "----------------------------------------" | tee -a "$LOG_FILE"
echo "全セキュリティグループの一覧:" | tee -a "$LOG_FILE"
while read -r GROUP_ID GROUP_NAME; do
    echo "  セキュリティグループ ID: $GROUP_ID, 名前: $GROUP_NAME" | tee -a "$LOG_FILE"
done <<< "$SECURITY_GROUPS"
# 未使用のセキュリティグループを表示
echo "----------------------------------------" | tee -a "$LOG_FILE"
echo "未使用のセキュリティグループ:" | tee -a "$LOG_FILE"
UNUSED_SECURITY_GROUPS_COUNT=0
while read -r GROUP_ID GROUP_NAME; do
    if [[ -z ${USED_SECURITY_GROUPS["$GROUP_ID"]} ]]; then
        echo "  セキュリティグループ ID: $GROUP_ID, 名前: $GROUP_NAME" | tee -a "$LOG_FILE"
        ((UNUSED_SECURITY_GROUPS_COUNT++))
    fi
done <<< "$SECURITY_GROUPS"
# 結果の出力
echo "----------------------------------------" | tee -a "$LOG_FILE"
echo "全セキュリティグループの件数: $TOTAL_SECURITY_GROUPS" | tee -a "$LOG_FILE"
echo "未使用のセキュリティグループの件数: $UNUSED_SECURITY_GROUPS_COUNT" | tee -a "$LOG_FILE"
echo "レポートは $LOG_FILE に保存されました。"

このスクリプトを実行すると、使用中のセキュリティグループとその関連リソース、さらに未使用のセキュリティグループが表示されます。必要に応じて、スクリプトをカスタマイズして特定のリソースをチェックすることも可能です。


スポンサーリンク

自動化の例:スクリプトでの処理

上記のシェルスクリプトを定期的に実行することで、使われていないセキュリティグループをリストアップできます。これを定期的に実行することで、環境をクリーンに保つことが可能です。

Lambdaを使った自動化

AWS LambdaとCloudWatchを使用すれば、このスクリプトをAWS環境で定期的に実行させることもできます。CloudWatchイベントをトリガーとしてLambda関数を実行し、未使用のセキュリティグループを定期的に確認することができます。

未使用のセキュリティグループの削除コマンド

未使用のセキュリティグループを削除するには、次のコマンドを使用します。<security-group-id> を削除したいセキュリティグループのIDに置き換えてください。削除前に本当に不要かどうか、ご確認ください。

aws ec2 delete-security-group --group-id <security-group-id>

スポンサーリンク

一括削除のスクリプト

未使用のセキュリティグループが多数ある場合は、以下のスクリプトを使用して一括削除することができます。

#!/bin/bash

# エラーメッセージを出力する関数
error_exit() {
    echo "$1"
    exit 1
}

# 全てのセキュリティグループのIDを取得
all_sgs=$(aws ec2 describe-security-groups --query 'SecurityGroups[*].GroupId' --output text) || error_exit "セキュリティグループの取得中にエラーが発生しました。"

# 使用中のセキュリティグループのIDを取得
used_sgs=$(aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text) || error_exit "使用中のセキュリティグループの取得中にエラーが発生しました。"

# その他のリソースからも使用中のセキュリティグループを追加取得
used_sgs+=" $(aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Groups[*].GroupId' --output text) || error_exit "ネットワークインターフェースの取得中にエラーが発生しました。"
used_sgs+=" $(aws rds describe-db-instances --query 'DBInstances[*].VpcSecurityGroups[*].VpcSecurityGroupId' --output text) || error_exit "RDSインスタンスの取得中にエラーが発生しました。"
used_sgs+=" $(aws redshift describe-clusters --query 'Clusters[*].VpcSecurityGroups[*].VpcSecurityGroupId' --output text) || error_exit "Redshiftクラスタの取得中にエラーが発生しました。"
used_sgs+=" $(aws elasticache describe-cache-clusters --query 'CacheClusters[*].[CacheClusterId,VpcSecurityGroupIds]' --output text) || error_exit "ElastiCacheの取得中にエラーが発生しました。"
used_sgs+=" $(aws lambda list-functions --query "Functions[?VpcConfig!=null].[FunctionName, VpcConfig.SecurityGroupIds]" --output text) || error_exit "Lambda関数の取得中にエラーが発生しました。"

# 使用中のセキュリティグループのリストをユニークなものに整形
used_sgs=$(echo "$used_sgs" | tr ' ' '\n' | sort -u)

# 未使用のセキュリティグループを抽出
unused_sgs=$(comm -23 <(echo "$all_sgs" | tr ' ' '\n' | sort) <(echo "$used_sgs"))

# 結果を表示
echo "使用中のセキュリティグループとその関連リソース:"
echo "-----------------------------------------------------"
if [ -z "$used_sgs" ]; then
    echo "使用中のセキュリティグループはありません。"
else
    for sg in $used_sgs; do
        echo "セキュリティグループ ID: $sg"
        echo "関連リソース:"

        # EC2インスタンスを表示
        echo "EC2インスタンス:"
        ec2_instances=$(aws ec2 describe-instances --filters "Name=instance.group-id,Values=$sg" --query 'Reservations[*].Instances[*].InstanceId' --output text) || error_exit "EC2インスタンスの取得中にエラーが発生しました。"
        if [ -n "$ec2_instances" ]; then
            echo "$ec2_instances"
        else
            echo "  なし"
        fi

        # ネットワークインターフェースを表示
        echo "ネットワークインターフェース (ENI):"
        eni_ids=$(aws ec2 describe-network-interfaces --filters "Name=group-id,Values=$sg" --query 'NetworkInterfaces[*].NetworkInterfaceId' --output text) || error_exit "ENIの取得中にエラーが発生しました。"
        if [ -n "$eni_ids" ]; then
            echo "$eni_ids"
        else
            echo "  なし"
        fi

        # RDSインスタンスを表示
        echo "RDSインスタンス:"
        rds_instances=$(aws rds describe-db-instances --query 'DBInstances[?VpcSecurityGroups[?VpcSecurityGroupId==`'$sg'`]].{ID:DBInstanceIdentifier, SecurityGroups:VpcSecurityGroups[*].VpcSecurityGroupId}' --output table) || error_exit "RDSインスタンスの取得中にエラーが発生しました。"
        if [ -n "$rds_instances" ]; then
            echo "$rds_instances"
        else
            echo "  なし"
        fi

        # Redshiftインスタンスを表示
        echo "Redshiftクラスタ:"
        redshift_clusters=$(aws redshift describe-clusters --query 'Clusters[*].[ClusterIdentifier,VpcSecurityGroups[*].VpcSecurityGroupId]' --output text | grep "$sg") || error_exit "Redshiftクラスタの取得中にエラーが発生しました。"
        if [ -n "$redshift_clusters" ]; then
            echo "$redshift_clusters"
        else
            echo "  なし"
        fi

        # ElastiCacheインスタンスを表示
        echo "ElastiCacheインスタンス:"
        elasticache_clusters=$(aws elasticache describe-cache-clusters --query 'CacheClusters[*].[CacheClusterId,VpcSecurityGroupIds]' --output text) || error_exit "ElastiCacheの取得中にエラーが発生しました。"
        if [ -n "$elasticache_clusters" ]; then
            echo "$elasticache_clusters"
        else
            echo "  なし"
        fi

        # Lambda関数を表示
        echo "Lambda関数:"
        lambda_functions=$(aws lambda list-functions --query "Functions[?VpcConfig!=null].[FunctionName, VpcConfig.SecurityGroupIds]" --output text) || error_exit "Lambda関数の取得中にエラーが発生しました。"
        if [ -n "$lambda_functions" ]; then
            echo "$lambda_functions"
        else
            echo "  なし"
        fi
        echo "-----------------------------------------------------"
    done
fi

# 未使用のセキュリティグループの表示
echo ""
if [ -z "$unused_sgs" ]; then
    echo "未使用のセキュリティグループはありません。"
else
    echo "未使用のセキュリティグループ:"
    echo "$unused_sgs"
fi

まとめ

AWS環境を最適化し、無駄なリソースを削減するためには、使われていないセキュリティグループを定期的に確認し、削除することが重要です。AWS CLIを使用して、使用中のセキュリティグループがどのリソースに関連付けられているかを確認し、未使用のセキュリティグループを特定する方法を紹介しました。このプロセスを自動化することで、管理作業を効率化し、より安全な環境を維持できます。


スポンサーリンク

AWS Lambdaで使われていないセキュリティグループ(SG)を自動削除する方法:完全ガイド

AWSCLIでの個別の削除方法を解説しました。lambda(条件自動実行)でセキュリティグループ(SG)を自動削除する方法は別記事のこちらで紹介いたします。

コメントを残す