Skip to content

Instantly share code, notes, and snippets.

@jfut
Created April 19, 2022 12:55
Show Gist options
  • Save jfut/fe5132cc99eb85e94a141269778bf1f9 to your computer and use it in GitHub Desktop.
Save jfut/fe5132cc99eb85e94a141269778bf1f9 to your computer and use it in GitHub Desktop.
aws-security-group-dump
#!/bin/bash
#
# AWS Security Group dump
#
# Supported name resolution targets:
#
# - EC2
# - RDS
# - RDS Procy
# - ElastiCache
#
# Run:
#
# aws-vault exec "${AWS_PROFILE}" -- ./aws-security-group-dump > aws-security-group-dump.csv
#
# Copyright 2022 Jun Futagawa (jfut)
#
# This software is released under the MIT License.
# http://opensource.org/licenses/mit-license.php
# The only delimiter is a newline
IFS='
'
# ------------------------------------------------------------------------------
# Get lists
# ------------------------------------------------------------------------------
# Security Group list
# "sg-00000000000000000","prod-xxx-yyy-zzz-sg-20220220115051762300000002"
SECURITY_GROUP_TARGET=".GroupId, .GroupName"
SECURITY_GROUP_LIST=$(aws ec2 describe-security-groups --output json \
| jq -r ".SecurityGroups[] | [ ${SECURITY_GROUP_TARGET} ] | @csv")
# Security Group Rule list
# "sg-00000000000000001","000000000000",false,"tcp",80,80,,,"sg-99999999999999999","From ALB XXX"
# "sg-00000000000000002","000000000000",false,"tcp",443,443,"xxx.xxx.xxx.xxx/yy",,,"From XXX"
# "sg-00000000000000003","000000000000",true,"tcp",3306,3306,,,"sg-88888888888888888","To RDS XXX"
SECURITY_GROUP_RULE_TARGET=".GroupId, .GroupOwnerId, .IsEgress, .IpProtocol, .FromPort, .ToPort, .CidrIpv4, .CidrIpv6, .ReferencedGroupInfo.GroupId, .Description"
SECURITY_GROUP_RULE_LIST=$(aws ec2 describe-security-group-rules --output json \
| jq -r ".SecurityGroupRules[] | [ ${SECURITY_GROUP_RULE_TARGET} ] | @csv")
# EC2 instance list
# "i-xxxxxxxxxxxxxxxxx","instance-name","sg-00000000000000000","sg-11111111111111111","sg-22222222222222222",...
EC2_INSTANCE_LIST=$(aws ec2 describe-instances \
--query "Reservations[].Instances[].{
InstanceId: InstanceId,
InstanceName: Tags[?Key=='Name'].Value,
SecurityGroupIdList: NetworkInterfaces[].Groups[].GroupId
}" \
--output json \
| jq -r ".[] | select(.SecurityGroupIdList != null) | [.InstanceId, .InstanceName[0], .SecurityGroupIdList[] ] | @csv")
# LB instance list
# "arn:aws:elasticloadbalancing:ap-northeast-1:000000000000:loadbalancer/app/lb-name/xxxxxxxxxxxxxxxx","lb-name","sg-00000000000000000","sg-11111111111111111","sg-22222222222222222",...
LB_INSTANCE_LIST=$(aws elbv2 describe-load-balancers \
--query "LoadBalancers[].{
LoadBalancerArn: LoadBalancerArn,
LoadBalancerName: LoadBalancerName,
SecurityGroups: SecurityGroups
}" \
--output json \
| jq -r ".[] | select(.SecurityGroups != null) | [ .LoadBalancerArn, .LoadBalancerName, .SecurityGroups[] ] | @csv")
# RDS instance list
# "instance-identifier","instance-name","sg-00000000000000000","sg-11111111111111111","sg-22222222222222222",...
RDS_INSTANCE_LIST=$(aws rds describe-db-instances \
--query "DBInstances[].{
DBInstanceIdentifier: DBInstanceIdentifier,
DBInstanceName: TagList[?Key=='Name'].Value,
VpcSecurityGroups: VpcSecurityGroups
}" \
--output json \
| jq -r ".[] | select(.VpcSecurityGroups != null) | [ .DBInstanceIdentifier, .DBInstanceName[0], .VpcSecurityGroups[].VpcSecurityGroupId ] | @csv")
# RDS Proxy instance list
# "arn:aws:rds:ap-northeast-1:000000000000:db-proxy:prx-xxxxxxxxxxxxxxxxx","proxy-name","sg-00000000000000000","sg-11111111111111111","sg-22222222222222222",...
RDS_PROXY_INSTANCE_LIST=$(aws rds describe-db-proxies \
--query "DBProxies[].{
DBProxyArn: DBProxyArn,
DBProxyName: DBProxyName,
VpcSecurityGroupIds: VpcSecurityGroupIds
}" \
--output json \
| jq -r ".[] | select(.VpcSecurityGroupIds != null) | [ .DBProxyArn, .DBProxyName, .VpcSecurityGroupIds[] ] | @csv")
# ElastiCache instance list
# "arn:aws:elasticache:ap-northeast-1:000000000000:cluster:instance-name","instance-name","sg-00000000000000000","sg-11111111111111111","sg-22222222222222222",...
ELASTICACHE_INSTANCE_LIST=$(aws elasticache describe-cache-clusters \
--query "CacheClusters[].{
ARN: ARN,
CacheClusterId: CacheClusterId,
SecurityGroups: SecurityGroups
}" \
--output json \
| jq -r ".[] | select(.SecurityGroups != null) | [ .ARN, .CacheClusterId, .SecurityGroups[].SecurityGroupId ] | @csv")
# ------------------------------------------------------------------------------
# Resolve security group references in security group rules to instance names by name
# ------------------------------------------------------------------------------
ALL_INSTANCE_LIST="${EC2_INSTANCE_LIST}
${LB_INSTANCE_LIST}
${RDS_INSTANCE_LIST}
${RDS_PROXY_INSTANCE_LIST}
${ELASTICACHE_INSTANCE_LIST}
"
# Resolve instance information to name
SECURITY_GROUP_RULE_LIST_WITH_INSTANCE=""
for SECURITY_GROUP_RULE in ${SECURITY_GROUP_RULE_LIST}
do
REFERENCED_INSTANCE_INFO=""
REFERENCED_SECURITY_GROUP_ID=$(echo "${SECURITY_GROUP_RULE}" | cut -d',' -f 9 | sed 's/"//g')
if [[ ! -z "${REFERENCED_SECURITY_GROUP_ID}" ]]; then
# Resolves the name of the .ReferencedGroupInfo.GroupId
REFERENCED_INSTANCE_LIST=$(echo "${ALL_INSTANCE_LIST}" | grep "${REFERENCED_SECURITY_GROUP_ID}" | sed 's/"//g')
if [[ ! -z "${REFERENCED_INSTANCE_LIST}" ]]; then
# echo "# DEBUG: ${SECURITY_GROUP_RULE}"
# echo "# DEBUG: REFERENCED_SECURITY_GROUP_ID: ${REFERENCED_SECURITY_GROUP_ID}"
for REFERENCED_INSTANCE in ${REFERENCED_INSTANCE_LIST}
do
# Add referenced instance information: InstanceName(InstanceID)
REFERENCED_INSTANCE_ID=$(echo "${REFERENCED_INSTANCE}" | cut -d',' -f 1)
REFERENCED_INSTANCE_NAME=$(echo "${REFERENCED_INSTANCE}" | cut -d',' -f 2)
REFERENCED_INSTANCE_ID="${REFERENCED_INSTANCE_ID##*/}"
REFERENCED_INSTANCE_ID="${REFERENCED_INSTANCE_ID##*:}"
REFERENCED_INSTANCE_INFO="${REFERENCED_INSTANCE_INFO},${REFERENCED_INSTANCE_NAME}(${REFERENCED_INSTANCE_ID})"
# echo "# DEBUG: REFERENCED_INSTANCE_INFO: ${REFERENCED_INSTANCE_INFO}"
done
fi
fi
SECURITY_GROUP_RULE_LIST_WITH_INSTANCE="${SECURITY_GROUP_RULE_LIST_WITH_INSTANCE}
${SECURITY_GROUP_RULE}${REFERENCED_INSTANCE_INFO}"
done
SECURITY_GROUP_RULE_LIST="${SECURITY_GROUP_RULE_LIST_WITH_INSTANCE}"
# ------------------------------------------------------------------------------
# Output
# ------------------------------------------------------------------------------
# Header
echo "InstanceId,InstanceName,GroupName,$(echo ${SECURITY_GROUP_RULE_TARGET} | sed 's/, /,/g' | sed 's/\.//g'),Reference Results..."
# Output list
for INSTANCE in ${EC2_INSTANCE_LIST}
do
ID=$(echo "${INSTANCE}" | cut -d',' -f 1 | sed 's/"//g')
NAME=$(echo "${INSTANCE}" | cut -d',' -f 2 | sed 's/"//g')
SECURITY_GROUP_ID_LIST=$(echo "${INSTANCE}" | cut -d',' -f 3- | sed 's/"//g' | sed 's/,/\n/g')
# echo "# DEBUG: ID: ${ID}, NAME: ${NAME}, SECURITY_GROUP_ID_LIST: ${SECURITY_GROUP_ID_LIST}"
for SECURITY_GROUP_ID in ${SECURITY_GROUP_ID_LIST}
do
# Get security group name
# "sg-00000000000000000","prod-xxx-yyy-zzz-sg-20220220115051762300000002" -> prod-xxx-yyy-zzz-sg-20220220115051762300000002
SECURITY_GROUP_NAME=$(echo "${SECURITY_GROUP_LIST}" | grep "${SECURITY_GROUP_ID}" | cut -d',' -f 2 | sed 's/"//g')
# Output list of security group rules with EC2 instance information
# echo "# DEBUG: SECURITY_GROUP_ID: ${SECURITY_GROUP_ID}, SECURITY_GROUP_NAME: ${SECURITY_GROUP_NAME}"
echo "${SECURITY_GROUP_RULE_LIST}" | egrep "^\"${SECURITY_GROUP_ID}\"," | sed "s/^/${ID},${NAME},${SECURITY_GROUP_NAME},/g" | sort
done
done
@jfut
Copy link
Author

jfut commented Apr 19, 2022

Run:

$ aws-vault exec "${AWS_PROFILE}" -- ./aws-security-group-dump > aws-security-group-dump.csv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment