Как найти неиспользуемые группы безопасности Amazon EC2


93

Я пытаюсь найти способ определить сиротские группы безопасности, чтобы я мог очистить их и избавиться от них. Кто-нибудь знает способ обнаружить неиспользуемые группы безопасности.

Будет работать либо через консоль, либо с помощью инструментов командной строки (Запуск инструментов командной строки на машинах Linux и OSX).


4
Мое Королевство за ответ, который полностью отвечает на этот вопрос, без исключений для долгоживущих неэкземплярных объектов (RDS, ELB, ALB), которым могут быть назначены SG, и которые не включают `` выберите все, а затем удалите '' ужасные выходные -разрушительный подход. :)
Джесси Адельман

Ответы:


78

Примечание: это учитывает только использование безопасности в EC2, а не другие службы, такие как RDS. Вам нужно будет проделать больше работы, чтобы включить группы безопасности, используемые вне EC2. Хорошо, что вы не можете легко (может быть, даже невозможно) удалить активные группы безопасности, если вы пропустите одну связанную с другой службой.

Используя новый инструмент 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
вы можете добавить --filter для вашего vpc, чтобы вам не приходилось видеть другие vpc по умолчанию sg
shadowbq

2
Группа безопасности также может использоваться ELB. Эта команда выведет список uniq набор идентификаторов групп безопасности, на которые ссылаются ELB в регионе по умолчанию:aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | sort | uniq
astletron

2
Группа безопасности EC2 также может использоваться экземпляром RDS. Эта команда выведет список идентификаторов групп безопасности, используемых экземплярами 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просто для описания сетевых интерфейсов.
Джонатан

63

Если вы выберете все свои группы безопасности в консоли EC2, а затем нажмете действия -> Удалить группы безопасности, появится всплывающее окно с сообщением, что вы не можете удалить группы безопасности, прикрепленные к экземплярам, ​​другим группам безопасности или сетевым интерфейсам, и это перечислит группы безопасности, которые вы можете удалить; т.е. неиспользуемые группы безопасности :)


15
Хотя я должен согласиться, использование «выбрать все + удалить» обычно не очень хорошая привычка.
Balmipour

3
Если вы не уверены, что это сработает, вы можете просто создать фиктивную группу безопасности и прикрепить к ней что-нибудь, попробовать удалить ее и убедиться, что она вам не позволит.
NLail

2
На самом деле вам не нужно подтверждать удаление, во всплывающем окне будет показано, какие из них можно удалить (сиротские), а какие нет. Затем вы можете нажать «Отмена», а затем удалить «сиротские».
rjarmstrong

4
Чего я не понимаю: если консоль AWS может предлагать эту информацию, когда вы делаете этот scary.maneuver, почему бы им не рассказать, как сделать то же самое через API? Не похоже, что это не то, что, вероятно, нужно в среде коричневого поля ...
Джесси Адельман

1
будь храбрым :: do it
zanuka

29

Это пример кода, написанного на boto (Python SDK для 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

Легко и приятно! Спасибо
Крис Костон

6
ну да, а что с эльбами?
Илья

Также обратите внимание, что сюда входят только запущенные экземпляры. Вы также не можете удалить SG, который связан с остановленным экземпляром.
AgDude

6
При этом игнорируются интерфейсы таких служб, как RDS. RDS владеет экземпляром, но вы владеете ENI. Я думаю, что ElasticSearch и ELB работают одинаково и не будут отображаться с этим скриптом
раджат банерджи

6

Примерно через год неаудированного использования я счел необходимым провести аудит моих групп безопасности AWS EC2 и очистить устаревшие, неиспользуемые группы.

Это была непростая задача для выполнения через веб-интерфейс, поэтому я обратился к интерфейсу командной строки AWS, чтобы упростить задачу. Я нашел начало тому, как это сделать, в StackOverflow, но это было далеко не все. Поэтому я решил написать свой собственный сценарий. Я использовал AWS CLI, MySQL и немного «Bash-foo», чтобы выполнить следующее:

  1. Получите список всех групп безопасности EC2. Я сохраняю идентификатор группы, имя группы и описание в таблице под названием «группы» в базе данных MySQL под названием aws_security_groups на локальном хосте. Общее количество найденных групп сообщается пользователю.

  2. Получите список всех групп безопасности, связанных с каждым из следующих сервисов, и исключите их из таблицы: EC2 Istances EC2 Elastic Load Balancers AWS RDS Instances AWS OpsWorks (не следует удалять на Amazon) Группы безопасности по умолчанию (нельзя удалять ) ElastiCache

Для каждой службы я указываю количество групп, оставшихся в таблице после завершения исключения.

  1. Наконец, я показываю идентификатор группы, имя группы и описание для оставшихся групп. Это «неиспользуемые» группы, которые необходимо проверить и / или удалить. Я обнаружил, что SG между экземплярами и Elastic Load Balancers (ELB) часто ссылаются друг на друга. Перед удалением перекрестных ссылок и групп безопасности рекомендуется провести небольшое расследование вручную, чтобы убедиться, что они действительно не используются. Но мой сценарий, по крайней мере, сокращает это до чего-то более управляемого.

ПРИМЕЧАНИЯ: 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

Пример 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. Сообщение об ошибке можно увидеть ниже.

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

По идентификатору:

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-stack, но оно было до смешного сложным.

Вот инструмент и заявление о том, что я работал над ним. Но я надеюсь, что вы все сочтете это уместным: https://www.piasoftware.net/single-post/2018/04/24/VIDEO-Watch-as-we-clean-up-EC2-security-groups-in-just -несколько минут


0

К сожалению, выбранный ответ не так точен, как мне нужно (я пытался выяснить, почему, но предпочел реализовать его).
Если я проверю ВСЕ NetworkInterfaces, ищу вложения к любому SecurityGroup, это даст мне частичные результаты. Если я проверю только EC2Instances, он также вернет мне частичные результаты.

Вот мой подход к проблеме:

  1. Я получаю ВСЕ группы безопасности EC2 -> all_secgrp
  2. Я получаю ВСЕ экземпляры EC2 -> all_instances
  3. Для каждого экземпляра я получаю все прикрепленные к нему группы безопасности
    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))

Это не распространяется на SG, используемые RDS
Alexandernst
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.