Skip to content

Commit

Permalink
Merge pull request #58 from thedebugger/add_tls_support
Browse files Browse the repository at this point in the history
Add tls support
  • Loading branch information
johnbellone committed Nov 18, 2014
2 parents 2ee2df4 + 8031632 commit 5a4e1a4
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 0.5.0
* Add support for TLS, and gossip encryption

# 0.4.4
* Adds server list to a consul instance running as a cluster with a `bootstrap_expect` value greater than one.

Expand Down
121 changes: 121 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,126 @@ Installs and configures [Consul][1].
</td>
<td><tt>{}</tt></td>
</tr>
<tr>
<td><tt>['consul']['encrypt_enabled']</tt></td>
<td>Boolean</td>
<td>
To enable Consul gossip encryption
</td>
<td><tt>false</tt></td>
</tr>
<tr>
<td><tt>['consul']['verify_incoming']</tt></td>
<td>Boolean</td>
<td>
If set to True, Consul requires that all incoming connections make use of TLS.
</td>
<td><tt>false</tt></td>
</tr>
<tr>
<td><tt>['consul']['verify_outgoing']</tt></td>
<td>Boolean</td>
<td>
If set to True, Consul requires that all outgoing connections make use of TLS.
</td>
<td><tt>false</tt></td>
</tr>
<tr>
<td><tt>['consul']['key_file']</tt></td>
<td>String</td>
<td>
The content of PEM encoded private key
</td>
<td><tt>nil</tt></td>
</tr>
<tr>
<td><tt>['consul']['key_file_path']</tt></td>
<td>String</td>
<td>
Path where the private key is stored on the disk
</td>
<td><tt>/etc/consul.d/key.pem</tt></td>
</tr>
<tr>
<td><tt>['consul']['ca_file']</tt></td>
<td>String</td>
The content of PEM encoded ca cert
<td>
</td>
<td><tt>nil</tt></td>
</tr>
<tr>
<td><tt>['consul']['ca_file_path']</tt></td>
<td>String</td>
<td>
Path where ca is stored on the disk
</td>
<td><tt>/etc/consul.d/ca.pem</tt></td>
</tr>
<tr>
<td><tt>['consul']['cert_file']</tt></td>
<td>String</td>
<td>
The content of PEM encoded cert. It should only contain the public key.
</td>
<td><tt>nil</tt></td>
</tr>
<tr>
<td><tt>['consul']['cert_file_path']</tt></td>
<td>String</td>
<td>
Path where cert is stored on the disk
</td>
<td><tt>/etc/consul.d/cert.pem</tt></td>
</tr>
</table>

### Databag Attributes (optional)
Following attributes, if exist in the [encrypted databag][7], override the node attributes

<table>
<tr>
<th>Key</th>
<th>Databag item</th>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td><tt>key_file</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>The content of PEM encoded private key</td>
</tr>
<tr>
<td><tt>key_file_{fqdn}</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>Node's(identified by fqdn) unique PEM encoded private key. If it exists, it will override the databag and node key_file attribute</td>
</tr>
<tr>
<td><tt>ca_file</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>The content of PEM encoded ca cert</td>
</tr>
<tr>
<td><tt>encrypt</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>Consul Gossip encryption key</td>
</tr>
<tr>
<td><tt>cert_file</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>The content of PEM encoded cert</td>
</tr>
<tr>
<td><tt>cert_file_{fqdn}</tt></td>
<td>['consul']['encrypt']</td>
<td>String</td>
<td>Node's(identified by fqdn) unique PEM encoded cert. If it exists, it will override the databag and node cert_file attribute</td>
</tr>
</table>

### Consul UI Attributes
Expand Down Expand Up @@ -320,3 +439,5 @@ Created and maintained by [John Bellone][3] [@johnbellone][2] (<jbellone@bloombe
[4]: https://github.com/johnbellone/consul-cookbook/graphs/contributors
[5]: http://travis-ci.org/johnbellone/consul-cookbook
[6]: https://coveralls.io/r/johnbellone/consul-cookbook
[7]: https://docs.getchef.com/essentials_data_bags.html

17 changes: 17 additions & 0 deletions attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@

# Service attributes
default['consul']['service_mode'] = 'bootstrap'
# In the cluster mode, set the default cluster size to 3
default['consul']['bootstrap_expect'] = 3
default['consul']['data_dir'] = '/var/lib/consul'
default['consul']['config_dir'] = '/etc/consul.d'
case node['platform_family']
Expand All @@ -69,6 +71,21 @@
"server" => 8300,
}

# Gossip encryption
default['consul']['encrypt_enabled'] = false
default['consul']['encrypt'] = nil
# TLS support
default['consul']['verify_incoming'] = false
default['consul']['verify_outgoing'] = false
# Cert in pem format
default['consul']['ca_cert'] = nil
default['consul']['ca_path'] = "%{config_dir}/ca.pem"
default['consul']['cert_file'] = nil
default['consul']['cert_path'] = "%{config_dir}/cert.pem"
# Cert in pem format. It can be unique for each host
default['consul']['key_file'] = nil
default['consul']['key_file_path'] = "%{config_dir}/key.pem"

# Optionally bind to a specific interface
default['consul']['bind_interface'] = nil
default['consul']['advertise_interface'] = nil
Expand Down
21 changes: 21 additions & 0 deletions libraries/encrypt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class Chef
class Recipe
# Don't throw the error if it doesn't exist
def consul_encrypted_dbi
begin
# loads the secret from /etc/chef/encrypted_data_bag_secret
Chef::EncryptedDataBagItem.load('consul', 'encrypt')
rescue Net::HTTPServerException => e
raise e unless e.response.code == '404'
end
end

def consul_dbi_key_with_node_default(dbi, key)
value = dbi[key]
Chef::Log.warn "Consul encrypt key=#{key} doesn't exist in the databag. \
Reading it from node's attributes" if value.nil?
value ||= node['consul'][key]
value
end
end
end
49 changes: 48 additions & 1 deletion recipes/_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@
end

copy_params = [
:bind_addr, :datacenter, :domain, :log_level, :node_name, :advertise_addr, :ports, :enable_syslog, :encrypt
:bind_addr, :datacenter, :domain, :log_level, :node_name, :advertise_addr, :ports, :enable_syslog
]
copy_params.each do |key|
if node['consul'][key]
Expand All @@ -123,6 +123,53 @@
end
end

dbi = nil
# Gossip encryption
if node.consul.encrypt_enabled
# Fetch the databag only once, and use empty hash if it doesn't exists
dbi = consul_encrypted_dbi || {}
secret = consul_dbi_key_with_node_default(dbi, 'encrypt')
raise "Consul encrypt key is empty or nil" if secret.nil? or secret.empty?
service_config['encrypt'] = secret
else
# for backward compatibilty
service_config['encrypt'] = node.consul.encrypt unless node.consul.encrypt.nil?
end

# TLS encryption
if node.consul.verify_incoming || node.consul.verify_outgoing
dbi = consul_encrypted_dbi || {} if dbi.nil?
service_config['verify_outgoing'] = node.consul.verify_outgoing
service_config['verify_incoming'] = node.consul.verify_incoming

ca_path = node.consul.ca_path % { config_dir: node.consul.config_dir }
service_config['ca_file'] = ca_path

cert_path = node.consul.cert_path % { config_dir: node.consul.config_dir }
service_config['cert_file'] = cert_path

key_path = node.consul.key_file_path % { config_dir: node.consul.config_dir }
service_config['key_file'] = key_path

# Search for key_file_hostname since key and cert file can be unique/host
key_content = dbi['key_file_' + node.fqdn] || consul_dbi_key_with_node_default(dbi, 'key_file')
cert_content = dbi['cert_file_' + node.fqdn] || consul_dbi_key_with_node_default(dbi, 'cert_file')
ca_content = consul_dbi_key_with_node_default(dbi, 'ca_cert')

# Save the certs if exists
{ca_path => ca_content, key_path => key_content, cert_path => cert_content}.each do |path, content|
unless content.nil? or content.empty?
file path do
user consul_user
group consul_group
mode 0600
action :create
content content
end
end
end
end

consul_config_filename = File.join(node['consul']['config_dir'], 'default.json')

file consul_config_filename do
Expand Down
Loading

0 comments on commit 5a4e1a4

Please sign in to comment.