Was looking at our AWS configuration audit in Threat Stack today. One issue it highlighted was that some of our security groups had too many ports open. My first guess was that there were vestigial “default” groups created from hackier days of adding things from the console.

But before I could go deleting them all, I wanted to see if any were in use. I’m a lazy, lazy man, so I’m not going to click around and read stuff to figure it out. Scripting to the rescue!

#!/usr/bin/env ruby

require 'bundler/setup'
require 'aws-sdk'
require 'json'

client = Aws::EC2::Client.new

groups = client.describe_security_groups

SecGroup = Struct.new(:open_count, :group_name, :group_id) do
  def to_json(*a)
    self.to_h.to_json(*a)
  end
end

open_counts = groups.security_groups.map do |group|
  counts = group.ip_permissions.map {|ip| ip.to_port.to_i - ip.from_port.to_i + 1 }
  SecGroup.new counts.inject(&:+), group.group_name, group.group_id
end

wide_opens = open_counts.select {|oc| oc.open_count > 1000 }

if wide_opens.empty?
  puts "No wide-open security groups! Yay!"
  exit(0)
end

puts "Found some wide open security groups:"
puts JSON.pretty_generate(wide_opens)

Boxen = Struct.new(:instance_id, :group, :tags) do
  def to_json(*a)
    self.to_h.to_json(*a)
  end
end

instances_coll = wide_opens.map do |group|

  resp = client.describe_instances(
    dry_run: false,
    filters: [
      {
        name: "instance.group-id",
        values: [group.group_id],
      }
    ]
  )

  resp.reservations.map do |r|
    r.instances.map do |i|
      Boxen.new(i.instance_id, group, i.tags)
    end
  end
end

instances = instances_coll.flatten

puts "Being used by the following instances:"
puts JSON.pretty_generate(instances)

Something to throw in the ‘ole snippets folder. Maybe it’ll help you, too!