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 +2 -2
- data/lib/fog/bouncer.rb +26 -38
- data/lib/fog/bouncer/cli.rb +60 -2
- data/lib/fog/bouncer/cli/diff.rb +76 -0
- data/lib/fog/bouncer/protocols.rb +4 -0
- data/lib/fog/bouncer/security.rb +4 -1
- data/lib/fog/bouncer/version.rb +1 -1
- data/spec/helper.rb +10 -1
- metadata +9 -8
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
|
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:
|
55
|
+
# Public: Allows the user to specify a logger for the log messages that Fog::Bouncer
|
56
|
+
# produces.
|
58
57
|
#
|
59
|
-
#
|
58
|
+
# logger = The object you want logs to be sent too
|
60
59
|
#
|
61
|
-
#
|
60
|
+
# Examples
|
62
61
|
#
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
#
|
70
|
-
#
|
71
|
-
# Example
|
70
|
+
# Internal: Top level log method for use by Fog::Bouncer
|
72
71
|
#
|
73
|
-
#
|
72
|
+
# data = Logging data (typically a hash)
|
73
|
+
# blk = block to execute
|
74
74
|
#
|
75
|
-
# Returns
|
76
|
-
def self.log
|
77
|
-
|
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
|
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
|
data/lib/fog/bouncer/cli.rb
CHANGED
@@ -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-
|
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
|
data/lib/fog/bouncer/security.rb
CHANGED
@@ -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)
|
data/lib/fog/bouncer/version.rb
CHANGED
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
|
-
|
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.
|
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-
|
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:
|
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:
|
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
|
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
|
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
|