From 57f2b23d35abf46187a87f7f9f8ff94ea91dbefe Mon Sep 17 00:00:00 2001 From: Imtiaz Chowdhury Date: Sat, 18 Apr 2015 06:32:23 -0700 Subject: [PATCH] Make SSL settings configurable for Glance This commit allows enabling SSL for glance-api and registry endpoints by adding few new node attributes. Glance API and registry configuration files are also modified to use these node attributes. With these changes, users can easily enable SSL - both in secure and insecure mode. However, it is user's responsibility to generate and provide location of SSL certificate and its key. Closes-Bug #1445773 Change-Id: I1d0f776efb392e058bc3dbf0ee5223512b60f584 --- README.md | 11 +++ attributes/default.rb | 15 ++++ spec/api_spec.rb | 82 ++++++++++++++++++++++ spec/registry_spec.rb | 48 +++++++++++++ spec/spec_helper.rb | 12 ++++ templates/default/glance-api.conf.erb | 33 ++++++--- templates/default/glance-registry.conf.erb | 12 ++-- 7 files changed, 198 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a6e1bc1..99cf413 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,16 @@ Attributes for the Image service are in the ['openstack']['image'] namespace. * `openstack['image']['cron']['redirection']` - Redirection of cron output TODO: Add DB2 support on other platforms +SSL attributes +--------------- + +* `openstack['image']['ssl']['enabled']` - Enable SSL for Glance API and registry endpoints. NOTE: Once enabled, Glance service endpoint must be configured to use https on Keystone. Default is false. +* `openstack['image']['ssl']['basedir']` - Base directory for SSL certficate and key file. +* `openstack['image']['ssl']['cert_file']` - Path of the cert file for SSL. +* `openstack['image']['ssl']['key_file']` - Path of the keyfile for SSL. +* `openstack['image']['ssl']['cert_required']` - Client certificate required. Default is False. +* `openstack['image']['ssl']['ca_file']` - Path of the CA cert file + VMWare attributes ----------------- @@ -242,6 +252,7 @@ Author:: Chen Zhiwei (zhiwchen@cn.ibm.com) Author:: Eric Zhou (zyouzhou@cn.ibm.com) Author:: Jian Hua Geng (gengjh@cn.ibm.com) Author:: Ionut Artarisi (iartarisi@suse.cz) +Author:: Imtiaz Chowdhury () Copyright 2012, Rackspace US, Inc. Copyright 2012-2013, Opscode, Inc. diff --git a/attributes/default.rb b/attributes/default.rb index c07969e..f66caab 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -27,6 +27,21 @@ default['openstack']['image']['custom_template_banner'] = ' # Do not edit, changes will be overwritten ' +# SSL Options +# Enable SSL for glance-api endpoint. NOTE: Once enabled, Glance service endpoint +# must be set to https on Keystone +default['openstack']['image']['ssl']['enabled'] = false +# Base directory for SSL certficate and key +default['openstack']['image']['ssl']['basedir'] = '/etc/glance/ssl' +# Path of the cert file for SSL. +default['openstack']['image']['ssl']['cert_file'] = "#{node['openstack']['image']['ssl']['basedir']}/certs/sslcert.pem" +# Path of the keyfile for SSL. +default['openstack']['image']['ssl']['key_file'] = "#{node['openstack']['image']['ssl']['basedir']}/private/sslkey.pem" +# Specify server whether SSL certificate is required +default['openstack']['image']['ssl']['cert_required'] = false +# Path of the CA cert file for SSL. Only use if client certificate is required +default['openstack']['image']['ssl']['ca_file'] = "#{node['openstack']['image']['ssl']['basedir']}/certs/sslca.pem" + default['openstack']['image']['verbose'] = 'False' default['openstack']['image']['debug'] = 'False' # This is the name of the Chef role that will install the Keystone Service API diff --git a/spec/api_spec.rb b/spec/api_spec.rb index 2f1559d..2c1a88a 100644 --- a/spec/api_spec.rb +++ b/spec/api_spec.rb @@ -27,6 +27,7 @@ describe 'openstack-image::api' do runner.converge(described_recipe) end + include Helpers include_context 'image-stubs' include_examples 'common-logging-recipe' include_examples 'common-packages' @@ -93,6 +94,87 @@ describe 'openstack-image::api' do let(:file_name) { file.name } end + context 'glance-api configuration with ssl enabled' do + default_opts = { + cert_file: '/etc/glance/ssl/certs/sslcert.pem', + key_file: '/etc/glance/ssl/private/sslkey.pem' + } + + it 'configures SSL cert and key file' do + node.set['openstack']['image']['ssl']['enabled'] = true + default_opts.each do |key, val| + r = line_regexp("#{key} = #{val}") + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + end + + context 'glance-api configuration with ssl disabled' do + default_opts = { + cert_file: '/etc/glance/ssl/certs/sslcert.pem', + key_file: '/etc/glance/ssl/private/sslkey.pem' + } + it 'does not set cert or key file' do + default_opts.each do |key, val| + r = line_regexp("#{key} = #{val}") + expect(chef_run).not_to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + end + + context 'glance-registry configuration with ssl enabled' do + it 'sets registry client protocol to https' do + node.set['openstack']['image']['ssl']['enabled'] = true + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', /^registry_client_protocol = https$/) + end + + # if cert required then certfile + context 'glance-registry with cert required' do + it 'configures CA cert file' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['ssl']['cert_required'] = true + node.set['openstack']['image']['registry']['auth']['cafile'] = '/etc/glance/ssl/certs/sslca.pem' + r = line_regexp('registry_client_ca_file = /etc/glance/ssl/certs/sslca.pem') + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + + context 'glance-registry with cert not required' do + it 'does not configure CA cert file' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['ssl']['cert_required'] = false + node.set['openstack']['image']['registry']['auth']['cafile'] = '/etc/glance/ssl/certs/sslca.pem' + r = line_regexp('registry_client_ca_file = /etc/glance/ssl/certs/sslca.pem') + expect(chef_run).not_to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + + context 'glance-registry with certificate validation enabled' do + it 'enables SSL in insecure mode' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['registry']['auth']['insecure'] = false + r = line_regexp('registry_client_insecure = false') + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + + context 'glance-registry with certificate validation disabled' do + it 'enables SSL in secure mode' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['registry']['auth']['insecure'] = true + r = line_regexp('registry_client_insecure = true') + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + end + + context 'glance-registry configuration with ssl disabled' do + it 'sets registry client protocol to http' do + node.set['openstack']['image']['ssl']['enabled'] = false + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', /^registry_client_protocol = http$/) + end + end + context 'commonly named attributes' do %w(verbose debug filesystem_store_datadir).each do |attr| it "sets the #{attr} attribute" do diff --git a/spec/registry_spec.rb b/spec/registry_spec.rb index ea555a7..771e610 100644 --- a/spec/registry_spec.rb +++ b/spec/registry_spec.rb @@ -15,6 +15,7 @@ describe 'openstack-image::registry' do runner.converge(described_recipe) end + include Helpers include_context 'image-stubs' include_examples 'common-logging-recipe' include_examples 'common-packages' @@ -196,6 +197,53 @@ describe 'openstack-image::registry' do expect(chef_run).to render_file(file.name).with_content(/^hash_algorithms = sha2$/) end end + + context 'glance-registry configuration with ssl disabled' do + default_opts = { + cert_file: '/etc/glance/ssl/certs/sslcert.pem', + key_file: '/etc/glance/ssl/private/sslkey.pem' + } + it 'does not set cert or key file' do + default_opts.each do |key, val| + r = line_regexp("#{key} = #{val}") + expect(chef_run).not_to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + end + + context 'glance-registry configuration with ssl enabled' do + default_opts = { + cert_file: '/etc/glance/ssl/certs/sslcert.pem', + key_file: '/etc/glance/ssl/private/sslkey.pem' + } + cert = { 'ca_file' => '/etc/glance/ssl/certs/sslca.pem' } + + it 'configures SSL cert and key file' do + node.set['openstack']['image']['ssl']['enabled'] = true + default_opts.each do |key, val| + r = line_regexp("#{key} = #{val}") + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + context 'with cert required' do + it 'configures CA cert ' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['ssl']['cert_required'] = true + r = line_regexp("ca_file = #{cert['ca_file']}") + expect(chef_run).to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + + context 'with cert not required' do + it 'configures CA cert ' do + node.set['openstack']['image']['ssl']['enabled'] = true + node.set['openstack']['image']['ssl']['cert_required'] = false + r = line_regexp("ca_file = #{cert['ca_file']}") + expect(chef_run).not_to render_config_file(file.name).with_section_content('DEFAULT', r) + end + end + end + end it 'notifies glance-registry restart' do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fa21e93..32e74c2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -23,6 +23,18 @@ SUSE_OPTS = { log_lovel: LOG_LEVEL } +# Helper methods +module Helpers + # Create an anchored regex to exactly match the entire line + # (name borrowed from grep --line-regexp) + # + # @param [String] str The whole line to match + # @return [Regexp] The anchored/escaped regular expression + def line_regexp(str) + /^#{Regexp.quote(str)}$/ + end +end + shared_context 'image-stubs' do before do allow_any_instance_of(Chef::Recipe).to receive(:address_for) diff --git a/templates/default/glance-api.conf.erb b/templates/default/glance-api.conf.erb index 326deb3..51d4bad 100644 --- a/templates/default/glance-api.conf.erb +++ b/templates/default/glance-api.conf.erb @@ -130,14 +130,18 @@ log_file = /var/log/glance/api.log # ================= SSL Options =============================== # Certificate file to use when starting API server securely -#cert_file = /path/to/certfile + +<% if node['openstack']['image']['ssl']['enabled'] -%> +cert_file = <%= node['openstack']['image']['ssl']['cert_file'] %> # Private key file to use when starting API server securely -#key_file = /path/to/keyfile +key_file = <%= node['openstack']['image']['ssl']['key_file'] %> +<% if node['openstack']['image']['ssl']['cert_required'] -%> # CA certificate file to use to verify connecting clients -#ca_file = /path/to/cafile - +ca_file = <%=node['openstack']['image']['ssl']['ca_file'] %> +<% end -%> +<% end -%> # ================= Security Options ========================== # AES key for encrypting store 'location' metadata, including @@ -152,33 +156,40 @@ log_file = /var/log/glance/api.log registry_host = <%= @registry_ip_address %> # Port the registry server is listening on -#registry_port = 9191 + registry_port = <%= @registry_port %> # What protocol to use when connecting to the registry server? + +<% if node['openstack']['image']['ssl']['enabled'] -%> # Set to https for secure HTTP communication -registry_client_protocol = http +registry_client_protocol = https # The path to the key file to use in SSL connections to the # registry server, if any. Alternately, you may set the # GLANCE_CLIENT_KEY_FILE environ variable to a filepath of the key file -#registry_client_key_file = /path/to/key/file +registry_client_key_file = <%= node['openstack']['image']['ssl']['key_file'] %> # The path to the cert file to use in SSL connections to the # registry server, if any. Alternately, you may set the # GLANCE_CLIENT_CERT_FILE environ variable to a filepath of the cert file -#registry_client_cert_file = /path/to/cert/file - +registry_client_cert_file = <%= node['openstack']['image']['ssl']['cert_file'] %> + <% if node['openstack']['image']['ssl']['cert_required'] %> # The path to the certifying authority cert file to use in SSL connections # to the registry server, if any. Alternately, you may set the # GLANCE_CLIENT_CA_FILE environ variable to a filepath of the CA cert file -#registry_client_ca_file = /path/to/ca/file +registry_client_ca_file = <%= node['openstack']['image']['registry']['auth']['cafile'] %> + + <% end %> # When using SSL in connections to the registry server, do not require # validation via a certifying authority. This is the registry's equivalent of # specifying --insecure on the command line using glanceclient for the API # Default: False -#registry_client_insecure = False +registry_client_insecure = <%= node['openstack']['image']['registry']['auth']['insecure'] %> +<% else -%> +registry_client_protocol = http +<% end -%> # The period of time, in seconds, that the API server will wait for a registry # request to complete. A value of '0' implies no timeout. diff --git a/templates/default/glance-registry.conf.erb b/templates/default/glance-registry.conf.erb index be8d098..7e4208c 100644 --- a/templates/default/glance-registry.conf.erb +++ b/templates/default/glance-registry.conf.erb @@ -85,15 +85,18 @@ log_file = /var/log/glance/registry.log # ================= SSL Options =============================== +<% if node['openstack']['image']['ssl']['enabled'] -%> # Certificate file to use when starting registry server securely -#cert_file = /path/to/certfile +cert_file = <%= node['openstack']['image']['ssl']['cert_file'] %> # Private key file to use when starting registry server securely -#key_file = /path/to/keyfile +key_file = <%= node['openstack']['image']['ssl']['key_file'] %> +<% if node['openstack']['image']['ssl']['cert_required'] -%> # CA certificate file to use to verify connecting clients -#ca_file = /path/to/cafile - +ca_file = <%= node['openstack']['image']['ssl']['ca_file'] %> +<% end -%> +<% end -%> # ============ Notification System Options ===================== # Driver or drivers to handle sending notifications. Set to @@ -235,6 +238,7 @@ admin_tenant_name = <%= node["openstack"]["image"]["service_tenant_name"] %> admin_user = <%= node["openstack"]["image"]["service_user"] %> admin_password = <%= @service_pass %> signing_dir = <%= node["openstack"]["image"]["registry"]["auth"]["cache_dir"] %> +insecure = <%= node['openstack']['image']['registry']['auth']['insecure'] %> # A list of memcached server(s) to use for caching. <% if node['openstack']['image']['registry']['auth']['memcached_servers'] %>