fog-bouncer 0.1.1 → 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.
data/fog-bouncer.gemspec CHANGED
@@ -19,8 +19,8 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency "fog", "~> 1.2"
20
20
  gem.add_dependency "ipaddress", "~> 0.8.0"
21
21
  gem.add_dependency "jruby-openssl", "~> 0.7.6" if RUBY_PLATFORM == "java"
22
- gem.add_dependency "rake"
23
- gem.add_dependency "scrolls", "~> 0.0.5"
22
+ gem.add_dependency "rake", "~> 0.9.0"
23
+ gem.add_dependency "scrolls", "~> 0.1.0"
24
24
 
25
25
  gem.add_development_dependency "minitest"
26
26
  end
data/lib/fog/bouncer.rb CHANGED
@@ -9,8 +9,6 @@ require "fog/bouncer/ip_permissions"
9
9
  require "fog/bouncer/group_manager"
10
10
  require "fog/bouncer/source_manager"
11
11
 
12
- require "scrolls"
13
-
14
12
  module Fog
15
13
  module Bouncer
16
14
  # Public: An AWS account ID
@@ -54,54 +52,36 @@ module Fog
54
52
  )
55
53
  end
56
54
 
57
- # Public: Log data through Scrolls
55
+ # Public: Allows the user to specify a logger for the log messages that Fog::Bouncer
56
+ # produces.
58
57
  #
59
- # Example
58
+ # logger = The object you want logs to be sent too
60
59
  #
61
- # Fog::Bouncer.log(data_one: true, data_two: true)
60
+ # Examples
62
61
  #
63
- # Returns nothing
64
- def self.log(data, &block)
65
- log! unless logging?
66
- Scrolls.log({ 'fog-bouncer' => true, 'pretending' => pretending? }.merge(data), &block)
62
+ # Fog::Bouncer.instrument_with(STDOUT.method(:puts))
63
+ # # => #<Method: IO#puts>
64
+ #
65
+ # Returns the logger object
66
+ def self.instrument_with(logger)
67
+ @logger = logger
67
68
  end
68
69
 
69
- # Public: Start the Scrolls logger
70
- #
71
- # Example
70
+ # Internal: Top level log method for use by Fog::Bouncer
72
71
  #
73
- # Fog::Bouncer.log!
72
+ # data = Logging data (typically a hash)
73
+ # blk = block to execute
74
74
  #
75
- # Returns nothing
76
- def self.log!
77
- Scrolls::Log.start(logger)
78
- @logging = true
75
+ # Returns the response from calling the logger with the arguments
76
+ def self.log(data, &blk)
77
+ logger.call({ 'fog-bouncer' => true, 'pretending' => pretending? }.merge(data), &blk)
79
78
  end
80
79
 
81
80
  # Public: The logging location
82
81
  #
83
82
  # Returns an Object
84
83
  def self.logger
85
- @logger ||= STDOUT
86
- end
87
-
88
- # Public: Set the logging location
89
- #
90
- # Returns nothing
91
- def self.logger=(logger)
92
- @logger = logger
93
- end
94
-
95
- # Public: Check the logging state
96
- #
97
- # Example
98
- #
99
- # Fog::Bouncer.logging?
100
- # # => true
101
- #
102
- # Returns false or true if logging has been started
103
- def self.logging?
104
- @logging ||= false
84
+ @logger || STDOUT.method(:puts)
105
85
  end
106
86
 
107
87
  # Public: Load a file for evaluation
@@ -184,8 +164,16 @@ module Fog
184
164
  # Returns a Fog::Bouncer::Security object
185
165
  def self.security(name, &block)
186
166
  Fog::Bouncer.log(security: true, name: name) do
187
- doorlists[name] = Fog::Bouncer::Security.new(name, &block)
167
+ doorlists[name] = Fog::Bouncer::Security.new(name, specific_groups, &block)
188
168
  end
189
169
  end
170
+
171
+ def self.specific_groups
172
+ @specific_groups ||= []
173
+ end
174
+
175
+ def self.specific_groups=(groups)
176
+ @specific_groups = Array(groups)
177
+ end
190
178
  end
191
179
  end
@@ -1,23 +1,81 @@
1
1
  require "clamp"
2
-
3
2
  require "fog/bouncer"
3
+ require "scrolls"
4
4
 
5
5
  module Fog
6
6
  module Bouncer
7
7
  module CLI
8
+ class Logger
9
+ def self.log(data, &block)
10
+ Scrolls.log(data, &block)
11
+ end
12
+ end
13
+
8
14
  def self.run(*a)
9
15
  MainCommand.run(*a)
10
16
  end
11
17
 
12
18
  class AbstractCommand < Clamp::Command
19
+ option "--aws-account-id", "AWS_ACCOUNT_ID", "AWS Account ID" do |id|
20
+ ENV['AWS_ACCOUNT_ID'] = id
21
+ end
22
+ option "--aws-access-key-id", "AWS_ACCESS_KEY_ID", "AWS Access Key ID" do |key|
23
+ ENV['AWS_ACCESS_KEY_ID'] = key
24
+ end
25
+ option "--aws-secret-access-key", "AWS_SECRET_ACCESS_KEY", "AWS Secret Access Key" do |key|
26
+ ENV['AWS_SECRET_ACCESS_KEY'] = key
27
+ end
28
+
29
+ option ["--confirm"], "CONFIRMATION", "Confirm dangerous action", :attribute_name => :confirmation
30
+
31
+ option ["--file", "-f"], "FILE", "Doorlist"
32
+
33
+ option ["--groups", "-g"], "GROUPS", "Comma separated list of groups", :default => [] do |groups|
34
+ Fog::Bouncer.specific_groups = groups.split(',')
35
+ end
36
+
37
+ option ["--pretend"], :flag, "Run in pretend mode" do
38
+ Fog::Bouncer.pretend!
39
+ end
40
+
13
41
  option "--version", :flag, "show version" do
14
- puts "fog-bounder #{Fog::Bouncer::VERSION}"
42
+ puts "fog-bouncer #{Fog::Bouncer::VERSION}"
15
43
  exit 0
16
44
  end
45
+
46
+ def confirm
47
+ unless confirmation
48
+ puts
49
+ puts " ! WARNING: This action is not marked as being safe."
50
+ puts " ! To proceed, enter \"confirmation\" or re-run this command with --confirm confirmation"
51
+ puts
52
+ print "> "
53
+
54
+ confirmation = $stdin.gets.chomp
55
+ end
56
+
57
+ confirmation == "confirmation" || raise("Confirmation failed")
58
+ end
59
+
60
+ def file
61
+ if @file && File.exists?(File.expand_path(@file))
62
+ File.expand_path(@file)
63
+ elsif File.exists?(File.expand_path("Doorlist"))
64
+ File.expand_path("Doorlist")
65
+ else
66
+ raise("Doorlist not found")
67
+ end
68
+ end
17
69
  end
18
70
 
71
+ require "fog/bouncer/cli/diff"
72
+
19
73
  class MainCommand < AbstractCommand
74
+ subcommand "diff", "Generate a diff between local and remote", DiffCommand
20
75
  end
21
76
  end
22
77
  end
23
78
  end
79
+
80
+ Scrolls::Log.start(STDOUT)
81
+ Fog::Bouncer.instrument_with(Fog::Bouncer::CLI::Logger.method(:log))
@@ -0,0 +1,76 @@
1
+ module Fog
2
+ module Bouncer
3
+ module CLI
4
+ class DiffCommand < AbstractCommand
5
+ option ["--diff-format"], "DIFF_FORMAT", "The diff output format (ec2)", :default => :ec2
6
+ option ["--apply"], :flag, "Apply the differences"
7
+
8
+ def execute
9
+ doorlist = Fog::Bouncer.load(file)
10
+ doorlist.import_remote_groups
11
+ groups = doorlist.groups
12
+
13
+ Fog::Bouncer::CLI::Diff.for(doorlist, diff_format)
14
+
15
+ if apply? && confirm
16
+ doorlist.sync
17
+ end
18
+ end
19
+ end
20
+
21
+ class Diff
22
+ class EC2
23
+ def self.diff(doorlist)
24
+ doorlist.groups.each do |group|
25
+ if group.local? && !group.remote?
26
+ puts "ec2-create-group #{group.name} -d '#{group.description}'"
27
+ end
28
+
29
+ group.sources.each do |source|
30
+ source.protocols.each do |protocol|
31
+ if protocol.local? && !protocol.remote?
32
+ authorize_cmd = "ec2-authorize #{protocol.group.name} -P #{protocol.type}"
33
+ if protocol.type == "icmp"
34
+ authorize_cmd << " -t #{protocol.from}:#{protocol.to}"
35
+ else
36
+ authorize_cmd << " -p #{protocol.from}-#{protocol.to}"
37
+ end
38
+
39
+ if source.is_a?(Fog::Bouncer::Sources::CIDR)
40
+ authorize_cmd << " -s #{source.range}"
41
+ else
42
+ authorize_cmd << " -u #{source.user_id} -o #{source.name}"
43
+ end
44
+
45
+ puts authorize_cmd
46
+ elsif !protocol.local? && protocol.remote?
47
+ revoke_cmd = "ec2-revoke #{protocol.group.name} -P #{protocol.type}"
48
+ if protocol.type == "icmp"
49
+ revoke_cmd << " -t #{protocol.from}:#{protocol.to}"
50
+ else
51
+ revoke_cmd << " -p #{protocol.from}-#{protocol.to}"
52
+ end
53
+
54
+ puts revoke_cmd
55
+ end
56
+ end
57
+ end
58
+
59
+ if group.remote? && !group.local?
60
+ puts "ec2-delete-group #{group.name}"
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ FORMATS = {
67
+ :ec2 => Fog::Bouncer::CLI::Diff::EC2
68
+ }
69
+
70
+ def self.for(doorlist, diff_format)
71
+ FORMATS[diff_format.to_sym].diff(doorlist)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -18,6 +18,10 @@ module Fog
18
18
  validate
19
19
  end
20
20
 
21
+ def group
22
+ source.group
23
+ end
24
+
21
25
  def local
22
26
  @local ||= false
23
27
  end
@@ -5,9 +5,10 @@ module Fog
5
5
  class Security
6
6
  attr_reader :name, :description
7
7
 
8
- def initialize(name, &block)
8
+ def initialize(name, specific_groups = [], &block)
9
9
  @name = name
10
10
  @definitions = {}
11
+ @specific_groups = specific_groups
11
12
  @using = []
12
13
  instance_eval(&block)
13
14
  apply_definitions
@@ -36,6 +37,7 @@ module Fog
36
37
 
37
38
  def import_remote_groups
38
39
  Fog::Bouncer.fog.security_groups.each do |remote_group|
40
+ next if @specific_groups.any? && !@specific_groups.include?(remote_group.name)
39
41
  group = group(remote_group.name, remote_group.description)
40
42
  group.remote = remote_group
41
43
  IPPermissions.to(group, remote_group.ip_permissions) if remote_group.ip_permissions
@@ -77,6 +79,7 @@ module Fog
77
79
  end
78
80
 
79
81
  def group(name, description, &block)
82
+ return if @specific_groups.any? && !@specific_groups.include?(name)
80
83
  group = groups.find { |group| group.name == name }
81
84
  if group.nil?
82
85
  group = Group.new(name, description, self, &block)
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module Bouncer
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
data/spec/helper.rb CHANGED
@@ -6,8 +6,17 @@ ENV['AWS_SECRET_ACCESS_KEY'] ||= "abcde1234"
6
6
  ENV['AWS_ACCOUNT_ID'] ||= "1234567890"
7
7
 
8
8
  require "fog/bouncer"
9
+ require "scrolls"
9
10
 
10
- Fog::Bouncer.logger = File.open(File.dirname(__FILE__) + '/../logs/test.log', 'w')
11
+ Scrolls::Log.start(File.open(File.dirname(__FILE__) + '/../logs/test.log', 'w'))
12
+
13
+ module TestLogger
14
+ def self.log(data, &blk)
15
+ Scrolls.log(data, &blk)
16
+ end
17
+ end
18
+
19
+ Fog::Bouncer.instrument_with(TestLogger.method(:log))
11
20
 
12
21
  def load_security(security)
13
22
  Fog::Bouncer.load File.dirname(__FILE__) + "/support/security/#{security}.rb"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog-bouncer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-17 00:00:00.000000000 Z
12
+ date: 2012-05-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: clamp
@@ -64,17 +64,17 @@ dependencies:
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
67
- - - ! '>='
67
+ - - ~>
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 0.9.0
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
- - - ! '>='
75
+ - - ~>
76
76
  - !ruby/object:Gem::Version
77
- version: '0'
77
+ version: 0.9.0
78
78
  - !ruby/object:Gem::Dependency
79
79
  name: scrolls
80
80
  requirement: !ruby/object:Gem::Requirement
@@ -82,7 +82,7 @@ dependencies:
82
82
  requirements:
83
83
  - - ~>
84
84
  - !ruby/object:Gem::Version
85
- version: 0.0.5
85
+ version: 0.1.0
86
86
  type: :runtime
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -90,7 +90,7 @@ dependencies:
90
90
  requirements:
91
91
  - - ~>
92
92
  - !ruby/object:Gem::Version
93
- version: 0.0.5
93
+ version: 0.1.0
94
94
  - !ruby/object:Gem::Dependency
95
95
  name: minitest
96
96
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +128,7 @@ files:
128
128
  - fog-bouncer.gemspec
129
129
  - lib/fog/bouncer.rb
130
130
  - lib/fog/bouncer/cli.rb
131
+ - lib/fog/bouncer/cli/diff.rb
131
132
  - lib/fog/bouncer/group.rb
132
133
  - lib/fog/bouncer/group_manager.rb
133
134
  - lib/fog/bouncer/ip_permissions.rb