사용하지 않는 Amazon EC2 보안 그룹을 찾는 방법


93

정리하고 제거 할 수 있도록 고아 보안 그룹을 확인하는 방법을 찾으려고합니다. 사용하지 않는 보안 그룹을 검색하는 방법을 아는 사람이 있습니까?

콘솔 또는 명령 줄 도구를 통해 작동합니다 (Linux 및 OSX 시스템에서 명령 줄 도구 실행).


4
SG를 할당 할 수 있고 '모두 선택 후 삭제'를 포함하지 않는 수명이 긴 비 인스턴스 객체 (RDS, ELB, ALB)에 대한 예외없이이 질문에 완전히 답하는 내 왕국 무서운 주말 -파괴자 접근. :)
Jesse Adelman

답변:


78

참고 : 이것은 RDS와 같은 다른 서비스가 아닌 EC2의 보안 사용만을 고려합니다. 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

그런 다음 그것을 모아 두 목록을 비교하고 마스터 목록에서 사용되지 않는 것을 확인하십시오.

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
당신은 당신이 다른 기본 VPC의 SG 볼 필요 없다 귀하의 VPC에 대한 --filter을 추가 할 수 있습니다
shadowbq

2
보안 그룹은 ELB에서도 사용 중일 수 있습니다. 이 명령은 기본 리전에서 ELB가 참조하는 aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | sort | uniq
고유

2
RDS 인스턴스에서 EC2 보안 그룹을 사용할 수도 있습니다. 이 명령은 기본 리전의 RDS 인스턴스에서 사용하는 보안 그룹 ID를 나열합니다.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네트워크 인터페이스를 설명하는 데 사용할 수도 있습니다 .
Jonathan

63

EC2 콘솔에서 모든 보안 그룹을 선택한 다음 작업-> 보안 그룹 삭제를 누르면 인스턴스, 다른 보안 그룹 또는 네트워크 인터페이스에 연결된 보안 그룹을 삭제할 수 없음을 알리는 팝업이 나타납니다. 삭제할 수있는 보안 그룹이 나열됩니다. 즉, 사용되지 않는 보안 그룹 :)


15
동의해야하지만 "모두 선택 + 삭제"를 사용하는 것은 일반적으로 좋은 습관이 아닙니다.
Balmipour

3
작동하는지 확실하지 않은 경우 더미 보안 그룹을 만들어 여기에 첨부하고 삭제 해보고 허용되지 않는지 확인하십시오.
NLail

2
실제로 삭제를 확인할 필요는 없습니다. 팝업에서 삭제할 수있는 (고아) 항목과 불가능한 항목에 대한 분석이 표시됩니다. 그런 다음 취소를 누른 다음 고아를 삭제할 수 있습니다.
rjarmstrong

4
내가 이해하지 못하는 것은 이것이다 :이 scary.maneuver를 수행 할 때 AWS 콘솔이이 정보를 제공 할 수 있다면 API를 통해 동일한 작업을 수행하는 방법을 공유하지 않는 이유는 무엇입니까? 아니고과 같습니다 ... 가능성 갈색 필드 환경에서 필요한 것이 아닙니다
제시 아델

1
be brave :: do it
zanuka

29

연결된 인스턴스 수에 대해 보안 그룹을 나열하기 위해 boto (AWS 용 Python SDK)로 작성된 샘플 코드입니다.

이 논리를 사용하여 명령 줄에서도 동일한 결과를 얻을 수 있습니다.

Boto 코드

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

멋지고 쉽습니다! 감사합니다
크리스 Koston

6
음, 그래, 근데 무슨 일이야?
Ilja

또한 여기에는 실행중인 인스턴스 만 포함됩니다. 중지 된 인스턴스에 연결된 SG도 삭제할 수 없습니다.
AgDude

6
이것은 RDS와 같은 서비스의 인터페이스를 무시합니다. RDS는 인스턴스를 소유하지만 ENI는 사용자가 소유합니다. 나는 유사 ElasticSearch와 ELB 일을 생각하고이 스크립트에 표시되지 않을 것입니다
얀 배너 지 라자

6

약 1 년 동안 감사를받지 않고 사용한 후 AWS EC2 보안 그룹을 감사하고 사용하지 않는 레거시 그룹을 정리해야한다는 것을 알게되었습니다.

이것은 웹 GUI를 통해 수행하기 어려운 작업 이었으므로 작업을 더 쉽게 만들기 위해 AWS CLI를 살펴 보았습니다. StackOverflow에서이 작업을 수행하는 방법에 대한 시작을 찾았지만 아직 완료되지 않았습니다. 그래서 저는 제 스크립트를 쓰기로했습니다. AWS CLI, MySQL 및 일부 "Bash-foo"를 사용하여 다음을 수행했습니다.

  1. 모든 EC2 보안 그룹 목록을 가져옵니다. 나는 localhost의 aws_security_groups라는 MySQL 데이터베이스에있는 "groups"라는 테이블에 group-id, group-name 및 설명을 저장합니다. 발견 된 총 그룹 수가 사용자에게보고됩니다.

  2. 다음 서비스 각각과 연결된 모든 보안 그룹의 목록을 가져 와서 테이블에서 제외합니다. EC2 Istances EC2 Elastic Load Balancers AWS RDS 인스턴스 AWS OpsWorks (Amazon별로 제거 할 수 없음) 기본 보안 그룹 (삭제할 수 없음) ) ElastiCache

각 서비스에 대해 제외가 완료된 후 테이블에 남아있는 그룹 수를보고합니다.

  1. 마지막으로 남은 그룹에 대한 그룹 ID, 그룹 이름 및 설명을 표시합니다. 감사 및 / 또는 삭제해야하는 "사용되지 않는"그룹입니다. 인스턴스와 ELB (Elastic Load Balancer) 간의 SG가 서로를 참조하는 경우가 많습니다. 상호 참조를 제거하고 보안 그룹을 삭제하기 전에 실제로 사용되지 않는지 확인하기 위해 몇 가지 수동 조사를 수행하는 것이 가장 좋습니다. 그러나 내 스크립트는 적어도 이것을 관리 할 수있는 것으로 축소합니다.

참고 : 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

현재 인스턴스가없는 보안 그룹 의 그룹 ID와 이름 인쇄하는 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

ID 별 :

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 스택 솔루션을 게시했지만 엄청나게 복잡했습니다.

여기에 내가 작업 한 도구와 면책 조항이 있습니다. 하지만 여러분 모두가 적절하다고 생각하길 바랍니다 : https://www.piasoftware.net/single-post/2018/04/24/VIDEO-Watch-as-we-clean-up-EC2-security-groups-in-just -몇 분


0

불행히도 선택한 답변이 필요한만큼 정확하지 않습니다 (이유를 조사하려고 시도했지만 구현하는 것을 선호했습니다).
ALL NetworkInterfaces을 선택하여 첨부 파일을 SecurityGroup찾으면 부분적인 결과를 얻습니다. 만 확인하면 EC2Instances부분 결과도 반환됩니다.

이것이 문제에 대한 나의 접근 방식입니다.

  1. 모든 EC2 보안 그룹을 얻습니다-> all_secgrp
  2. 모든 EC2 인스턴스를 얻었습니다-> all_instances
  3. 각 인스턴스에 대해 모든 보안 그룹이 연결됩니다.
    1. 이 SecurityGroup 각각을 all_secgrp에서 제거합니다 (연결 되었기 때문에).
  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))

RDS에서 사용하는 SG는 다루지 않습니다
alexandernst
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.