未使用のAmazon EC2セキュリティグループを見つける方法


93

孤立したセキュリティグループを特定して、クリーンアップして取り除くことができる方法を探しています。誰もが未使用のセキュリティグループを発見する方法を知っていますか。

コンソールまたはコマンドラインツールのどちらでも機能します(LinuxおよびOSXマシンでのコマンドラインツールの実行)。


3
SGを割り当てることができ、「すべてを選択してから削除する」scarybadの週末を含まない、長期間有効な非インスタンスオブジェクト(RDS、ELB、ALB)を例外とせずに、この質問に完全に答える私の王国-破壊者アプローチ。:)
ジェシーアデルマン

回答:


77

注:これはEC2でのセキュリティの使用のみを考慮し、RDSなどの他のサービスは考慮しません。EC2の外部で使用されるセキュリティグループを含めるには、さらに作業を行う必要があります。良い点は、関連付けられている1つのサービスと関連するサービスがないと、アクティブなセキュリティグループを簡単に削除できない(場合によっては不可能である)ことです。

新しいAWS CLIツールを使用して、必要なものを取得する簡単な方法を見つけました。

まず、すべてのセキュリティグループのリストを取得します

aws ec2 describe-security-groups --query 'SecurityGroups[*].GroupId'  --output text | tr '\t' '\n'

その後、その後、インスタンスに関連付けられたすべてのセキュリティグループを取得するために、パイプsort、その後uniq

aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text | tr '\t' '\n' | sort | uniq

次に、それをまとめて2つのリストを比較し、マスターリストから使用されていないものを確認します。

comm -23  <(aws ec2 describe-security-groups --query 'SecurityGroups[*].GroupId'  --output text | tr '\t' '\n'| sort) <(aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text | tr '\t' '\n' | sort | uniq)

1
@Erikはい、私は単一のリージョンしか持っておらず、AWSスクリプトにはホーム変数が環境変数を介して設定されています。このスクリプトのマルチリージョンバージョンに興味があります。
Ray

1
vpcに--filterを追加すると、他のデフォルトのvpc sgを表示する必要が
なくなり

2
ELBがセキュリティグループを使用している可能性もあります。このコマンドは、デフォルトの地域のELBsによって参照されるセキュリティ・グループIDのuniqのセットが一覧表示されます:aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | sort | uniq
astletron

2
EC2セキュリティグループがRDSインスタンスによって使用されている可能性もあります。セキュリティグループIDの一覧が表示されます。このコマンドは、デフォルト領域にRDSインスタンスによって使用されます:aws rds describe-db-security-groups --query 'DBSecurityGroups[*].EC2SecurityGroups[*].EC2SecurityGroupId' --output text | tr '\t' '\n' | sort | uniq
aharden

2
を使用aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Groups[*].GroupId' --output text| tr '\t' '\n' | sort | uniqして、ネットワークインターフェイスを説明することもできます。
ジョナサン

61

EC2コンソールですべてのセキュリティグループを選択して、アクション-> [セキュリティグループの削除]を押すと、ポップアップが表示され、インスタンス、他のセキュリティグループ、またはネットワークインターフェイスに接続されているセキュリティグループを削除できないことを通知します。削除できるセキュリティグループが一覧表示されます。つまり、未使用のセキュリティグループ:)


15
私は同意しなければなりませんが、「すべて選択+削除」を使用することは、通常、実際に良い習慣ではありません。
Balmipour

3
うまくいくかどうかわからない場合は、ダミーのセキュリティグループを作成してそれにアタッチし、削除してみてください。
NLail 2017

2
実際に削除を確認する必要はありません。ポップアップで、削除できる(孤立している)ものと削除できないものの内訳が表示されます。次に、キャンセルを押して、孤立したものを削除します。
rjarmstrong

4
私が取得できないのはこれです。このscary.maneuverを実行するときにAWSコンソールがこの情報を提供できる場合、APIを介して同じことを行う方法を共有しないのはなぜですか?これは、ブラウンフィールド環境で必要になる可能性のあるものではありません...
Jesse Adelman

1
勇敢になる::それを行う
zanuka '21 / 11/18

29

これは、関連付けられているインスタンスの数に対してセキュリティグループを一覧表示するboto(Python SDK for AWS)で記述されたサンプルコードです。

このロジックを使用して、コマンドラインでも同様に取得できます。

Botoコード

import boto
ec2 = boto.connect_ec2()
sgs = ec2.get_all_security_groups()
for sg in sgs:
    print sg.name, len(sg.instances())

出力

Security-Group-1 0
Security-Group-2 1
Security-Group-3 0
Security-Group-4 3

素敵で簡単!ありがとう
Chris Koston

6
ええ、はい、でも何エルブ?
Ilja、

これには、実行中のインスタンスのみが含まれることにも注意してください。停止したインスタンスにリンクされているSGも削除できません。
AgDude 2016

6
これは、RDSなどのサービスからのインターフェースを無視します。RDSはインスタンスを所有しますが、あなたはENIを所有します。ElasticSearchとELBは同様に動作し、このスクリプトでは表示されないと思います
rajat banerjee

6

約1年の監査されていない使用の後、AWS EC2セキュリティグループを監査して、未使用のレガシーグループをクリーンアップする必要があることに気付きました。

これはウェブGUIを介して実行するのは困難な作業だったので、作業を簡単にするためにAWS CLIを検討しました。StackOverflowでこれを行う方法の出発点を見つけましたが、完全とはほど遠いものでした。だから私は自分のスクリプトを書くことにしました。AWS CLI、MySQL、およびいくつかの「Bash-foo」を使用して、以下を実行しました。

  1. すべてのEC2セキュリティグループのリストを取得します。ローカルホスト上のaws_security_groupsと呼ばれるMySQLデータベースの「グループ」と呼ばれるテーブルにグループID、グループ名、および説明を保存します。見つかったグループの総数はユーザーに報告されます。

  2. 次の各サービスに関連付けられているすべてのセキュリティグループのリストを取得し、それらをテーブルから除外します。 )ElastiCache

各サービスについて、除外が完了した後、テーブルに残っているグループの数を報告します。

  1. 最後に、残っているグループのグループID、グループ名、説明を表示します。これらは、監査や削除が必要な「未使用」のグループです。インスタンスとElastic Load Balancer(ELB)の間のSGは、しばしば相互に参照していることがわかりました。相互参照を削除してセキュリティグループを削除する前に、手動で調査して本当に使用されていないことを確認することをお勧めします。しかし、私のスクリプトでは、これを少なくとも管理可能なものにまで絞り込んでいます。

注:1. MySQLホスト、ユーザー名、パスワードを保存するファイルを作成し、$ DBCONFIG変数にそれを指定します。次のように構成する必要があります。

[mysql]
host=your-mysql-server-host.com
user=your-mysql-user
password=your-mysql-user-password
  1. 必要に応じてデータベースの名前を変更できます。必ずスクリプトの$ DB変数を変更してください

これが有用であるか、コメント、修正、または機能強化がある場合は、お知らせください。

これがスクリプトです。

#!/bin/bash
# Initialize Variables
DBCONFIG="--defaults-file=mysql-defaults.cnf"
DB="aws_security_groups"
SGLOOP=0
EC2LOOP=0
ELBLOOP=0
RDSLOOP=0
DEFAULTLOOP=0
OPSLOOP=0
CACHELOOP=0
DEL_GROUP=""

# Function to report back # of rows
function Rows {
    ROWS=`echo "select count(*) from groups" | mysql $DBCONFIG --skip-column-names $DB`
#   echo -e "Excluding $1 Security Groups.\nGroups Left to audit: "$ROWS
    echo -e $ROWS" groups left after Excluding $1 Security Groups."
}


# Empty the table
echo -e "delete from groups where groupid is not null" | mysql $DBCONFIG $DB

# Get all Security Groups
aws ec2 describe-security-groups --query "SecurityGroups[*].[GroupId,GroupName,Description]" --output text > /tmp/security_group_audit.txt
while IFS=$'\t' read -r -a myArray
do
    if [ $SGLOOP -eq 0 ];
    then
        VALUES="(\""${myArray[0]}"\",\""${myArray[1]}"\",\""${myArray[2]}"\")"
    else
        VALUES=$VALUES",(\""${myArray[0]}"\",\""${myArray[1]}"\",\""${myArray[2]}"\")"
    fi
    let SGLOOP="$SGLOOP + 1"
done < /tmp/security_group_audit.txt
echo -e "insert into groups (groupid, groupname, description) values $VALUES" | mysql $DBCONFIG $DB
echo -e $SGLOOP" security groups total."


# Exclude Security Groups assigned to Instances
for groupId in `aws ec2 describe-instances --output json | jq -r ".Reservations[].Instances[].SecurityGroups[].GroupId" | sort | uniq`
do
    if [ $EC2LOOP -eq 0 ];
    then
        DEL_GROUP="'$groupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$groupId'"
    fi
    let EC2LOOP="$EC2LOOP + 1"
done
echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "EC2 Instance"
DEL_GROUP=""


# Exclude groups assigned to Elastic Load Balancers
for elbGroupId in `aws elb describe-load-balancers --output json | jq -c -r ".LoadBalancerDescriptions[].SecurityGroups" | tr -d "\"[]\"" | sort | uniq`
do
    if [ $ELBLOOP -eq 0 ];
    then
        DEL_GROUP="'$elbGroupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$elbGroupId'"
    fi
    let ELBLOOP="$ELBLOOP + 1"
done
    echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "Elastic Load Balancer"
DEL_GROUP=""


# Exclude groups assigned to RDS
for RdsGroupId in `aws rds describe-db-instances --output json | jq -c -r ".DBInstances[].VpcSecurityGroups[].VpcSecurityGroupId" | sort | uniq`
do
    if [ $RDSLOOP -eq 0 ];
    then
        DEL_GROUP="'$RdsGroupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$RdsGroupId'"
    fi
    let RDSLOOP="$RDSLOOP + 1"
done
    echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "RDS Instances"
DEL_GROUP=""

# Exclude groups assigned to OpsWorks
for OpsGroupId in `echo -e "select groupid from groups where groupname like \"AWS-OpsWorks%\"" | mysql $DBCONFIG $DB`
do
    if [ $OPSLOOP -eq 0 ];
    then
        DEL_GROUP="'$OpsGroupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$OpsGroupId'"
    fi
    let OPSLOOP="$OPSLOOP + 1"
done
echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "OpsWorks"
DEL_GROUP=""

# Exclude default groups (can't be deleted)
for DefaultGroupId in `echo -e "select groupid from groups where groupname like \"default%\"" | mysql $DBCONFIG $DB`
do
    if [ $DEFAULTLOOP -eq 0 ];
    then
        DEL_GROUP="'$DefaultGroupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$DefaultGroupId'"
    fi
    let DEFAULTLOOP="$DEFAULTLOOP + 1"
done
echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "Default"
DEL_GROUP=""

# Exclude Elasticache groups
for CacheGroupId in `aws elasticache describe-cache-clusters --output json | jq -r ".CacheClusters[].SecurityGroups[].SecurityGroupId" | sort | uniq`
do
    if [ $CACHELOOP -eq 0 ];
    then
        DEL_GROUP="'$CacheGroupId'"
    else
        DEL_GROUP=$DEL_GROUP",'$CacheGroupId'"
    fi
    let CACHELOOP="$CACHELOOP + 1"
done
echo -e "delete from groups where groupid in ($DEL_GROUP)" | mysql $DBCONFIG $DB
Rows "ElastiCache"

# Display Security Groups left to audit / delete
echo "select * from groups order by groupid" | mysql $DBCONFIG $DB | sed 's/groupid\t/groupid\t\t/'

そして、これがデータベースを作成するためのSQLです。

-- MySQL dump 10.13  Distrib 5.5.41, for debian-linux-gnu (x86_64)
--
-- Host:  localhost   Database: aws_security_groups
-- ------------------------------------------------------
-- Server version   5.5.40-log

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `groups`
--

DROP TABLE IF EXISTS `groups`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `groups` (
  `groupid` varchar(12) DEFAULT NULL,
  `groupname` varchar(200) DEFAULT NULL,
  `description` varchar(200) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `groups`
--

LOCK TABLES `groups` WRITE;
/*!40000 ALTER TABLE `groups` DISABLE KEYS */;
/*!40000 ALTER TABLE `groups` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2015-01-27 16:07:44

3

現在のインスタンスを持たないセキュリティグループのグループIDと名前のみを出力するbotoの例。

また、関係するリージョンを指定する方法も示します。

import boto
import boto.ec2
EC2_REGION='ap-southeast-2'
ec2region = boto.ec2.get_region(EC2_REGION)
ec2 = boto.connect_ec2(region=ec2region)
sgs = ec2.get_all_security_groups()
for sg in sgs:
    if len(sg.instances()) == 0:
        print ("{0}\t{1}".format(sg.id, sg.name))

セキュリティグループを確認するためにされて、まだ使用されているあなたは、逆転または削除する必要がありif len(sg.instances()) == 0、テストをして印刷するlen(sg.instances())値を。

例えば

print ("{0}\t{1}\t{2} instances".format(sg.id, sg.name, len(sg.instances())))

3

node.js AWS SDKを使用して、使用中のセキュリティグループをAWSが削除できないことを確認できます。すべてのグループを削除しようとするだけでエラーを適切に処理するスクリプトを作成しました。これは、クラシックVPCとモダンVPCで機能します。エラーメッセージは次のとおりです。

Err { [DependencyViolation: resource sg-12345678 has a dependent object]
  message: 'resource sg-12345678 has a dependent object',
  code: 'DependencyViolation',
  time: Mon Dec 07 2015 12:12:43 GMT-0500 (EST),
  statusCode: 400,
  retryable: false,
  retryDelay: 30 }


1

ネットワークインターフェイスに接続されているSGへ:

名前で:

aws ec2 describe-network-interfaces --output text --query NetworkInterfaces[*].Groups[*].GroupName | tr -d '\r' | tr "\t" "\n" | sort | uniq

ID別:

aws ec2 describe-network-interfaces --output text --query NetworkInterfaces[*].Groups[*].GroupId | tr -d '\r' | tr "\t" "\n" | sort | uniq

0

AWSマーケットプレイスには、これをはるかに簡単にするツールがあります。簡単に削除できるようにアタッチ/デタッチされたグループが表示されますが、VPCフローログとセキュリティグループルールが比較され、使用中または未使用のSGルールも表示されます。AWSはこれを行うためにELKスタックソリューションを投稿しましたが、それは途方もなく複雑でした。

これがツールで、私が取り組んだ免責事項です。しかし、私はあなたがすべてそれが適切であることを願っています:https : //www.piasoftware.net/single-post/2018/04/24/VIDEO-Watch-as-we-clean-up-EC2-security-groups-in-just -数分


0

残念ながら、選択した回答は必要なほど正確ではありません(理由を調査しようとしましたが、実装することを選択しました)。
ALLをチェックしNetworkInterfaces、への添付ファイルを探すとSecurityGroup、部分的な結果が得られます。のみをチェックするとEC2Instances、部分的な結果も返されます。

それが問題への私のアプローチです:

  1. すべてのEC2 SecurityGroupsを取得します-> all_secgrp
  2. すべてのEC2インスタンスを取得します-> all_instances
  3. インスタンスごとに、それに接続されているすべてのSecurityGroupを取得します
    1. all_secgrpからこれらの各SecurityGroupを削除します(添付されているため)。
  4. SecurityGroupごとに、NetworkInterfacesとの関連付けをチェックします(filter関数を使用して、それを使用してフィルタリングしますsecurity-group-id)。
    1. 関連付けが見つからない場合は、セキュリティグループを削除します all_secgrp

添付すると、コードのスニペットを見ることができます。効率について文句を言うのではなく、必要に応じて最適化してください。

all_secgrp = list(ec2_connector.security_groups.all())
all_instances = ec2_connector.instances.all()

for single_instance in all_instances:
    instance_secgrp = ec2_connector.Instance(single_instance.id).security_groups
    for single_sec_grp in instance_secgrp:
        if ec2.SecurityGroup(id=single_sec_grp['GroupId']) in all_secgrp:
            all_secgrp.remove(ec2.SecurityGroup(id=single_sec_grp['GroupId']))

all_secgrp_detached_tmp = all_secgrp[:]
for single_secgrp in all_secgrp_detached_tmp:
    try:
        print(single_secgrp.id)
        if len(list(ec2_connector.network_interfaces.filter(Filters=[{'Name': 'group-id', 'Values': [single_secgrp.id]}]))) > 0:
            all_secgrp.remove(single_secgrp)
    except Exception:
        all_secgrp.remove(single_secgrp)

return all_secgrp_detached  

0

ルール内の他のセキュリティグループを参照するセキュリティグループがある場合、これは難しい問題です。その場合、自明ではないDependencyErrorsを解決する必要があります。

IPアドレスのみを使用している場合、boto3クライアントを作成した後、このソリューションは機能します。

# pull all security groups from all vpcs in the given profile and region and save as a set
all_sgs = {sg['GroupId'] for sg in client.describe_security_groups()['SecurityGroups']}

# create a new set for all of the security groups that are currently in use
in_use = set()

# cycle through the ENIs and add all found security groups to the in_use set
for eni in client.describe_network_interfaces()['NetworkInterfaces']:
    for group in eni['Groups']:
        in_use.add(group['GroupId'])

unused_security_groups = all_sgs - in_use

for security_group in unused_security_groups:
    try:
        response = client.delete_security_group(GroupId=security_group)
    except ClientError as e:
        if e.response['Error']['Code'] == 'DependencyViolation':
            print('EC2/Security Group Dependencies Exist')
    else:
        print('Unexpected error: {}'.format(e))

これには、RDSで使用されるSGは含まれません
alexandernst
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.