chamber 2.11.0 → 2.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +40 -29
- data/lib/chamber/binary/runner.rb +23 -0
- data/lib/chamber/commands/initialize.rb +103 -31
- data/lib/chamber/commands/secure.rb +3 -5
- data/lib/chamber/commands/sign.rb +17 -0
- data/lib/chamber/commands/verify.rb +25 -0
- data/lib/chamber/encryption_methods/public_key.rb +5 -3
- data/lib/chamber/encryption_methods/ssl.rb +2 -0
- data/lib/chamber/file.rb +23 -0
- data/lib/chamber/file_set.rb +15 -1
- data/lib/chamber/files/signature.rb +85 -0
- data/lib/chamber/filters/encryption_filter.rb +0 -1
- data/lib/chamber/filters/environment_filter.rb +2 -0
- data/lib/chamber/instance.rb +8 -0
- data/lib/chamber/{rails/railtie.rb → integrations/rails.rb} +2 -2
- data/lib/chamber/integrations/sinatra.rb +29 -0
- data/lib/chamber/key_pair.rb +4 -0
- data/lib/chamber/keys/base.rb +15 -3
- data/lib/chamber/rails.rb +1 -1
- data/lib/chamber/version.rb +1 -1
- metadata +21 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2244ac836ff26be17476fae140643427bd61ec3
|
4
|
+
data.tar.gz: 3acbda9e98904305001f0aad0cd45f92909afbfa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca89abd49137ef3cae8a54b5a4a38029a55ef4e9498473dab173094704be265f0801e8698c34281dc624cbedb1b3f9f5d68ff6a3466b97b6c328575a6ab5c829
|
7
|
+
data.tar.gz: 5205ce62e2c54e5d5348a50e7bffa7fe2e196516b9d667f2b903c086f646e885c7d6459aba57fb9620edd96930f1480aa8655baa10f658fd312ad294a5e2c44a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/README.md
CHANGED
@@ -1,45 +1,56 @@
|
|
1
|
-
# Chamber
|
1
|
+
# Chamber
|
2
|
+
[![Gem Version](https://img.shields.io/gem/v/chamber.svg)](https://rubygems.org/gems/chamber) ![Rubygems Rank Overall](https://img.shields.io/gem/rt/chamber.svg) ![Rubygems Rank Daily](https://img.shields.io/gem/rd/chamber.svg) ![Rubygems Downloads](https://img.shields.io/gem/dv/chamber/stable.svg) [![Build Status](https://img.shields.io/travis/thekompanee/chamber/master.svg)](http://travis-ci.org/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber.svg)](https://codeclimate.com/github/thekompanee/chamber) [![Code Climate](https://codeclimate.com/github/thekompanee/chamber/coverage.svg)](https://codeclimate.com/github/thekompanee/chamber)
|
2
3
|
|
3
|
-
Chamber is the auto-encrypting, extremely organizable, Heroku-loving,
|
4
|
-
non-extra-repo-needing, non-Rails-specific-ing, CI-serving
|
5
|
-
management library.
|
4
|
+
Chamber is the auto-encrypting, extremely organizable, Heroku-loving,
|
5
|
+
CLI-having, non-extra-repo-needing, non-Rails-specific-ing, CI-serving
|
6
|
+
configuration management library.
|
6
7
|
|
7
|
-
|
8
|
+
We looked at all of the options out there and thought something was still
|
9
|
+
missing, so we wrote Chamber. We made it with lots of ❤ and we hope you like it
|
10
|
+
as much as we do.
|
8
11
|
|
9
|
-
|
12
|
+
## What Sets Chamber Apart?
|
10
13
|
|
11
|
-
|
14
|
+
For an idea of how Chamber compares to other popular libraries, check out our
|
15
|
+
[Gem Comparison][comparison].
|
12
16
|
|
13
|
-
|
14
|
-
necessary](https://github.com/thekompanee/chamber/wiki/Basic-Usage#convention-over-configuration)
|
15
|
-
1. Thou shalt [seamlessly work with Heroku](https://github.com/thekompanee/chamber/wiki/Heroku) or other deployment platforms, where custom
|
16
|
-
settings must be stored in [environment variables](https://github.com/thekompanee/chamber/wiki/Environment-Variable-Compatibility)
|
17
|
-
1. Thou shalt seamlessly work with [Travis CI](https://github.com/thekompanee/chamber/wiki/TravisCI) and other cloud CI platforms
|
18
|
-
1. Thou shalt not force users to use arcane
|
19
|
-
[long_variables_to_keep_their_settings_organized](https://github.com/thekompanee/chamber/wiki/Accessing-Settings)
|
20
|
-
1. Thou shalt not require users keep a separate repo or cloud share sync [just to
|
21
|
-
keep their secure settings updated](https://github.com/thekompanee/chamber/wiki/Encrypting-Your-Settings)
|
22
|
-
1. Thou shalt not be bound to a single framework like Rails (it should be usable [in
|
23
|
-
plain Ruby projects](https://github.com/thekompanee/chamber/wiki/Basic-Usage#in-a-plain-old-ruby-project))
|
24
|
-
1. Thou shalt have an [easy-to-use CLI](https://github.com/thekompanee/chamber/wiki/Command-Line-Reference) for scripting
|
25
|
-
1. Thou shalt easily integrate with Capistrano for deployments
|
26
|
-
1. Thou shalt be [well documented](https://github.com/thekompanee/chamber/wiki/) with full test coverage
|
27
|
-
1. Thou shalt not have to worry about [accidentally committing secure settings](https://github.com/thekompanee/chamber/wiki/Git-Commit-Hook)
|
17
|
+
## Basic Usage
|
28
18
|
|
29
|
-
|
30
|
-
|
31
|
-
Visit the [wiki](https://github.com/thekompanee/chamber/wiki)
|
19
|
+
You can view our Basic Usage Guide [here][basic-usage]. Otherwise, for the full
|
20
|
+
Chamber guide, visit the [wiki][wiki].
|
32
21
|
|
33
22
|
## Credits
|
34
23
|
|
35
|
-
Chamber was written by Jeff Felchner and
|
24
|
+
Chamber was written by [Jeff Felchner][jeff-profile] and
|
25
|
+
[Mark McEahern][mark-profile]
|
36
26
|
|
37
|
-
![The Kompanee]
|
27
|
+
![The Kompanee][kompanee-logo]
|
38
28
|
|
39
|
-
Chamber is maintained and funded by [The Kompanee, Ltd.]
|
29
|
+
Chamber is maintained and funded by [The Kompanee, Ltd.][kompanee-site]
|
40
30
|
|
41
31
|
The names and logos for The Kompanee are trademarks of The Kompanee, Ltd.
|
42
32
|
|
43
33
|
## License
|
44
34
|
|
45
|
-
Chamber is Copyright © 2014 Jeff Felchner and Mark McEahern. It is free
|
35
|
+
Chamber is Copyright © 2014-2018 Jeff Felchner and Mark McEahern. It is free
|
36
|
+
software, and may be redistributed under the terms specified in the
|
37
|
+
[LICENSE][license] file.
|
38
|
+
|
39
|
+
[accessing]: https://github.com/thekompanee/chamber/wiki/Accessing-Settings
|
40
|
+
[basic-usage]: https://github.com/thekompanee/chamber/wiki/Basic-Usage
|
41
|
+
[cli]: https://github.com/thekompanee/chamber/wiki/CLI-Overview
|
42
|
+
[commit-hook]: https://github.com/thekompanee/chamber/wiki/Git-Commit-Hooks
|
43
|
+
[comparison]: https://github.com/thekompanee/chamber/wiki/Gem-Comparison
|
44
|
+
[encryption]: https://github.com/thekompanee/chamber/wiki/Encryption-Basics
|
45
|
+
[env-vars]: https://github.com/thekompanee/chamber/wiki/Environment-Variables
|
46
|
+
[heroku]: https://github.com/thekompanee/chamber/wiki/Heroku
|
47
|
+
[inch]: https://inch-ci.org/github/thekompanee/chamber
|
48
|
+
[jeff-profile]: https://github.com/jfelchner
|
49
|
+
[kompanee-logo]: https://kompanee-public-assets.s3.amazonaws.com/readmes/kompanee-horizontal-black.png
|
50
|
+
[kompanee-site]: http://www.thekompanee.com
|
51
|
+
[license]: https://github.com/thekompanee/chamber/blob/master/LICENSE.txt
|
52
|
+
[mark-profile]: https://github.com/m5rk
|
53
|
+
[namespace-keys]: https://github.com/thekompanee/chamber/wiki/Namespaced-Key-Pairs
|
54
|
+
[plain-ruby]: https://github.com/thekompanee/chamber/wiki/Installation#in-a-ruby-project-or-ruby-gem
|
55
|
+
[travis]: https://github.com/thekompanee/chamber/wiki/TravisCI
|
56
|
+
[wiki]: https://github.com/thekompanee/chamber/wiki
|
@@ -7,6 +7,8 @@ require 'chamber/binary/heroku'
|
|
7
7
|
require 'chamber/commands/show'
|
8
8
|
require 'chamber/commands/files'
|
9
9
|
require 'chamber/commands/secure'
|
10
|
+
require 'chamber/commands/sign'
|
11
|
+
require 'chamber/commands/verify'
|
10
12
|
require 'chamber/commands/compare'
|
11
13
|
require 'chamber/commands/initialize'
|
12
14
|
|
@@ -143,9 +145,30 @@ class Runner < Thor
|
|
143
145
|
|
144
146
|
################################################################################
|
145
147
|
|
148
|
+
desc 'sign', 'Creates or verifies signatures for all current settings files using ' \
|
149
|
+
'the signature private key.'
|
150
|
+
|
151
|
+
method_option :verify,
|
152
|
+
type: :boolean,
|
153
|
+
default: false
|
154
|
+
|
155
|
+
def sign
|
156
|
+
if options[:verify]
|
157
|
+
Commands::Verify.call(options.merge(shell: self))
|
158
|
+
else
|
159
|
+
Commands::Sign.call(options.merge(shell: self))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
################################################################################
|
164
|
+
|
146
165
|
desc 'init', 'Sets Chamber up using best practices for secure configuration ' \
|
147
166
|
'management'
|
148
167
|
|
168
|
+
method_option :signature,
|
169
|
+
type: :boolean,
|
170
|
+
default: false
|
171
|
+
|
149
172
|
def init
|
150
173
|
Commands::Initialize.call(options.merge(shell: self))
|
151
174
|
end
|
@@ -16,13 +16,15 @@ class Initialize < Chamber::Commands::Base
|
|
16
16
|
end
|
17
17
|
|
18
18
|
attr_accessor :basepath,
|
19
|
-
:namespaces
|
19
|
+
:namespaces,
|
20
|
+
:signature
|
20
21
|
|
21
22
|
def initialize(options = {})
|
22
23
|
super
|
23
24
|
|
24
25
|
self.basepath = Chamber.configuration.basepath
|
25
26
|
self.namespaces = options.fetch(:namespaces, [])
|
27
|
+
self.signature = options.fetch(:signature)
|
26
28
|
end
|
27
29
|
|
28
30
|
# rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
|
@@ -36,9 +38,16 @@ class Initialize < Chamber::Commands::Base
|
|
36
38
|
|
37
39
|
key_pairs.each { |key_pair| generate_key_pair(key_pair) }
|
38
40
|
|
41
|
+
if signature
|
42
|
+
signature_key_pair = Chamber::KeyPair.new(namespace: 'signature',
|
43
|
+
key_file_path: rootpath)
|
44
|
+
|
45
|
+
generate_key_pair(signature_key_pair)
|
46
|
+
end
|
47
|
+
|
39
48
|
append_to_gitignore
|
40
49
|
|
41
|
-
shell.copy_file settings_template_filepath, settings_filepath
|
50
|
+
shell.copy_file settings_template_filepath, settings_filepath, skip: true
|
42
51
|
|
43
52
|
shell.say ''
|
44
53
|
shell.say '********************************************************************************', :green
|
@@ -46,47 +55,103 @@ class Initialize < Chamber::Commands::Base
|
|
46
55
|
shell.say '********************************************************************************', :green
|
47
56
|
shell.say ''
|
48
57
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
if namespaces.empty?
|
59
|
+
shell.say '.chamber.pem is your DEFAULT Chamber key.', :yellow
|
60
|
+
shell.say ''
|
61
|
+
shell.say 'If you would like a key which is used only for a certain environment (such as'
|
62
|
+
shell.say 'production), or your local machine, you can rerun the command like so:'
|
63
|
+
shell.say ''
|
64
|
+
shell.say '$ chamber init --namespaces="production my_machines_hostname"', :yellow
|
65
|
+
shell.say ''
|
66
|
+
shell.say 'You can find more information about namespace keys here:'
|
67
|
+
shell.say ''
|
68
|
+
shell.say ' * '
|
69
|
+
shell.say 'https://github.com/thekompanee/chamber/wiki/Namespaced-Key-Pairs', :blue
|
70
|
+
shell.say ''
|
71
|
+
shell.say '--------------------------------------------------------------------------------'
|
72
|
+
shell.say ''
|
73
|
+
end
|
74
|
+
|
75
|
+
if signature
|
76
|
+
shell.say ' Your Signature Keys'
|
77
|
+
shell.say ''
|
78
|
+
shell.say 'Your signature keys, which will be used for verification, are located at:'
|
79
|
+
shell.say ''
|
80
|
+
shell.say ' * Public Key: '
|
81
|
+
shell.say signature_key_pair.
|
82
|
+
public_key_filepath.
|
83
|
+
relative_path_from(Pathname.pwd), :yellow
|
84
|
+
shell.say ' * Private Key: '
|
85
|
+
shell.say signature_key_pair.
|
86
|
+
unencrypted_private_key_filepath.
|
87
|
+
relative_path_from(Pathname.pwd), :yellow
|
88
|
+
shell.say ' * Encrypted Private Key: '
|
89
|
+
shell.say signature_key_pair.
|
90
|
+
encrypted_private_key_filepath.
|
91
|
+
relative_path_from(Pathname.pwd), :yellow
|
92
|
+
shell.say ' * Encrypted Passphrase: '
|
93
|
+
shell.say signature_key_pair.
|
94
|
+
encrypted_private_key_passphrase_filepath.
|
95
|
+
relative_path_from(Pathname.pwd), :yellow
|
96
|
+
|
97
|
+
shell.say ''
|
98
|
+
shell.say 'The signature private keys should be thought of separately from the other'
|
99
|
+
shell.say 'project private keys you generate. They are not required to run the app'
|
100
|
+
shell.say 'and should only be given out to *very select* people.'
|
101
|
+
shell.say ''
|
102
|
+
shell.say 'You can find more information about settings verification here:'
|
103
|
+
shell.say ''
|
104
|
+
shell.say ' * '
|
105
|
+
shell.say 'https://github.com/thekompanee/chamber/wiki/Verifying-Settings', :blue
|
106
|
+
shell.say ''
|
107
|
+
shell.say '--------------------------------------------------------------------------------'
|
108
|
+
shell.say ''
|
109
|
+
end
|
57
110
|
|
58
|
-
shell.say '
|
111
|
+
shell.say ' Your Encrypted Keys'
|
112
|
+
shell.say ''
|
113
|
+
shell.say 'You can send your team members any of the file(s) located at:'
|
59
114
|
shell.say ''
|
60
115
|
|
61
116
|
key_pairs.each do |key_pair|
|
62
|
-
shell.say
|
63
|
-
shell.say key_pair.
|
117
|
+
shell.say ' * '
|
118
|
+
shell.say key_pair.encrypted_private_key_filepath.relative_path_from(Pathname.pwd), :yellow
|
64
119
|
end
|
65
120
|
|
66
121
|
shell.say ''
|
67
|
-
shell.say '
|
122
|
+
shell.say 'and not have to worry about sending them via a secure medium, however do'
|
123
|
+
shell.say 'not send the passphrase along with it. Give it to your team members in'
|
124
|
+
shell.say 'person.'
|
68
125
|
shell.say ''
|
69
|
-
shell.say 'You can
|
126
|
+
shell.say 'You can learn more about encrypted keys here:'
|
127
|
+
shell.say ''
|
128
|
+
shell.say ' * '
|
129
|
+
shell.say 'https://github.com/thekompanee/chamber/wiki/Keypair-Encryption#the-encrypted-private-key', :blue
|
130
|
+
shell.say ''
|
131
|
+
shell.say '--------------------------------------------------------------------------------'
|
132
|
+
shell.say ''
|
133
|
+
shell.say ' Your Key Passphrases'
|
134
|
+
shell.say ''
|
135
|
+
shell.say 'The passphrases for your encrypted private key(s) are stored in the'
|
136
|
+
shell.say 'following locations:'
|
70
137
|
shell.say ''
|
71
138
|
|
72
139
|
key_pairs.each do |key_pair|
|
73
|
-
shell.say '* '
|
74
|
-
shell.say key_pair.
|
140
|
+
shell.say ' * '
|
141
|
+
shell.say key_pair.encrypted_private_key_passphrase_filepath.relative_path_from(Pathname.pwd), :yellow
|
75
142
|
end
|
76
143
|
|
77
|
-
shell.say ''
|
78
|
-
shell.say 'and not have to worry about sending it via a secure medium (such as'
|
79
|
-
shell.say 'email), however do not send the passphrase along with it. Give it to'
|
80
|
-
shell.say 'your team members in person.'
|
81
144
|
shell.say ''
|
82
145
|
shell.say 'In order for them to decrypt it (for use with Chamber), they can use something'
|
83
146
|
shell.say 'like the following (swapping out the actual key filenames if necessary):'
|
84
147
|
shell.say ''
|
85
|
-
shell.say "$ cp #{key_pairs[0].encrypted_private_key_filepath} #{key_pairs[0].unencrypted_private_key_filepath}", :yellow
|
86
|
-
shell.say "$ ssh-keygen -p -f #{key_pairs[0].unencrypted_private_key_filepath}", :yellow
|
148
|
+
shell.say "$ cp #{key_pairs[0].encrypted_private_key_filepath.relative_path_from(Pathname.pwd)} #{key_pairs[0].unencrypted_private_key_filepath.relative_path_from(Pathname.pwd)}", :yellow
|
149
|
+
shell.say "$ ssh-keygen -p -f #{key_pairs[0].unencrypted_private_key_filepath.relative_path_from(Pathname.pwd)}", :yellow
|
87
150
|
shell.say ''
|
88
151
|
shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.'
|
89
152
|
shell.say ''
|
153
|
+
shell.say '--------------------------------------------------------------------------------'
|
154
|
+
shell.say ''
|
90
155
|
end
|
91
156
|
# rubocop:enable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
|
92
157
|
|
@@ -102,27 +167,34 @@ class Initialize < Chamber::Commands::Base
|
|
102
167
|
shell.create_file key_pair.public_key_filepath,
|
103
168
|
key_pair.public_key_pem,
|
104
169
|
skip: true
|
170
|
+
shell.create_file key_pair.encrypted_private_key_passphrase_filepath,
|
171
|
+
key_pair.passphrase,
|
172
|
+
skip: true
|
105
173
|
|
106
174
|
`chmod 600 #{key_pair.unencrypted_private_key_filepath}`
|
107
175
|
`chmod 600 #{key_pair.encrypted_private_key_filepath}`
|
176
|
+
`chmod 600 #{key_pair.encrypted_private_key_passphrase_filepath}`
|
108
177
|
`chmod 644 #{key_pair.public_key_filepath}`
|
109
178
|
end
|
110
179
|
|
111
|
-
# rubocop:disable Style/GuardClause
|
112
180
|
def append_to_gitignore
|
113
181
|
::FileUtils.touch gitignore_filepath
|
114
182
|
|
115
183
|
gitignore_contents = ::File.read(gitignore_filepath)
|
116
184
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
185
|
+
%w{
|
186
|
+
**/settings/*-local.yml
|
187
|
+
**/settings-local.yml
|
188
|
+
.chamber*.enc
|
189
|
+
.chamber*.pem
|
190
|
+
.chamber*.enc.pass
|
191
|
+
!.chamber*.pub.pem
|
192
|
+
}.each do |pattern|
|
193
|
+
unless gitignore_contents =~ Regexp.new(Regexp.escape(pattern))
|
194
|
+
shell.append_to_file gitignore_filepath, "#{pattern}\n"
|
195
|
+
end
|
123
196
|
end
|
124
197
|
end
|
125
|
-
# rubocop:enable Style/GuardClause
|
126
198
|
|
127
199
|
def settings_template_filepath
|
128
200
|
@settings_template_filepath ||= templates_path + 'settings.yml'
|
@@ -15,11 +15,9 @@ class Secure < Chamber::Commands::Base
|
|
15
15
|
def call
|
16
16
|
disable_warnings do
|
17
17
|
insecure_environment_variables.each_key do |key|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
shell.say_status 'encrypt', key, :green
|
22
|
-
end
|
18
|
+
color = dry_run ? :blue : :green
|
19
|
+
|
20
|
+
shell.say_status 'encrypt', key, color
|
23
21
|
end
|
24
22
|
end
|
25
23
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'chamber/commands/base'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
class Sign < Chamber::Commands::Base
|
8
|
+
def initialize(options = {})
|
9
|
+
super(options.merge(namespaces: ['*']))
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
chamber.sign
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'chamber/commands/base'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Commands
|
7
|
+
class Verify < Chamber::Commands::Base
|
8
|
+
def initialize(options = {})
|
9
|
+
super(options.merge(namespaces: ['*']))
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
verification_results = chamber.verify
|
14
|
+
|
15
|
+
verification_results.each_pair do |filename, result|
|
16
|
+
unless result
|
17
|
+
shell.say("The signature for '#{filename}' failed verification.", :yellow)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
verification_results
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'base64'
|
4
|
+
|
3
5
|
module Chamber
|
4
6
|
module EncryptionMethods
|
5
7
|
class PublicKey
|
6
|
-
def self.encrypt(_key, value,
|
7
|
-
value
|
8
|
-
encrypted_string =
|
8
|
+
def self.encrypt(_key, value, encryption_key)
|
9
|
+
value = YAML.dump(value)
|
10
|
+
encrypted_string = encryption_key.public_encrypt(value)
|
9
11
|
|
10
12
|
Base64.strict_encode64(encrypted_string)
|
11
13
|
end
|
data/lib/chamber/file.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'pathname'
|
4
4
|
require 'yaml'
|
5
5
|
require 'erb'
|
6
|
+
require 'chamber/files/signature'
|
6
7
|
|
7
8
|
###
|
8
9
|
# Internal: Represents a single file containing settings information in a given
|
@@ -104,6 +105,28 @@ class File < Pathname
|
|
104
105
|
end
|
105
106
|
# rubocop:enable Metrics/LineLength
|
106
107
|
|
108
|
+
def sign
|
109
|
+
signature_key_contents = decryption_keys[:signature]
|
110
|
+
|
111
|
+
fail ArgumentError, 'You asked to sign your settings files but no signature key was found. Run `chamber init --signature` to generate one.' \
|
112
|
+
unless signature_key_contents
|
113
|
+
|
114
|
+
signature = Files::Signature.new(to_s, read, signature_key_contents)
|
115
|
+
|
116
|
+
signature.write
|
117
|
+
end
|
118
|
+
|
119
|
+
def verify
|
120
|
+
signature_key_contents = encryption_keys[:signature]
|
121
|
+
|
122
|
+
fail ArgumentError, 'You asked to verify your settings files but no signature key was found. Run `chamber init --signature` to generate one.' \
|
123
|
+
unless signature_key_contents
|
124
|
+
|
125
|
+
signature = Files::Signature.new(to_s, read, signature_key_contents)
|
126
|
+
|
127
|
+
signature.verify
|
128
|
+
end
|
129
|
+
|
107
130
|
private
|
108
131
|
|
109
132
|
def secure_prefix
|
data/lib/chamber/file_set.rb
CHANGED
@@ -115,13 +115,15 @@ class FileSet
|
|
115
115
|
attr_reader :namespaces,
|
116
116
|
:paths
|
117
117
|
attr_accessor :decryption_keys,
|
118
|
-
:encryption_keys
|
118
|
+
:encryption_keys,
|
119
|
+
:basepath
|
119
120
|
|
120
121
|
def initialize(options = {})
|
121
122
|
self.namespaces = options[:namespaces] || {}
|
122
123
|
self.decryption_keys = options[:decryption_keys]
|
123
124
|
self.encryption_keys = options[:encryption_keys]
|
124
125
|
self.paths = options.fetch(:files)
|
126
|
+
self.basepath = options[:basepath]
|
125
127
|
end
|
126
128
|
|
127
129
|
###
|
@@ -181,6 +183,18 @@ class FileSet
|
|
181
183
|
files.each(&:secure)
|
182
184
|
end
|
183
185
|
|
186
|
+
def sign
|
187
|
+
files.each(&:sign)
|
188
|
+
end
|
189
|
+
|
190
|
+
def verify
|
191
|
+
files.each_with_object({}) do |file, memo|
|
192
|
+
relative_filepath = Pathname.new(file.to_s).relative_path_from(basepath).to_s
|
193
|
+
|
194
|
+
memo[relative_filepath] = file.verify
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
184
198
|
protected
|
185
199
|
|
186
200
|
###
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'pathname'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Chamber
|
8
|
+
module Files
|
9
|
+
class Signature
|
10
|
+
SIGNATURE_HEADER = '-----BEGIN CHAMBER SIGNATURE-----'
|
11
|
+
SIGNATURE_FOOTER = '-----END CHAMBER SIGNATURE-----'
|
12
|
+
SIGNATURE_IN_SIGNATURE_FILE_PATTERN = /#{SIGNATURE_HEADER}\n(.*)\n#{SIGNATURE_FOOTER}/
|
13
|
+
|
14
|
+
attr_accessor :settings_content,
|
15
|
+
:settings_filename
|
16
|
+
|
17
|
+
attr_reader :signature_key
|
18
|
+
|
19
|
+
def initialize(settings_filename, settings_content, signature_key)
|
20
|
+
self.signature_key = signature_key
|
21
|
+
self.settings_content = settings_content
|
22
|
+
self.settings_filename = Pathname.new(settings_filename)
|
23
|
+
end
|
24
|
+
|
25
|
+
def signature_key=(keyish)
|
26
|
+
@signature_key ||= if keyish.is_a?(OpenSSL::PKey::RSA)
|
27
|
+
keyish
|
28
|
+
elsif ::File.readable?(::File.expand_path(keyish))
|
29
|
+
file_contents = ::File.read(::File.expand_path(keyish))
|
30
|
+
OpenSSL::PKey::RSA.new(file_contents)
|
31
|
+
else
|
32
|
+
OpenSSL::PKey::RSA.new(keyish)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def write
|
37
|
+
signature_filename.write(<<-HEREDOC, 0, mode: 'w+')
|
38
|
+
Signed By: #{`git config --get 'user.name'`.chomp}
|
39
|
+
Signed At: #{Time.now.utc.iso8601}
|
40
|
+
|
41
|
+
#{SIGNATURE_HEADER}
|
42
|
+
#{encoded_signature}
|
43
|
+
#{SIGNATURE_FOOTER}
|
44
|
+
HEREDOC
|
45
|
+
end
|
46
|
+
|
47
|
+
def verify
|
48
|
+
signature_key.verify(digest, signature_content, settings_content)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def encoded_signature
|
54
|
+
@encoded_signature ||= Base64.strict_encode64(raw_signature)
|
55
|
+
end
|
56
|
+
|
57
|
+
def raw_signature
|
58
|
+
@raw_signature ||= signature_key.
|
59
|
+
sign(digest, settings_content)
|
60
|
+
end
|
61
|
+
|
62
|
+
def signature_filename
|
63
|
+
@signature_filename ||= settings_filename.
|
64
|
+
sub('.yml', '.sig').
|
65
|
+
sub('.erb', '')
|
66
|
+
end
|
67
|
+
|
68
|
+
def encoded_signature_content
|
69
|
+
@encoded_signature_content ||= signature_filename.
|
70
|
+
read.
|
71
|
+
match(SIGNATURE_IN_SIGNATURE_FILE_PATTERN) do |match|
|
72
|
+
match[1]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def signature_content
|
77
|
+
@signature_content ||= Base64.strict_decode64(encoded_signature_content)
|
78
|
+
end
|
79
|
+
|
80
|
+
def digest
|
81
|
+
@digest ||= OpenSSL::Digest::SHA512.new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/chamber/instance.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
require 'socket'
|
4
4
|
|
5
5
|
module Chamber
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Integrations
|
7
|
+
class Rails < ::Rails::Railtie
|
8
8
|
initializer 'chamber.load', before: :load_environment_config do
|
9
9
|
Chamber.load(basepath: ::Rails.root.join('config'),
|
10
10
|
namespaces: {
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module Chamber
|
6
|
+
module Integrations
|
7
|
+
module Sinatra
|
8
|
+
def self.registered(app)
|
9
|
+
app.configure do |inner_app|
|
10
|
+
env = inner_app.environment || ENV['RACK_ENV']
|
11
|
+
root = inner_app.root
|
12
|
+
|
13
|
+
if defined?(Padrino)
|
14
|
+
env = Padrino.env if Padrino.respond_to?(:env)
|
15
|
+
root = Padrino.root if Padrino.respond_to?(:root)
|
16
|
+
end
|
17
|
+
|
18
|
+
Chamber.load(
|
19
|
+
basepath: root,
|
20
|
+
namespaces: {
|
21
|
+
environment: -> { env },
|
22
|
+
hostname: -> { Socket.gethostname },
|
23
|
+
},
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/chamber/key_pair.rb
CHANGED
@@ -15,6 +15,10 @@ class KeyPair
|
|
15
15
|
self.key_file_path = Pathname.new(options.fetch(:key_file_path))
|
16
16
|
end
|
17
17
|
|
18
|
+
def encrypted_private_key_passphrase_filepath
|
19
|
+
key_file_path + "#{encrypted_private_key_filename}.pass"
|
20
|
+
end
|
21
|
+
|
18
22
|
def encrypted_private_key_filepath
|
19
23
|
key_file_path + encrypted_private_key_filename
|
20
24
|
end
|
data/lib/chamber/keys/base.rb
CHANGED
@@ -7,9 +7,9 @@ class Base
|
|
7
7
|
new(*args).resolve
|
8
8
|
end
|
9
9
|
|
10
|
-
attr_accessor :
|
11
|
-
|
12
|
-
|
10
|
+
attr_accessor :rootpath
|
11
|
+
attr_reader :filenames,
|
12
|
+
:namespaces
|
13
13
|
|
14
14
|
def initialize(options = {})
|
15
15
|
self.rootpath = Pathname.new(options.fetch(:rootpath))
|
@@ -45,6 +45,18 @@ class Base
|
|
45
45
|
|
46
46
|
private
|
47
47
|
|
48
|
+
def namespaces=(other)
|
49
|
+
@namespaces ||= begin
|
50
|
+
keys = if other.respond_to?(:keys)
|
51
|
+
other.keys.map(&:to_s)
|
52
|
+
else
|
53
|
+
other
|
54
|
+
end
|
55
|
+
|
56
|
+
keys + %w{signature}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
def key_from_file_contents(filename)
|
49
61
|
filename.readable? && filename.read
|
50
62
|
end
|
data/lib/chamber/rails.rb
CHANGED
data/lib/chamber/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chamber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekompanee
|
@@ -34,7 +34,7 @@ cert_chain:
|
|
34
34
|
etYUO0DlNY/qYfSfExrgt0W5dZeT09V++WPlYauHw/EZtAB0AsJwVdtIscq0HSvX
|
35
35
|
yH9AFp3KIe0v70EXzao/94n+XoDULrHEhqGMo34iS+37ZA==
|
36
36
|
-----END CERTIFICATE-----
|
37
|
-
date: 2018-01-
|
37
|
+
date: 2018-01-16 00:00:00.000000000 Z
|
38
38
|
dependencies:
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: thor
|
@@ -120,6 +120,20 @@ dependencies:
|
|
120
120
|
- - "~>"
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '4.0'
|
123
|
+
- !ruby/object:Gem::Dependency
|
124
|
+
name: timecop
|
125
|
+
requirement: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - "~>"
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0.0'
|
130
|
+
type: :development
|
131
|
+
prerelease: false
|
132
|
+
version_requirements: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - "~>"
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0.0'
|
123
137
|
description: Chamber lets you source your Settings from an arbitrary number of YAML
|
124
138
|
files and provides a simple mechanism for overriding settings from the ENV, which
|
125
139
|
is friendly to how Heroku addons work.
|
@@ -149,8 +163,10 @@ files:
|
|
149
163
|
- lib/chamber/commands/securable.rb
|
150
164
|
- lib/chamber/commands/secure.rb
|
151
165
|
- lib/chamber/commands/show.rb
|
166
|
+
- lib/chamber/commands/sign.rb
|
152
167
|
- lib/chamber/commands/travis.rb
|
153
168
|
- lib/chamber/commands/travis/secure.rb
|
169
|
+
- lib/chamber/commands/verify.rb
|
154
170
|
- lib/chamber/configuration.rb
|
155
171
|
- lib/chamber/context_resolver.rb
|
156
172
|
- lib/chamber/encryption_methods/none.rb
|
@@ -159,6 +175,7 @@ files:
|
|
159
175
|
- lib/chamber/errors/decryption_failure.rb
|
160
176
|
- lib/chamber/file.rb
|
161
177
|
- lib/chamber/file_set.rb
|
178
|
+
- lib/chamber/files/signature.rb
|
162
179
|
- lib/chamber/filters/decryption_filter.rb
|
163
180
|
- lib/chamber/filters/encryption_filter.rb
|
164
181
|
- lib/chamber/filters/environment_filter.rb
|
@@ -168,13 +185,14 @@ files:
|
|
168
185
|
- lib/chamber/filters/secure_filter.rb
|
169
186
|
- lib/chamber/filters/translate_secure_keys_filter.rb
|
170
187
|
- lib/chamber/instance.rb
|
188
|
+
- lib/chamber/integrations/rails.rb
|
189
|
+
- lib/chamber/integrations/sinatra.rb
|
171
190
|
- lib/chamber/key_pair.rb
|
172
191
|
- lib/chamber/keys/base.rb
|
173
192
|
- lib/chamber/keys/decryption.rb
|
174
193
|
- lib/chamber/keys/encryption.rb
|
175
194
|
- lib/chamber/namespace_set.rb
|
176
195
|
- lib/chamber/rails.rb
|
177
|
-
- lib/chamber/rails/railtie.rb
|
178
196
|
- lib/chamber/rubinius_fix.rb
|
179
197
|
- lib/chamber/settings.rb
|
180
198
|
- lib/chamber/types/secured.rb
|
metadata.gz.sig
CHANGED
Binary file
|