0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSセキュリティグループを消すのが怖いときに使うスクリプト、あります。

Posted at

はじめに

「このセキュリティグループ、ほんまに消してええんか...?」

ってことありますよね。

というわけで、そのセキュリティグループが紐づいているサービスをチェックするスクリプトを作りました。

かつて自分で作って使っていたものを生成AIに改善していただきまして、人様に晒しても大丈夫そうなのでこちらに残しておこうと思います。

スクリプト

コードはこちら ↓

クリックして展開
#!/bin/bash

# セキュリティ設定
set -euo pipefail  # エラー時即座に停止、未定義変数使用禁止、パイプラインエラー検知

# 第一引数からセキュリティグループIDを取得
SECURITY_GROUP_ID=$1

# 第二引数が指定されていない場合はデフォルトプロファイルを使用
export AWS_PROFILE=${AWS_PROFILE:-default}
export AWS_REGION=${AWS_REGION:-ap-northeast-1}

# ANSIエスケープコードで色を定義
readonly BLUE="\033[0;34m"
readonly YELLOW="\033[1;33m"
readonly GREEN="\033[0;32m"
readonly GRAY="\033[0;90m"
readonly RED="\033[0;31m"
readonly NC="\033[0m" # テキスト色をリセットするためのコード

# エラーメッセージ表示関数
error_exit() {
    echo -e "${RED}Error: $1${NC}" >&2
    exit 1
}

# 引数チェック
if [[ -z "${SECURITY_GROUP_ID:-}" ]]; then
    echo "Usage: $0 <security-group-id>" >&2
    exit 1
fi

# セキュリティグループIDの形式検証(インジェクション対策)
if [[ ! "$SECURITY_GROUP_ID" =~ ^sg-[0-9a-f]{8,17}$ ]]; then
    error_exit "Invalid Security Group ID format: $SECURITY_GROUP_ID (expected format: sg-xxxxxxxxx)"
fi

# AWS CLIの存在確認
if ! command -v aws &> /dev/null; then
    error_exit "AWS CLI is not installed. Please install it first."
fi

# AWS認証チェック(実行前に確認)
if ! aws sts get-caller-identity &> /dev/null; then
    error_exit "AWS authentication failed. Please check your credentials and profile."
fi

# セキュリティグループの存在確認
echo -e "${GRAY}Validating security group...${NC}" >&2
if ! aws ec2 describe-security-groups --group-ids "$SECURITY_GROUP_ID" &> /dev/null; then
    error_exit "Security group not found: $SECURITY_GROUP_ID"
fi

# 現在のAWSプロファイルとアカウント情報を表示
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text 2>/dev/null || echo "unknown")
SG_INFO=$(aws ec2 describe-security-groups --group-ids "$SECURITY_GROUP_ID" --query "SecurityGroups[0].[GroupName,VpcId]" --output text 2>/dev/null)
SG_NAME=$(echo "$SG_INFO" | awk '{print $1}')
VPC_ID=$(echo "$SG_INFO" | awk '{print $2}')

echo ""
echo "=========================================="
echo -e "${GREEN}AWS Account:${NC} $AWS_ACCOUNT_ID"
echo -e "${GREEN}AWS Profile:${NC} $AWS_PROFILE"
echo -e "${GREEN}AWS Region:${NC} $AWS_REGION"
echo -e "${GREEN}Security Group:${NC} $SG_NAME ($SECURITY_GROUP_ID)"
echo -e "${GREEN}VPC:${NC} $VPC_ID"
echo "=========================================="
echo ""

# === 高速チェック(単一APIコール) ===

# Network Interfaces (ENI)の一覧をコンソールに出力
echo -e "${BLUE}Network Interfaces (ENI):${NC}"
result=$(aws ec2 describe-network-interfaces --filters "Name=group-id,Values=$SECURITY_GROUP_ID" --query "NetworkInterfaces[*].[NetworkInterfaceId,Description,Status,Attachment.InstanceId]" --output text 2>/dev/null | awk '{if ($4 && $4 != "None") printf "%s - %s (%s) [Instance: %s]\n", $1, $2, $3, $4; else printf "%s - %s (%s)\n", $1, $2, $3}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# EC2インスタンスの一覧をコンソールに出力
echo -e "${BLUE}EC2 Instances:${NC}"
result=$(aws ec2 describe-instances --filters "Name=instance.group-id,Values=$SECURITY_GROUP_ID" --query "Reservations[*].Instances[*].[InstanceId,Tags[?Key=='Name'].Value|[0],State.Name]" --output text 2>/dev/null | awk '{if ($2) printf "%s (%s) - %s\n", $1, $2, $3; else printf "%s - %s\n", $1, $3}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# === ロードバランサー ===

# ALB/NLBの一覧をコンソールに出力
echo -e "${BLUE}Application/Network Load Balancers:${NC}"
result=$(aws elbv2 describe-load-balancers --query "LoadBalancers[?SecurityGroups != null && contains(SecurityGroups, '$SECURITY_GROUP_ID')].[LoadBalancerName,Type]" --output text 2>/dev/null | awk '{printf "%s (%s)\n", $1, $2}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# CLBの一覧をコンソールに出力
echo -e "${BLUE}Classic Load Balancers:${NC}"
result=$(aws elb describe-load-balancers --query "LoadBalancerDescriptions[?SecurityGroups.contains(@, '$SECURITY_GROUP_ID')].[LoadBalancerName]" --output text 2>/dev/null)
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# === データベース・キャッシュ ===

# RDSインスタンスの一覧をコンソールに出力
echo -e "${BLUE}RDS Instances:${NC}"
result=$(aws rds describe-db-instances --query "DBInstances[?VpcSecurityGroups[?VpcSecurityGroupId=='$SECURITY_GROUP_ID']].[DBInstanceIdentifier,Engine]" --output text 2>/dev/null | awk '{printf "%s (%s)\n", $1, $2}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# Elasticacheクラスターの一覧をコンソールに出力
echo -e "${BLUE}Elasticache Clusters:${NC}"
result=$(aws elasticache describe-cache-clusters --show-cache-node-info --query "CacheClusters[?SecurityGroups[?SecurityGroupId=='$SECURITY_GROUP_ID']].[CacheClusterId,Engine]" --output text 2>/dev/null | awk '{printf "%s (%s)\n", $1, $2}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# === サーバーレス ===

# AWS Lambda関数の一覧をコンソールに出力
echo -e "${BLUE}AWS Lambda Functions:${NC}"
result=$(aws lambda list-functions --query "Functions[?VpcConfig.SecurityGroupIds != null && contains(VpcConfig.SecurityGroupIds, '$SECURITY_GROUP_ID')].[FunctionName,Runtime]" --output text 2>/dev/null | awk '{printf "%s (%s)\n", $1, $2}')
if [[ -z "$result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$result"
fi
echo ""

# === コンテナサービス ===

# ECS Servicesの一覧をコンソールに出力
echo -e "${BLUE}ECS Services:${NC}"
ecs_result=""
clusters=$(aws ecs list-clusters --query "clusterArns[*]" --output text 2>/dev/null)
if [[ -n "$clusters" ]]; then
    # クラスター数を取得
    cluster_array=($clusters)
    total_clusters=${#cluster_array[@]}
    current_cluster=0

    echo -e "${GRAY}  Checking $total_clusters cluster(s)...${NC}" >&2

    for cluster_arn in $clusters; do
        cluster_name=$(basename "$cluster_arn")
        current_cluster=$((current_cluster + 1))

        services=$(aws ecs list-services --cluster "$cluster_name" --query "serviceArns[*]" --output text 2>/dev/null)
        if [[ -n "$services" ]]; then
            # サービス数を取得
            service_array=($services)
            total_services=${#service_array[@]}
            current_service=0

            echo -e "${GRAY}  [$current_cluster/$total_clusters] Cluster: $cluster_name ($total_services service(s))${NC}" >&2

            for service_arn in $services; do
                service_name=$(basename "$service_arn")
                current_service=$((current_service + 1))

                # 進捗をリアルタイム表示(上書き)
                printf "\r${GRAY}    Checking service $current_service/$total_services: $service_name...${NC}" >&2

                sg_check=$(aws ecs describe-services \
                    --cluster "$cluster_name" \
                    --services "$service_name" \
                    --query "services[0].networkConfiguration.awsvpcConfiguration.securityGroups" \
                    --output text 2>/dev/null | grep -o "$SECURITY_GROUP_ID" || true)
                if [[ -n "$sg_check" ]]; then
                    # マッチした場合は改行して結果を表示
                    printf "\r${GREEN}    ✓ Found: $cluster_name / $service_name${NC}\n" >&2
                    ecs_result+="$cluster_name / $service_name"$'\n'
                fi
            done
            # 最後の行をクリア
            printf "\r%*s\r" 100 "" >&2
        else
            echo -e "${GRAY}  [$current_cluster/$total_clusters] Cluster: $cluster_name (no services)${NC}" >&2
        fi
    done
fi
if [[ -z "$ecs_result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$ecs_result"
fi
echo ""

# === 検索・分析サービス ===

# Amazon OpenSearch Serviceドメインの一覧をコンソールに出力
echo -e "${BLUE}Amazon OpenSearch Service Domains:${NC}"
opensearch_result=$(aws es list-domain-names --query "DomainNames[].DomainName" --output text 2>/dev/null | tr '\t' '\n' | \
    while read domainName; do
        if [[ -n "$domainName" ]]; then
            sg_ids=$(aws es describe-elasticsearch-domain --domain-name "$domainName" --query "DomainStatus.VPCOptions.SecurityGroupIds" --output text 2>/dev/null)
            if echo "$sg_ids" | grep -q "$SECURITY_GROUP_ID"; then
                echo "$domainName"
            fi
        fi
    done)
if [[ -z "$opensearch_result" ]]; then
    echo -e "${YELLOW}  (No resources found)${NC}"
else
    echo "$opensearch_result"
fi
echo ""

echo "=========================================="
echo ""
echo -e "${GREEN}✓ Resource fetching complete${NC}"

実行結果

スクリーンショット 2025-12-04 11.25.19.png

さいごに

セキュリティグループに紐づくサービスが分かれば、判断しやすくなります。

これでセキュリティグループの年末の大掃除も捗ることでしょう。

ただし、自己責任でお願いします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?