Refactor and standardize SSL/TLS and vhost config

Make SSL/TLS certificate file handling and snakeoil fallback logic
more flexible, no longer expecting you to unconditionally set file
paths so you can just provide contents and allow the module to store
them in a location it considers sane.

Also adjust the vhost template to match the pattern we've been
standardizing on across existing modules (such as our recently
improved mediawiki module), with clearer variable scope lookups and
stronger crypto configuration.

While in the vicinity, also remove a hard-coded default ServerAdmin
E-mail address default to make the module less OpenStack-community
specific.

Change-Id: I238682ac05bdd20ec293b7a16370563763e35249
This commit is contained in:
Jeremy Stanley 2016-11-16 18:23:47 +00:00
parent 06e46181cb
commit a72ab07bef
5 changed files with 172 additions and 90 deletions

View File

@ -26,30 +26,115 @@ class phabricator::certificates (
$ssl_key_file_contents = $phabricator::vars::ssl_key_file_contents,
) {
if $ssl_cert_file_contents != undef {
file { $ssl_cert_file:
owner => 'root',
group => 'root',
mode => '0640',
content => $ssl_cert_file_contents,
# To use the standard ssl-certs package snakeoil certificate, leave both
# $ssl_cert_file and $ssl_cert_file_contents empty. To use an existing
# certificate, specify its path for $ssl_cert_file and leave
# $ssl_cert_file_contents empty. To manage the certificate with puppet,
# provide $ssl_cert_file_contents and optionally specify the path to use for
# it in $ssl_cert_file.
if ($ssl_cert_file == undef) and ($ssl_cert_file_contents == undef) {
$cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
if ! defined(Package['ssl-cert']) {
package { 'ssl-cert':
ensure => present,
}
}
} else {
if $ssl_cert_file == undef {
$cert_file = "/etc/ssl/certs/${::fqdn}.pem"
if ! defined(File['/etc/ssl/certs']) {
file { '/etc/ssl/certs':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
before => File[$cert_file],
}
}
} else {
$cert_file = $ssl_cert_file
}
if $ssl_cert_file_contents != undef {
file { $cert_file:
ensure => present,
owner => 'root',
group => 'root',
mode => '0644',
content => $ssl_cert_file_contents,
}
}
}
if $ssl_key_file_contents != undef {
file { $ssl_key_file:
owner => 'root',
group => 'ssl-cert',
mode => '0640',
content => $ssl_key_file_contents,
# To avoid using an intermediate certificate chain, leave both
# $ssl_chain_file and $ssl_chain_file_contents empty. To use an existing
# chain, specify its path for $ssl_chain_file and leave
# $ssl_chain_file_contents empty. To manage the chain with puppet, provide
# $ssl_chain_file_contents and optionally specify the path to use for it in
# $ssl_chain_file.
if ($ssl_chain_file == undef) and ($ssl_chain_file_contents == undef) {
$chain_file = undef
} else {
if $ssl_chain_file == undef {
$chain_file = "/etc/ssl/certs/${::fqdn}_intermediate.pem"
if ! defined(File['/etc/ssl/certs']) {
file { '/etc/ssl/certs':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
before => File[$chain_file],
}
}
} else {
$chain_file = $ssl_chain_file
}
if $ssl_chain_file_contents != undef {
file { $chain_file:
ensure => present,
owner => 'root',
group => 'root',
mode => '0644',
content => $ssl_chain_file_contents,
}
}
}
if $ssl_chain_file_contents != undef {
file { $ssl_chain_file:
owner => 'root',
group => 'root',
mode => '0640',
content => $ssl_chain_file_contents,
# To use the standard ssl-certs package snakeoil key, leave both
# $ssl_key_file and $ssl_key_file_contents empty. To use an existing key,
# specify its path for $ssl_key_file and leave $ssl_key_file_contents empty.
# To manage the key with puppet, provide $ssl_key_file_contents and
# optionally specify the path to use for it in $ssl_key_file.
if ($ssl_key_file == undef) and ($ssl_key_file_contents == undef) {
$key_file = '/etc/ssl/private/ssl-cert-snakeoil.key'
if ! defined(Package['ssl-cert']) {
package { 'ssl-cert':
ensure => present,
}
}
} else {
if $ssl_key_file == undef {
$key_file = "/etc/ssl/private/${::fqdn}.key"
if ! defined(File['/etc/ssl/private']) {
file { '/etc/ssl/private':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0700',
before => File[$key_file],
}
}
} else {
$key_file = $ssl_key_file
}
if $ssl_key_file_contents != undef {
file { $key_file:
ensure => present,
owner => 'root',
group => 'root',
mode => '0600',
content => $ssl_key_file_contents,
}
}
}
}

View File

@ -17,11 +17,7 @@
# Set up the virtual host for phabricator.
#
class phabricator::httpd (
$ssl_cert_file = $phabricator::vars::ssl_cert_file,
$ssl_chain_file = $phabricator::vars::ssl_chain_file,
$ssl_key_file = $phabricator::vars::ssl_key_file,
$httpd_vhost = $phabricator::vars::httpd_vhost,
$httpd_admin_email = $phabricator::vars::httpd_admin_email,
$httpd_docroot = $phabricator::vars::httpd_docroot,
) {
include ::httpd
@ -39,11 +35,12 @@ class phabricator::httpd (
# Set up Phabricator as TLS.
if defined(Class['phabricator::certificates']) {
::httpd::vhost { $httpd_vhost:
port => 443,
docroot => $httpd_docroot,
priority => '50',
template => 'phabricator/vhost.erb',
ssl => true,
port => 443, # Is required despite not being used.
docroot => $httpd_docroot,
priority => '50',
template => 'phabricator/vhost.erb',
ssl => true,
vhost_name => $httpd_vhost,
}
}
}

View File

@ -42,7 +42,7 @@ class phabricator (
# Httpd config.
$httpd_vhost = $::fqdn,
$httpd_admin_email = 'noc@openstack.org',
$httpd_admin_email = "webmaster@${::fqdn}",
) {
# Set up the shared configuration.

View File

@ -39,7 +39,7 @@ class phabricator::vars (
# Virtual host config.
$httpd_vhost = $::fqdn,
$httpd_admin_email = 'noc@openstack.org',
$httpd_admin_email = "webmaster@${::fqdn}",
) {
# Non-configurable-options (derived)

View File

@ -1,70 +1,70 @@
# ************************************
# Managed by Puppet
# ************************************
# Unconditionally redirect all HTTP traffic for this vhost to HTTPS
<VirtualHost *:80>
ServerAdmin <%= @httpd_admin_email %>
ServerName <%= @httpd_vhost %>
DocumentRoot /var/www
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory /var/www/>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
RewriteEngine on
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/(.*)$ https://<%= @httpd_vhost %>/$1 [L,R]
ErrorLog /var/log/apache2/phabricator-error.log
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
CustomLog /var/log/apache2/phabricator-access.log combined
ServerSignature Off
ServerName <%= @vhost_name %>
ServerAdmin <%= scope['phabricator::vars::httpd_admin_email'] %>
RewriteEngine On
RewriteRule ^/(.*) https://<%= @vhost_name %>/$1 [last,redirect=permanent]
LogLevel warn
ErrorLog /var/log/apache2/<%= @vhost_name %>_error.log
CustomLog /var/log/apache2/<%= @vhost_name %>_access.log combined
ServerSignature Off
</VirtualHost>
<VirtualHost *:443>
ServerAdmin noc@openstack.org
ServerName <%= @httpd_vhost %>
SSLEngine on
SSLProtocol All -SSLv2 -SSLv3
SSLCertificateFile <%= @ssl_cert_file %>
SSLCertificateKeyFile <%= @ssl_key_file %>
<%# scope.lookupvar returns nil for an undefined variable in puppet 4 -%>
<%# scope.lookupvar returns :undef for an undefined variable in puppet 3 -%>
<% unless ['', nil, :undef].include?(scope.lookupvar("ssl_chain_file")) %>
SSLCertificateChainFile <%= @ssl_chain_file %>
<% end %>
ServerName <%= @vhost_name %>
ServerAdmin <%= scope['phabricator::vars::httpd_admin_email'] %>
DocumentRoot <%= @httpd_docroot %>
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory <%= @httpd_docroot %>>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
Require all granted
</Directory>
SSLEngine on
SSLProtocol All -SSLv2 -SSLv3
# Once the machine is using something to terminate TLS that supports ECDHE
# then this should be edited to remove the RSA+AESGCM:RSA+AES so that PFS
# only is guaranteed.
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!AES256:!aNULL:!eNULL:!MD5:!DSS:!PSK:!SRP
SSLHonorCipherOrder on
SSLCertificateFile <%= scope['phabricator::certs::cert_file'] %>
SSLCertificateKeyFile <%= scope['phabricator::certs::key_file'] %>
<% unless [nil, :undef].include?(scope['phabricator::certs::chain_file']) %>
SSLCertificateChainFile <%= scope['phabricator::certs::chain_file'] %>
<% end %>
<Location <%= @auth_location %> >
AuthType OpenID
require valid-user
AuthOpenIDSingleIdP <%= @authopenidsingleidp %>
</Location>
DocumentRoot <%= @docroot %>
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>
<Directory <%= @docroot %>>
Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
Allow from all
Require all granted
</Directory>
RewriteEngine on
RewriteRule ^/rsrc/(.*) - [L,QSA]
RewriteRule ^/favicon.ico - [L,QSA]
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
<Location <%= scope['phabricator::auth_location'] %> >
AuthType OpenID
require valid-user
AuthOpenIDSingleIdP <%= scope['phabricator::authopenidsingleidp'] %>
</Location>
RewriteEngine On
RewriteRule ^/rsrc/(.*) - [last,qsappend]
RewriteRule ^/favicon.ico - [last,qsappend]
RewriteRule ^(.*) /index.php?__path__=$1 [B,last,qsappend]
SetEnv PHABRICATOR_ENV production
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
LogLevel warn
ErrorLog /var/log/apache2/<%= @vhost_name %>_error.log
CustomLog /var/log/apache2/<%= @vhost_name %>_access.log combined
ServerSignature Off
SetEnv PHABRICATOR_ENV production
</VirtualHost>