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'] %>