aws-inventory 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +16 -0
 - data/.rspec +2 -0
 - data/Gemfile +6 -0
 - data/Gemfile.lock +661 -0
 - data/Guardfile +19 -0
 - data/LICENSE.txt +22 -0
 - data/README.md +65 -0
 - data/Rakefile +6 -0
 - data/exe/aws-inventory +14 -0
 - data/inventory.gemspec +37 -0
 - data/lib/inventory.rb +29 -0
 - data/lib/inventory/acm.rb +15 -0
 - data/lib/inventory/aws_services.rb +53 -0
 - data/lib/inventory/base.rb +74 -0
 - data/lib/inventory/cfn.rb +50 -0
 - data/lib/inventory/cli.rb +86 -0
 - data/lib/inventory/cloudwatch.rb +38 -0
 - data/lib/inventory/command.rb +25 -0
 - data/lib/inventory/eb.rb +19 -0
 - data/lib/inventory/ec2.rb +86 -0
 - data/lib/inventory/ecs.rb +10 -0
 - data/lib/inventory/ecs/cluster.rb +20 -0
 - data/lib/inventory/ecs/service.rb +33 -0
 - data/lib/inventory/elb.rb +71 -0
 - data/lib/inventory/help.rb +9 -0
 - data/lib/inventory/help/acm.md +1 -0
 - data/lib/inventory/help/cfn.md +1 -0
 - data/lib/inventory/help/cw.md +1 -0
 - data/lib/inventory/help/eb.md +1 -0
 - data/lib/inventory/help/ec2.md +1 -0
 - data/lib/inventory/help/ecs.md +1 -0
 - data/lib/inventory/help/elb.md +1 -0
 - data/lib/inventory/help/iam.md +15 -0
 - data/lib/inventory/help/keypair.md +1 -0
 - data/lib/inventory/help/rds.md +5 -0
 - data/lib/inventory/help/sg.md +1 -0
 - data/lib/inventory/help/vpc.md +1 -0
 - data/lib/inventory/iam.rb +13 -0
 - data/lib/inventory/iam/group.rb +22 -0
 - data/lib/inventory/iam/shared.rb +62 -0
 - data/lib/inventory/iam/summary.rb +16 -0
 - data/lib/inventory/iam/user.rb +21 -0
 - data/lib/inventory/keypair.rb +25 -0
 - data/lib/inventory/presenter.rb +20 -0
 - data/lib/inventory/presenters/base.rb +5 -0
 - data/lib/inventory/presenters/tab.rb +7 -0
 - data/lib/inventory/presenters/table.rb +10 -0
 - data/lib/inventory/rds.rb +11 -0
 - data/lib/inventory/rds/port.rb +53 -0
 - data/lib/inventory/rds/shared.rb +43 -0
 - data/lib/inventory/rds/summary.rb +23 -0
 - data/lib/inventory/route53.rb +29 -0
 - data/lib/inventory/security_group.rb +11 -0
 - data/lib/inventory/security_group/open.rb +76 -0
 - data/lib/inventory/security_group/shared.rb +14 -0
 - data/lib/inventory/security_group/summary.rb +17 -0
 - data/lib/inventory/shared.rb +16 -0
 - data/lib/inventory/version.rb +3 -0
 - data/lib/inventory/vpc.rb +55 -0
 - data/spec/lib/cli_spec.rb +31 -0
 - data/spec/lib/inventory/base_spec.rb +7 -0
 - data/spec/lib/inventory/security_group/open_spec.rb +31 -0
 - data/spec/spec_helper.rb +24 -0
 - metadata +308 -0
 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Iam
         
     | 
| 
      
 2 
     | 
    
         
            +
              class User < Inventory::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Shared
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def header
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ["User", "Password Last Used"]
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def data
         
     | 
| 
      
 10 
     | 
    
         
            +
                  users.map do |user|
         
     | 
| 
      
 11 
     | 
    
         
            +
                    group_names = group_names(user).join(',')
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    [user.user_name, group_names]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def sort(data)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  data.sort_by { |item| item[1].to_i }.reverse
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Keypair < Inventory::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              def header
         
     | 
| 
      
 3 
     | 
    
         
            +
                ["Key Name", "Instance Count"]
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def data
         
     | 
| 
      
 7 
     | 
    
         
            +
                key_pairs.map do |key|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  instance_count = instance_count(key)
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  [key.key_name, instance_count]
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def sort(data)
         
     | 
| 
      
 15 
     | 
    
         
            +
                data.sort_by { |i| i[1] }.reverse
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def key_pairs
         
     | 
| 
      
 19 
     | 
    
         
            +
                @key_pairs ||= ec2.describe_key_pairs.key_pairs
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def instance_count(key)
         
     | 
| 
      
 23 
     | 
    
         
            +
                instances.count { |i| i.key_name == key.key_name }
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Presenter
         
     | 
| 
      
 2 
     | 
    
         
            +
              autoload :Base, "inventory/presenters/base"
         
     | 
| 
      
 3 
     | 
    
         
            +
              autoload :Tab, "inventory/presenters/tab"
         
     | 
| 
      
 4 
     | 
    
         
            +
              autoload :Table, "inventory/presenters/table"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def initialize(data)
         
     | 
| 
      
 7 
     | 
    
         
            +
                @data = data
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def display
         
     | 
| 
      
 11 
     | 
    
         
            +
                presenter_class = "Inventory::Presenter::#{format.classify}".constantize
         
     | 
| 
      
 12 
     | 
    
         
            +
                presenter = presenter_class.new(@data)
         
     | 
| 
      
 13 
     | 
    
         
            +
                presenter.display
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              # Formats: tabs, markdown
         
     | 
| 
      
 17 
     | 
    
         
            +
              def format
         
     | 
| 
      
 18 
     | 
    
         
            +
                ENV['AWS_INVENTORY_FORMAT'] || "table"
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Rds < Inventory::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              autoload :Shared, "inventory/rds/shared"
         
     | 
| 
      
 3 
     | 
    
         
            +
              autoload :Summary, "inventory/rds/summary"
         
     | 
| 
      
 4 
     | 
    
         
            +
              autoload :Port, "inventory/rds/port"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              # Default is the open report because it seems like the most useful report
         
     | 
| 
      
 7 
     | 
    
         
            +
              def report
         
     | 
| 
      
 8 
     | 
    
         
            +
                Summary.new(@options).report if show(:summary)
         
     | 
| 
      
 9 
     | 
    
         
            +
                Port.new(@options).report if show(:port)
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Rds
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Port < Inventory::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Shared
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def header
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ["RDS Db Name", "Security Group", "Range/Source", "Port"]
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def data
         
     | 
| 
      
 10 
     | 
    
         
            +
                  data = []
         
     | 
| 
      
 11 
     | 
    
         
            +
                  db_instances.each do |db|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    db_security_groups = vpc_security_groups(db)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    db_security_groups.each do |sg|
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      sg.ip_permissions.each do |permission|
         
     | 
| 
      
 16 
     | 
    
         
            +
                        data << [
         
     | 
| 
      
 17 
     | 
    
         
            +
                          db.db_name,
         
     | 
| 
      
 18 
     | 
    
         
            +
                          "#{sg.group_id} (#{sg.group_name})",
         
     | 
| 
      
 19 
     | 
    
         
            +
                          ip_range_and_source(permission),
         
     | 
| 
      
 20 
     | 
    
         
            +
                          port(permission)
         
     | 
| 
      
 21 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 22 
     | 
    
         
            +
                      end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  data
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def port(permission)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  ports = [permission.from_port, permission.to_port].uniq
         
     | 
| 
      
 31 
     | 
    
         
            +
                  if ports.size > 1
         
     | 
| 
      
 32 
     | 
    
         
            +
                    raise "TODO: account for port ranges"
         
     | 
| 
      
 33 
     | 
    
         
            +
                  else
         
     | 
| 
      
 34 
     | 
    
         
            +
                    ports.first
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def ip_range_and_source(permission)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  cidr_ips = permission.ip_ranges.map {|range| range.cidr_ip }
         
     | 
| 
      
 40 
     | 
    
         
            +
                  user_id_group_pairs = permission.user_id_group_pairs.map do |pair|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    # pair.group_name is always returning nil :( Might be AWS bug
         
     | 
| 
      
 42 
     | 
    
         
            +
                    # so fetching it from security groups themselves
         
     | 
| 
      
 43 
     | 
    
         
            +
                    sg = security_groups.find {|sg| sg.group_id == pair.group_id }
         
     | 
| 
      
 44 
     | 
    
         
            +
                    sg_name = " (#{sg.group_name})" if sg
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    "#{pair.group_id}#{sg_name}" # pretty format
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  result = cidr_ips + user_id_group_pairs
         
     | 
| 
      
 49 
     | 
    
         
            +
                  result.join(', ')
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Inventory::Rds::Shared
         
     | 
| 
      
 2 
     | 
    
         
            +
              # pretty name of vpc
         
     | 
| 
      
 3 
     | 
    
         
            +
              def vpc_name(db)
         
     | 
| 
      
 4 
     | 
    
         
            +
                group_ids = db.vpc_security_groups.map(&:vpc_security_group_id)
         
     | 
| 
      
 5 
     | 
    
         
            +
                resp = ec2.describe_security_groups(group_ids: group_ids)
         
     | 
| 
      
 6 
     | 
    
         
            +
                groups = resp.security_groups
         
     | 
| 
      
 7 
     | 
    
         
            +
                vpc_ids = groups.map(&:vpc_id)
         
     | 
| 
      
 8 
     | 
    
         
            +
                vpc_ids.map do |vpc_id|
         
     | 
| 
      
 9 
     | 
    
         
            +
                  pretty_vpc_name = lookup_vpc_name(vpc_id)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  "#{vpc_id} (#{pretty_vpc_name})"
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def lookup_vpc_name(vpc_id)
         
     | 
| 
      
 15 
     | 
    
         
            +
                inventory_vpc = Inventory::Vpc.new(@options)
         
     | 
| 
      
 16 
     | 
    
         
            +
                inventory_vpc.vpc_name(vpc_id)
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def vpcs
         
     | 
| 
      
 20 
     | 
    
         
            +
                @vpcs ||= ec2.describe_vpcs.vpcs
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              def pretty_vpc_security_group(db)
         
     | 
| 
      
 24 
     | 
    
         
            +
                groups = vpc_security_groups(db)
         
     | 
| 
      
 25 
     | 
    
         
            +
                groups.map { |g| "#{g.group_id} (#{g.group_name})" }
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              # pretty name of the vpc security groups
         
     | 
| 
      
 29 
     | 
    
         
            +
              def vpc_security_groups(db)
         
     | 
| 
      
 30 
     | 
    
         
            +
                group_ids = db.vpc_security_groups.map(&:vpc_security_group_id)
         
     | 
| 
      
 31 
     | 
    
         
            +
                group_ids.map do |db_security_group_id|
         
     | 
| 
      
 32 
     | 
    
         
            +
                  security_groups.find {|sg| sg.group_id == db_security_group_id }
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              def db_instances
         
     | 
| 
      
 37 
     | 
    
         
            +
                @db_instances ||= rds.describe_db_instances.db_instances
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              def security_group_names(instance)
         
     | 
| 
      
 41 
     | 
    
         
            +
                instance.security_groups.map {|sg| sg.group_name}.join(', ')
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Rds
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Summary < Inventory::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Shared
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def header
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ["Name", "Engine", "Instance Class", "Publicly Accessible", "VPC", "Security Groups"]
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def data
         
     | 
| 
      
 11 
     | 
    
         
            +
                  db_instances.map do |db|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    [
         
     | 
| 
      
 13 
     | 
    
         
            +
                      db.db_name,
         
     | 
| 
      
 14 
     | 
    
         
            +
                      db.engine,
         
     | 
| 
      
 15 
     | 
    
         
            +
                      db.db_instance_class,
         
     | 
| 
      
 16 
     | 
    
         
            +
                      db.publicly_accessible ? "yes" : "no",
         
     | 
| 
      
 17 
     | 
    
         
            +
                      vpc_name(db),
         
     | 
| 
      
 18 
     | 
    
         
            +
                      pretty_vpc_security_group(db),
         
     | 
| 
      
 19 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Route53 < Inventory::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              def header
         
     | 
| 
      
 3 
     | 
    
         
            +
                ["Domain", "Record Set Count"]
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def data
         
     | 
| 
      
 7 
     | 
    
         
            +
                zones.map do |zone|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  record_sets = resource_record_sets(zone)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  [zone.name, record_sets.count]
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def records
         
     | 
| 
      
 14 
     | 
    
         
            +
                zones.inject([]) do |array, zone|
         
     | 
| 
      
 15 
     | 
    
         
            +
                  array << resource_record_sets(zone)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              @@resource_record_sets = {}
         
     | 
| 
      
 20 
     | 
    
         
            +
              def resource_record_sets(zone)
         
     | 
| 
      
 21 
     | 
    
         
            +
                @@resource_record_sets[zone.id] ||= route53
         
     | 
| 
      
 22 
     | 
    
         
            +
                  .list_resource_record_sets(hosted_zone_id: zone.id)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  .resource_record_sets
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def zones
         
     | 
| 
      
 27 
     | 
    
         
            +
                @zones ||= route53.list_hosted_zones.hosted_zones
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::SecurityGroup < Inventory::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              autoload :Shared, "inventory/security_group/shared"
         
     | 
| 
      
 3 
     | 
    
         
            +
              autoload :Summary, "inventory/security_group/summary"
         
     | 
| 
      
 4 
     | 
    
         
            +
              autoload :Open, "inventory/security_group/open"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              # Default is the open report because it seems like the most useful report
         
     | 
| 
      
 7 
     | 
    
         
            +
              def report
         
     | 
| 
      
 8 
     | 
    
         
            +
                Summary.new(@options).report if show(:summary)
         
     | 
| 
      
 9 
     | 
    
         
            +
                Open.new(@options).report if show(:open)
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'facets/array/arrange'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Inventory::SecurityGroup
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Open < Inventory::Base
         
     | 
| 
      
 5 
     | 
    
         
            +
                include Shared
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def header
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ["Security Group", "Open to World"]
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def data
         
     | 
| 
      
 12 
     | 
    
         
            +
                  opened_security_groups_in_use = opened_security_groups.select do |sg|
         
     | 
| 
      
 13 
     | 
    
         
            +
                    group_ids_in_use = used_security_groups.map(&:group_id)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    group_ids_in_use.include?(sg.group_id)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  # Only display used security groups that have opened ports for review.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # will delete the unused security groups anyway.
         
     | 
| 
      
 19 
     | 
    
         
            +
                  opened_security_groups_in_use.map do |sg|
         
     | 
| 
      
 20 
     | 
    
         
            +
                    ports = ports_open_to_world(sg)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    [
         
     | 
| 
      
 22 
     | 
    
         
            +
                      sg.group_name,
         
     | 
| 
      
 23 
     | 
    
         
            +
                      ports
         
     | 
| 
      
 24 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def opened_security_groups
         
     | 
| 
      
 29 
     | 
    
         
            +
                  security_groups.select do |sg|
         
     | 
| 
      
 30 
     | 
    
         
            +
                    ports = ports_open_to_world(sg)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    !ports.empty?
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                # Returns an Array of ports with a cidr of 0.0.0.0/0
         
     | 
| 
      
 36 
     | 
    
         
            +
                def ports_open_to_world(sg)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  ip_permissions = sg.ip_permissions.select do |permission|
         
     | 
| 
      
 38 
     | 
    
         
            +
                      permission.ip_ranges.detect do |ip_range|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        ip_range.include?('0.0.0.0/0')
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  ports = ip_permissions.map do |p|
         
     | 
| 
      
 44 
     | 
    
         
            +
                    if p.from_port == p.to_port
         
     | 
| 
      
 45 
     | 
    
         
            +
                      p.from_port
         
     | 
| 
      
 46 
     | 
    
         
            +
                    else
         
     | 
| 
      
 47 
     | 
    
         
            +
                      (p.from_port..p.to_port)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  ports = combine_ports(ports)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  # convert to string for printing
         
     | 
| 
      
 53 
     | 
    
         
            +
                  ports.map(&:to_s).join(', ')
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                # Examples
         
     | 
| 
      
 57 
     | 
    
         
            +
                #
         
     | 
| 
      
 58 
     | 
    
         
            +
                # Input:
         
     | 
| 
      
 59 
     | 
    
         
            +
                #    ports: [80, 443]
         
     | 
| 
      
 60 
     | 
    
         
            +
                # Output:
         
     | 
| 
      
 61 
     | 
    
         
            +
                #    ports: [80, 443
         
     | 
| 
      
 62 
     | 
    
         
            +
                #
         
     | 
| 
      
 63 
     | 
    
         
            +
                # Input:
         
     | 
| 
      
 64 
     | 
    
         
            +
                #    ports: [8001, 8000..8002]
         
     | 
| 
      
 65 
     | 
    
         
            +
                # Output:
         
     | 
| 
      
 66 
     | 
    
         
            +
                #    ports: [8000..8002]
         
     | 
| 
      
 67 
     | 
    
         
            +
                def combine_ports(port_objects)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  ports = port_objects.inject([]) do |array, port|
         
     | 
| 
      
 69 
     | 
    
         
            +
                    ports = port.is_a?(Range) ? port.to_a : [port]
         
     | 
| 
      
 70 
     | 
    
         
            +
                    array += ports
         
     | 
| 
      
 71 
     | 
    
         
            +
                    array
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end.uniq
         
     | 
| 
      
 73 
     | 
    
         
            +
                  ports.arrange
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Inventory::SecurityGroup::Shared
         
     | 
| 
      
 2 
     | 
    
         
            +
              def used_security_groups
         
     | 
| 
      
 3 
     | 
    
         
            +
                groups = instances.inject([]) do |results, i|
         
     | 
| 
      
 4 
     | 
    
         
            +
                  results += i.security_groups
         
     | 
| 
      
 5 
     | 
    
         
            +
                  results
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
                groups.uniq(&:group_id)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def unused_security_groups
         
     | 
| 
      
 11 
     | 
    
         
            +
                used_group_ids = used_security_groups.map(&:group_id)
         
     | 
| 
      
 12 
     | 
    
         
            +
                security_groups.reject {|sg| used_group_ids.include?(sg.group_id) }
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::SecurityGroup
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Summary < Inventory::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include Shared
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def header
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ["Security Group", "Count"]
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def data
         
     | 
| 
      
 10 
     | 
    
         
            +
                  [
         
     | 
| 
      
 11 
     | 
    
         
            +
                    ["Total", security_groups.size],
         
     | 
| 
      
 12 
     | 
    
         
            +
                    ["Used", used_security_groups.size],
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ["Unused", unused_security_groups.size],
         
     | 
| 
      
 14 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Inventory::Shared
         
     | 
| 
      
 2 
     | 
    
         
            +
              def instances
         
     | 
| 
      
 3 
     | 
    
         
            +
                return @instances if @instances
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                @instances = []
         
     | 
| 
      
 6 
     | 
    
         
            +
                resp = ec2.describe_instances
         
     | 
| 
      
 7 
     | 
    
         
            +
                resp.reservations.each do |res|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @instances += res.instances
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                @instances
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              def security_groups
         
     | 
| 
      
 14 
     | 
    
         
            +
                @security_groups ||= ec2.describe_security_groups.security_groups
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,55 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Inventory::Vpc < Inventory::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              def header
         
     | 
| 
      
 3 
     | 
    
         
            +
                ["Name", "Vpc ID", "CIDR", "Subnets", "Instances"]
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def data
         
     | 
| 
      
 7 
     | 
    
         
            +
                vpcs.map do |vpc|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  subnets = subnets_for(vpc)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  instances = instances_in(subnets)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  [
         
     | 
| 
      
 12 
     | 
    
         
            +
                    vpc_name(vpc.vpc_id),
         
     | 
| 
      
 13 
     | 
    
         
            +
                    vpc.vpc_id,
         
     | 
| 
      
 14 
     | 
    
         
            +
                    vpc.cidr_block,
         
     | 
| 
      
 15 
     | 
    
         
            +
                    subnets.count,
         
     | 
| 
      
 16 
     | 
    
         
            +
                    instances.count
         
     | 
| 
      
 17 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              # Pretty vpc name
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Use vpc_id as argument so other classes can use this method also
         
     | 
| 
      
 23 
     | 
    
         
            +
              def vpc_name(vpc_id)
         
     | 
| 
      
 24 
     | 
    
         
            +
                vpc = vpcs.find { |vpc| vpc.vpc_id == vpc_id }
         
     | 
| 
      
 25 
     | 
    
         
            +
                tag = vpc.tags.find {|t| t.key == "Name"}
         
     | 
| 
      
 26 
     | 
    
         
            +
                name = tag ? tag.value : "(unnamed)"
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              def vpcs
         
     | 
| 
      
 30 
     | 
    
         
            +
                @vpcs ||= ec2.describe_vpcs.vpcs
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def subnets_for(vpc)
         
     | 
| 
      
 34 
     | 
    
         
            +
                ec2.describe_subnets(
         
     | 
| 
      
 35 
     | 
    
         
            +
                  filters: [
         
     | 
| 
      
 36 
     | 
    
         
            +
                    {
         
     | 
| 
      
 37 
     | 
    
         
            +
                      name: "vpc-id",
         
     | 
| 
      
 38 
     | 
    
         
            +
                      values: [
         
     | 
| 
      
 39 
     | 
    
         
            +
                        vpc.vpc_id,
         
     | 
| 
      
 40 
     | 
    
         
            +
                      ],
         
     | 
| 
      
 41 
     | 
    
         
            +
                    },
         
     | 
| 
      
 42 
     | 
    
         
            +
                ]).subnets
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              def instances_in(subnets)
         
     | 
| 
      
 46 
     | 
    
         
            +
                subnet_ids = subnets.map(&:subnet_id)
         
     | 
| 
      
 47 
     | 
    
         
            +
                instances.select do |i|
         
     | 
| 
      
 48 
     | 
    
         
            +
                  subnet_ids.include?(i.subnet_id)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              def subnets
         
     | 
| 
      
 53 
     | 
    
         
            +
                @subnets ||= ec2.describe_subnets.subnets
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
            end
         
     |