Blog: How-Tos

Auditing AWS Security Groups

Jamie Riden 02 Jul 2014

aws-code

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:
http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html

2. configure it with access keys – create a new read only user for this purpose:
http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html

$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
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”: “0.0.0.0/0”
     }
    ],
   “UserIdGroupPairs”: []
  }
 ],
 “Description”: “SSH access”,
 “Tags”: [

4. the following Security Groups Perl audit script can be used to parse this – mine is saved as json.pl 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.

#!/usr/bin/perl

use JSON qw( decode_json );

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

my $decoded = decode_json($json);

my @secgrp = @{ $decoded->{‘SecurityGroups’} };
foreach my $f ( @secgrp ) {
 $desc=$f->{“Description”};
 $group=$f->{“GroupName”};

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

 foreach my $g ( @ipperm ) {
  $toport=$g->{‘ToPort’};
  $fromport=$g->{‘FromPort’};
  $proto=$g->{‘IpProtocol’};

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

    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 json.pl
Group Name : SomeGroup
Description: SSH Access
port 22/tcp, from source 0.0.0.0/0

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 “0.0.0.0” 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.