So finden Sie nicht verwendete Amazon EC2-Sicherheitsgruppen


93

Ich versuche einen Weg zu finden, um verwaiste Sicherheitsgruppen zu bestimmen, damit ich sie bereinigen und loswerden kann. Kennt jemand eine Möglichkeit, nicht verwendete Sicherheitsgruppen zu erkennen?

Entweder über die Konsole oder mit den Befehlszeilentools funktionieren (Ausführen von Befehlszeilentools auf Linux- und OSX-Computern).


3
Mein Königreich für eine Antwort, die diese Frage vollständig beantwortet, ohne Ausnahmen für langlebige Nicht-Instanz-Objekte (RDS, ELBs, ALBs), denen SGs zugewiesen werden können, und bei denen nicht alle ausgewählt und dann gelöscht werden -Zerstörer Ansatz. :)
Jesse Adelman

Antworten:


77

Hinweis: Dies berücksichtigt nur die Sicherheitsnutzung in EC2, nicht andere Dienste wie RDS. Sie müssen mehr Arbeit leisten, um Sicherheitsgruppen einzubeziehen, die außerhalb von EC2 verwendet werden. Das Gute ist, dass Sie aktive Sicherheitsgruppen nicht einfach (möglicherweise sogar nicht möglich) löschen können, wenn Sie einen zugeordneten Dienst verpassen.

Mit dem neueren AWS CLI-Tool habe ich einen einfachen Weg gefunden, um das zu bekommen, was ich brauche:

Holen Sie sich zunächst eine Liste aller Sicherheitsgruppen

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

Dann bekommen alle Sicherheitsgruppen gebunden an eine Instanz, geleitet dann sortdann uniq:

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

Setzen Sie es dann zusammen und vergleichen Sie die 2 Listen und sehen Sie, was nicht aus der Masterliste verwendet wird:

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 Ja, ich habe nur eine einzige Region und die Heimatregion der AWS-Skripte wird über Umgebungsvariablen festgelegt. Ich würde gerne eine Version dieses Skripts für mehrere Regionen sehen.
Ray

1
Sie können einen --filter für Ihren vpc hinzufügen, damit Sie nicht andere Standard-vpc sg
shadowbq

2
Eine Sicherheitsgruppe kann auch von einer ELB verwendet werden. Dieser Befehl listet die eindeutigen Sicherheitsgruppen-IDs auf, auf die ELBs in der Standardregion aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | sort | uniq
verweisen

2
Eine EC2-Sicherheitsgruppe kann auch von einer RDS-Instanz verwendet werden. Dieser Befehl listet die Sicherheitsgruppen-IDs auf, die von RDS-Instanzen in der Standardregion verwendet werden:aws rds describe-db-security-groups --query 'DBSecurityGroups[*].EC2SecurityGroups[*].EC2SecurityGroupId' --output text | tr '\t' '\n' | sort | uniq
aharden

2
Sie können auch aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Groups[*].GroupId' --output text| tr '\t' '\n' | sort | uniqnur die Netzwerkschnittstellen beschreiben.
Jonathan

61

Wenn Sie alle Ihre Sicherheitsgruppen in der EC2-Konsole auswählen und dann auf Aktionen -> Sicherheitsgruppen löschen klicken, wird ein Popup angezeigt, in dem Sie darauf hingewiesen werden, dass Sie keine Sicherheitsgruppen löschen können, die an Instanzen, andere Sicherheitsgruppen oder Netzwerkschnittstellen angeschlossen sind listet die Sicherheitsgruppen auf, die Sie löschen können; dh die nicht verwendeten Sicherheitsgruppen :)


15
Obwohl ich zustimmen muss, ist die Verwendung von "Alle auswählen + Löschen" normalerweise keine gute Angewohnheit.
Balmipour

3
Wenn Sie sich nicht sicher sind, ob es funktioniert, können Sie einfach eine Dummy-Sicherheitsgruppe erstellen und etwas anhängen, versuchen, es zu löschen, und feststellen, dass Sie dies nicht zulassen.
NLail

2
Sie müssen das Löschen nicht wirklich bestätigen. Im Popup wird angezeigt, welche gelöscht werden können (verwaist) und welche nicht. Sie können dann auf Abbrechen klicken und die verwaisten löschen.
rjarmstrong

4
Was ich nicht bekomme, ist Folgendes: Wenn die AWS-Konsole diese Informationen bei diesem beängstigenden Manöver anbieten kann, warum teilen sie dann nicht mit, wie dasselbe über die API gemacht wird? Es ist nicht so, dass dies wahrscheinlich nicht in braunen Feldern benötigt wird ...
Jesse Adelman

1
sei mutig :: mach es
zanuka

29

Dies ist der in boto (Python SDK für AWS) geschriebene Beispielcode, um die Sicherheitsgruppe anhand der Anzahl der Instanzen aufzulisten, denen sie zugeordnet ist.

Sie können diese Logik verwenden, um dasselbe auch in der Befehlszeile zu erhalten

Boto-Code

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

Ausgabe

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

Schön und einfach! Vielen Dank
Chris Koston

6
Na ja, aber was ist mit den Elben?
Ilja

Beachten Sie auch, dass dies nur das Ausführen von Instanzen umfasst. Sie können auch keine SG löschen, die mit einer gestoppten Instanz verknüpft ist.
AgDude

6
Dies ignoriert Schnittstellen von Diensten wie RDS. RDS besitzt die Instanz, aber Sie besitzen die ENI. Ich denke, ElasticSearch und ELB funktionieren ähnlich und würden mit diesem Skript nicht auftauchen
rajat banerjee

6

Nach etwa einem Jahr ungeprüfter Verwendung war es für mich erforderlich, meine AWS EC2-Sicherheitsgruppen zu überprüfen und ältere, nicht verwendete Gruppen zu bereinigen.

Dies war eine entmutigende Aufgabe, die über die Web-GUI ausgeführt werden musste. Daher habe ich mich an die AWS-CLI gewandt, um die Aufgabe zu vereinfachen. Ich habe bei StackOverflow einen Anfang gefunden, aber es war noch lange nicht abgeschlossen. Also habe ich beschlossen, mein eigenes Skript zu schreiben. Ich habe die AWS CLI, MySQL und einige "Bash-foo" verwendet, um Folgendes auszuführen:

  1. Holen Sie sich eine Liste aller EC2-Sicherheitsgruppen. Ich speichere die Gruppen-ID, den Gruppennamen und die Beschreibung in einer Tabelle mit dem Namen "groups" in einer MySQL-Datenbank mit dem Namen aws_security_groups auf dem lokalen Host. Die Gesamtzahl der gefundenen Gruppen wird dem Benutzer gemeldet.

  2. Rufen Sie eine Liste aller Sicherheitsgruppen ab, die den folgenden Diensten zugeordnet sind, und schließen Sie sie aus der Tabelle aus: EC2 Istances EC2 Elastic Load Balancers AWS RDS-Instanzen AWS OpsWorks (sollte nicht pro Amazon entfernt werden) Standardsicherheitsgruppen (Kann nicht gelöscht werden ) ElastiCache

Für jeden Dienst gebe ich eine Anzahl der Gruppen an, die nach Abschluss des Ausschlusses in der Tabelle verbleiben.

  1. Schließlich zeige ich die Gruppen-ID, den Gruppennamen und die Beschreibung für die verbleibenden Gruppen an. Dies sind die "nicht verwendeten" Gruppen, die geprüft und / oder gelöscht werden müssen. Ich habe festgestellt, dass SGs zwischen Instanzen und ELBs (Elastic Load Balancers) häufig aufeinander verweisen. Es wird empfohlen, einige manuelle Untersuchungen durchzuführen, um sicherzustellen, dass sie wirklich nicht verwendet werden, bevor die Querverweise entfernt und die Sicherheitsgruppen gelöscht werden. Aber mein Drehbuch reduziert dies zumindest auf etwas mehr Verwaltbares.

HINWEISE: 1. Sie möchten eine Datei erstellen, in der Sie Ihren MySQL-Host, Ihren Benutzernamen und Ihr Kennwort speichern und die Variable $ DBCONFIG darauf verweisen. Es sollte so aufgebaut sein:

[mysql]
host=your-mysql-server-host.com
user=your-mysql-user
password=your-mysql-user-password
  1. Sie können den Namen der Datenbank ändern, wenn Sie möchten. Stellen Sie sicher, dass Sie die Variable $ DB im Skript ändern

Lassen Sie mich wissen, wenn Sie dies nützlich finden oder Kommentare, Korrekturen oder Verbesserungen haben.

Hier ist das Skript.

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

Und hier ist die SQL zum Erstellen der Datenbank.

-- 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

Ein Boto-Beispiel zum Drucken der Gruppen-IDs und -Namen nur der Sicherheitsgruppen, die keine aktuellen Instanzen haben.

Außerdem wird gezeigt, wie Sie angeben, um welche Region es sich handelt.

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))

Um zu bestätigen , welche Sicherheitsgruppen sind noch verwendet wird , sollten Sie die rückgängig zu machen oder entfernen if len(sg.instances()) == 0Test und drucken Sie den len(sg.instances())Wert aus.

Z.B

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

3

Mit dem AWS SDK von node.js kann ich bestätigen, dass Sie mit AWS keine verwendeten Sicherheitsgruppen löschen können. Ich habe ein Skript geschrieben, das einfach versucht, alle Gruppen zu löschen und die Fehler ordnungsgemäß zu behandeln. Dies funktioniert für klassische und moderne VPC. Die Fehlermeldung ist unten zu sehen.

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

An die an die Netzwerkschnittstellen angeschlossenen SGs:

Namentlich:

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

Nach ID:

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

0

Auf dem AWS-Marktplatz gibt es ein Tool, das dies erheblich vereinfacht. Es zeigt Ihnen, welche Gruppen zum einfachen Löschen angehängt / getrennt sind, vergleicht aber auch Ihre VPC-Flussprotokolle mit den Sicherheitsgruppenregeln und zeigt Ihnen, welche SG-Regeln verwendet oder nicht verwendet werden. AWS hat dazu eine ELK-Stack-Lösung veröffentlicht, die jedoch lächerlich komplex war.

Hier ist das Tool und ein Haftungsausschluss, an dem ich gearbeitet habe. Aber ich hoffe, Sie alle finden es relevant: https://www.piasoftware.net/single-post/2018/04/24/VIDEO-Watch-as-we-clean-up-EC2-security-groups-in-just -ein paar Minuten


0

Leider ist die gewählte Antwort nicht so genau wie ich brauche (ich habe versucht, das Warum zu untersuchen, aber ich habe es vorgezogen, sie zu implementieren).
Wenn ich ALLE überprüfe NetworkInterfacesund nach Anhängen zu irgendwelchen suche SecurityGroup, erhalte ich teilweise Ergebnisse. Wenn ich nur einchecke EC2Instances, bekomme ich auch Teilergebnisse zurück.

Das ist also meine Herangehensweise an das Problem:

  1. Ich bekomme ALLE EC2-Sicherheitsgruppen -> all_secgrp
  2. Ich bekomme ALLE EC2-Instanzen -> all_instances
  3. Für jede Instanz werden alle SecurityGroups angehängt
    1. Ich entferne aus all_secgrp jede dieser Sicherheitsgruppen (weil angehängt)
  4. Für jede Sicherheitsgruppe überprüfe ich eine Zuordnung zu beliebigen NetworkInterfaces (mithilfe der filterFunktion und Filterung damit security-group-id).
    1. Wenn keine Zuordnung gefunden wird, entferne ich die Sicherheitsgruppe aus all_secgrp

Im Anhang sehen Sie einen Codeausschnitt. Beschweren Sie sich nicht über die Effizienz, sondern versuchen Sie, sie zu optimieren, wenn Sie möchten.

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

Dies ist ein schwieriges Problem, wenn Sie Sicherheitsgruppen haben, die in den Regeln auf andere Sicherheitsgruppen verweisen. In diesem Fall müssen Sie DependencyErrors auflösen, was nicht trivial ist.

Wenn Sie nur IP-Adressen verwenden, funktioniert diese Lösung nach dem Erstellen eines Boto3-Clients:

# 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))

Dies gilt nicht für SGs, die von RDS verwendet werden
Alexander
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.