Cara menemukan grup Keamanan Amazon EC2 yang Tidak Digunakan


93

Saya mencoba menemukan cara untuk menentukan kelompok keamanan yatim piatu sehingga saya dapat membersihkan dan menyingkirkan mereka. Apakah ada yang tahu cara menemukan grup keamanan yang tidak digunakan.

Baik melalui konsol atau dengan alat baris perintah akan bekerja (Menjalankan alat baris perintah di linux dan mesin OSX).


4
Kerajaan saya untuk jawaban yang sepenuhnya menjawab pertanyaan ini, tanpa pengecualian untuk objek non-Instance yang berumur panjang (RDS, ELB, ALB) yang dapat memiliki SG yang ditetapkan, dan tidak melibatkan 'pilih semua, lalu hapus' akhir pekan yang menakutkan pendekatan -destroyer. :)
Jesse Adelman

Jawaban:


78

Catatan: ini hanya mempertimbangkan penggunaan keamanan di EC2, bukan layanan lain seperti RDS. Anda harus melakukan lebih banyak pekerjaan untuk memasukkan grup keamanan yang digunakan di luar EC2. Hal baiknya adalah Anda tidak dapat dengan mudah (bahkan mungkin tidak mungkin) menghapus grup keamanan aktif jika Anda melewatkan satu grup yang terkait dengan layanan lain.

Dengan menggunakan alat AWS CLI yang lebih baru, saya menemukan cara mudah untuk mendapatkan apa yang saya butuhkan:

Pertama, dapatkan daftar semua grup keamanan

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

Kemudian mendapatkan semua kelompok keamanan diikat ke sebuah contoh, kemudian disalurkan ke sortkemudian uniq:

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

Kemudian gabungkan dan bandingkan 2 daftar dan lihat apa yang tidak digunakan dari daftar utama:

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 Ya, saya hanya memiliki satu wilayah dan skrip AWS menetapkan wilayah asalnya melalui variabel lingkungan. Saya tertarik melihat versi multiwilayah dari skrip ini.
Ray

1
Anda mungkin ingin menambahkan --filter untuk vpc Anda sehingga Anda tidak perlu melihat vpc default lainnya sg
shadowbq

2
Grup keamanan juga dapat digunakan oleh ELB. Perintah ini akan mencantumkan kumpulan ID grup keamanan unik yang dirujuk oleh ELB di wilayah default:aws elb describe-load-balancers --query 'LoadBalancerDescriptions[*].SecurityGroups[*]' --output text | tr '\t' '\n' | sort | uniq
astletron

2
Grup keamanan EC2 juga dapat digunakan oleh instans RDS. Perintah ini akan mencantumkan ID grup keamanan yang digunakan oleh instance RDS di wilayah default:aws rds describe-db-security-groups --query 'DBSecurityGroups[*].EC2SecurityGroups[*].EC2SecurityGroupId' --output text | tr '\t' '\n' | sort | uniq
aharden

2
Anda juga dapat menggunakan aws ec2 describe-network-interfaces --query 'NetworkInterfaces[*].Groups[*].GroupId' --output text| tr '\t' '\n' | sort | uniquntuk mendeskripsikan antarmuka jaringan.
Jonathan

63

Jika Anda memilih semua grup keamanan Anda di konsol EC2, lalu tekan tindakan -> Hapus Grup Keamanan, munculan akan muncul yang memberi tahu Anda bahwa Anda tidak dapat menghapus grup keamanan yang dilampirkan ke instans, grup keamanan lain, atau antarmuka jaringan, dan itu akan mencantumkan grup keamanan yang dapat Anda hapus; yaitu grup keamanan yang tidak digunakan :)


15
Meskipun saya harus setuju, menggunakan "pilih semua + hapus" biasanya bukan kebiasaan yang baik.
Balmipour

3
Jika Anda tidak yakin apakah itu akan berhasil, Anda dapat membuat grup keamanan tiruan dan melampirkan sesuatu padanya, coba hapus, dan lihat bahwa itu tidak akan membiarkan Anda.
NLail

2
Anda tidak perlu benar-benar mengkonfirmasi penghapusan, dalam popup itu akan menunjukkan kepada Anda rincian mana yang dapat dihapus (yatim piatu) dan mana yang tidak. Anda kemudian dapat menekan batal dan kemudian menghapus yang yatim piatu.
rjarmstrong

4
Apa yang tidak saya dapatkan adalah: Jika konsol AWS dapat menawarkan informasi ini saat Anda melakukan manuver yang menakutkan ini, mengapa mereka tidak membagikan cara melakukan hal yang sama melalui API? Ini tidak seperti ini bukanlah sesuatu yang mungkin dibutuhkan di lingkungan lapangan coklat ...
Jesse Adelman

1
berani :: lakukan
zanuka

29

Ini adalah kode sampel yang ditulis dalam boto (Python SDK untuk AWS) untuk mencantumkan Grup Keamanan berdasarkan jumlah instans yang terkait dengannya.

Anda dapat menggunakan logika ini untuk mendapatkan hal yang sama di baris perintah juga

Kode Boto

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

Keluaran

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

Baik dan mudah! Terima kasih
Chris Koston

6
ya, tapi bagaimana dengan elbs?
Ilja

Perhatikan juga bahwa ini hanya termasuk menjalankan instance. Anda juga tidak dapat menghapus SG yang ditautkan ke instans yang dihentikan.
AgDude

6
Ini mengabaikan antarmuka dari layanan seperti RDS. RDS memiliki instans, tetapi Anda memiliki ENI. Saya pikir ElasticSearch dan ELB bekerja dengan cara yang sama dan tidak akan muncul dengan skrip ini
rajat banerjee

6

Setelah sekitar satu tahun penggunaan yang tidak diaudit, saya merasa perlu untuk mengaudit grup keamanan AWS EC2 saya dan membersihkan grup lama yang tidak digunakan.

Ini adalah tugas yang menakutkan untuk dilakukan melalui GUI web, jadi saya melihat ke AWS CLI untuk mempermudah tugas. Saya menemukan awal tentang cara melakukan ini di StackOverflow, tetapi itu masih jauh dari selesai. Jadi saya memutuskan untuk menulis naskah saya sendiri. Saya menggunakan AWS CLI, MySQL dan beberapa "Bash-foo" untuk melakukan hal berikut:

  1. Dapatkan daftar semua grup keamanan EC2. Saya menyimpan group-id, group-name dan description dalam tabel yang disebut "groups" dalam database MySQL yang disebut aws_security_groups di localhost. Jumlah total grup yang ditemukan dilaporkan ke pengguna.

  2. Dapatkan daftar semua grup keamanan yang terkait dengan masing-masing layanan berikut dan kecualikan mereka dari tabel: EC2 Istances EC2 Elastic Load Balancers AWS RDS Instans AWS OpsWorks (tidak boleh dihapus per Amazon) Grup keamanan default (Tidak dapat dihapus ) ElastiCache

Untuk setiap layanan, saya melaporkan hitungan jumlah grup yang tersisa di tabel setelah pengecualian selesai.

  1. Akhirnya saya menampilkan group-id, group-name dan description untuk group yang tersisa. Ini adalah grup "tidak terpakai" yang perlu diaudit dan / atau dihapus. Saya menemukan bahwa SG antara instans dan Elastic Load Balancers (ELB) sering merujuk satu sama lain. Ini praktik terbaik untuk melakukan beberapa investigasi manual untuk memastikan mereka benar-benar tidak digunakan sebelum menghapus referensi silang dan menghapus grup keamanan. Tapi skrip saya setidaknya membandingkan ini menjadi sesuatu yang lebih bisa diatur.

CATATAN: 1. Anda akan ingin membuat file untuk menyimpan host MySQL Anda, nama pengguna dan kata sandi dan mengarahkan variabel $ DBCONFIG ke sana. Ini harus terstruktur seperti ini:

[mysql]
host=your-mysql-server-host.com
user=your-mysql-user
password=your-mysql-user-password
  1. Anda dapat mengubah nama database jika Anda ingin - pastikan untuk mengubah variabel $ DB di skrip

Beri tahu saya jika Anda merasa ini berguna atau memiliki komentar, perbaikan, atau peningkatan.

Ini skripnya.

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

Dan inilah sql untuk membuat database.

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

Contoh boto mencetak ID Grup dan Nama hanya dari grup keamanan yang tidak memiliki contoh saat ini.

Ini juga menunjukkan bagaimana menentukan wilayah mana yang Anda khawatirkan.

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

Untuk memastikan grup keamanan mana yang masih digunakan, Anda harus membalik atau menghapus if len(sg.instances()) == 0pengujian dan mencetak len(sg.instances())nilainya.

Misalnya

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

3

Dengan menggunakan AWS SDK node.js, saya dapat mengonfirmasi bahwa AWS tidak mengizinkan Anda untuk menghapus grup keamanan yang sedang digunakan. Saya menulis skrip yang hanya mencoba menghapus semua grup dan menangani kesalahan dengan baik. Ini berfungsi untuk VPC klasik dan modern. Pesan error tersebut dapat dilihat di bawah.

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

Ke SG yang terpasang ke antarmuka jaringan:

Dengan nama:

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

Menurut id:

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

0

Ada alat di pasar AWS yang membuat ini jauh lebih mudah. Ini menunjukkan kepada Anda grup mana yang dilampirkan / dilepas agar mudah dihapus, tetapi juga membandingkan Log Aliran VPC Anda dengan aturan grup keamanan dan menunjukkan kepada Anda aturan SG mana yang sedang digunakan atau tidak. AWS memposting solusi ELK-stack untuk melakukan ini, tetapi itu sangat rumit.

Ini alatnya, dan penafian yang saya kerjakan. Tapi saya harap Anda semua menganggapnya relevan: https://www.piasoftware.net/single-post/2018/04/24/VIDEO-Watch-as-we-clean-up-EC2-security-groups-in-just -beberapa menit


0

Sayangnya jawaban yang dipilih tidak seakurat yang saya butuhkan (saya sudah mencoba menyelidiki mengapa, tetapi saya lebih suka menerapkannya).
Jika saya memeriksa SEMUA NetworkInterfaces, mencari keterikatan pada apa pun SecurityGroup, Itu memberi saya hasil parsial. Jika saya hanya memeriksanya EC2Instances, hasilnya juga sebagian.

Jadi itulah pendekatan saya terhadap masalah ini:

  1. Saya mendapatkan SEMUA Grup Keamanan EC2 -> all_secgrp
  2. Saya mendapatkan SEMUA Instans EC2 -> all_instances
  3. Untuk setiap Instance, saya mendapatkan semua SecurityGroups yang dilampirkan padanya
    1. Saya menghapus dari all_secgrp masing-masing SecurityGroup ini (karena terlampir)
  4. Untuk setiap SecurityGroup, saya memeriksa hubungan dengan NetworkInterfaces (menggunakan filterfungsi dan pemfilteran menggunakannya security-group-id)
    1. JIKA tidak ada asosiasi yang ditemukan, saya menghapus grup keamanan dari all_secgrp

Terlampir Anda dapat melihat potongan kode. Jangan mengeluh tentang efisiensi, tetapi cobalah untuk mengoptimalkannya jika Anda mau.

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

Ini adalah masalah yang sulit, jika Anda memiliki grup keamanan yang mereferensikan grup keamanan lain dalam aturan. Jika demikian, Anda harus menyelesaikan DependencyErrors, yang tidak sepele.

Jika Anda hanya menggunakan alamat IP, maka solusi ini akan berfungsi, setelah Anda membuat klien 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))

Ini tidak akan mencakup SG yang digunakan oleh RDS
alexandernst
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.