awshark 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5706c9a35383e578bac90c8f432f2b4d730857556112222ff122ba7f7fba8e0
4
- data.tar.gz: 6a3c0ca64b7f017aaea42c7fed255a5e5f44ec33bce1de59a00c875c1023e86e
3
+ metadata.gz: 8f014eaddd54562cad6064bc0b28a9fde800b7144f3be26e4af11f02a99d1f13
4
+ data.tar.gz: 258b5c71b20180623ca66646d4081c38d8c14e590a1b2a2773193523423dc614
5
5
  SHA512:
6
- metadata.gz: a18d22c21cda523abfa5bd6369df2855b55eb479a2d43a0fa1bd66de0902e055db4e164bab332338f417fcc010094a168b4d2f92a16e4915a840fcb580608584
7
- data.tar.gz: c4e5e7d9a2105ff44c58ce0f08ae742e48f780d18b4f63459d39ec6f670d372b5636e966f90e081fec071f4c56ad0923b3b1cb94549ef10cf819e064a57575ac
6
+ metadata.gz: 42970eec188f9fe6a4f561a2d42b01387b08c98f26ee93e0352d83f1fda165f119ae09909fbbb62c80e5380ca259a8d667bb46cf416e742db333051da4891204
7
+ data.tar.gz: ecf2602e7bb5cf37ebd508d3bb95d44eff004214f38bb6fa19475ee38d6b094093c6572c17acb3d48ca59d6b018a39129019d450e80aa7a6db4d84d0cc4b7c17
data/.rubocop.yml CHANGED
@@ -69,7 +69,7 @@ Lint/UselessTimes:
69
69
 
70
70
  Metrics/AbcSize:
71
71
  Enabled: true
72
- Max: 20
72
+ Max: 25
73
73
  Metrics/BlockLength:
74
74
  Exclude:
75
75
  - '*.gemspec'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  ## Changelog
2
2
 
3
+ #### 1.3.0
4
+ - [new] add `awshark ec2 authorize` and `unauthorize`
5
+
3
6
  #### 1.2.0
4
7
  - [new] add `awshark ecs list`
5
8
  - [break] remove options `--profile` and `--region`; use `AWS_PROFILE` and `AWS_REGION` instead
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Awshark
4
+ module ClassOptions
5
+ def process_class_options
6
+ command = current_command_chain.last
7
+ cli_options = options.merge(parent_options || {}).symbolize_keys
8
+
9
+ if cli_options[:help]
10
+ respond_to?(command) ? help(command) : help
11
+ exit(0)
12
+ end
13
+
14
+ setup_aws_credentials(options)
15
+ end
16
+
17
+ private
18
+
19
+ def setup_aws_credentials(options)
20
+ profile_resolver = ProfileResolver.new(options)
21
+
22
+ ::Aws.config[:region] = profile_resolver.region
23
+ ::Aws.config[:credentials] = profile_resolver.credentials
24
+ end
25
+ end
26
+ end
data/lib/awshark/cli.rb CHANGED
@@ -1,13 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'awshark/profile_resolver'
4
-
5
- require 'awshark/subcommands/class_options'
6
- require 'awshark/subcommands/cloud_formation'
7
- require 'awshark/subcommands/ec2'
8
- require 'awshark/subcommands/ecs'
9
- require 'awshark/subcommands/rds'
10
- require 'awshark/subcommands/s3'
4
+ require 'awshark/class_options'
5
+ require 'awshark/cloud_formation/subcommand'
6
+ require 'awshark/ec2/subcommand'
7
+ require 'awshark/ecs/subcommand'
8
+ require 'awshark/rds/subcommand'
9
+ require 'awshark/s3/subcommand'
11
10
 
12
11
  module Awshark
13
12
  class Cli < Thor
@@ -18,19 +17,19 @@ module Awshark
18
17
  class_option :help, type: :boolean, desc: 'Prints this help'
19
18
 
20
19
  desc 'cf COMMAND', 'Run CloudFormation command'
21
- subcommand 'cf', Awshark::Subcommands::CloudFormation
20
+ subcommand 'cf', Awshark::CloudFormation::Subcommand
22
21
 
23
22
  desc 'ec2 COMMAND', 'Run EC2 command'
24
- subcommand 'ec2', Awshark::Subcommands::EC2
23
+ subcommand 'ec2', Awshark::Ec2::Subcommand
25
24
 
26
25
  desc 'ecs COMMAND', 'Run ECS command'
27
- subcommand 'ecs', Awshark::Subcommands::Ecs
26
+ subcommand 'ecs', Awshark::Ecs::Subcommand
28
27
 
29
28
  desc 'rds COMMAND', 'Run RDS command'
30
- subcommand 'rds', Awshark::Subcommands::Rds
29
+ subcommand 'rds', Awshark::Rds::Subcommand
31
30
 
32
31
  desc 's3 COMMAND', 'Run CloudFormation command'
33
- subcommand 's3', Awshark::Subcommands::S3
32
+ subcommand 's3', Awshark::S3::Subcommand
34
33
 
35
34
  desc 'version', 'Displays current version of AwsShark'
36
35
  long_desc <<-LONGDESC
@@ -14,9 +14,9 @@ require 'awshark/cloud_formation/stack_events'
14
14
  require 'awshark/cloud_formation/template'
15
15
 
16
16
  module Awshark
17
- module Subcommands
18
- class CloudFormation < Thor
19
- include Awshark::Subcommands::ClassOptions
17
+ module CloudFormation
18
+ class Subcommand < Thor
19
+ include Awshark::ClassOptions
20
20
 
21
21
  class_option :bucket, type: :string, desc: 'S3 bucket for template'
22
22
  class_option :iam, type: :boolean, desc: 'Needs IAM capabilities'
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Awshark
4
+ module Logging
5
+ def logger
6
+ Awshark.logger
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Awshark
4
+ module Ec2
5
+ class Configuration
6
+ def client
7
+ region = Aws.config[:region] || 'eu-central-1'
8
+ @client ||= Aws::EC2::Client.new(region: region)
9
+ end
10
+
11
+ attr_writer :client
12
+ end
13
+ end
14
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Awshark
4
- module EC2
4
+ module Ec2
5
5
  class Instance
6
6
  attr_reader :id
7
7
  attr_reader :type
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Awshark
4
- module EC2
4
+ module Ec2
5
5
  class Manager
6
6
  def all_instances
7
7
  return @all_instances if defined?(@all_instances)
@@ -29,11 +29,7 @@ module Awshark
29
29
  private
30
30
 
31
31
  def client
32
- @client ||= Aws::EC2::Client.new(region: region)
33
- end
34
-
35
- def region
36
- Aws.config[:region] || 'eu-central-1'
32
+ Awshark.config.ec2.client
37
33
  end
38
34
  end
39
35
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Awshark
4
+ module Ec2
5
+ class SecurityGroup
6
+ include Logging
7
+
8
+ attr_reader :security_group_id, :username
9
+
10
+ def initialize(id:, username:)
11
+ validate!(:id, id)
12
+ validate!(:username, username)
13
+
14
+ @security_group_id = id
15
+ @username = username
16
+ end
17
+
18
+ def authorize(ip:, ports:)
19
+ ports.each do |port|
20
+ ip_rule = SecurityRule.new(
21
+ ip: ip,
22
+ from_port: port,
23
+ to_port: port,
24
+ description: username
25
+ )
26
+ client.authorize_security_group_ingress(
27
+ group_id: security_group_id,
28
+ ip_permissions: [ip_rule.to_hash]
29
+ )
30
+ logger.info "Created ingress rule in for #{ip_rule.cidr_ip}, port #{port}."
31
+ rescue Aws::EC2::Errors::InvalidPermissionDuplicate
32
+ logger.warn "An ingress rule for #{ip} and port #{port} exists."
33
+ end
34
+ end
35
+
36
+ def unauthorize
37
+ return if my_ingress_rules.empty?
38
+
39
+ client.revoke_security_group_ingress(
40
+ group_id: security_group_id,
41
+ ip_permissions: my_ingress_rules
42
+ )
43
+ logger.info "Removed all ingress rules for #{username}."
44
+ end
45
+
46
+ def my_ingress_rules
47
+ return @my_ingress_rules if defined?(@my_ingress_rules)
48
+
49
+ response = client.describe_security_groups(group_ids: [security_group_id])
50
+ return [] if response.security_groups.empty?
51
+
52
+ security_group = response.security_groups.first
53
+ security_rules = security_group.ip_permissions.map do |ip_permission|
54
+ SecurityRule.new(ip_permission)
55
+ end
56
+
57
+ @my_ingress_rules = security_rules.map do |rule|
58
+ rule.ip_ranges.keep_if { |ip_range| ip_range.description == username }
59
+ rule.ip_ranges.any? ? rule.to_hash : nil
60
+ end
61
+
62
+ @my_ingress_rules.compact!
63
+ end
64
+
65
+ private
66
+
67
+ def client
68
+ Awshark.config.ec2.client
69
+ end
70
+
71
+ def validate!(name, value)
72
+ raise ArgumentError, "Argument #{name} cannot be empty" if value.blank?
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Awshark
4
+ module Ec2
5
+ class SecurityRule
6
+ attr_reader :ip_protocol, :ip_ranges, :from_port, :to_port
7
+
8
+ def initialize(args)
9
+ if args.is_a?(Aws::EC2::Types::IpPermission)
10
+ @ip_protocol = args.ip_protocol
11
+ @ip_ranges = args.ip_ranges
12
+ @from_port = args.from_port
13
+ @to_port = args.to_port
14
+ else
15
+ ip = args.fetch(:ip)
16
+ description = args.fetch(:description)
17
+ @ip_protocol = args.fetch(:ip_protocol, 'tcp')
18
+ @ip_ranges = [OpenStruct.new({ cidr_ip: "#{ip}/32", description: description })]
19
+ @from_port = args.fetch(:from_port)
20
+ @to_port = args.fetch(:to_port)
21
+ end
22
+ end
23
+
24
+ def cidr_ip
25
+ ip_ranges[0].cidr_ip
26
+ end
27
+
28
+ def description
29
+ ip_ranges[0].description
30
+ end
31
+
32
+ def to_hash
33
+ {
34
+ ip_protocol: ip_protocol,
35
+ from_port: from_port,
36
+ to_port: to_port,
37
+ ip_ranges: ip_ranges.map(&:to_h)
38
+ }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-ec2'
4
+
5
+ require 'awshark/ec2/instance'
6
+ require 'awshark/ec2/manager'
7
+ require 'awshark/ec2/security_group'
8
+ require 'awshark/ec2/security_rule'
9
+
10
+ module Awshark
11
+ module Ec2
12
+ class Subcommand < Thor
13
+ include Awshark::ClassOptions
14
+
15
+ desc 'list', 'List all EC2 instances'
16
+ long_desc <<-LONGDESC
17
+ List all EC2 instances in a region
18
+
19
+ Example:
20
+ awshark ec2 list STATE
21
+
22
+ LONGDESC
23
+ def list(state = 'running')
24
+ process_class_options
25
+
26
+ instances = manager.public_send("#{state}_instances")
27
+ instances = instances.sort_by(&:name)
28
+
29
+ instances.each do |i|
30
+ args = { name: i.name, type: i.type, public_dns: i.public_dns_name, state: i.state }
31
+ printf "%-40<name>s %-12<type>s %-60<public_dns>s %<state>s\n", args
32
+ end
33
+ end
34
+
35
+ desc 'authorize', 'Authorises your IP to access AWS'
36
+ long_desc <<-LONGDESC
37
+ Adds your IP address to the security group to allow direct access to the VPCs.
38
+
39
+ Example:
40
+ awshark ec2 authorize
41
+
42
+ LONGDESC
43
+ option :ports,
44
+ type: :string,
45
+ desc: 'Ports to register. Only uses ports from 1 to 65535.',
46
+ default: '443'
47
+ option :security_group,
48
+ type: :string,
49
+ required: true,
50
+ desc: 'Security group to allow access to.'
51
+ option :username,
52
+ type: :string,
53
+ desc: 'Ports to register. Only uses ports from 1 to 65535.'
54
+ def authorize
55
+ process_class_options
56
+
57
+ group = Ec2::SecurityGroup.new(id: security_group_id, username: username)
58
+ group.authorize(ip: my_ip, ports: ports)
59
+ end
60
+
61
+ desc 'unauthorize', 'Removes your IP from access to AWS'
62
+ long_desc <<-LONGDESC
63
+ Removes all your ingress rules from the home office security group in the VPCs.
64
+
65
+ Example:
66
+ awshark ec2 unauthorize
67
+
68
+ LONGDESC
69
+ option :security_group,
70
+ type: :string,
71
+ required: true,
72
+ desc: 'Security group to remove access from.'
73
+ option :username,
74
+ type: :string,
75
+ desc: 'Ports to register. Only uses ports from 1 to 65535.'
76
+ def unauthorize
77
+ process_class_options
78
+
79
+ group = Ec2::SecurityGroup.new(id: security_group_id, username: username)
80
+ group.unauthorize
81
+ end
82
+
83
+ private
84
+
85
+ def manager
86
+ @manager ||= Ec2::Manager.new
87
+ end
88
+
89
+ def my_ip
90
+ @my_ip ||= `curl -s https://api.ipify.org`.strip
91
+ end
92
+
93
+ def ports
94
+ result = options[:ports].split(',').map(&:to_i)
95
+ result.select { |port| (1..65_535).cover?(port) }
96
+ end
97
+
98
+ def security_group_id
99
+ options[:security_group].strip
100
+ end
101
+
102
+ def username
103
+ options[:username].presence || `whoami`.strip
104
+ end
105
+ end
106
+ end
107
+ end
@@ -7,9 +7,9 @@ require 'awshark/ecs/cluster'
7
7
  require 'awshark/ecs/manager'
8
8
 
9
9
  module Awshark
10
- module Subcommands
11
- class Ecs < Thor
12
- include Awshark::Subcommands::ClassOptions
10
+ module Ecs
11
+ class Subcommand < Thor
12
+ include Awshark::ClassOptions
13
13
 
14
14
  desc 'list', 'list ECS tasks'
15
15
  long_desc <<-LONGDESC
@@ -6,9 +6,9 @@ require 'awshark/rds/check_reservations'
6
6
  require 'awshark/rds/manager'
7
7
 
8
8
  module Awshark
9
- module Subcommands
10
- class Rds < Thor
11
- include Awshark::Subcommands::ClassOptions
9
+ module Rds
10
+ class Subcommand < Thor
11
+ include Awshark::ClassOptions
12
12
 
13
13
  desc 'check', 'Check RDS reservations'
14
14
  long_desc <<-LONGDESC
@@ -9,9 +9,9 @@ require 'awshark/s3/bucket'
9
9
  require 'awshark/s3/manager'
10
10
 
11
11
  module Awshark
12
- module Subcommands
13
- class S3 < Thor
14
- include Awshark::Subcommands::ClassOptions
12
+ module S3
13
+ class Subcommand < Thor
14
+ include Awshark::ClassOptions
15
15
  include ActiveSupport::NumberHelper
16
16
 
17
17
  desc 'list', 'List S3 bucket statistics'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Awshark
4
- VERSION = '1.2.0'
4
+ VERSION = '1.3.0'
5
5
  end
data/lib/awshark.rb CHANGED
@@ -6,7 +6,9 @@ require 'thor'
6
6
  require 'yaml'
7
7
 
8
8
  require 'awshark/version'
9
+ require 'awshark/concerns/logging'
9
10
  require 'awshark/cloud_formation/configuration'
11
+ require 'awshark/ec2/configuration'
10
12
  require 'awshark/ecs/configuration'
11
13
  require 'awshark/s3/configuration'
12
14
  require 'awshark/sts/configuration'
@@ -17,12 +19,14 @@ module Awshark
17
19
  def self.config
18
20
  @config ||= begin
19
21
  cf = CloudFormation::Configuration.new
22
+ ec2 = Ec2::Configuration.new
20
23
  ecs = Ecs::Configuration.new
21
24
  s3 = S3::Configuration.new
22
25
  sts = Sts::Configuration.new
23
26
 
24
27
  OpenStruct.new(
25
28
  cloud_formation: cf,
29
+ ec2: ec2,
26
30
  ecs: ecs,
27
31
  s3: s3,
28
32
  sts: sts
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awshark
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joergen Dahlke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-16 00:00:00.000000000 Z
11
+ date: 2022-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -252,6 +252,7 @@ files:
252
252
  - exe/awshark
253
253
  - gems.rb
254
254
  - lib/awshark.rb
255
+ - lib/awshark/class_options.rb
255
256
  - lib/awshark/cli.rb
256
257
  - lib/awshark/cloud_formation/configuration.rb
257
258
  - lib/awshark/cloud_formation/file_loading.rb
@@ -260,26 +261,29 @@ files:
260
261
  - lib/awshark/cloud_formation/parameters.rb
261
262
  - lib/awshark/cloud_formation/stack.rb
262
263
  - lib/awshark/cloud_formation/stack_events.rb
264
+ - lib/awshark/cloud_formation/subcommand.rb
263
265
  - lib/awshark/cloud_formation/template.rb
266
+ - lib/awshark/concerns/logging.rb
267
+ - lib/awshark/ec2/configuration.rb
264
268
  - lib/awshark/ec2/instance.rb
265
269
  - lib/awshark/ec2/manager.rb
270
+ - lib/awshark/ec2/security_group.rb
271
+ - lib/awshark/ec2/security_rule.rb
272
+ - lib/awshark/ec2/subcommand.rb
266
273
  - lib/awshark/ecs/cluster.rb
267
274
  - lib/awshark/ecs/configuration.rb
268
275
  - lib/awshark/ecs/manager.rb
276
+ - lib/awshark/ecs/subcommand.rb
269
277
  - lib/awshark/profile_resolver.rb
270
278
  - lib/awshark/rds/check_reservations.rb
271
279
  - lib/awshark/rds/manager.rb
280
+ - lib/awshark/rds/subcommand.rb
272
281
  - lib/awshark/s3/artifact.rb
273
282
  - lib/awshark/s3/bucket.rb
274
283
  - lib/awshark/s3/configuration.rb
275
284
  - lib/awshark/s3/manager.rb
285
+ - lib/awshark/s3/subcommand.rb
276
286
  - lib/awshark/sts/configuration.rb
277
- - lib/awshark/subcommands/class_options.rb
278
- - lib/awshark/subcommands/cloud_formation.rb
279
- - lib/awshark/subcommands/ec2.rb
280
- - lib/awshark/subcommands/ecs.rb
281
- - lib/awshark/subcommands/rds.rb
282
- - lib/awshark/subcommands/s3.rb
283
287
  - lib/awshark/version.rb
284
288
  homepage: https://github.com/jdahlke/awshark
285
289
  licenses:
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Awshark
4
- module Subcommands
5
- module ClassOptions
6
- def process_class_options
7
- command = current_command_chain.last
8
- cli_options = options.merge(parent_options || {}).symbolize_keys
9
-
10
- if cli_options[:help]
11
- respond_to?(command) ? help(command) : help
12
- exit(0)
13
- end
14
-
15
- setup_aws_credentials(options)
16
- end
17
-
18
- private
19
-
20
- def setup_aws_credentials(options)
21
- profile_resolver = ProfileResolver.new(options)
22
-
23
- ::Aws.config[:region] = profile_resolver.region
24
- ::Aws.config[:credentials] = profile_resolver.credentials
25
- end
26
- end
27
- end
28
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'aws-sdk-ec2'
4
-
5
- require 'awshark/ec2/instance'
6
- require 'awshark/ec2/manager'
7
-
8
- module Awshark
9
- module Subcommands
10
- class EC2 < Thor
11
- include Awshark::Subcommands::ClassOptions
12
-
13
- desc 'list', 'List all EC2 instances'
14
- long_desc <<-LONGDESC
15
- List all EC2 instances in a region
16
-
17
- Example: `awshark ec2 list STATE`
18
- LONGDESC
19
- def list(state = 'running')
20
- process_class_options
21
-
22
- instances = manager.public_send("#{state}_instances")
23
- instances = instances.sort_by(&:name)
24
-
25
- instances.each do |i|
26
- args = { name: i.name, type: i.type, public_dns: i.public_dns_name, state: i.state }
27
- printf "%-40<name>s %-12<type>s %-60<public_dns>s %<state>s\n", args
28
- end
29
- end
30
-
31
- private
32
-
33
- def manager
34
- @manager ||= Awshark::EC2::Manager.new
35
- end
36
- end
37
- end
38
- end