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


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

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

8 53

8 ответов:

Примечание: это только рассматривает использование безопасности в 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)

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

это пример кода, написанного в boto (Python SDK для AWS), чтобы перечислить группу безопасности по количеству экземпляров, с которыми она связана.

Вы можете использовать эту логику, чтобы получить то же самое в командной строке

Boto Code

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

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

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

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

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

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

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

заметки: 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  Security Groups.\nGroups Left to audit: "$ROWS
    echo -e $ROWS" groups left after Excluding  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

С помощью узла.JS AWS SDK я могу подтвердить, что AWS не позволяет удалять группы безопасности, которые используются. Я написал скрипт, который просто пытается удалить все группы и корректно обрабатывает ошибки. Это работает для классических и современных СИЗ. Сообщение об ошибке можно увидеть ниже.

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 }

пример 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))

подтвердить, какие группы безопасности are по-прежнему используется, Вы должны отменить или удалить if len(sg.instances()) == 0 проверьте и распечатайте len(sg.instances()) значение.

например.

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

в AWS marketplace есть инструмент, который делает это намного проще. Он показывает, какие группы подключены / отсоединены для легкого удаления, но также сравнивает ваши журналы потока 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-a-few-minutes

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

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

  1. я получаю все EC2 SecurityGroups ->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