Blog: How Tos

Auditing AWS Security Groups

Jamie Riden 02 Jul 2014


It’s difficult to run through and check a substantial list of AWS security groups using the console, so I wanted to dump it out as easily parsable text. To do this I followed these steps:

1. install AWS client. I used Linux, but there’s a Windows MSI as well:

2. configure it with access keys – create a new read only user for this purpose:

$ aws configure
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: eu-west-1
Default output format [None]: json

3. You should then be able to get the JSON output for the security groups, like this:

$ aws –output json –region eu-west-1 ec2 describe-security-groups | head -20
 “SecurityGroups”: [
   “IpPermissionsEgress”: [
     “IpProtocol”: “-1”,
     “IpRanges”: [
      “CidrIp”: “”
   “UserIdGroupPairs”: []
 “Description”: “SSH access”,
 “Tags”: [

4. the following Security Groups Perl audit script can be used to parse this – mine is saved as for example. I had to also install the JSON parsing library with “apt-get install libjson-*perl” on Debian Linux, though CPAN should be able to do this on Windows.


use JSON qw( decode_json );

my $json = do { local $/; <STDIN> };

my $decoded = decode_json($json);

my @secgrp = @{ $decoded->{‘SecurityGroups’} };
foreach my $f ( @secgrp ) {

 my @ipperm = @{ $f->{‘IpPermissions’} };

 foreach my $g ( @ipperm ) {

  my @cidr = @{ $g->{‘IpRanges’} };
  foreach my $h ( @cidr ) {

    print “Group Name : $group\n”;
    print “Description: $desc\n”;
    if ($proto==-1) {
     print “any IP traffic, from source $cidr\n”;
    } else {
     if ($fromport ne $toport) {
      print “ports $fromport:$toport/$proto, from source $cidr\n”;
    } else {
     print “port $fromport/$proto, from source $cidr\n”;

   print “\n”;


5. Run this for the appropriate region, and it will display the inbound rules only:

$ aws –output json –region us-east-1 ec2 describe-security-groups | perl
Group Name : SomeGroup
Description: SSH Access
port 22/tcp, from source

Then you can search for potentially dangerous rules – in this case, I was interested in access from anywhere to particular services, but this currently gives the full list. You can always search for “” for any source, or for “23/tcp” if you’re worried about telnet for example.

If you like you could also run it daily and diff the output against a known good version of the output to see if any unexpected changes have happened.

UPDATE: Read part 2 for the improved Perl script, and a new one for S3 buckets.