aws_public_ips 1.0.3 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: c360fd8fc1dec710ad8ee00b18babdd8bb4781494dad119291a6fa03fcb65b1f
4
- data.tar.gz: bbf9fa5b7a48c45d5b9056117d5c56e9d1aac2a97acf27eebeda0198cc76cd72
2
+ SHA1:
3
+ metadata.gz: 4a083bab67810085c9610fee6ca593420f077afd
4
+ data.tar.gz: eec41af99070ed34d83759f3f042bb3461618e3d
5
5
  SHA512:
6
- metadata.gz: 7717d68059ba9b004df5f16755bfd8ce69af4fc73ade7e7cd559311d2c11d5ed2f6f704483eb667654d35e8fef4fa076ce1840f82e387dce028cb7b7dc7251a1
7
- data.tar.gz: c0b4e447f652d427077a0c9dbadc8c7b81ee620286d33508e04ef970978f8570110be11e69506f9eefac9021687e10f9ac3d424485ddbb7edff25a41e09b49d1
6
+ metadata.gz: 78688710a288065d81d6ce4ab60170cbbd3e1f83bed09d3c07efb89a4ad11e92155451ff03836b747554e485081db14b0f262c25636b38ae1c001c7556da80fc
7
+ data.tar.gz: 96ab667b2321e1c5f8b656551db71d92c1690715cba785900895493b8f402b48a3e8ea7ae56d9d8b575a2f5ccaa3412ac58f52f895bf2d5e005b616e09307560
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- $LOAD_PATH.unshift(File.expand_path(File.join('..', '..', 'lib'), __FILE__))
4
+ $LOAD_PATH.unshift(::File.expand_path(::File.join('..', '..', 'lib'), __FILE__))
5
5
  require 'aws_public_ips/cli'
6
6
 
7
- AwsPublicIps::CLI.new.run(ARGV)
7
+ ::AwsPublicIps::CLI.new.run(::ARGV)
@@ -7,7 +7,7 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Apigateway
9
9
  def self.run
10
- client = Aws::APIGateway::Client.new
10
+ client = ::Aws::APIGateway::Client.new
11
11
 
12
12
  # TODO(arkadiy) https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-private-integration.html
13
13
 
@@ -19,7 +19,7 @@ module AwsPublicIps
19
19
  {
20
20
  id: api.id,
21
21
  hostname: hostname,
22
- ip_addresses: Utils.resolve_hostname(hostname)
22
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(hostname)
23
23
  }
24
24
  end
25
25
  end
@@ -7,14 +7,17 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Cloudfront
9
9
  def self.run
10
- client = Aws::CloudFront::Client.new
10
+ client = ::Aws::CloudFront::Client.new
11
+
12
+ # Cloudfront distrubtions are always public, they don't have a concept of VPC
13
+ # No "coming up" problem here like with RDS/Redshift
11
14
 
12
15
  client.list_distributions.flat_map do |response|
13
16
  response.distribution_list.items.flat_map do |distribution|
14
17
  {
15
18
  id: distribution.id,
16
19
  hostname: distribution.domain_name,
17
- ip_addresses: Utils.resolve_hostname(distribution.domain_name)
20
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(distribution.domain_name)
18
21
  }
19
22
  end
20
23
  end
@@ -6,16 +6,15 @@ module AwsPublicIps
6
6
  module Checks
7
7
  module Ec2
8
8
  def self.run
9
- client = Aws::EC2::Client.new
9
+ client = ::Aws::EC2::Client.new
10
10
 
11
- # TODO(arkadiy) confirm this covers Batch, Fargate
12
11
  # Iterate over all EC2 instances. This will include those from EC2, ECS, EKS, Fargate, Batch,
13
12
  # Beanstalk, and NAT Instances
14
13
  # It will not include NAT Gateways (IPv4) or Egress Only Internet Gateways (IPv6), but they do not allow
15
14
  # ingress traffic so we skip them anyway
16
15
  client.describe_instances.flat_map do |response|
17
16
  response.reservations.flat_map do |reservation|
18
- reservation.instances.map do |instance|
17
+ reservation.instances.flat_map do |instance|
19
18
  # EC2-Classic instances have a `public_ip_address` and no `network_interfaces`
20
19
  # EC2-VPC instances both set, so we uniq the ip addresses
21
20
  ip_addresses = [instance.public_ip_address].compact + instance.network_interfaces.flat_map do |interface|
@@ -23,6 +22,9 @@ module AwsPublicIps
23
22
  public_ip + interface.ipv_6_addresses.map(&:ipv_6_address)
24
23
  end
25
24
 
25
+ # Don't return an entry if all ips were private
26
+ next [] if ip_addresses.empty?
27
+
26
28
  # If hostname is empty string, canonicalize to nil
27
29
  hostname = instance.public_dns_name.empty? ? nil : instance.public_dns_name
28
30
  {
@@ -7,10 +7,10 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Elasticsearch
9
9
  def self.run
10
- client = Aws::ElasticsearchService::Client.new
10
+ client = ::Aws::ElasticsearchService::Client.new
11
11
 
12
- # ElasticSearch instances can be launched publicly or into VPCs. Public instances have a
13
- # `domain_status.endpoint` hostname and VPC instances have a `domain_status.endpoints['vpc']` hostname.
12
+ # ElasticSearch instances can be launched into classic into VPCs. Classic instances are public and have a
13
+ # `domain_status.endpoint` hostname, and VPC instances have a `domain_status.endpoints['vpc']` hostname.
14
14
  # However VPC ElasticSearch instances create their own Network Interface and AWS will not allow you
15
15
  # to associate an Elastic IP to it. As a result VPC ElasticSearch instances are always private, even with an
16
16
  # internet gateway.
@@ -23,7 +23,7 @@ module AwsPublicIps
23
23
  {
24
24
  id: domain.domain_status.domain_id,
25
25
  hostname: hostname,
26
- ip_addresses: Utils.resolve_hostname(hostname)
26
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(hostname)
27
27
  }
28
28
  end.compact
29
29
  end
@@ -7,18 +7,19 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Elb
9
9
  def self.run
10
- client = Aws::ElasticLoadBalancing::Client.new
10
+ client = ::Aws::ElasticLoadBalancing::Client.new
11
11
 
12
12
  # EC2-Classic load balancers are only returned by the 'elasticloadbalancing' API, and
13
13
  # EC2-VPC ALBs/NLBs are only returned by the 'elasticloadbalancingv2' API
14
14
  client.describe_load_balancers.flat_map do |response|
15
15
  response.load_balancer_descriptions.flat_map do |load_balancer|
16
16
  next [] unless load_balancer.scheme == 'internet-facing'
17
+ # EC2-Classic load balancers get IPv6 DNS records created but they are not returned by the API
18
+ hostnames = [load_balancer.dns_name, "ipv6.#{load_balancer.dns_name}"]
17
19
  {
18
20
  id: load_balancer.canonical_hosted_zone_name_id,
19
21
  hostname: load_balancer.dns_name,
20
- # EC2-Classic load balancers get IPv6 DNS records created but they are not returned by the API
21
- ip_addresses: Utils.resolve_hostnames([load_balancer.dns_name, "ipv6.#{load_balancer.dns_name}"])
22
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostnames(hostnames)
22
23
  }
23
24
  end
24
25
  end
@@ -7,7 +7,7 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Elbv2
9
9
  def self.run
10
- client = Aws::ElasticLoadBalancingV2::Client.new
10
+ client = ::Aws::ElasticLoadBalancingV2::Client.new
11
11
 
12
12
  # EC2-Classic load balancers are only returned by the 'elasticloadbalancing' API, and
13
13
  # EC2-VPC ALBs/NLBs are only returned by the 'elasticloadbalancingv2' API
@@ -21,7 +21,7 @@ module AwsPublicIps
21
21
  {
22
22
  id: load_balancer.canonical_hosted_zone_id,
23
23
  hostname: load_balancer.dns_name,
24
- ip_addresses: Utils.resolve_hostname(load_balancer.dns_name)
24
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(load_balancer.dns_name)
25
25
  }
26
26
  end
27
27
  end
@@ -7,7 +7,7 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Lightsail
9
9
  def self.run
10
- client = Aws::Lightsail::Client.new
10
+ client = ::Aws::Lightsail::Client.new
11
11
 
12
12
  # Lightsail instances are always exposed directly, and can also be put behind a load balancer
13
13
 
@@ -28,7 +28,7 @@ module AwsPublicIps
28
28
  # Names are unique
29
29
  id: load_balancer.name,
30
30
  hostname: load_balancer.dns_name,
31
- ip_addresses: Utils.resolve_hostname(load_balancer.dns_name)
31
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(load_balancer.dns_name)
32
32
  }
33
33
  end
34
34
  end
@@ -7,21 +7,25 @@ module AwsPublicIps
7
7
  module Checks
8
8
  module Rds
9
9
  def self.run
10
- client = Aws::RDS::Client.new
10
+ client = ::Aws::RDS::Client.new
11
11
 
12
- # TODO(arkadiy) not sure if this is true anymore after redshift, do more testing
13
- # RDS instances can be:
14
- # - launched into classic
15
- # - launched into VPC
16
- # - launched into a VPC but marked as `publicly_accessible`, in which case the VPC must have an Internet
17
- # Gateway attached, and the DNS endpoint will resolve to a public ip address
12
+ # RDS instances can be launched into VPCs or into Classic mode.
13
+ # In classic mode they are always public.
14
+ # In VPC mode they can be marked as `publicly_accessible` or not - if they are then its VPC must have
15
+ # an Internet Gateway attached, and the DNS endpoint will resolve to a public ip address.
18
16
  client.describe_db_instances.flat_map do |response|
19
17
  response.db_instances.flat_map do |instance|
20
18
  next [] unless instance.publicly_accessible
19
+
20
+ if instance.endpoint.nil?
21
+ raise StandardError, "RDS DB '#{instance.dbi_resource_id}' has a nil endpoint. This likely" \
22
+ ' means the DB is being brought up right now.'
23
+ end
24
+
21
25
  {
22
26
  id: instance.dbi_resource_id,
23
27
  hostname: instance.endpoint.address,
24
- ip_addresses: Utils.resolve_hostname(instance.endpoint.address)
28
+ ip_addresses: ::AwsPublicIps::Utils.resolve_hostname(instance.endpoint.address)
25
29
  }
26
30
  end
27
31
  end
@@ -1,24 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'aws-sdk-redshift'
4
+ require 'aws_public_ips/utils'
4
5
 
5
6
  module AwsPublicIps
6
7
  module Checks
7
8
  module Redshift
8
9
  def self.run
9
- client = Aws::Redshift::Client.new
10
+ client = ::Aws::Redshift::Client.new
10
11
 
11
- # TODO(arkadiy) update copy from RDS
12
- # Redshift clusters can only be launched into VPCs. They can be marked as `publicly_accessible`,
13
- # in which case the VPC must have an Internet Gateway attached, and the DNS endpoint will
14
- # resolve to a public ip address
12
+ # Redshift clusters can be launched into VPCs or into Classic mode.
13
+ # In classic mode they are always public.
14
+ # In VPC mode they can be marked as `publicly_accessible` or not - if they are then its VPC must have
15
+ # an Internet Gateway attached, and the DNS endpoint will resolve to a public ip address.
15
16
  client.describe_clusters.flat_map do |response|
16
17
  response.clusters.flat_map do |cluster|
17
18
  next [] unless cluster.publicly_accessible
19
+
20
+ if cluster.endpoint.nil?
21
+ raise StandardError, "Redshift cluster '#{cluster.cluster_identifier}' has a nil endpoint. This likely" \
22
+ ' means the cluster is being brought up right now.'
23
+ end
24
+
18
25
  {
19
26
  id: cluster.cluster_identifier,
20
27
  hostname: cluster.endpoint.address,
21
- ip_addresses: cluster.cluster_nodes.map(&:public_ip_address)
28
+ ip_addresses: cluster.cluster_nodes.map(&:public_ip_address) +
29
+ ::AwsPublicIps::Utils.resolve_hostname(cluster.endpoint.address)
22
30
  }
23
31
  end
24
32
  end
@@ -39,11 +39,11 @@ module AwsPublicIps
39
39
  # AWS Neptune (still in preview / not GA yet)
40
40
 
41
41
  def all_services
42
- @all_services ||= Dir["#{__dir__}/checks/*.rb"].map { |path| File.basename(path, '.rb') }.sort
42
+ @all_services ||= ::Dir["#{__dir__}/checks/*.rb"].map { |path| ::File.basename(path, '.rb') }.sort
43
43
  end
44
44
 
45
45
  def all_formats
46
- @all_formats ||= Dir["#{__dir__}/formatters/*.rb"].map { |path| File.basename(path, '.rb') }.sort
46
+ @all_formats ||= ::Dir["#{__dir__}/formatters/*.rb"].map { |path| ::File.basename(path, '.rb') }.sort
47
47
  end
48
48
 
49
49
  def parse(args)
@@ -53,28 +53,39 @@ module AwsPublicIps
53
53
  verbose: false
54
54
  }
55
55
 
56
- OptionParser.new do |opts|
57
- opts.banner = 'Usage: aws_public_ips [options]'
56
+ ::OptionParser.new do |parser|
57
+ parser.banner = 'Usage: aws_public_ips [options]'
58
58
 
59
- opts.on('-s', '--services <s1>,<s2>,<s3>', Array, 'List of AWS services to check. Available services: ' \
59
+ parser.on('-s', '--services <s1>,<s2>,<s3>', Array, 'List of AWS services to check. Available services: ' \
60
60
  "#{all_services.join(',')}. Defaults to all.") do |services|
61
61
  services.map(&:downcase!).uniq!
62
62
  invalid_services = services - all_services
63
- raise ArgumentError, "Invalid service(s): #{invalid_services.join(',')}" unless invalid_services.empty?
63
+ raise ::ArgumentError, "Invalid service(s): #{invalid_services.join(',')}" unless invalid_services.empty?
64
64
  options[:services] = services
65
65
  end
66
66
 
67
- opts.on('-f', '--format <format>', String, 'Set output format. Available formats: ' \
67
+ parser.on('-f', '--format <format>', String, 'Set output format. Available formats: ' \
68
68
  "#{all_formats.join(',')}. Defaults to text.") do |fmt|
69
69
  unless all_formats.include?(fmt)
70
- raise ArgumentError, "Invalid format '#{fmt}'. Valid formats are: #{all_formats.join(',')}"
70
+ raise ::ArgumentError, "Invalid format '#{fmt}'. Valid formats are: #{all_formats.join(',')}"
71
71
  end
72
72
  options[:format] = fmt
73
73
  end
74
74
 
75
- opts.on('-v', '--[no-]verbose', 'Enable debug/trace output') do |verbose|
75
+ parser.on('-v', '--[no-]verbose', 'Enable debug/trace output') do |verbose|
76
76
  options[:verbose] = verbose
77
77
  end
78
+
79
+ parser.on_tail('--version', 'Print version') do
80
+ require 'aws_public_ips/version'
81
+ ::STDOUT.puts ::AwsPublicIps::VERSION
82
+ return nil # nil to avoid rubocop warning
83
+ end
84
+
85
+ parser.on_tail('-h', '--help', 'Show this help message') do
86
+ ::STDOUT.puts parser
87
+ return nil # nil to avoid rubocop warning
88
+ end
78
89
  end.parse(args)
79
90
 
80
91
  options
@@ -82,28 +93,29 @@ module AwsPublicIps
82
93
 
83
94
  def check_service(service)
84
95
  require "aws_public_ips/checks/#{service}.rb"
85
- AwsPublicIps::Checks.const_get(service.capitalize).run
96
+ ::AwsPublicIps::Checks.const_get(service.capitalize).run
86
97
  end
87
98
 
88
99
  def output(formatter, results)
89
100
  require "aws_public_ips/formatters/#{formatter}.rb"
90
- formatter_klass = AwsPublicIps::Formatters.const_get(formatter.capitalize)
101
+ formatter_klass = ::AwsPublicIps::Formatters.const_get(formatter.capitalize)
91
102
  output = formatter_klass.new(results).format
92
- puts output unless output.empty?
103
+ ::STDOUT.puts output unless output.empty?
93
104
  end
94
105
 
95
106
  def run(args)
96
107
  options = parse(args)
108
+ return unless options
97
109
 
98
110
  results = options[:services].map do |service|
99
111
  [service.to_sym, check_service(service)]
100
112
  end.to_h
101
113
 
102
114
  output(options[:format], results)
103
- rescue StandardError, Interrupt => ex
104
- puts ex.inspect
105
- puts ex.backtrace if options[:verbose]
106
- Process.exit(1)
115
+ rescue ::StandardError, ::Interrupt => ex
116
+ ::STDERR.puts ex.inspect
117
+ ::STDERR.puts ex.backtrace if options && options[:verbose]
118
+ ::Process.exit(1)
107
119
  end
108
120
  end
109
121
  end
@@ -10,7 +10,7 @@ module AwsPublicIps
10
10
  end
11
11
 
12
12
  def format
13
- JSON.pretty_generate(@results)
13
+ ::JSON.pretty_generate(@results)
14
14
  end
15
15
  end
16
16
  end
@@ -10,9 +10,9 @@ module AwsPublicIps
10
10
 
11
11
  def self.resolve_hostname(hostname)
12
12
  # Default Resolv.getaddresses doesn't seem to return IPv6 results
13
- resources = Resolv::DNS.open do |dns|
14
- dns.getresources(hostname, Resolv::DNS::Resource::IN::A) +
15
- dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA)
13
+ resources = ::Resolv::DNS.open do |dns|
14
+ dns.getresources(hostname, ::Resolv::DNS::Resource::IN::A) +
15
+ dns.getresources(hostname, ::Resolv::DNS::Resource::IN::AAAA)
16
16
  end
17
17
 
18
18
  resources.map do |resource|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AwsPublicIps
4
- VERSION = '1.0.3'.freeze
4
+ VERSION = '1.0.4'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_public_ips
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkadiy Tetelman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-17 00:00:00.000000000 Z
11
+ date: 2018-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-apigateway
@@ -184,14 +184,14 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: 0.55.0
187
+ version: 0.56.0
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
- version: 0.55.0
194
+ version: 0.56.0
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: webmock
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -253,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
253
253
  version: '0'
254
254
  requirements: []
255
255
  rubyforge_project:
256
- rubygems_version: 2.7.6
256
+ rubygems_version: 2.6.14
257
257
  signing_key:
258
258
  specification_version: 4
259
259
  summary: A library/cli to fetch all public IP addresses associated with an AWS account