Standardize HTTPS and vhost configuration
Adjust the SSL/TLS X.509 file handling to match our flexible standard, which allows the deployer to choose between managing the contents in or outside Puppet while still providing for a sane snakeoil fallback to ease testing and development. Also tune the SSL configuration to our typical stricter defaults, unconditionally redirect all HTTP requests to HTTPS, and reformat the vhost configuration for consistency and ease of future maintenance. Change-Id: Id5241377665845f8c453cbb833bc40d3a5915d76
This commit is contained in:
parent
670312c04a
commit
4cbe39375c
|
@ -5,12 +5,13 @@ class mediawiki(
|
||||||
$mediawiki_images_location = '/srv/mediawiki/images',
|
$mediawiki_images_location = '/srv/mediawiki/images',
|
||||||
$role = 'all',
|
$role = 'all',
|
||||||
$site_hostname = $::fqdn,
|
$site_hostname = $::fqdn,
|
||||||
$ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem',
|
$serveradmin = "webmaster@${::fqdn}",
|
||||||
$ssl_cert_file_contents = undef, # If left empty puppet will not create file.
|
$ssl_cert_file = undef,
|
||||||
|
$ssl_cert_file_contents = undef,
|
||||||
$ssl_chain_file = undef,
|
$ssl_chain_file = undef,
|
||||||
$ssl_chain_file_contents = undef, # If left empty puppet will not create file.
|
$ssl_chain_file_contents = undef,
|
||||||
$ssl_key_file = '/etc/ssl/private/ssl-cert-snakeoil.key',
|
$ssl_key_file = undef,
|
||||||
$ssl_key_file_contents = undef, # If left empty puppet will not create file.
|
$ssl_key_file_contents = undef,
|
||||||
$wg_recaptchapublickey = undef,
|
$wg_recaptchapublickey = undef,
|
||||||
$wg_recaptchaprivatekey = undef,
|
$wg_recaptchaprivatekey = undef,
|
||||||
$wg_googleanalyticsaccount = undef,
|
$wg_googleanalyticsaccount = undef,
|
||||||
|
@ -95,42 +96,129 @@ class mediawiki(
|
||||||
ensure => present,
|
ensure => present,
|
||||||
}
|
}
|
||||||
|
|
||||||
if $ssl_cert_file_contents != undef {
|
# To use the standard ssl-certs package snakeoil certificate, leave both
|
||||||
file { $ssl_cert_file:
|
# $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,
|
||||||
|
before => Httpd::Vhost[$site_hostname],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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',
|
owner => 'root',
|
||||||
group => 'root',
|
group => 'root',
|
||||||
mode => '0640',
|
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,
|
content => $ssl_cert_file_contents,
|
||||||
before => Httpd::Vhost[$site_hostname],
|
before => Httpd::Vhost[$site_hostname],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if $ssl_key_file_contents != undef {
|
|
||||||
file { $ssl_key_file:
|
|
||||||
owner => 'root',
|
|
||||||
group => 'ssl-cert',
|
|
||||||
mode => '0640',
|
|
||||||
content => $ssl_key_file_contents,
|
|
||||||
before => Httpd::Vhost[$site_hostname],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if $ssl_chain_file_contents != undef {
|
# To avoid using an intermediate certificate chain, leave both
|
||||||
file { $ssl_chain_file:
|
# $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',
|
owner => 'root',
|
||||||
group => 'root',
|
group => 'root',
|
||||||
mode => '0640',
|
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,
|
content => $ssl_chain_file_contents,
|
||||||
before => Httpd::Vhost[$site_hostname],
|
before => Httpd::Vhost[$site_hostname],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 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,
|
||||||
|
before => Httpd::Vhost[$site_hostname],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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,
|
||||||
|
before => Httpd::Vhost[$site_hostname],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
::httpd::vhost { $site_hostname:
|
::httpd::vhost { $site_hostname:
|
||||||
port => 443,
|
port => 443, # Is required despite not being used.
|
||||||
docroot => 'MEANINGLESS ARGUMENT',
|
docroot => '/var/www',
|
||||||
priority => '50',
|
priority => '50',
|
||||||
template => 'mediawiki/apache/mediawiki.erb',
|
template => 'mediawiki/apache/mediawiki.erb',
|
||||||
ssl => true,
|
ssl => true,
|
||||||
|
vhost_name => $site_hostname,
|
||||||
}
|
}
|
||||||
httpd_mod { 'rewrite':
|
httpd_mod { 'rewrite':
|
||||||
ensure => present,
|
ensure => present,
|
||||||
|
|
|
@ -1,68 +1,54 @@
|
||||||
#####################################################################
|
# ************************************
|
||||||
### THIS FILE IS MANAGED BY PUPPET
|
# Managed by Puppet
|
||||||
### puppet:///files/apache/sites/labconsole.wikimedia.org
|
# ************************************
|
||||||
#####################################################################
|
|
||||||
# vim: filetype=apache
|
|
||||||
|
|
||||||
|
# Unconditionally redirect all HTTP traffic for this vhost to HTTPS
|
||||||
<VirtualHost *:80>
|
<VirtualHost *:80>
|
||||||
ServerAdmin noc@openstack.org
|
ServerName <%= @vhost_name %>
|
||||||
ServerName <%= scope.lookupvar("mediawiki::site_hostname") %>
|
ServerAdmin <%= scope['mediawiki::serveradmin'] %>
|
||||||
|
RewriteEngine On
|
||||||
DocumentRoot /var/www
|
RewriteRule ^/(.*) https://<%= @vhost_name %>/$1 [last,redirect=permanent]
|
||||||
<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://<%= scope.lookupvar("mediawiki::site_hostname") %>/$1 [L,R]
|
|
||||||
|
|
||||||
ErrorLog /var/log/apache2/mediawiki-error.log
|
|
||||||
|
|
||||||
# Possible values include: debug, info, notice, warn, error, crit,
|
|
||||||
# alert, emerg.
|
|
||||||
LogLevel warn
|
LogLevel warn
|
||||||
|
ErrorLog /var/log/apache2/<%= @vhost_name %>_error.log
|
||||||
CustomLog /var/log/apache2/mediawiki-access.log combined
|
CustomLog /var/log/apache2/<%= @vhost_name %>_access.log combined
|
||||||
ServerSignature Off
|
ServerSignature Off
|
||||||
|
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
||||||
<VirtualHost *:443>
|
<VirtualHost *:443>
|
||||||
ServerAdmin noc@openstack.org
|
|
||||||
ServerName <%= scope.lookupvar("mediawiki::site_hostname") %>
|
ServerName <%= @vhost_name %>
|
||||||
|
ServerAdmin <%= scope['mediawiki::serveradmin'] %>
|
||||||
|
|
||||||
SSLEngine on
|
SSLEngine on
|
||||||
SSLProtocol All -SSLv2 -SSLv3
|
SSLProtocol All -SSLv2 -SSLv3
|
||||||
SSLCertificateFile <%= scope.lookupvar("mediawiki::ssl_cert_file") %>
|
# Once the machine is using something to terminate TLS that supports ECDHE
|
||||||
SSLCertificateKeyFile <%= scope.lookupvar("mediawiki::ssl_key_file") %>
|
# then this should be edited to remove the RSA+AESGCM:RSA+AES so that PFS
|
||||||
<%# The original default was '' -%>
|
# only is guaranteed.
|
||||||
<%# scope.lookupvar returns nil for an undefined variable in puppet 4 -%>
|
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!AES256:!aNULL:!eNULL:!MD5:!DSS:!PSK:!SRP
|
||||||
<%# scope.lookupvar returns :undef for an undefined variable in puppet 3 -%>
|
SSLHonorCipherOrder on
|
||||||
<% unless ['', nil, :undef].include?(scope.lookupvar("mediawiki::ssl_chain_file")) %>
|
SSLCertificateFile <%= scope['mediawiki::cert_file'] %>
|
||||||
SSLCertificateChainFile <%= scope.lookupvar("mediawiki::ssl_chain_file") %>
|
SSLCertificateKeyFile <%= scope['mediawiki::key_file'] %>
|
||||||
|
<% unless [nil, :undef].include?(scope['mediawiki::chain_file']) %>
|
||||||
|
SSLCertificateChainFile <%= scope['mediawiki::chain_file'] %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
RedirectMatch ^/$ http://<%= scope.lookupvar("mediawiki::site_hostname") %>/wiki/
|
RedirectMatch ^/$ https://<%= @vhost_name %>/wiki/
|
||||||
|
|
||||||
|
DocumentRoot <%= @docroot %>
|
||||||
|
|
||||||
DocumentRoot /var/www
|
|
||||||
<Directory />
|
<Directory />
|
||||||
Options FollowSymLinks
|
Options FollowSymLinks
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<Directory /var/www/>
|
<Directory /var/www/>
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
Order allow,deny
|
Order allow,deny
|
||||||
allow from all
|
allow from all
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory "<%= scope.lookupvar('mediawiki::mediawiki_images_location') %>">
|
|
||||||
|
<Directory "<%= scope['mediawiki::mediawiki_images_location'] %>">
|
||||||
# Ignore .htaccess files
|
# Ignore .htaccess files
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
|
|
||||||
|
@ -72,12 +58,14 @@
|
||||||
# Don't run arbitrary PHP code.
|
# Don't run arbitrary PHP code.
|
||||||
php_admin_flag engine off
|
php_admin_flag engine off
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory "<%= scope.lookupvar('mediawiki::mediawiki_location') %>">
|
|
||||||
|
<Directory "<%= scope['mediawiki::mediawiki_location'] %>">
|
||||||
Require all granted
|
Require all granted
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<IfModule mod_expires.c>
|
<IfModule mod_expires.c>
|
||||||
ExpiresActive On
|
ExpiresActive On
|
||||||
<Directory "<%= scope.lookupvar('mediawiki::mediawiki_location') %>">
|
<Directory "<%= scope['mediawiki::mediawiki_location'] %>">
|
||||||
<FilesMatch "\.(gif|jpe?g|png|css|js|woff|svg|eot|ttf)$">
|
<FilesMatch "\.(gif|jpe?g|png|css|js|woff|svg|eot|ttf)$">
|
||||||
ExpiresByType image/gif A2592000
|
ExpiresByType image/gif A2592000
|
||||||
ExpiresByType image/png A2592000
|
ExpiresByType image/png A2592000
|
||||||
|
@ -96,28 +84,30 @@
|
||||||
</FilesMatch>
|
</FilesMatch>
|
||||||
</Directory>
|
</Directory>
|
||||||
</IfModule>
|
</IfModule>
|
||||||
|
|
||||||
AddType application/x-font-woff .woff
|
AddType application/x-font-woff .woff
|
||||||
AddType application/vnd.ms-fontobject .eot
|
AddType application/vnd.ms-fontobject .eot
|
||||||
|
|
||||||
# TTF doesn't have an official MIME type, but I really don't want to use application/octet-stream for it
|
# TTF doesn't have an official MIME type, but I really don't want to use application/octet-stream for it
|
||||||
AddType application/x-font-ttf .ttf
|
AddType application/x-font-ttf .ttf
|
||||||
|
|
||||||
Alias /w/images <%= scope.lookupvar('mediawiki::mediawiki_images_location') %>
|
Alias /w/images <%= scope['mediawiki::mediawiki_images_location'] %>
|
||||||
Alias /w <%= scope.lookupvar('mediawiki::mediawiki_location') %>
|
Alias /w <%= scope['mediawiki::mediawiki_location'] %>
|
||||||
Alias /wiki <%= scope.lookupvar('mediawiki::mediawiki_location') %>/index.php
|
Alias /wiki <%= scope['mediawiki::mediawiki_location'] %>/index.php
|
||||||
|
|
||||||
# Redirect old /Article_Name urls
|
# Redirect old /Article_Name urls
|
||||||
RewriteEngine on
|
RewriteEngine on
|
||||||
RewriteCond %{REQUEST_URI} !^/w/
|
RewriteCond %{REQUEST_URI} !^/w/
|
||||||
RewriteCond %{REQUEST_URI} !^/wiki/
|
RewriteCond %{REQUEST_URI} !^/wiki/
|
||||||
RewriteRule ^/(.*)$ https://<%= scope.lookupvar("mediawiki::site_hostname") %>/wiki/$1 [L,R]
|
RewriteRule ^/(.*)$ https://<%= @vhost_name %>/wiki/$1 [L,R]
|
||||||
|
|
||||||
ErrorLog /var/log/apache2/error.log
|
|
||||||
|
|
||||||
# Possible values include: debug, info, notice, warn, error, crit,
|
# Possible values include: debug, info, notice, warn, error, crit,
|
||||||
# alert, emerg.
|
# alert, emerg.
|
||||||
LogLevel warn
|
LogLevel warn
|
||||||
|
|
||||||
CustomLog /var/log/apache2/access.log combined
|
ErrorLog /var/log/apache2/<%= @vhost_name %>_error.log
|
||||||
|
CustomLog /var/log/apache2/<%= @vhost_name %>_access.log combined
|
||||||
|
|
||||||
ServerSignature Off
|
ServerSignature Off
|
||||||
|
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
|
|
Loading…
Reference in New Issue