chamber 2.10.2 → 2.11.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/LICENSE.txt +1 -1
- data/lib/chamber.rb +3 -6
- data/lib/chamber/binary/heroku.rb +1 -0
- data/lib/chamber/binary/runner.rb +29 -13
- data/lib/chamber/binary/travis.rb +1 -0
- data/lib/chamber/commands/base.rb +10 -9
- data/lib/chamber/commands/comparable.rb +1 -0
- data/lib/chamber/commands/compare.rb +8 -7
- data/lib/chamber/commands/files.rb +1 -0
- data/lib/chamber/commands/heroku.rb +1 -0
- data/lib/chamber/commands/heroku/clear.rb +2 -1
- data/lib/chamber/commands/heroku/compare.rb +1 -0
- data/lib/chamber/commands/heroku/pull.rb +3 -4
- data/lib/chamber/commands/heroku/push.rb +1 -0
- data/lib/chamber/commands/initialize.rb +88 -76
- data/lib/chamber/commands/securable.rb +3 -2
- data/lib/chamber/commands/secure.rb +3 -1
- data/lib/chamber/commands/show.rb +7 -6
- data/lib/chamber/commands/travis.rb +1 -0
- data/lib/chamber/commands/travis/secure.rb +1 -0
- data/lib/chamber/configuration.rb +14 -13
- data/lib/chamber/context_resolver.rb +52 -55
- data/lib/chamber/encryption_methods/none.rb +4 -2
- data/lib/chamber/encryption_methods/public_key.rb +4 -2
- data/lib/chamber/encryption_methods/ssl.rb +11 -9
- data/lib/chamber/errors/decryption_failure.rb +1 -0
- data/lib/chamber/file.rb +27 -18
- data/lib/chamber/file_set.rb +14 -13
- data/lib/chamber/filters/decryption_filter.rb +48 -18
- data/lib/chamber/filters/encryption_filter.rb +32 -22
- data/lib/chamber/filters/environment_filter.rb +109 -16
- data/lib/chamber/filters/failed_decryption_filter.rb +10 -8
- data/lib/chamber/filters/insecure_filter.rb +1 -0
- data/lib/chamber/filters/namespace_filter.rb +8 -7
- data/lib/chamber/filters/secure_filter.rb +10 -9
- data/lib/chamber/filters/translate_secure_keys_filter.rb +10 -9
- data/lib/chamber/instance.rb +5 -4
- data/lib/chamber/key_pair.rb +82 -0
- data/lib/chamber/keys/base.rb +64 -0
- data/lib/chamber/keys/decryption.rb +41 -0
- data/lib/chamber/keys/encryption.rb +41 -0
- data/lib/chamber/namespace_set.rb +10 -9
- data/lib/chamber/rails.rb +1 -0
- data/lib/chamber/rails/railtie.rb +1 -0
- data/lib/chamber/rubinius_fix.rb +1 -0
- data/lib/chamber/settings.rb +45 -41
- data/lib/chamber/types/secured.rb +14 -12
- data/lib/chamber/version.rb +2 -1
- metadata +28 -27
- metadata.gz.sig +0 -0
- data/lib/chamber/decryption_key.rb +0 -52
- data/lib/chamber/environmentable.rb +0 -27
- data/lib/chamber/filters/boolean_conversion_filter.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 212f658524053ccae210207899aaadd11fca8dc3
|
4
|
+
data.tar.gz: 2ab2300b8a8a0107f7c094b79e344209f24a385a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d90c504c34d974a5d915aa1eb63f5c5c1c6dff4cf7fda43a072b2464e04d6d11ecacf196d921a5ecb9c2521a685a6199421abcfb6dad90c62f149cba277a273
|
7
|
+
data.tar.gz: d9168743dc703563e8e5ef86f4fb5fce13d00a3d6a7c590a7147d0902d2f8e73df7957fb070f8ce7d5541b483a7c5f8d94bf7b350ec56ab63a8d5ef58f27f357
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/LICENSE.txt
CHANGED
data/lib/chamber.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'chamber/rubinius_fix'
|
3
4
|
require 'chamber/instance'
|
4
5
|
require 'chamber/rails'
|
5
6
|
|
6
7
|
module Chamber
|
8
|
+
attr_writer :instance
|
9
|
+
|
7
10
|
def load(options = {})
|
8
11
|
self.instance = Instance.new(options)
|
9
12
|
end
|
@@ -16,16 +19,10 @@ module Chamber
|
|
16
19
|
instance.settings
|
17
20
|
end
|
18
21
|
|
19
|
-
protected
|
20
|
-
|
21
|
-
attr_accessor :instance
|
22
|
-
|
23
22
|
def instance
|
24
23
|
@instance ||= Instance.new({})
|
25
24
|
end
|
26
25
|
|
27
|
-
public
|
28
|
-
|
29
26
|
def method_missing(name, *args)
|
30
27
|
return instance.public_send(name, *args) if instance.respond_to?(name)
|
31
28
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'thor'
|
3
4
|
require 'chamber/rubinius_fix'
|
4
5
|
require 'chamber/binary/travis'
|
@@ -46,22 +47,28 @@ class Runner < Thor
|
|
46
47
|
desc: 'Used to quickly assign a given scenario to the chamber ' \
|
47
48
|
'command (eg Rails apps)'
|
48
49
|
|
49
|
-
class_option :
|
50
|
-
type: :
|
51
|
-
desc: 'The path to or contents of the private key associated
|
52
|
-
'the project (typically .chamber.pem)'
|
50
|
+
class_option :decryption_keys,
|
51
|
+
type: :array,
|
52
|
+
desc: 'The path to or contents of the private key (or keys) associated ' \
|
53
|
+
'with the project (typically .chamber.pem)'
|
54
|
+
|
55
|
+
class_option :encryption_keys,
|
56
|
+
type: :array,
|
57
|
+
desc: 'The path to or contents of the public key (or keys) associated ' \
|
58
|
+
'with the project (typically .chamber.pub.pem)'
|
53
59
|
|
54
|
-
|
55
|
-
type: :string,
|
56
|
-
desc: 'The path to or contents of the public key associated with ' \
|
57
|
-
'the project (typically .chamber.pub.pem)'
|
60
|
+
################################################################################
|
58
61
|
|
59
62
|
desc 'travis SUBCOMMAND ...ARGS', 'For manipulating Travis CI environment variables'
|
60
63
|
subcommand 'travis', Chamber::Binary::Travis
|
61
64
|
|
65
|
+
################################################################################
|
66
|
+
|
62
67
|
desc 'heroku SUBCOMMAND ...ARGS', 'For manipulating Heroku environment variables'
|
63
68
|
subcommand 'heroku', Chamber::Binary::Heroku
|
64
69
|
|
70
|
+
################################################################################
|
71
|
+
|
65
72
|
desc 'show', 'Displays the list of settings and their values'
|
66
73
|
|
67
74
|
method_option :as_env,
|
@@ -70,8 +77,6 @@ class Runner < Thor
|
|
70
77
|
desc: 'Whether the displayed settings should be environment ' \
|
71
78
|
'variable compatible'
|
72
79
|
|
73
|
-
desc 'only_sensitive', 'Only show secured/securable settings'
|
74
|
-
|
75
80
|
method_option :only_sensitive,
|
76
81
|
type: :boolean,
|
77
82
|
aliases: '-s',
|
@@ -82,13 +87,20 @@ class Runner < Thor
|
|
82
87
|
puts Commands::Show.call(options.merge(shell: self))
|
83
88
|
end
|
84
89
|
|
90
|
+
################################################################################
|
91
|
+
|
85
92
|
desc 'files', 'Lists the settings files which are parsed with the given options'
|
93
|
+
|
86
94
|
def files
|
87
95
|
puts Commands::Files.call(options.merge(shell: self))
|
88
96
|
end
|
89
97
|
|
90
|
-
|
91
|
-
|
98
|
+
################################################################################
|
99
|
+
|
100
|
+
desc 'compare', 'Displays the difference between the settings in the first set ' \
|
101
|
+
'of namespaces and the settings in the second set. Useful for ' \
|
102
|
+
'tracking down why there may be issues in development versus test ' \
|
103
|
+
'or differences between staging and production.'
|
92
104
|
|
93
105
|
method_option :keys_only,
|
94
106
|
type: :boolean,
|
@@ -110,6 +122,8 @@ class Runner < Thor
|
|
110
122
|
Commands::Compare.call(options.merge(shell: self))
|
111
123
|
end
|
112
124
|
|
125
|
+
################################################################################
|
126
|
+
|
113
127
|
desc 'secure', 'Secures any values which appear to need to be encrypted in any of ' \
|
114
128
|
'the settings files which match irrespective of namespaces'
|
115
129
|
|
@@ -127,7 +141,9 @@ class Runner < Thor
|
|
127
141
|
Commands::Secure.call(options.merge(shell: self))
|
128
142
|
end
|
129
143
|
|
130
|
-
|
144
|
+
################################################################################
|
145
|
+
|
146
|
+
desc 'init', 'Sets Chamber up using best practices for secure configuration ' \
|
131
147
|
'management'
|
132
148
|
|
133
149
|
def init
|
@@ -1,28 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'pathname'
|
3
4
|
require 'chamber/instance'
|
4
5
|
|
5
6
|
module Chamber
|
6
7
|
module Commands
|
7
8
|
class Base
|
8
|
-
def initialize(options = {})
|
9
|
-
self.chamber = Chamber::Instance.new options
|
10
|
-
self.shell = options[:shell]
|
11
|
-
self.rootpath = options[:rootpath]
|
12
|
-
self.dry_run = options[:dry_run]
|
13
|
-
end
|
14
|
-
|
15
9
|
def self.call(options = {})
|
16
10
|
new(options).call
|
17
11
|
end
|
18
12
|
|
19
|
-
protected
|
20
|
-
|
21
13
|
attr_accessor :chamber,
|
22
14
|
:shell,
|
23
15
|
:dry_run
|
24
16
|
attr_reader :rootpath
|
25
17
|
|
18
|
+
def initialize(options = {})
|
19
|
+
self.chamber = Chamber::Instance.new options
|
20
|
+
self.shell = options[:shell]
|
21
|
+
self.rootpath = options[:rootpath]
|
22
|
+
self.dry_run = options[:dry_run]
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
26
27
|
def rootpath=(other)
|
27
28
|
@rootpath ||= Pathname.new(other)
|
28
29
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'chamber/instance'
|
3
4
|
require 'chamber/commands/base'
|
4
5
|
require 'chamber/commands/comparable'
|
@@ -8,6 +9,13 @@ module Commands
|
|
8
9
|
class Compare < Chamber::Commands::Base
|
9
10
|
include Chamber::Commands::Comparable
|
10
11
|
|
12
|
+
attr_accessor :first_settings_instance,
|
13
|
+
:second_settings_instance
|
14
|
+
|
15
|
+
def self.call(options = {})
|
16
|
+
new(options).call
|
17
|
+
end
|
18
|
+
|
11
19
|
def initialize(options = {})
|
12
20
|
super
|
13
21
|
|
@@ -18,15 +26,8 @@ class Compare < Chamber::Commands::Base
|
|
18
26
|
self.second_settings_instance = Chamber::Instance.new(second_settings_options)
|
19
27
|
end
|
20
28
|
|
21
|
-
def self.call(options = {})
|
22
|
-
new(options).call
|
23
|
-
end
|
24
|
-
|
25
29
|
protected
|
26
30
|
|
27
|
-
attr_accessor :first_settings_instance,
|
28
|
-
:second_settings_instance
|
29
|
-
|
30
31
|
def first_settings_data
|
31
32
|
settings_data(first_settings_instance)
|
32
33
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'chamber/commands/base'
|
3
4
|
require 'chamber/commands/heroku'
|
4
5
|
|
@@ -9,7 +10,7 @@ class Clear < Chamber::Commands::Base
|
|
9
10
|
include Chamber::Commands::Heroku
|
10
11
|
|
11
12
|
def call
|
12
|
-
chamber.to_environment.
|
13
|
+
chamber.to_environment.each_key do |key|
|
13
14
|
next unless configuration.match(key)
|
14
15
|
|
15
16
|
if dry_run
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'chamber/commands/base'
|
3
4
|
require 'chamber/commands/heroku'
|
4
5
|
|
@@ -8,6 +9,8 @@ module Heroku
|
|
8
9
|
class Pull < Chamber::Commands::Base
|
9
10
|
include Chamber::Commands::Heroku
|
10
11
|
|
12
|
+
attr_accessor :target_file
|
13
|
+
|
11
14
|
def initialize(options = {})
|
12
15
|
super
|
13
16
|
|
@@ -21,10 +24,6 @@ class Pull < Chamber::Commands::Base
|
|
21
24
|
configuration
|
22
25
|
end
|
23
26
|
end
|
24
|
-
|
25
|
-
protected
|
26
|
-
|
27
|
-
attr_accessor :target_file
|
28
27
|
end
|
29
28
|
end
|
30
29
|
end
|
@@ -1,71 +1,128 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'pathname'
|
3
4
|
require 'fileutils'
|
4
5
|
require 'openssl'
|
6
|
+
require 'securerandom'
|
5
7
|
require 'chamber/configuration'
|
8
|
+
require 'chamber/key_pair'
|
6
9
|
require 'chamber/commands/base'
|
7
10
|
|
8
11
|
module Chamber
|
9
12
|
module Commands
|
10
13
|
class Initialize < Chamber::Commands::Base
|
14
|
+
def self.call(options = {})
|
15
|
+
new(options).call
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :basepath,
|
19
|
+
:namespaces
|
20
|
+
|
11
21
|
def initialize(options = {})
|
12
22
|
super
|
13
23
|
|
14
|
-
self.basepath
|
24
|
+
self.basepath = Chamber.configuration.basepath
|
25
|
+
self.namespaces = options.fetch(:namespaces, [])
|
15
26
|
end
|
16
27
|
|
17
28
|
# rubocop:disable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
|
18
29
|
def call
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
`chmod 644 #{public_key_filepath}`
|
30
|
+
key_pairs = namespaces.map do |namespace|
|
31
|
+
Chamber::KeyPair.new(namespace: namespace,
|
32
|
+
key_file_path: rootpath)
|
33
|
+
end
|
34
|
+
key_pairs << Chamber::KeyPair.new(namespace: nil,
|
35
|
+
key_file_path: rootpath)
|
26
36
|
|
27
|
-
|
37
|
+
key_pairs.each { |key_pair| generate_key_pair(key_pair) }
|
28
38
|
|
29
|
-
|
30
|
-
shell.append_to_file gitignore_filepath, "\n# Private and protected key files for Chamber\n"
|
31
|
-
shell.append_to_file gitignore_filepath, "#{private_key_filename}\n"
|
32
|
-
shell.append_to_file gitignore_filepath, "#{protected_key_filename}\n"
|
33
|
-
end
|
39
|
+
append_to_gitignore
|
34
40
|
|
35
41
|
shell.copy_file settings_template_filepath, settings_filepath
|
36
42
|
|
37
43
|
shell.say ''
|
38
|
-
shell.say '
|
44
|
+
shell.say '********************************************************************************', :green
|
45
|
+
shell.say ' Success!', :green
|
46
|
+
shell.say '********************************************************************************', :green
|
47
|
+
shell.say ''
|
48
|
+
|
49
|
+
shell.say '.chamber.pem is a DEFAULT Chamber key.', :red
|
50
|
+
shell.say ''
|
51
|
+
shell.say 'If you would like a key which is used only for things such as a certain'
|
52
|
+
shell.say 'environment (such as production), or your local machine, you can rerun'
|
53
|
+
shell.say 'the command like so:'
|
54
|
+
shell.say ''
|
55
|
+
shell.say '$ chamber init --namespaces="production my_machines_hostname"', :yellow
|
39
56
|
shell.say ''
|
40
|
-
|
57
|
+
|
58
|
+
shell.say 'The passphrase for your encrypted private key(s) are:'
|
41
59
|
shell.say ''
|
42
|
-
|
60
|
+
|
61
|
+
key_pairs.each do |key_pair|
|
62
|
+
shell.say "* #{key_pair.encrypted_private_key_filename}: "
|
63
|
+
shell.say key_pair.passphrase, :yellow
|
64
|
+
end
|
65
|
+
|
43
66
|
shell.say ''
|
44
|
-
shell.say '
|
67
|
+
shell.say 'Store these securely somewhere.'
|
45
68
|
shell.say ''
|
46
|
-
shell.say
|
69
|
+
shell.say 'You can send your team members any of the file(s) located at:'
|
70
|
+
shell.say ''
|
71
|
+
|
72
|
+
key_pairs.each do |key_pair|
|
73
|
+
shell.say '* '
|
74
|
+
shell.say key_pair.encrypted_private_key_filepath, :yellow
|
75
|
+
end
|
76
|
+
|
47
77
|
shell.say ''
|
48
|
-
shell.say 'and not have to worry about sending it via a secure medium (such as'
|
49
|
-
shell.say 'email), however do not send the passphrase along with it. Give it to'
|
50
|
-
shell.say 'your team members in person.'
|
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.'
|
51
81
|
shell.say ''
|
52
|
-
shell.say 'In order for them to decrypt it (for use with Chamber), they can
|
82
|
+
shell.say 'In order for them to decrypt it (for use with Chamber), they can use something'
|
83
|
+
shell.say 'like the following (swapping out the actual key filenames if necessary):'
|
53
84
|
shell.say ''
|
54
|
-
shell.say "$ cp
|
55
|
-
shell.say "$ ssh-keygen -p -f
|
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
|
56
87
|
shell.say ''
|
57
|
-
shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.'
|
88
|
+
shell.say 'Enter the passphrase when prompted and leave the new passphrase blank.'
|
58
89
|
shell.say ''
|
59
90
|
end
|
60
91
|
# rubocop:enable Metrics/LineLength, Metrics/MethodLength, Metrics/AbcSize
|
61
92
|
|
62
|
-
|
63
|
-
|
93
|
+
protected
|
94
|
+
|
95
|
+
def generate_key_pair(key_pair)
|
96
|
+
shell.create_file key_pair.unencrypted_private_key_filepath,
|
97
|
+
key_pair.unencrypted_private_key_pem,
|
98
|
+
skip: true
|
99
|
+
shell.create_file key_pair.encrypted_private_key_filepath,
|
100
|
+
key_pair.encrypted_private_key_pem,
|
101
|
+
skip: true
|
102
|
+
shell.create_file key_pair.public_key_filepath,
|
103
|
+
key_pair.public_key_pem,
|
104
|
+
skip: true
|
105
|
+
|
106
|
+
`chmod 600 #{key_pair.unencrypted_private_key_filepath}`
|
107
|
+
`chmod 600 #{key_pair.encrypted_private_key_filepath}`
|
108
|
+
`chmod 644 #{key_pair.public_key_filepath}`
|
64
109
|
end
|
65
110
|
|
66
|
-
|
111
|
+
# rubocop:disable Style/GuardClause
|
112
|
+
def append_to_gitignore
|
113
|
+
::FileUtils.touch gitignore_filepath
|
114
|
+
|
115
|
+
gitignore_contents = ::File.read(gitignore_filepath)
|
67
116
|
|
68
|
-
|
117
|
+
unless gitignore_contents =~ /^\.chamber\*\.enc$/
|
118
|
+
shell.append_to_file gitignore_filepath, ".chamber*.enc\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
unless gitignore_contents =~ /^\.chamber\*\.pem$/
|
122
|
+
shell.append_to_file gitignore_filepath, ".chamber*.pem\n"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# rubocop:enable Style/GuardClause
|
69
126
|
|
70
127
|
def settings_template_filepath
|
71
128
|
@settings_template_filepath ||= templates_path + 'settings.yml'
|
@@ -78,7 +135,7 @@ class Initialize < Chamber::Commands::Base
|
|
78
135
|
def gem_path
|
79
136
|
@gem_path ||= Pathname.new(
|
80
137
|
::File.expand_path('../../../..', __FILE__),
|
81
|
-
|
138
|
+
)
|
82
139
|
end
|
83
140
|
|
84
141
|
def settings_filepath
|
@@ -88,51 +145,6 @@ class Initialize < Chamber::Commands::Base
|
|
88
145
|
def gitignore_filepath
|
89
146
|
@gitignore_filepath ||= rootpath + '.gitignore'
|
90
147
|
end
|
91
|
-
|
92
|
-
def protected_key_filepath
|
93
|
-
@protected_key_filepath ||= rootpath + protected_key_filename
|
94
|
-
end
|
95
|
-
|
96
|
-
def private_key_filepath
|
97
|
-
@private_key_filepath ||= rootpath + private_key_filename
|
98
|
-
end
|
99
|
-
|
100
|
-
def public_key_filepath
|
101
|
-
@public_key_filepath ||= rootpath + public_key_filename
|
102
|
-
end
|
103
|
-
|
104
|
-
def protected_key_filename
|
105
|
-
'.chamber.pem.enc'
|
106
|
-
end
|
107
|
-
|
108
|
-
def private_key_filename
|
109
|
-
'.chamber.pem'
|
110
|
-
end
|
111
|
-
|
112
|
-
def public_key_filename
|
113
|
-
'.chamber.pub.pem'
|
114
|
-
end
|
115
|
-
|
116
|
-
def rsa_protected_key
|
117
|
-
@rsa_protected_key ||= begin
|
118
|
-
cipher = OpenSSL::Cipher.new 'AES-128-CBC'
|
119
|
-
key = OpenSSL::PKey::RSA.new(2048)
|
120
|
-
|
121
|
-
key.export cipher, rsa_key_passphrase
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def rsa_private_key
|
126
|
-
@rsa_private_key ||= OpenSSL::PKey::RSA.new(2048)
|
127
|
-
end
|
128
|
-
|
129
|
-
def rsa_public_key
|
130
|
-
rsa_private_key.public_key
|
131
|
-
end
|
132
|
-
|
133
|
-
def rsa_key_passphrase
|
134
|
-
@rsa_key_passphrase ||= SecureRandom.uuid
|
135
|
-
end
|
136
148
|
end
|
137
149
|
end
|
138
150
|
end
|