reyes 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.
- checksums.yaml +8 -8
- data/bin/reyes +66 -1
- data/config.yaml.example +7 -0
- data/lib/reyes.rb +2 -0
- data/lib/reyes/aws_manager.rb +12 -0
- data/lib/reyes/config.rb +4 -0
- data/lib/reyes/fake_aws.rb +4 -5
- data/lib/reyes/group_manager.rb +10 -0
- data/lib/reyes/pgp_wrapper.rb +73 -0
- data/lib/reyes/run_generation.rb +3 -0
- data/lib/reyes/s3_loader.rb +32 -0
- data/lib/reyes/version.rb +1 -1
- data/reyes.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTZhZTI3NWU5Yjk3ZWE1NWI4MzlkYjVjMzg1NDg0NGYwNTAxMzU0OA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NzE1OGRiMzYxMWE2OWQwNDdhNDc4ZGFhYThlMTZmZDMyMGI1MGQ4NQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2NhNTZjZDI3NTIzOGFhMzJmY2EyY2JhNjdhZWE1OTQ1OTZlM2Q2ZjBhOGUy
|
10
|
+
MzQ5NWRjYzAzNjk2NGZiZTFkYjI5MDczOGZhODA0NTZmYmZmZTZjN2E3ZjM4
|
11
|
+
NmIyZGU4YzBjZTI5ZDY0MTVjODI4NTY4ZGJkNjc0ZjYyYWVhZDE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YjE1MjliYjFmMWJhMmI2YTdlZmQzMGMwYmIyOTg0NWZkMjIxYTE3ZjRhNTky
|
14
|
+
YTNjYWU5OGYyZDhiZjU1ZDcyOGEzNDZlMjUyNWU5MTEzNjI5MzYwNmE3MmFi
|
15
|
+
NmMwOWNmNTQ1NjVhMjRlYmQyYmYwN2I1ZmNiNjlmYjllMWM4OGU=
|
data/bin/reyes
CHANGED
@@ -7,6 +7,27 @@ def command_dump(output_file, options)
|
|
7
7
|
aws.dump_fake_data(output_file)
|
8
8
|
end
|
9
9
|
|
10
|
+
def command_fetch(instance_id, options)
|
11
|
+
region = options.fetch(:region)
|
12
|
+
aws = Reyes::AwsManager.new(options[:config])
|
13
|
+
s3 = Reyes::S3Loader.new(aws, options[:config])
|
14
|
+
wrapper = Reyes::PgpWrapper.new(options[:config])
|
15
|
+
|
16
|
+
armoured_rules = s3.fetch_rules
|
17
|
+
cleartext_rules = wrapper.verify!(armoured_rules)
|
18
|
+
|
19
|
+
fake = Reyes::FakeAws.new(JSON.load cleartext_rules)
|
20
|
+
g = Reyes::GroupManager.new(fake, region, instance_id)
|
21
|
+
r = Reyes::RunManager.new(g)
|
22
|
+
|
23
|
+
data = r.generate_data!(options.fetch(:gen_options))
|
24
|
+
r.apply_data!(data, options.fetch(:apply_options))
|
25
|
+
|
26
|
+
if options[:prune]
|
27
|
+
r.prune_ipsets
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
10
31
|
def command_install(json_file, instance_id, options)
|
11
32
|
region = options.fetch(:region)
|
12
33
|
|
@@ -14,8 +35,16 @@ def command_install(json_file, instance_id, options)
|
|
14
35
|
Reyes::Utils.sleep_random(options[:splay])
|
15
36
|
end
|
16
37
|
|
17
|
-
|
38
|
+
data = JSON.load(File.open(json_file, 'r'))
|
39
|
+
generated_time = data.fetch("metadata").fetch("generated_stamp")
|
40
|
+
fake = Reyes::FakeAws.new(data)
|
18
41
|
g = Reyes::GroupManager.new(fake, region, instance_id)
|
42
|
+
|
43
|
+
if Time.new(generated_time) > g.run_generation_time
|
44
|
+
# FIXME Deal gracefully with this case
|
45
|
+
# Should bail out, exiting nonzero if there were changes to commit
|
46
|
+
end
|
47
|
+
|
19
48
|
r = Reyes::RunManager.new(g)
|
20
49
|
|
21
50
|
data = r.generate_data!(options.fetch(:gen_options))
|
@@ -26,6 +55,18 @@ def command_install(json_file, instance_id, options)
|
|
26
55
|
end
|
27
56
|
end
|
28
57
|
|
58
|
+
def command_upload(options)
|
59
|
+
aws = Reyes::AwsManager.new(options[:config])
|
60
|
+
wrapper = Reyes::PgpWrapper.new(options[:config])
|
61
|
+
|
62
|
+
data = aws.generate_fake_data_json
|
63
|
+
|
64
|
+
armoured_data = wrapper.clearsign(data)
|
65
|
+
|
66
|
+
s3 = Reyes::S3Loader.new(aws, options[:config])
|
67
|
+
s3.upload_rules(armoured_data)
|
68
|
+
end
|
69
|
+
|
29
70
|
def parse_args
|
30
71
|
options = {
|
31
72
|
:region => 'us-west-1', # TODO: make required
|
@@ -33,6 +74,7 @@ def parse_args
|
|
33
74
|
:apply_options => {
|
34
75
|
:log_accept => true, # TODO remove this default
|
35
76
|
},
|
77
|
+
:fetch_options => {},
|
36
78
|
}
|
37
79
|
|
38
80
|
optparse = OptionParser.new do |opts|
|
@@ -51,6 +93,14 @@ Commands:
|
|
51
93
|
|
52
94
|
#{File.basename($0)} [options] dump JSON_FILE
|
53
95
|
|
96
|
+
fetch: load new rules from s3 and install them on the local system
|
97
|
+
|
98
|
+
#{File.basename($0)} [options] fetch INSTANCE_ID
|
99
|
+
|
100
|
+
upload: generate and sign a full dump of the rule inputs and upload them to s3
|
101
|
+
|
102
|
+
#{File.basename($0)} [options] upload
|
103
|
+
|
54
104
|
|
55
105
|
Defaults:
|
56
106
|
region: #{options.fetch(:region)}
|
@@ -127,6 +177,21 @@ Options:
|
|
127
177
|
exit 2
|
128
178
|
end
|
129
179
|
command_install(ARGV.fetch(0), ARGV.fetch(1), options)
|
180
|
+
when 'fetch'
|
181
|
+
unless ARGV.length == 1
|
182
|
+
STDERR.puts optparse
|
183
|
+
exit 2
|
184
|
+
end
|
185
|
+
|
186
|
+
command_fetch(ARGV.fetch(0), options)
|
187
|
+
when 'upload'
|
188
|
+
unless ARGV.length == 0
|
189
|
+
STDERR.puts optparse
|
190
|
+
exit 2
|
191
|
+
end
|
192
|
+
|
193
|
+
command_upload(options)
|
194
|
+
|
130
195
|
else
|
131
196
|
STDERR.puts optparse
|
132
197
|
STDERR.puts "\nError: Must provide a command"
|
data/config.yaml.example
CHANGED
data/lib/reyes.rb
CHANGED
data/lib/reyes/aws_manager.rb
CHANGED
@@ -32,6 +32,14 @@ module Reyes
|
|
32
32
|
connections.fetch(:ec2).fetch(region)
|
33
33
|
end
|
34
34
|
|
35
|
+
def s3
|
36
|
+
@s3 ||= AWS::S3.new({
|
37
|
+
access_key_id: @config.aws_credentials.fetch(:access_key_id),
|
38
|
+
secret_access_key: @config.aws_credentials.fetch(:secret_access_key),
|
39
|
+
logger: Chalk::Log::Logger.new("s3"),
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
35
43
|
def connections
|
36
44
|
@connections ||= connect!
|
37
45
|
end
|
@@ -145,6 +153,10 @@ module Reyes
|
|
145
153
|
data
|
146
154
|
end
|
147
155
|
|
156
|
+
def generate_fake_data_json
|
157
|
+
JSON.pretty_generate(generate_fake_data)
|
158
|
+
end
|
159
|
+
|
148
160
|
def dump_fake_data(filename)
|
149
161
|
log.info("Dumping AWS data to #{filename.inspect}")
|
150
162
|
data = generate_fake_data
|
data/lib/reyes/config.rb
CHANGED
data/lib/reyes/fake_aws.rb
CHANGED
@@ -5,11 +5,10 @@ module Reyes
|
|
5
5
|
class FakeAws
|
6
6
|
include Chalk::Log
|
7
7
|
|
8
|
-
# @param
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
log.info("Loaded JSON with metadata: #{metadata.inspect}")
|
8
|
+
# @param data [Hash]
|
9
|
+
def initialize(data)
|
10
|
+
@data = data
|
11
|
+
log.info("Initialized FakeAws with metadata: #{metadata.inspect}")
|
13
12
|
end
|
14
13
|
|
15
14
|
def region_data(region)
|
data/lib/reyes/group_manager.rb
CHANGED
@@ -48,6 +48,11 @@ module Reyes
|
|
48
48
|
}
|
49
49
|
end
|
50
50
|
|
51
|
+
def load_from_s3(aws, config)
|
52
|
+
s3 = S3Loader.new(aws, config)
|
53
|
+
data = s3.latest
|
54
|
+
end
|
55
|
+
|
51
56
|
# Given our instance ID and security group rules, generate IPTables rules
|
52
57
|
# needed to emulate security group behavior for foreign VPCs.
|
53
58
|
#
|
@@ -147,6 +152,11 @@ module Reyes
|
|
147
152
|
@generation.value
|
148
153
|
end
|
149
154
|
|
155
|
+
# @return [Time]
|
156
|
+
def run_generation_time
|
157
|
+
@generation.mtime
|
158
|
+
end
|
159
|
+
|
150
160
|
# Increment the run generation and persist it to disk
|
151
161
|
def run_generation_increment!
|
152
162
|
@generation.increment!
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Reyes
|
2
|
+
class PgpWrapper
|
3
|
+
class VerificationFailed < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
attr_reader :key_id, :keyring_directory
|
7
|
+
|
8
|
+
# Create a PgpVerifier
|
9
|
+
#
|
10
|
+
# @param key_id [String] 40 digit key fingerprint
|
11
|
+
def initialize(config_path=nil)
|
12
|
+
@config ||= Reyes::Config.new(config_path)
|
13
|
+
@key_id = @config.reyes_config.fetch("signing_key").upcase
|
14
|
+
@keyring_directory = @config.reyes_config.fetch("keyring_directory")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Pattern for parsing gpg --status-fd signature output
|
18
|
+
PATTERN = /^\[GNUPG:\] VALIDSIG ([A-F0-9]{40}) .+ ([A-F0-9]{40})$/
|
19
|
+
|
20
|
+
# Verifies +data+ against +@keyid+
|
21
|
+
#
|
22
|
+
# @param data [String] the data to verify
|
23
|
+
#
|
24
|
+
# @raise [VerificationFailed]
|
25
|
+
#
|
26
|
+
# @return [String] the stripped cleartext data
|
27
|
+
#
|
28
|
+
def verify!(data)
|
29
|
+
gpg_cmd = %w{gpg --batch --decrypt --status-fd 2} + keyring_args + ['-']
|
30
|
+
Subprocess.check_call(gpg_cmd,
|
31
|
+
:stdin => Subprocess::PIPE,
|
32
|
+
:stdout => Subprocess::PIPE,
|
33
|
+
:stderr => Subprocess::PIPE) do |child|
|
34
|
+
out, err = child.communicate(data)
|
35
|
+
|
36
|
+
if err =~ PATTERN
|
37
|
+
raise VerificationFailed.new("Bad key match") unless $1 == $2
|
38
|
+
raise VerificationFailed.new("Bad Key ID") unless $1 == key_id
|
39
|
+
else
|
40
|
+
raise VerificationFailed.new("Pattern does not match")
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sig looks ok
|
44
|
+
return out
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def clearsign(data)
|
49
|
+
gpg_cmd = %W{gpg --batch --clearsign -u #{key_id}} + keyring_args + ['-']
|
50
|
+
Subprocess.check_call(gpg_cmd,
|
51
|
+
:stdin => Subprocess::PIPE,
|
52
|
+
:stdout => Subprocess::PIPE) do |child|
|
53
|
+
out, _ = child.communicate(data)
|
54
|
+
return out
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def keyring_args
|
61
|
+
[
|
62
|
+
'--no-default-keyring',
|
63
|
+
'--keyring', keyring_file('pubring.gpg'),
|
64
|
+
'--secret-keyring', keyring_file('secring.gpg'),
|
65
|
+
'--trustdb-name', keyring_file('trustdb.gpg'),
|
66
|
+
]
|
67
|
+
end
|
68
|
+
|
69
|
+
def keyring_file(name)
|
70
|
+
File.join(@keyring_directory, name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/reyes/run_generation.rb
CHANGED
@@ -8,6 +8,7 @@ module Reyes
|
|
8
8
|
DefaultGenerationPath = "/tmp/reyes.u#{Process.euid}.generation"
|
9
9
|
|
10
10
|
attr_reader :value
|
11
|
+
attr_reader :mtime
|
11
12
|
|
12
13
|
# @param path [String] Path to generation file
|
13
14
|
#
|
@@ -52,8 +53,10 @@ module Reyes
|
|
52
53
|
@fh = open(@path)
|
53
54
|
if @fh.size == 0
|
54
55
|
@value = 0
|
56
|
+
@mtime = Time.at(0)
|
55
57
|
else
|
56
58
|
@value = load_value
|
59
|
+
@mtime = @fh.mtime
|
57
60
|
end
|
58
61
|
log.debug("Loaded generation value #{@value.inspect}")
|
59
62
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Reyes
|
2
|
+
class S3Loader
|
3
|
+
|
4
|
+
include Chalk::Log
|
5
|
+
|
6
|
+
def initialize(aws, config)
|
7
|
+
@aws = aws
|
8
|
+
@config = Reyes::Config.new(config)
|
9
|
+
|
10
|
+
log.info("Initialized S3Loader: #{bucket.inspect}/#{path.inspect}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch_rules
|
14
|
+
@aws.s3.buckets[bucket].objects[path].read
|
15
|
+
end
|
16
|
+
|
17
|
+
def upload_rules(data)
|
18
|
+
@aws.s3.buckets[bucket].objects[path].write(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def bucket
|
24
|
+
@config.aws_config.fetch("s3").fetch("bucket")
|
25
|
+
end
|
26
|
+
|
27
|
+
def path
|
28
|
+
@config.aws_config.fetch("s3").fetch("path")
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/lib/reyes/version.rb
CHANGED
data/reyes.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reyes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Brody
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-02-
|
12
|
+
date: 2015-02-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
@@ -122,13 +122,15 @@ files:
|
|
122
122
|
- lib/reyes/group_tools.rb
|
123
123
|
- lib/reyes/ipset.rb
|
124
124
|
- lib/reyes/iptables.rb
|
125
|
+
- lib/reyes/pgp_wrapper.rb
|
125
126
|
- lib/reyes/run_generation.rb
|
126
127
|
- lib/reyes/run_manager.rb
|
128
|
+
- lib/reyes/s3_loader.rb
|
127
129
|
- lib/reyes/set_manager.rb
|
128
130
|
- lib/reyes/utils.rb
|
129
131
|
- lib/reyes/version.rb
|
130
132
|
- reyes.gemspec
|
131
|
-
homepage:
|
133
|
+
homepage: https://github.com/stripe/reyes/
|
132
134
|
licenses: []
|
133
135
|
metadata: {}
|
134
136
|
post_install_message:
|