I can’t take any credit for this script. Rich Adams created it and shared kindly on github:

https://gist.github.com/richadams/384020d6e4e6d4f400d7

Steps:

1. Login to AWS account

2. IAM > Users > Username > Security Credentials > Create Access Key

3. Add ‘Access key Id’ and ‘Secret access key’ to relevant section in the script

4. Make sure script is executable (chmod +x)

5. Run script, outputting security groups to text file i.e.

sh aws_security_group_details.sh >> aws_all_regions_secgroups.txt

6. Remove access key from AWS > IAM if not longer required

Code below in case the version is removed from github:

#!/bin/bash
# Requires: awscli (http://aws.amazon.com/cli/)
# Prints out a list of all security groups and their settings, just for quickly auditing it.

# Your AWS credentials
if [ -z ${AWS_ACCESS_KEY_ID} ]; then
    export AWS_ACCESS_KEY_ID='***'
    export AWS_SECRET_ACCESS_KEY='***'
fi

# Want to do this for all regions...
REGIONS=(`aws ec2 describe-regions --region us-west-1 --output text | grep "-" | awk -F\t '{print $3}'`)
for REGION in ${REGIONS[*]}; do
    echo "=> $REGION"

    # Grab all the security group info for this region in one call.
    GFILE='/tmp/aws-sec-groups'
    aws ec2 describe-security-groups --region $REGION --output text > $GFILE

    # Grab list of actively used security groups for EC2.
    EC2FILE='/tmp/aws-sec-groups-ec2'
    aws ec2 describe-instances --query 'Reservations[*].Instances[*].SecurityGroups[*].GroupId' --output text --region $REGION | tr '\t' '\n' | sort | uniq > $EC2FILE

    # Grab list of actively used security groups for RDS.
    RDSFILE='/tmp/aws-sec-groups-rds'
    aws rds describe-db-security-groups --query 'DBSecurityGroups[*].EC2SecurityGroups[*].EC2SecurityGroupId' --output text --region $REGION | tr '\t' '\n' | sort | uniq > $RDSFILE

    # Loop over each line of the file and parse it.
    old_IFS=$IFS; IFS=$'\n'
    cat $GFILE | while read line
    do
        case $line in
            # Header
            SECURITYGROUPS*)
                PORT_HAS_GLOBAL_RULE=0
                SID=(`echo $line | awk -F\t '{print $3}'`)
                GNAME=(`echo $line | awk -F\t '{print $4}'`)

                # Determine if this group is currently being used by an EC2/RDS instance.
                EXTRA=""
                grep $SID $EC2FILE &> /dev/null
                if [ $? -ne 0 ]; then
                    grep $SID $RDSFILE &> /dev/null
                    if [ $? -ne 0 ]; then
                      EXTRA=" <= ** Not currently used by any EC2 or RDS instance in this region!"
                    fi
                fi

                echo "  => $SID ($GNAME) $EXTRA"
                ;;

            # Rule Info
            IPPERMISSIONS*)
                INPORT=(`echo $line | awk -F\t '{print $2}'`)
                OUTPORT=(`echo $line | awk -F\t '{print $4}'`)
                PROTO=(`echo $line | awk -F\t '{print $3}'`)
                ;;
            IPRANGES*)
                EXTRA=""
                CIDR=(`echo $line | awk -F\t '{print $2}'`)

                # If a global rule was already seen for this port combo, then this rule is redundant!
                if [[ "$PORT_HAS_GLOBAL_RULE" = "$PROTO:$INPORT-$OUTPORT" ]] ; then
                  EXTRA=" <= ** Redundant, /0 was already specified for $PORT_HAS_GLOBAL_RULE."
                fi

                # Check if we have the global rule enabled.
                if [[ "$CIDR" = "0.0.0.0/0" ]]; then
                    EXTRA=" (!!)" # Mark it as potentially dangerous.
                    PORT_HAS_GLOBAL_RULE="$PROTO:$INPORT-$OUTPORT" # Also keep track, as it makes other rules redundant.
                fi

                echo -e "    => $PROTO:$INPORT->$OUTPORT\t\t$CIDR $EXTRA"
                ;;
            USERIDGROUPPAIRS*)
                EXTRA=""
                GROUPID=(`echo $line | awk -F\t '{print $2}'`)
                GROUPNAME=(`echo $line | awk -F\t '{print $3}'`)

                # If a global rule was already seen for this port combo, then this rule is redundant!
                if [[ "$PORT_HAS_GLOBAL_RULE" = "$PROTO:$INPORT-$OUTPORT" ]] ; then
                  EXTRA=" <= ** Redundant, /0 was already specified for $PORT_HAS_GLOBAL_RULE."
                fi

                echo -e "    => $PROTO:$INPORT->$OUTPORT\t\t$GROUPID ($GROUPNAME) $EXTRA"
                ;;
        esac
    done
    IFS=$old_IFS

    # Clean up
    rm $GFILE
    rm $EC2FILE
    rm $RDSFILE
done

# Remove any credentials from env.
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY

echo ""
Written by Matt Cooper
Hi, I'm Matt Cooper. I started this blog to pretty much act as a brain dump area for things I learn from day to day. You can contact me at: matt@linuxtutorial.co.uk.