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 +5 -5
- data/bin/aws_public_ips +2 -2
- data/lib/aws_public_ips/checks/apigateway.rb +2 -2
- data/lib/aws_public_ips/checks/cloudfront.rb +5 -2
- data/lib/aws_public_ips/checks/ec2.rb +5 -3
- data/lib/aws_public_ips/checks/elasticsearch.rb +4 -4
- data/lib/aws_public_ips/checks/elb.rb +4 -3
- data/lib/aws_public_ips/checks/elbv2.rb +2 -2
- data/lib/aws_public_ips/checks/lightsail.rb +2 -2
- data/lib/aws_public_ips/checks/rds.rb +12 -8
- data/lib/aws_public_ips/checks/redshift.rb +14 -6
- data/lib/aws_public_ips/cli.rb +28 -16
- data/lib/aws_public_ips/formatters/prettyjson.rb +1 -1
- data/lib/aws_public_ips/utils.rb +3 -3
- data/lib/aws_public_ips/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4a083bab67810085c9610fee6ca593420f077afd
|
4
|
+
data.tar.gz: eec41af99070ed34d83759f3f042bb3461618e3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 78688710a288065d81d6ce4ab60170cbbd3e1f83bed09d3c07efb89a4ad11e92155451ff03836b747554e485081db14b0f262c25636b38ae1c001c7556da80fc
|
7
|
+
data.tar.gz: 96ab667b2321e1c5f8b656551db71d92c1690715cba785900895493b8f402b48a3e8ea7ae56d9d8b575a2f5ccaa3412ac58f52f895bf2d5e005b616e09307560
|
data/bin/aws_public_ips
CHANGED
@@ -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.
|
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
|
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
|
-
|
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
|
-
#
|
13
|
-
#
|
14
|
-
# -
|
15
|
-
#
|
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
|
-
#
|
12
|
-
#
|
13
|
-
#
|
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
|
data/lib/aws_public_ips/cli.rb
CHANGED
@@ -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 |
|
57
|
-
|
56
|
+
::OptionParser.new do |parser|
|
57
|
+
parser.banner = 'Usage: aws_public_ips [options]'
|
58
58
|
|
59
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/aws_public_ips/utils.rb
CHANGED
@@ -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|
|
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.
|
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-
|
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.
|
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.
|
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.
|
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
|