diff --git a/manifests/apache.pp b/manifests/apache.pp index 40f26c97..f7124414 100644 --- a/manifests/apache.pp +++ b/manifests/apache.pp @@ -1,38 +1,155 @@ # Configure an Apache vhost # @api private -class pulpcore::apache { +class pulpcore::apache ( + Boolean $manage_selinux_boolean = true, + Stdlib::Port $http_port = 80, + Stdlib::Port $https_port = 443, + Hash[String, Any] $http_vhost_options = {}, + Hash[String, Any] $https_vhost_options = {}, + Enum['none', 'optional', 'require', 'optional_no_ca'] $ssl_verify_client = 'optional', +) { + $vhost_priority = $pulpcore::apache_vhost_priority $api_path = '/pulp/api/v3' - $api_url = "http://${pulpcore::api_host}:${pulpcore::api_port}${api_path}" + $api_base_url = "http://${pulpcore::api_host}:${pulpcore::api_port}" + $api_url = "${api_base_url}${api_path}" $content_path = '/pulp/content' - $content_url = "http://${pulpcore::content_host}:${pulpcore::content_port}${content_path}" - - if $pulpcore::manage_apache { - include apache - apache::vhost { 'pulpcore': - servername => $pulpcore::servername, - port => 80, - priority => '10', - docroot => $pulpcore::apache_docroot, - docroot_owner => $pulpcore::user, - docroot_group => $pulpcore::group, - docroot_mode => '0755', - manage_docroot => true, - proxy_pass => [ - { - 'path' => $api_path, - 'url' => $api_url, - 'reverse_urls' => [$api_url], - }, - { - 'path' => $content_path, - 'url' => $content_url, - 'reverse_urls' => [$content_url], - }, - ], + $content_base_url = "http://${pulpcore::content_host}:${pulpcore::content_port}" + $content_url = "${content_base_url}${content_path}" + + $docroot_directory = { + 'provider' => 'Directory', + 'path' => $pulpcore::apache_docroot, + 'options' => ['-Indexes', '-FollowSymLinks'], + 'allow_override' => ['None'], + } + $content_directory = { + 'path' => $content_path, + 'provider' => 'location', + 'proxy_pass' => [ + { + 'url' => $content_url, + }, + ], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + } + + # Pulp has a default for remote header. Here it's ensured that the end user + # can't send that header to spoof users. + $remote_user_environ_header = $pulpcore::remote_user_environ_name.regsubst(/^HTTP_/, '') + $api_directory = { + 'path' => $api_path, + 'provider' => 'location', + 'proxy_pass' => [ + { + 'url' => $api_url, + }, + ], + 'request_headers' => [ + "unset ${remote_user_environ_header}", + "set ${remote_user_environ_header} \"%{SSL_CLIENT_S_DN_CN}s\" env=SSL_CLIENT_S_DN_CN", + ], + } + + # Static content is served by the whitenoise application. SELinux prevents + # Apache from serving it directly + $proxy_pass_static = { + 'path' => $pulpcore::static_url, + 'url' => "${api_base_url}${pulpcore::static_url}", + } + + case $pulpcore::apache_http_vhost { + true: { + $http_vhost_name = 'pulpcore' + $http_fragment = undef + + include apache + include apache::mod::headers + apache::vhost { $http_vhost_name: + servername => $pulpcore::servername, + port => $http_port, + priority => $vhost_priority, + docroot => $pulpcore::apache_docroot, + manage_docroot => false, + directories => [$docroot_directory, $content_directory], + * => $http_vhost_options, + } + } + false: { + $http_vhost_name = undef + $http_fragment = undef + } + default: { + $http_vhost_name = $pulpcore::apache_http_vhost + $http_fragment = epp('pulpcore/apache-fragment.epp', { + 'directories' => [$content_directory], + }) + } + } + + case $pulpcore::apache_https_vhost { + true: { + $https_vhost_name = 'pulpcore-https' + $https_fragment = undef + + include apache + include apache::mod::headers + apache::vhost { $https_vhost_name: + servername => $pulpcore::servername, + port => $https_port, + ssl => true, + priority => $vhost_priority, + docroot => $pulpcore::apache_docroot, + manage_docroot => false, + directories => [$docroot_directory, $content_directory, $api_directory], + proxy_pass => [$proxy_pass_static], + ssl_cert => $pulpcore::apache_https_cert, + ssl_key => $pulpcore::apache_https_key, + ssl_chain => $pulpcore::apache_https_chain, + ssl_ca => $pulpcore::apache_https_ca, + ssl_verify_client => $ssl_verify_client, + * => $https_vhost_options, + } + } + false: { + $https_vhost_name = undef + $https_fragment = undef + } + default: { + $https_vhost_name = $pulpcore::apache_https_vhost + $https_fragment = epp('pulpcore/apache-fragment.epp', { + 'directories' => [$content_directory, $api_directory], + 'proxy_pass' => [$proxy_pass_static], + }) + } + } + + if $pulpcore::apache_http_vhost == true or $pulpcore::apache_https_vhost == true { + file { $pulpcore::apache_docroot: + ensure => directory, + owner => $pulpcore::user, + group => $pulpcore::group, + mode => '0755', + } + } + + if $http_fragment or $https_fragment { + pulpcore::apache::fragment { 'pulpcore': + http_content => $http_fragment, + https_content => $https_fragment, } + } + if $manage_selinux_boolean and ($pulpcore::apache_http_vhost or $pulpcore::apache_https_vhost) { + # Doesn't use selinux::boolean since that doesn't use ensure_resource which + # then conflict with the foreman module which doesn't use the selinux module. if $facts['os']['selinux']['enabled'] { - selinux::boolean { 'httpd_can_network_connect': } + ensure_resource('selboolean', 'httpd_can_network_connect', { + value => 'on', + persistent => true, + }) } } } diff --git a/manifests/apache/fragment.pp b/manifests/apache/fragment.pp new file mode 100644 index 00000000..7cda5587 --- /dev/null +++ b/manifests/apache/fragment.pp @@ -0,0 +1,32 @@ +# @summary Deploy an Apache fragment. Only intended to be used within the module +# @param order +# This determines the order. See apache::vhost for more details. +# 165 is chosen because it's just before the Proxy setup. In Foreman a +# ProxyPass /pulp ! is generated and by placing all content before that, a +# broken setup is avoided. +# @api private +define pulpcore::apache::fragment ( + Optional[String] $http_content = undef, + Optional[String] $https_content = undef, + Integer[0] $order = 165, +) { + include pulpcore::apache + + if $pulpcore::apache::http_vhost_name and $http_content { + apache::vhost::fragment { "pulpcore-http-${title}": + vhost => $pulpcore::apache::http_vhost_name, + priority => $pulpcore::apache::vhost_priority, + content => $http_content, + order => $order, + } + } + + if $pulpcore::apache::https_vhost_name and $https_content { + apache::vhost::fragment { "pulpcore-https-${title}": + vhost => $pulpcore::apache::https_vhost_name, + priority => $pulpcore::apache::vhost_priority, + content => $https_content, + order => $order, + } + } +} diff --git a/manifests/init.pp b/manifests/init.pp index d7916f6a..97177796 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -9,8 +9,38 @@ # @param user_home # Pulp user home directory # -# @param manage_apache -# Deploy a separate apache vhost for pulp3 +# @param apache_http_vhost +# When true, deploy a separate apache vhost for pulp3 listening on HTTP. +# When a name is given, fragments are attached to the specified vhost. +# When false, no Apache HTTP vhost is touched. +# +# @param apache_https_vhost +# When true, deploy a separate apache vhost for pulp3 listening on HTTPS. +# When a name is given, fragments are attached to the specified vhost. +# When false, no Apache HTTPS vhost is touched. +# +# @param apache_https_cert +# The certificate file to use in the HTTPS vhost. Only used when +# apache_https_vhost is true. +# +# @param apache_https_key +# The key file to use in the HTTPS vhost. Only used when apache_https_vhost +# is true. +# +# @param apache_https_ca +# The ca file to use in the HTTPS vhost. Only used when apache_https_vhost is +# true. The ca file should contain the certificates allowed to sign client +# certificates. This can be a different CA than the chain. +# +# @param apache_https_chain +# The chain file to use in the HTTPS vhost. Only used when apache_https_vhost +# is true. The chain file should contain the CA certificate an any +# intermediate certificates that signed the certificate. +# +# @param apache_vhost_priority +# The Apache vhost priority. When a name is passed to apache_http_vhost or +# apache_https_vhost, this will be used when attaching fragments to those +# vhosts. Note that this implies both vhosts need to have the same priority. # # @param api_host # API service host @@ -119,9 +149,15 @@ Stdlib::Absolutepath $chunked_upload_dir = '/var/lib/pulp/upload', Stdlib::Absolutepath $media_root = '/var/lib/pulp/media', Stdlib::Absolutepath $static_root = '/var/lib/pulp/assets', - String[1] $static_url = '/assets/', + Pattern['^/.+/$'] $static_url = '/assets/', Stdlib::Absolutepath $apache_docroot = '/var/lib/pulp/docroot', - Boolean $manage_apache = true, + Variant[Boolean, String[1]] $apache_http_vhost = true, + Variant[Boolean, String[1]] $apache_https_vhost = true, + Optional[Stdlib::Absolutepath] $apache_https_cert = undef, + Optional[Stdlib::Absolutepath] $apache_https_key = undef, + Optional[Stdlib::Absolutepath] $apache_https_ca = undef, + Optional[Stdlib::Absolutepath] $apache_https_chain = undef, + String[1] $apache_vhost_priority = '10', Stdlib::Host $api_host = '127.0.0.1', Stdlib::Port $api_port = 24817, Stdlib::Host $content_host = '127.0.0.1', @@ -141,7 +177,7 @@ Integer[0] $redis_db = 8, Stdlib::Fqdn $servername = $facts['networking']['fqdn'], Array[Stdlib::Absolutepath] $allowed_import_path = ['/var/lib/pulp/sync_imports'], - Optional[String] $remote_user_environ_name = undef, + String[1] $remote_user_environ_name = 'HTTP_REMOTE_USER', Integer[0] $worker_count = min(8, $facts['processors']['count']), ) { $settings_file = "${config_dir}/settings.py" diff --git a/manifests/plugin.pp b/manifests/plugin.pp index 759482f3..c0907af3 100644 --- a/manifests/plugin.pp +++ b/manifests/plugin.pp @@ -5,9 +5,17 @@ # # @param config # An optional config in the Pulp settings file +# +# @param http_content +# Optional fragment for the Apache HTTP vhost +# +# @param https_content +# Optional fragment for the Apache HTTPS vhost define pulpcore::plugin( String $package_name = "python3-pulp-${title}", Optional[String] $config = undef, + Optional[String] $http_content = undef, + Optional[String] $https_content = undef, ) { package { $package_name: ensure => present, @@ -20,4 +28,11 @@ order => '10', } } + + if $http_content or $https_content { + pulpcore::apache::fragment { "plugin-${title}": + http_content => $http_content, + https_content => $https_content, + } + } } diff --git a/manifests/plugin/container.pp b/manifests/plugin/container.pp index db3a8f14..8a4fb66f 100644 --- a/manifests/plugin/container.pp +++ b/manifests/plugin/container.pp @@ -1,6 +1,40 @@ # @summary Pulp Container plugin -class pulpcore::plugin::container { +# @param location_prefix +# In the Apache configuration a location with this prefix is exposed. The +# version (currently v2) will be appended. +# @param registry_version_path +# The path beneath the location prefix to forward. This is also appended to +# the content base url. +class pulpcore::plugin::container ( + String $location_prefix = '/pulpcore_registry', + String $registry_version_path = '/v2/', +) { + $context = { + 'directories' => [ + { + 'provider' => 'location', + 'path' => "${location_prefix}${registry_version_path}", + 'proxy_pass' => [ + { + 'url' => "${pulpcore::apache::api_base_url}${registry_version_path}", + }, + ], + 'request_headers' => [ + "unset ${pulpcore::apache::remote_user_environ_header}", + "set ${pulpcore::apache::remote_user_environ_header} \"%{SSL_CLIENT_S_DN_CN}s\" env=SSL_CLIENT_S_DN_CN", + ], + }, + ], + 'proxy_pass' => [ + { + 'path' => '/pulp/container/', + 'url' => "${pulpcore::apache::content_base_url}/pulp/container/", + }, + ], + } + pulpcore::plugin { 'container': - config => 'TOKEN_AUTH_DISABLED=True', + config => 'TOKEN_AUTH_DISABLED=True', + https_content => epp('pulpcore/apache-fragment.epp', $context), } } diff --git a/manifests/plugin/file.pp b/manifests/plugin/file.pp index 73f0bd42..d9666625 100644 --- a/manifests/plugin/file.pp +++ b/manifests/plugin/file.pp @@ -1,5 +1,34 @@ # @summary Pulp File plugin -class pulpcore::plugin::file { +# @param use_pulp2_content_route +# Whether to redirect the legacy (Pulp 2) URLs to the content server +class pulpcore::plugin::file ( + Boolean $use_pulp2_content_route = false, +) { + if $use_pulp2_content_route { + $context = { + 'directories' => [ + { + 'provider' => 'location', + 'path' => '/pulp/isos', + 'proxy_pass' => [ + { + 'url' => $pulpcore::apache::content_url, + }, + ], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + }, + ], + } + $content = epp('pulpcore/apache-fragment.epp', $context) + } else { + $content = undef + } + pulpcore::plugin { 'file': + http_content => $content, + https_content => $content, } } diff --git a/manifests/plugin/rpm.pp b/manifests/plugin/rpm.pp index 7f045eb1..c182ad43 100644 --- a/manifests/plugin/rpm.pp +++ b/manifests/plugin/rpm.pp @@ -1,5 +1,34 @@ # @summary Pulp RPM plugin -class pulpcore::plugin::rpm { +# @param use_pulp2_content_route +# Whether to redirect the legacy (Pulp 2) URLs to the content server +class pulpcore::plugin::rpm ( + Boolean $use_pulp2_content_route = false, +) { + if $use_pulp2_content_route { + $context = { + 'directories' => [ + { + 'provider' => 'location', + 'path' => '/pulp/repos', + 'proxy_pass' => [ + { + 'url' => $pulpcore::apache::content_url, + }, + ], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + }, + ], + } + $content = epp('pulpcore/apache-fragment.epp', $context) + } else { + $content = undef + } + pulpcore::plugin { 'rpm': + http_content => $content, + https_content => $content, } } diff --git a/metadata.json b/metadata.json index 16d3d0d2..95c5ba81 100644 --- a/metadata.json +++ b/metadata.json @@ -20,7 +20,7 @@ }, { "name": "puppetlabs/apache", - "version_requirement": ">= 5.0.0 < 6.0.0" + "version_requirement": ">= 5.4.0 < 6.0.0" }, { "name": "puppetlabs/postgresql", diff --git a/spec/acceptance/basic_spec.rb b/spec/acceptance/basic_spec.rb index 4b45b488..34ec897e 100644 --- a/spec/acceptance/basic_spec.rb +++ b/spec/acceptance/basic_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper_acceptance' describe 'basic installation' do + certdir = '/etc/pulpcore-certs' + let(:pp) { <<-PUPPET if $facts['os']['release']['major'] == '7' { @@ -20,7 +22,10 @@ class { 'redis::globals': } class { 'pulpcore': - worker_count => 2, + worker_count => 2, + apache_https_cert => '#{certdir}/ca-cert.pem', + apache_https_key => '#{certdir}/ca-key.pem', + apache_https_ca => '#{certdir}/ca-cert.pem', } PUPPET } @@ -61,7 +66,11 @@ class { 'pulpcore': it { is_expected.to be_listening } end - describe curl_command("http://#{host_inventory['fqdn']}/pulp/api/v3/status/") do + describe port(443) do + it { is_expected.to be_listening } + end + + describe curl_command("https://#{host_inventory['fqdn']}/pulp/api/v3/status/", cacert: "#{certdir}/ca-cert.pem") do its(:response_code) { is_expected.to eq(200) } its(:exit_status) { is_expected.to eq 0 } end @@ -71,9 +80,23 @@ class { 'pulpcore': its(:exit_status) { is_expected.to eq 0 } end + describe curl_command("https://#{host_inventory['fqdn']}/pulp/api/v3/", cacert: "#{certdir}/ca-cert.pem") do + its(:response_code) { is_expected.to eq(200) } + its(:body) { is_expected.not_to contain('artifacts_list') } + its(:exit_status) { is_expected.to eq 0 } + end + + describe curl_command("https://#{host_inventory['fqdn']}/pulp/api/v3/", + cacert: "#{certdir}/ca-cert.pem", key: "#{certdir}/client-key.pem", cert: "#{certdir}/client-cert.pem") do + its(:response_code) { is_expected.to eq(200) } + its(:body) { is_expected.to contain('artifacts_list') } + its(:exit_status) { is_expected.to eq 0 } + end end describe 'reducing worker count' do + certdir = '/etc/pulpcore-certs' + let(:pp) { <<-PUPPET if $facts['os']['release']['major'] == '7' { @@ -93,7 +116,10 @@ class { 'redis::globals': } class { 'pulpcore': - worker_count => 1, + worker_count => 1, + apache_https_cert => '#{certdir}/ca-cert.pem', + apache_https_key => '#{certdir}/ca-key.pem', + apache_https_ca => '#{certdir}/ca-cert.pem', } PUPPET } diff --git a/spec/acceptance/plugins_spec.rb b/spec/acceptance/plugins_spec.rb index 68161521..8f754b86 100644 --- a/spec/acceptance/plugins_spec.rb +++ b/spec/acceptance/plugins_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper_acceptance' describe 'basic installation' do + certdir = '/etc/pulpcore-certs' + let(:pp) { <<-PUPPET if $facts['os']['release']['major'] == '7' { @@ -19,7 +21,11 @@ class { 'redis::globals': } } - include pulpcore + class { 'pulpcore': + apache_https_cert => '#{certdir}/ca-cert.pem', + apache_https_key => '#{certdir}/ca-key.pem', + apache_https_ca => '#{certdir}/ca-cert.pem', + } include pulpcore::plugin::certguard include pulpcore::plugin::container include pulpcore::plugin::deb @@ -60,7 +66,7 @@ class { 'redis::globals': it { is_expected.to be_listening } end - describe curl_command("http://#{host_inventory['fqdn']}/pulp/api/v3/status/") do + describe curl_command("https://#{host_inventory['fqdn']}/pulp/api/v3/status/", cacert: "#{certdir}/ca-cert.pem") do its(:response_code) { is_expected.to eq(200) } its(:exit_status) { is_expected.to eq 0 } end diff --git a/spec/acceptance/use_pulp2_content_route_spec.rb b/spec/acceptance/use_pulp2_content_route_spec.rb new file mode 100644 index 00000000..b9ba49ae --- /dev/null +++ b/spec/acceptance/use_pulp2_content_route_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper_acceptance' + +describe 'basic installation' do + certdir = '/etc/pulpcore-certs' + + let(:pp) { + <<-PUPPET + if $facts['os']['release']['major'] == '7' { + class { 'postgresql::globals': + version => '12', + client_package_name => 'rh-postgresql12-postgresql-syspaths', + server_package_name => 'rh-postgresql12-postgresql-server-syspaths', + contrib_package_name => 'rh-postgresql12-postgresql-contrib-syspaths', + service_name => 'postgresql', + datadir => '/var/lib/pgsql/data', + confdir => '/var/lib/pgsql/data', + bindir => '/usr/bin', + } + class { 'redis::globals': + scl => 'rh-redis5', + } + } + + class { 'pulpcore': + apache_https_cert => '#{certdir}/ca-cert.pem', + apache_https_key => '#{certdir}/ca-key.pem', + apache_https_ca => '#{certdir}/ca-cert.pem', + static_url => '/pulp/assets/', + } + + include pulpcore::plugin::certguard + include pulpcore::plugin::container + include pulpcore::plugin::deb + class { 'pulpcore::plugin::file': + use_pulp2_content_route => true, + } + include pulpcore::plugin::migration + class { 'pulpcore::plugin::rpm': + use_pulp2_content_route => true, + } + PUPPET + } + + it_behaves_like 'a idempotent resource' + + describe file('/etc/pulp/settings.py') do + it { is_expected.to be_file } + its(:content) { is_expected.to match(/^TOKEN_AUTH_DISABLED=True$/) } + end + + describe service('httpd') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe service('pulpcore-api') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe service('pulpcore-content') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe service('pulpcore-resource-manager') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe port(80) do + it { is_expected.to be_listening } + end + + describe curl_command("https://#{host_inventory['fqdn']}/pulp/api/v3/status/", cacert: "#{certdir}/ca-cert.pem") do + its(:response_code) { is_expected.to eq(200) } + its(:exit_status) { is_expected.to eq 0 } + end +end diff --git a/spec/classes/plugin_container_spec.rb b/spec/classes/plugin_container_spec.rb index 51e3c536..3c8d071b 100644 --- a/spec/classes/plugin_container_spec.rb +++ b/spec/classes/plugin_container_spec.rb @@ -4,21 +4,18 @@ on_supported_os.each do |os, os_facts| context "on #{os}" do let(:facts) { os_facts } + let(:pre_condition) { 'include pulpcore' } - it { is_expected.to compile.with_all_deps } - it { is_expected.to contain_pulpcore__plugin('container') } - it { is_expected.to contain_package('python3-pulp-container') } - it { is_expected.to contain_concat__fragment('plugin-container').with_content("\n# container plugin settings\nTOKEN_AUTH_DISABLED=True") } - - context 'with pulpcore' do - let(:pre_condition) { 'include pulpcore' } - - it do - is_expected.to compile.with_all_deps - is_expected.to contain_pulpcore__plugin('container') - .that_subscribes_to('Class[Pulpcore::Install]') - .that_notifies(['Class[Pulpcore::Database]', 'Class[Pulpcore::Service]']) - end + it 'configures the plugin' do + is_expected.to compile.with_all_deps + is_expected.to contain_pulpcore__plugin('container') + .that_subscribes_to('Class[Pulpcore::Install]') + .that_notifies(['Class[Pulpcore::Database]', 'Class[Pulpcore::Service]']) + is_expected.to contain_package('python3-pulp-container') + is_expected.to contain_concat__fragment('plugin-container').with_content("\n# container plugin settings\nTOKEN_AUTH_DISABLED=True") + is_expected.to contain_pulpcore__apache__fragment('plugin-container') + is_expected.not_to contain_apache__vhost__fragment('pulpcore-http-plugin-container') + is_expected.to contain_apache__vhost__fragment('pulpcore-https-plugin-container') end end end diff --git a/spec/classes/plugin_rpm_spec.rb b/spec/classes/plugin_rpm_spec.rb index c8fb6139..ba5d6cd3 100644 --- a/spec/classes/plugin_rpm_spec.rb +++ b/spec/classes/plugin_rpm_spec.rb @@ -8,6 +8,8 @@ it { is_expected.to compile.with_all_deps } it { is_expected.to contain_package('python3-pulp-rpm') } it { is_expected.to contain_pulpcore__plugin('rpm') } + it { is_expected.not_to contain_apache__vhost__fragment('pulpcore-http-plugin-rpm') } + it { is_expected.not_to contain_apache__vhost__fragment('pulpcore-https-plugin-rpm') } context 'with pulpcore' do let(:pre_condition) { 'include pulpcore' } @@ -18,6 +20,17 @@ .that_subscribes_to('Class[Pulpcore::Install]') .that_notifies(['Class[Pulpcore::Database]', 'Class[Pulpcore::Service]']) end + + context 'with pulp2 content route' do + let(:params) { { use_pulp2_content_route: true } } + + it 'contains the Apache fragment' do + is_expected.to compile.with_all_deps + is_expected.to contain_pulpcore__apache__fragment('plugin-rpm') + is_expected.to contain_apache__vhost__fragment('pulpcore-http-plugin-rpm') + is_expected.to contain_apache__vhost__fragment('pulpcore-https-plugin-rpm') + end + end end end end diff --git a/spec/classes/pulpcore_spec.rb b/spec/classes/pulpcore_spec.rb index 17ac4298..a547260d 100644 --- a/spec/classes/pulpcore_spec.rb +++ b/spec/classes/pulpcore_spec.rb @@ -20,7 +20,6 @@ is_expected.to contain_class('pulpcore::config') is_expected.to contain_concat('pulpcore settings').with_path('/etc/pulp/settings.py') is_expected.to contain_concat__fragment('base') - .without_content(/REMOTE_USER_ENVIRON_NAME/) .without_content(/sslmode/) is_expected.to contain_file('/etc/pulp') is_expected.to contain_file('/var/lib/pulp') @@ -32,6 +31,7 @@ end it 'sets up static files' do + is_expected.to contain_class('pulpcore::static') is_expected.to contain_file('/var/lib/pulp/assets') is_expected.to contain_pulpcore__admin('collectstatic --noinput') is_expected.to contain_exec('pulpcore-manager collectstatic --noinput') @@ -50,7 +50,59 @@ it 'configures apache' do is_expected.to contain_class('pulpcore::apache') is_expected.to contain_apache__vhost('pulpcore') - is_expected.to contain_selinux__boolean('httpd_can_network_connect') + is_expected.not_to contain_apache__vhost__fragment('pulpcore-http-pulpcore') + .with_directories([ + { + 'provider' => 'Directory', + 'path' => '/var/lib/pulp/docroot', + 'options' => ['-Indexes', '-FollowSymLinks'], + 'allow_override' => ['None'], + }, + { + 'path' => '/pulp/content', + 'provider' => 'location', + 'proxy_pass' => [{'url' => 'http://127.0.0.1:24816/pulp/content'}], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + }, + ]) + is_expected.to contain_apache__vhost('pulpcore-https') + .with_directories([ + { + 'path' => '/var/lib/pulp/docroot', + 'provider' => 'Directory', + 'options' => ['-Indexes', '-FollowSymLinks'], + 'allow_override' => ['None'], + }, + { + 'path' => '/pulp/content', + 'provider' => 'location', + 'proxy_pass' => [{'url' => 'http://127.0.0.1:24816/pulp/content'}], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + }, + { + 'path' => '/pulp/api/v3', + 'provider' => 'location', + 'proxy_pass' => [{'url'=>'http://127.0.0.1:24817/pulp/api/v3'}], + 'request_headers' => [ + 'unset REMOTE_USER', + 'set REMOTE_USER "%{SSL_CLIENT_S_DN_CN}s" env=SSL_CLIENT_S_DN_CN', + ], + } + ]) + .with_proxy_pass([ + { + 'path' => '/assets/', + 'url' => 'http://127.0.0.1:24817/assets/', + }, + ]) + is_expected.not_to contain_apache__vhost__fragment('pulpcore-https-pulpcore') + is_expected.to contain_selboolean('httpd_can_network_connect') end it 'configures services' do @@ -125,18 +177,92 @@ context 'without apache httpd' do let :params do { - manage_apache: false, + apache_http_vhost: false, + apache_https_vhost: false, } end it do is_expected.to compile.with_all_deps is_expected.not_to contain_file('/var/lib/pulp/docroot') + is_expected.not_to contain_class('apache') is_expected.not_to contain_apache__vhost('pulpcore') + is_expected.not_to contain_apache__vhost('pulpcore-https') is_expected.not_to contain_selinux__boolean('httpd_can_network_connect') end end + context 'with external vhosts' do + let :params do + { + apache_http_vhost: 'foreman', + apache_https_vhost: 'foreman-ssl', + } + end + + let :pre_condition do + <<~PUPPET + include apache + apache::vhost { 'foreman': + docroot => '/usr/share/foreman/public', + port => 80, + } + + apache::vhost { 'foreman-ssl': + docroot => '/usr/share/foreman/public', + port => 443, + ssl => true, + } + PUPPET + end + + it { is_expected.to compile.with_all_deps } + it do + is_expected.to contain_pulpcore__apache__fragment('pulpcore') + is_expected.to contain_apache__vhost__fragment('pulpcore-http-pulpcore') + .with_vhost('foreman') + .with_priority('10') + .with_content( +< + RequestHeader unset X-CLIENT-CERT + RequestHeader set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT + ProxyPass http://127.0.0.1:24816/pulp/content + ProxyPassReverse http://127.0.0.1:24816/pulp/content + +CONTENT + ) + end + it do + is_expected.to contain_pulpcore__apache__fragment('pulpcore') + is_expected.to contain_apache__vhost__fragment('pulpcore-https-pulpcore') + .with_vhost('foreman-ssl') + .with_priority('10') + .with_content( +< + RequestHeader unset X-CLIENT-CERT + RequestHeader set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT + ProxyPass http://127.0.0.1:24816/pulp/content + ProxyPassReverse http://127.0.0.1:24816/pulp/content + + + + RequestHeader unset REMOTE_USER + RequestHeader set REMOTE_USER "%{SSL_CLIENT_S_DN_CN}s" env=SSL_CLIENT_S_DN_CN + ProxyPass http://127.0.0.1:24817/pulp/api/v3 + ProxyPassReverse http://127.0.0.1:24817/pulp/api/v3 + + + ProxyPass /assets/ http://127.0.0.1:24817/assets/ + ProxyPassReverse /assets/ http://127.0.0.1:24817/assets/ +CONTENT + ) + end + end + context 'with a plugin' do let(:pre_condition) { "pulpcore::plugin { 'myplugin': }" } @@ -178,16 +304,28 @@ is_expected.to contain_systemd__unit_file('pulpcore-content.service') .with_content(%r{--bind '127.0.0.1:24818'}) is_expected.to contain_apache__vhost('pulpcore') - .with_proxy_pass([ + .with_directories([ { - 'path' => '/pulp/api/v3', - 'url' => "http://127.0.0.1:24819/pulp/api/v3", - 'reverse_urls' => ["http://127.0.0.1:24819/pulp/api/v3"], + 'provider' => 'Directory', + 'path' => '/var/lib/pulp/docroot', + 'options' => ['-Indexes', '-FollowSymLinks'], + 'allow_override' => ['None'], }, { - 'path' => '/pulp/content', - 'url' => "http://127.0.0.1:24818/pulp/content", - 'reverse_urls' => ["http://127.0.0.1:24818/pulp/content"], + 'path' => '/pulp/content', + 'provider' => 'location', + 'proxy_pass' => [{'url' => 'http://127.0.0.1:24818/pulp/content'}], + 'request_headers' => [ + 'unset X-CLIENT-CERT', + 'set X-CLIENT-CERT "%{SSL_CLIENT_CERT}s" env=SSL_CLIENT_CERT', + ], + }, + ]) + is_expected.to contain_apache__vhost('pulpcore-https') + .with_proxy_pass([ + { + 'path' => '/assets/', + 'url' => 'http://127.0.0.1:24819/assets/', }, ]) end diff --git a/spec/setup_acceptance_node.pp b/spec/setup_acceptance_node.pp index c28836a6..b5e166a0 100644 --- a/spec/setup_acceptance_node.pp +++ b/spec/setup_acceptance_node.pp @@ -34,3 +34,42 @@ require => Class['pulpcore::repo'], } } + +$directory = '/etc/pulpcore-certs' +$ca_cert = "${directory}/ca-cert.pem" +$ca_key = "${directory}/ca-key.pem" +$client_csr = "${directory}/client-csr.pem" +$client_cert = "${directory}/client-cert.pem" +$client_key = "${directory}/client-key.pem" + +exec { 'Create certificate directory': + command => "mkdir -p ${directory}", + path => ['/bin', '/usr/bin'], + creates => $directory, +} +-> exec { 'Generate certificate': + command => "openssl req -nodes -x509 -newkey rsa:2048 -subj '/CN=${facts['networking']['fqdn']}' -keyout '${ca_key}' -out '${ca_cert}' -days 365", + path => ['/bin', '/usr/bin'], + creates => $ca_cert, + logoutput => 'on_failure', + umask => '0022', +} +-> exec { 'Generate CSR': + command => "openssl req -nodes -new -newkey rsa:2048 -subj '/CN=admin' -out '${client_csr}' -keyout '${client_key}'", + path => ['/bin', '/usr/bin'], + creates => $client_csr, + logoutput => 'on_failure', + umask => '0022', +} +-> exec { 'Sign CSR': + command => "openssl x509 -req -days 360 -in '${client_csr}' -CA '${ca_cert}' -CAkey '${ca_key}' -CAcreateserial -out '${client_cert}'", + path => ['/bin', '/usr/bin'], + creates => $client_cert, + logoutput => 'on_failure', + umask => '0022', +} +-> file { [$ca_key, $ca_cert, $client_key, $client_cert]: + owner => 'root', + group => 'root', + mode => '0640', +} diff --git a/templates/apache-fragment.epp b/templates/apache-fragment.epp new file mode 100644 index 00000000..0abbea1b --- /dev/null +++ b/templates/apache-fragment.epp @@ -0,0 +1,60 @@ +<%- | + Array[Struct[{ + provider => Enum['directory', 'directorymatch', 'location', 'locationmatch', 'files', 'filesmatch', 'proxy', 'proxymatch'], + path => String[1], + Optional[options] => Array[String[1]], + Optional[allow_override] => Array[String[1]], + Optional[request_headers] => Array[String[1]], + Optional[proxy_pass] => Array[Struct[{ + url => String[1], + Optional[params] => Hash[String, Variant[String, Integer]], + Optional[reverse_urls] => Array[String[1]], + }]], + }]] $directories, + Array[Hash[String, String]] $proxy_pass = [], +| -%> +<%- $directories.each |$directory| { -%> + + <%- + if $directory['provider'] =~ /^(.*)match$/ { + $provider = $1.capitalize + 'Match' + } else { + $provider = $directory['provider'].capitalize + } + -%> + <<%= $provider %> "<%= $directory['path'] %>"> + <%- if $directory['options'] { -%> + Options <%= $directory['options'].join(' ') %> + <%- } -%> + <%- if $directory['allow_override'] { -%> + AllowOverride <%= $directory['allow_override'].join(' ') %> + <%- } elsif $provider == 'Directory' { -%> + AllowOverride None + <%- } -%> + <%- if $directory['request_headers'] { -%> + <%- $directory['request_headers'].each |$request_statement| { -%> + RequestHeader <%= $request_statement %> + <%- } -%> + <%- } -%> + <%- if $directory['proxy_pass'] and $provider in ['Location', 'LocationMatch'] { -%> + <%- $directory['proxy_pass'].each |$proxy| { -%> + ProxyPass <%= $proxy['url'] -%> + <%- if $proxy['params'] { -%> + <%- $proxy['params'].sort.each |$key, $value| { -%> <%= $key %>=<%= $value -%><%- } -%> + <%- } %> + <%- if $proxy['reverse_urls'] { -%> + <%- $proxy['reverse_urls'].each |$reverse_url| { -%> + ProxyPassReverse <%= $reverse_url %> + <%- } -%> + <%- } else { -%> + ProxyPassReverse <%= $proxy['url'] %> + <%- } -%> + <%- } -%> + <%- } -%> + > +<% } -%> +<% $proxy_pass.each |$proxy| { -%> + + ProxyPass <%= $proxy['path'] %> <%= $proxy['url'] %> + ProxyPassReverse <%= $proxy['path'] %> <%= $proxy['url'] %> +<% } -%> diff --git a/templates/settings.py.erb b/templates/settings.py.erb index 29360fde..e302d5d5 100644 --- a/templates/settings.py.erb +++ b/templates/settings.py.erb @@ -30,9 +30,7 @@ FILE_UPLOAD_TEMP_DIR = "<%= scope['pulpcore::cache_dir'] %>" WORKING_DIRECTORY = "<%= scope['pulpcore::cache_dir'] %>" CHUNKED_UPLOAD_DIR = "<%= scope['pulpcore::chunked_upload_dir'] %>" -<% if scope['pulpcore::remote_user_environ_name'] -%> REMOTE_USER_ENVIRON_NAME = '<%= scope['pulpcore::remote_user_environ_name'] %>' -<% end -%> AUTHENTICATION_BACKENDS = ['pulpcore.app.authentication.PulpNoCreateRemoteUserBackend'] REST_FRAMEWORK__DEFAULT_AUTHENTICATION_CLASSES = (