diff --git a/files/gitlab-cookbooks/consul/attributes/default.rb b/files/gitlab-cookbooks/consul/attributes/default.rb index 4cdcf1d849d0d32a5cc52a8e9c950f7f1997a67a_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9jb25zdWwvYXR0cmlidXRlcy9kZWZhdWx0LnJi..5a9bbb0a407f958e8777cd339694bdbd44af15a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9jb25zdWwvYXR0cmlidXRlcy9kZWZhdWx0LnJi 100644 --- a/files/gitlab-cookbooks/consul/attributes/default.rb +++ b/files/gitlab-cookbooks/consul/attributes/default.rb @@ -22,3 +22,7 @@ postgresql_warning: "-*agent: Check 'service:postgresql' is now critical" } default['consul']['monitoring_service_discovery'] = false + +default['consul']['encryption_key'] = nil +default['consul']['encryption_verify_incoming'] = nil +default['consul']['encryption_verify_outgoing'] = nil diff --git a/files/gitlab-cookbooks/consul/libraries/consul_helper.rb b/files/gitlab-cookbooks/consul/libraries/consul_helper.rb index 4cdcf1d849d0d32a5cc52a8e9c950f7f1997a67a_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9jb25zdWwvbGlicmFyaWVzL2NvbnN1bF9oZWxwZXIucmI=..5a9bbb0a407f958e8777cd339694bdbd44af15a2_ZmlsZXMvZ2l0bGFiLWNvb2tib29rcy9jb25zdWwvbGlicmFyaWVzL2NvbnN1bF9oZWxwZXIucmI= 100644 --- a/files/gitlab-cookbooks/consul/libraries/consul_helper.rb +++ b/files/gitlab-cookbooks/consul/libraries/consul_helper.rb @@ -19,7 +19,7 @@ 'node_name' => node['consul']['node_name'] || node['fqdn'], 'rejoin_after_leave' => true, 'server' => false - } + }.merge(encryption_configuration) @default_server_configuration = { 'bootstrap_expect' => 3 } @@ -54,6 +54,22 @@ config.to_json end + def use_encryption? + encryption_key = node['consul']['encryption_key'] + + !encryption_key.nil? && !encryption_key.empty? + end + + def encryption_configuration + return {} unless use_encryption? + + { + 'encrypt' => node['consul']['encryption_key'], + 'encrypt_verify_incoming' => node['consul']['encryption_verify_incoming'], + 'encrypt_verify_outgoing' => node['consul']['encryption_verify_outgoing'] + }.compact + end + def api_url %w[https http].each do |scheme| port = api_port(scheme) diff --git a/files/gitlab-ctl-commands-ee/lib/consul.rb b/files/gitlab-ctl-commands-ee/lib/consul.rb index 4cdcf1d849d0d32a5cc52a8e9c950f7f1997a67a_ZmlsZXMvZ2l0bGFiLWN0bC1jb21tYW5kcy1lZS9saWIvY29uc3VsLnJi..5a9bbb0a407f958e8777cd339694bdbd44af15a2_ZmlsZXMvZ2l0bGFiLWN0bC1jb21tYW5kcy1lZS9saWIvY29uc3VsLnJi 100644 --- a/files/gitlab-ctl-commands-ee/lib/consul.rb +++ b/files/gitlab-ctl-commands-ee/lib/consul.rb @@ -15,6 +15,21 @@ command.send(subcommand, input) end + class << self + def run_consul(cmd) + command = Mixlib::ShellOut.new("/opt/gitlab/embedded/bin/consul #{cmd}") + command.run_command + begin + command.error! + rescue StandardError => e + puts e + puts command.stderr + raise ConsulError, "#{e}: #{command.stderr}" + end + command.stdout + end + end + class Kv class << self def put(key, value = nil) @@ -18,7 +33,7 @@ class Kv class << self def put(key, value = nil) - run_consul("kv put #{key} #{value}") + ConsulHandler.run_consul("kv put #{key} #{value}") end def delete(key) @@ -22,7 +37,7 @@ end def delete(key) - run_consul("kv delete #{key}") + ConsulHandler.run_consul("kv delete #{key}") end def get(key) @@ -26,5 +41,5 @@ end def get(key) - run_consul("kv get #{key}") + ConsulHandler.run_consul("kv get #{key}") end @@ -30,4 +45,4 @@ end - - protected + end + end @@ -33,15 +48,8 @@ - def run_consul(cmd) - command = Mixlib::ShellOut.new("/opt/gitlab/embedded/bin/consul #{cmd}") - command.run_command - begin - command.error! - rescue StandardError => e - puts e - puts command.stderr - raise ConsulError, "#{e}: #{command.stderr}" - end - command.stdout + class Encrypt + class << self + def keygen + ConsulHandler.run_consul("keygen") end end end diff --git a/spec/chef/consul/recipes/consul_spec.rb b/spec/chef/consul/recipes/consul_spec.rb index 4cdcf1d849d0d32a5cc52a8e9c950f7f1997a67a_c3BlYy9jaGVmL2NvbnN1bC9yZWNpcGVzL2NvbnN1bF9zcGVjLnJi..5a9bbb0a407f958e8777cd339694bdbd44af15a2_c3BlYy9jaGVmL2NvbnN1bC9yZWNpcGVzL2NvbnN1bF9zcGVjLnJi 100644 --- a/spec/chef/consul/recipes/consul_spec.rb +++ b/spec/chef/consul/recipes/consul_spec.rb @@ -168,4 +168,56 @@ end end end + + describe 'encryption' do + it 'is not enabled by default' do + stub_gitlab_rb( + consul: { + enable: true, + } + ) + + expect(chef_run).to render_file(consul_conf).with_content { |content| + expect(content).not_to match(%r{"encrypt":}) + expect(content).not_to match(%r{"encrypt_verify_incoming":}) + expect(content).not_to match(%r{"encrypt_verify_outgoing":}) + } + end + + context 'new datacenter' do + it 'uses encryption key and falls back to defaults' do + stub_gitlab_rb( + consul: { + enable: true, + encryption_key: 'fake_key' + } + ) + + expect(chef_run).to render_file(consul_conf).with_content { |content| + expect(content).to match(%r{"encrypt":"fake_key"}) + expect(content).not_to match(%r{"encrypt_verify_incoming":}) + expect(content).not_to match(%r{"encrypt_verify_outgoing":}) + } + end + end + + context 'existing datacenter' do + it 'uses encryption key and specified verification settings' do + stub_gitlab_rb( + consul: { + enable: true, + encryption_key: 'fake_key', + encryption_verify_incoming: false, + encryption_verify_outgoing: true, + } + ) + + expect(chef_run).to render_file(consul_conf).with_content { |content| + expect(content).to match(%r{"encrypt":"fake_key"}) + expect(content).to match(%r{"encrypt_verify_incoming":false}) + expect(content).to match(%r{"encrypt_verify_outgoing":true}) + } + end + end + end end diff --git a/spec/gitlab-ctl-commands-ee/lib/consul_spec.rb b/spec/gitlab-ctl-commands-ee/lib/consul_spec.rb index 4cdcf1d849d0d32a5cc52a8e9c950f7f1997a67a_c3BlYy9naXRsYWItY3RsLWNvbW1hbmRzLWVlL2xpYi9jb25zdWxfc3BlYy5yYg==..5a9bbb0a407f958e8777cd339694bdbd44af15a2_c3BlYy9naXRsYWItY3RsLWNvbW1hbmRzLWVlL2xpYi9jb25zdWxfc3BlYy5yYg== 100644 --- a/spec/gitlab-ctl-commands-ee/lib/consul_spec.rb +++ b/spec/gitlab-ctl-commands-ee/lib/consul_spec.rb @@ -22,5 +22,4 @@ instance.execute end end -end @@ -26,4 +25,3 @@ -RSpec.describe ConsulHandler::Kv do let(:consul_cmd) { '/opt/gitlab/embedded/bin/consul' } @@ -28,8 +26,35 @@ let(:consul_cmd) { '/opt/gitlab/embedded/bin/consul' } - it 'allows nil values' do - results = double('results', run_command: [], error!: nil, stdout: '') - expect(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv put foo ").and_return(results) - described_class.send(:put, 'foo') + describe ConsulHandler::Kv do + it 'allows nil values' do + results = double('results', run_command: [], error!: nil, stdout: '') + expect(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv put foo ").and_return(results) + described_class.send(:put, 'foo') + end + + describe '#get' do + context 'existing key' do + before do + results = double('results', run_command: [], error!: nil, stdout: 'bar') + allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv get foo").and_return(results) + end + + it 'returns the expected key' do + expect(described_class.get('foo')).to eq('bar') + end + end + + context 'non-existing key' do + before do + results = double('results', run_command: [], stdout: '', stderr: 'oops') + allow(results).to receive(:error!).and_raise(StandardError) + allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv get foo").and_return(results) + end + + it 'raises an error' do + expect { described_class.get('foo') }.to raise_error(ConsulHandler::ConsulError, 'StandardError: oops') + end + end + end end @@ -34,9 +59,9 @@ end - describe '#get' do - context 'existing key' do - before do - results = double('results', run_command: [], error!: nil, stdout: 'bar') - allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv get foo").and_return(results) - end + describe ConsulHandler::Encrypt do + describe '#keygen' do + it 'returns the generated key' do + generated_key = 'BYX6EPaUiUI0TDdm6gAMmmLnpJSwePJ33Xwh6rjCYbg=' + results = double('results', run_command: [], error!: nil, stdout: generated_key) + allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} keygen").and_return(results) @@ -42,14 +67,5 @@ - it 'returns the expected key' do - expect(described_class.get('foo')).to eq('bar') - end - end - - context 'non-existing key' do - before do - results = double('results', run_command: [], stdout: '', stderr: 'oops') - allow(results).to receive(:error!).and_raise(StandardError) - allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} kv get foo").and_return(results) + expect(described_class.keygen).to eq(generated_key) end it 'raises an error' do @@ -53,7 +69,11 @@ end it 'raises an error' do - expect { described_class.get('foo') }.to raise_error(ConsulHandler::ConsulError, 'StandardError: oops') + results = double('results', run_command: [], stdout: '', stderr: 'oops') + allow(results).to receive(:error!).and_raise(StandardError) + allow(Mixlib::ShellOut).to receive(:new).with("#{consul_cmd} keygen").and_return(results) + + expect { described_class.keygen }.to raise_error(ConsulHandler::ConsulError, 'StandardError: oops') end end end