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