如何find未使用的Amazon EC2安全组

我试图find一种方法来确定孤儿安全组,所以我可以清理并摆脱它们。 有谁知道一种方法来发现未使用的安全组。

无论是通过控制台或与命令行工具将工作(在Linux和OSX机器上运行命令行工具)。

注意:这只考虑EC2中的安全使用,而不是像RDS这样的其他服务。 您需要做更多的工作来包含EC2之外使用的安全组。 好事是,如果你错过了一个与另一个服务相关的事件,你就不能轻易地(甚至不可能)删除活动的安全组。

使用新的AWS CLI工具,我find了一个简单的方法来获得我所需要的:

首先,获取所有安全组的列表

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

然后让所有安全组绑定到一个实例,然后通过pipe道进行sort然后uniq

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

然后把它们放在一起,比较两个列表,看看主列表中没有使用什么:

  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) 

这是用boto(Python SDK for AWS)编写的示例代码,用于列出安全组与其关联的实例的数量。

你也可以使用这个逻辑在命令行中获得相同的结果

博托码

 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 

如果您在EC2控制台中select了所有安全组,然后按操作 – >删除安全组,将出现一个popup窗口,告诉您不能删除连接到实例,其他安全组或networking接口的安全组,将列出您可以删除的安全组; 即未使用的安全组:)

使用node.js AWS SDK,我可以确认AWS不允许您删除正在使用的安全组。 我写了一个脚本,只是试图删除所有组,并优雅地处理错误。 这适用于经典和现代的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 } 

经过大约一年未经审计的使用,我发现有必要审计我的AWS EC2安全组,并清理遗留的未使用的组。

这是一个艰巨的任务,通过Web GUI执行,所以我期待着AWS CLI使任务更容易。 我发现如何在StackOverflow上做到这一点的开始,但还远远没有完成。 所以我决定写我自己的脚本。 我使用了AWS CLI,MySQL和一些“Bash-foo”来执行以下操作:

  1. 获取所有EC2安全组的列表。 我将group-id,group-name和description存储在一个名为“groups”的表中,这个表在本地主机上名为aws_security_groups的MySQL数据库中。 向用户报告find的组的总数。

  2. 获取与以下每个服务相关联的所有安全组的列表,并从表中排除它们:EC2 Istances EC2弹性负载平衡器AWS RDS实例AWS OpsWorks(不应删除每个Amazon)默认安全组(不能删除)ElastiCache

对于每项服务,我报告在排除完成之后表中剩余的组数。

  1. 最后,我显示剩下的组的组标识,组名称和描述。 这些是需要审计和/或删除的“未使用”的组。 我发现实例和弹性负载平衡器(ELB)之间的SG经常互相引用。 在删除交叉引用和删除安全组之前,最好做一些手动调查以确保它们确实没有被使用。 但是,我的脚本至less把这个东西压缩到了可pipe理的地步。

注意事项:1.您将需要创build一个文件来存储您的MySQL主机,用户名和密码,并将$ DBCONFIGvariables指向它。 它应该像这样构造:

 [mysql] host=your-mysql-server-host.com user=your-mysql-user password=your-mysql-user-password 
  1. 如果您愿意,可以更改数据库的名称 – 确保在脚本中更改$ DBvariables

让我知道如果你觉得这个有用或有任何意见,修复或增强。

这是脚本。

 #!/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/' 

这里是创build数据库的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 

一个boto示例仅打印没有当前实例的安全组的组ID和名称。

它还显示了如何指定您关心的区域。

 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 test并将len(sg.instances())值输出。

例如

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