如何查找未使用的Amazon EC2安全组

Ray*_*Ray 78 amazon-ec2 amazon-web-services

我试图找到一种方法来确定孤立的安全组,以便我可以清理并清除它们.有没有人知道发现未使用的安全组的方法.

通过控制台或命令行工具都可以工作(在Linux和OSX机器上运行命令行工具).

Ray*_*Ray 71

注意:这仅考虑EC2中的安全性使用,而不考虑RDS等其他服务.您需要做更多工作才能包含在EC2之外使用的安全组.好消息是,如果您错过了一个与其他服务相关联的服务,则无法轻松(甚至可能无法)删除活动安全组.

使用较新的AWS CLI工具,我找到了一种简单的方法来获得我需要的东西:

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

 aws ec2 describe-security-groups --query 'SecurityGroups[*].GroupId'  --output text | tr '\t' '\n'
Run Code Online (Sandbox Code Playgroud)

然后得到绑一个实例的所有安全组,然后通过管道输送到sort那么uniq:

aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text | tr '\t' '\n' | sort | uniq
Run Code Online (Sandbox Code Playgroud)

然后将它们放在一起并比较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)
Run Code Online (Sandbox Code Playgroud)

  • ELB 也可能正在使用安全组。此命令将列出默认区域中 ELB 引用的 uniq 安全组 ID 集:`aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | 排序 | uniq` (4认同)
  • EC2 安全组也可能被 RDS 实例使用。此命令将列出默认区域中 RDS 实例使用的安全组 ID:`aws rds describe-db-security-groups --query 'DBSecurityGroups[*].EC2SecurityGroups[*].EC2SecurityGroupId' --output text | tr '\t' '\n' | 排序 | uniq` (3认同)
  • 很好的答案。查询提示:将最后一个元素放在括号中,使用文本输出时每行得到一个值,无需使用 `tr` 命令。例如,`--query 'SecurityGroups[].[GroupId]'` vs '--query 'SecurityGroups[].GroupId'` (3认同)
  • @Erik是的,我只有一个区域,AWS脚本通过环境变量设置其主区域。我有兴趣查看该脚本的多区域版本。 (2认同)
  • 你可能想为你的vpc添加一个--filter,这样你就不必看到其他默认的vpc sg (2认同)
  • 您还可以使用`aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Groups[*].GroupId' --output text| tr '\t' '\n' | 排序 | uniq` 只描述网络接口。 (2认同)

NLa*_*ail 54

如果在EC2控制台中选择所有安全组,然后按操作 - >删除安全组,将出现一个弹出窗口,告知您无法删除连接到实例,其他安全组或网络接口的安全组,以及它将列出您可以删除的安全组; 即未使用的安全组:)

  • 虽然我必须同意,使用"全选+删除"通常不是一个好习惯. (12认同)
  • 我不明白的是:如果 AWS 控制台可以在您执行此操作时提供此信息,为什么不通过 API 分享如何执行相同操作?它不像这样,在棕地环境中可能不需要这样的东西...... (5认同)
  • 另外:并非所有 AWS 服务都提供这些类型的警告。我不会告诉您哪些,但如果您假设每次单击删除时都会收到警告,那么有一天您将使生产站点脱机(就像我上个月所做的那样) (4认同)
  • 如果您不确定它是否可行,您可以创建一个虚拟安全组并附加一些东西,尝试删除它,并看到它不会让您. (3认同)
  • 您不需要实际确认删除,在弹出窗口中,它会显示哪些可以删除(孤立)和哪些不能删除的明细。然后您可以按取消,然后删除孤立的。 (2认同)

Nav*_*jay 25

这是用boto(适用于AWS的Python SDK)编写的示例代码,用于根据与之关联的实例数列出安全组.

您也可以使用此逻辑在命令行中获取相同的逻辑

博托码

import boto
ec2 = boto.connect_ec2()
sgs = ec2.get_all_security_groups()
for sg in sgs:
    print sg.name, len(sg.instances())
Run Code Online (Sandbox Code Playgroud)

产量

Security-Group-1 0
Security-Group-2 1
Security-Group-3 0
Security-Group-4 3
Run Code Online (Sandbox Code Playgroud)

  • 嗯,是的,但是什么呢? (5认同)
  • 这忽略了RDS等服务的接口.RDS拥有该实例,但您拥有ENI.我认为ElasticSearch和ELB的工作方式类似,不会出现这个脚本 (5认同)

Big*_*kin 9

除其他功能外,ScoutSuiteProwler都报告未使用的 EC2 安全组。两者都是开源的。


小智 7

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

这是通过 Web GUI 执行的一项艰巨任务,因此我使用 AWS CLI 来简化任务。我在 StackOverflow 上找到了有关如何执行此操作的开始,但还远未完成。所以我决定自己写剧本。我使用 AWS CLI、MySQL 和一些“Bash-foo”来执行以下操作:

  1. 获取所有 EC2 安全组的列表。我将组 ID、组名称和描述存储在本地主机上名为 aws_security_groups 的 MySQL 数据库中名为“groups”的表中。找到的组总数将报告给用户。

  2. 获取与以下每个服务关联的所有安全组的列表,并将它们从表中排除: EC2 Istances EC2 Elastic Load Balancers AWS RDS Instances AWS OpsWorks(不应根据 Amazon 删除)默认安全组(无法删除) ) 弹性缓存

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

  1. 最后,我显示剩余组的组 ID、组名称和描述。这些是需要审核和/或删除的“未使用”组。我发现实例和弹性负载均衡器 (ELB) 之间的 SG 经常相互引用。在删除交叉引用和删除安全组之前,最好进行一些手动调查以确保它们确实没有被使用。但是我的脚本至少将其简化为更易于管理的内容。

注意: 1. 您需要创建一个文件来存储您的 MySQL 主机、用户名和密码,并将 $DBCONFIG 变量指向它。它的结构应该是这样的:

[mysql]
host=your-mysql-server-host.com
user=your-mysql-user
password=your-mysql-user-password
Run Code Online (Sandbox Code Playgroud)
  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/'
Run Code Online (Sandbox Code Playgroud)

这是创建数据库的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
Run Code Online (Sandbox Code Playgroud)