J'essaie de trouver un moyen de déterminer les groupes de sécurité Orphan afin de pouvoir les nettoyer et les éliminer. Est-ce que quelqu'un connaît un moyen de découvrir des groupes de sécurité inutilisés?.
Soit via la console ou avec les outils de ligne de commande fonctionnera (Exécution d’outils de ligne de commande sur des machines Linux et OSX).
Remarque: cela ne concerne que l'utilisation de la sécurité dans EC2, pas d'autres services comme RDS. Vous devrez faire plus de travail pour inclure les groupes de sécurité utilisés en dehors d'EC2. La bonne chose est que vous ne pouvez pas facilement (peut-être même pas être possible) supprimer des groupes de sécurité actifs si vous manquez un service associé w/autre.
À l'aide du nouvel outil AWS CLI, j'ai trouvé un moyen simple d'obtenir ce dont j'ai besoin:
Tout d'abord, obtenir une liste de tous les groupes de sécurité
aws ec2 describe-security-groups --query 'SecurityGroups[*].GroupId' --output text | tr '\t' '\n'
Ensuite, associez tous les groupes de sécurité à une instance, puis transmettez-les à sort
puis uniq
:
aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text | tr '\t' '\n' | sort | uniq
Ensuite, rassemblez-les, comparez les 2 listes et voyez ce qui n’est pas utilisé dans la liste principale:
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)
Si vous sélectionnez tous vos groupes de sécurité dans la console EC2, puis appuyez sur actions -> Supprimer les groupes de sécurité, une fenêtre contextuelle vous informant que vous ne pouvez pas supprimer les groupes de sécurité associés à des instances, à d'autres groupes de sécurité ou à des interfaces réseau, s'affiche. listera les groupes de sécurité que vous pouvez supprimer; c'est-à-dire les groupes de sécurité non utilisés :)
Il s'agit de l'exemple de code écrit en boto (Python SDK for AWS) permettant de répertorier le groupe de sécurité en fonction du nombre d'instances auquel il est associé.
Vous pouvez également utiliser cette logique pour obtenir la même chose en ligne de commande.
Boto Code
import boto
ec2 = boto.connect_ec2()
sgs = ec2.get_all_security_groups()
for sg in sgs:
print sg.name, len(sg.instances())
Sortie
Security-Group-1 0
Security-Group-2 1
Security-Group-3 0
Security-Group-4 3
Après environ un an d'utilisation non vérifiée, j'ai jugé nécessaire d'auditer mes groupes de sécurité AWS EC2 et de nettoyer les groupes hérités et inutilisés.
Il s'agissait d'une tâche ardue à effectuer via l'interface graphique Web. Je me suis donc tourné vers l'AWS CLI pour la rendre plus facile. J'ai trouvé un début sur comment faire ceci chez StackOverflow, mais c'était loin d'être complet. J'ai donc décidé d'écrire mon propre script. J'ai utilisé l'AWS CLI, MySQL et certains “Bash-foo” pour effectuer les opérations suivantes:
Obtenez une liste de tous les groupes de sécurité EC2 . Je stocke l'ID de groupe, le nom de groupe et la description dans un tableau appelé «groupes» dans une base de données MySQL appelée aws_security_groups sur l'hôte local. Le nombre total de groupes trouvés est signalé à l'utilisateur.
Obtenez une liste de tous les groupes de sécurité associés à chacun des services suivants et excluez-les du tableau: EC2 Instances EC2 Elastic Load BalancersAWS Instances RDSAWS OpsWorks (ne doit pas être supprimé par Amazon) Groupes de sécurité par défaut (ne peut pas être supprimé) ElastiCache
Pour chaque service, je rapporte le nombre de groupes restants dans le tableau une fois l'exclusion terminée.
NOTES: 1. Vous voudrez créer un fichier pour stocker votre hôte MySQL, votre nom d'utilisateur et votre mot de passe, et pointer la variable $ DBCONFIG vers celui-ci. Il devrait être structuré comme ceci:
[mysql]
Host=your-mysql-server-Host.com
user=your-mysql-user
password=your-mysql-user-password
Faites-moi savoir si vous trouvez cela utile ou si vous avez des commentaires, des corrections ou des améliorations.
Voici le script.
#!/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/'
Et voici le SQL pour créer la base de données.
-- 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
Utilisation du SDK AWS node.js Je peux confirmer qu'AWS ne vous permet pas de supprimer les groupes de sécurité en cours d'utilisation. J'ai écrit un script qui essaie simplement de supprimer tous les groupes et gère les erreurs avec élégance. Cela fonctionne pour le VPC classique et moderne. Le message d'erreur peut être vu ci-dessous.
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 }
Parmi d'autres fonctions, ScoutSuite et Prowler signalent les groupes de sécurité EC2 inutilisés. Les deux sont open source.
Un exemple de boto imprimant les ID de groupe et les noms uniquement des groupes de sécurité ne possédant aucune instance en cours.
Il montre également comment spécifier la région qui vous concerne.
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))
Pour confirmer quels groupes de sécurité sont encore utilisés, vous devez inverser ou supprimer le test if len(sg.instances()) == 0
et imprimer la valeur len(sg.instances())
.
Par exemple.
print ("{0}\t{1}\t{2} instances".format(sg.id, sg.name, len(sg.instances())))
Aux SG attachés aux interfaces réseau:
De nom:
aws ec2 describe-network-interfaces --output text --query NetworkInterfaces[*].Groups[*].GroupName | tr -d '\r' | tr "\t" "\n" | sort | uniq
Par identifiant:
aws ec2 describe-network-interfaces --output text --query NetworkInterfaces[*].Groups[*].GroupId | tr -d '\r' | tr "\t" "\n" | sort | uniq
C'est un problème difficile si vous avez des groupes de sécurité qui référencent d'autres groupes de sécurité dans les règles. Si tel est le cas, vous devrez résoudre DependencyErrors, ce qui n’est pas trivial.
Si vous utilisez uniquement des adresses IP, cette solution fonctionnera après la création d'un client 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))
Malheureusement, la réponse choisie n’est pas aussi précise que j’ai besoin (j’ai essayé de comprendre pourquoi mais j’ai préféré l’appliquer).
Si je vérifie TOUT NetworkInterfaces
en cherchant des pièces jointes à une SecurityGroup
, cela me donne des résultats partiels. Si je ne vérifie que EC2Instances
, il me restitue également des résultats partiels.
Voilà donc mon approche du problème:
all_secgrp
all_instances
filter
et du filtrage à l'aide de ce security-group-id
).all_secgrp
Ci-joint, vous pouvez voir un extrait de code. Ne vous plaignez pas pour l'efficacité, mais essayez de l'optimiser si vous le souhaitez.
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