class profile::apache { class { 'apache': root_directory_secured => true, root_directory_options => ["All"], default_mods => false, default_vhost => false, log_formats => { combined => '%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %p', common => '%h %l %u %t \"%r\" %>s %b', } } ::apache::custom_config { 'log_config.conf': content => 'CustomLog "/var/log/httpd/access_log" combined', filename => 'log_config.conf' } ::apache::custom_config { 'protocols.conf': content => 'Protocols h2 http/1.1', filename => 'protocols.conf' } ::apache::custom_config { 'document_root.conf': source => "puppet:///modules/profile/apache/document_root.conf", filename => "document_root.conf" } ::apache::custom_config { 'immae.conf': source => "puppet:///modules/profile/apache/immae.conf", filename => 'immae.conf' } ::apache::custom_config { 'letsencrypt.conf': source => "puppet:///modules/profile/apache/letsencrypt.conf", filename => 'letsencrypt.conf' } $apache_vhost_default = { no_proxy_uris => [ "/maintenance_immae.html", "/googleb6d69446ff4ca3e5.html", "/.well-known/acme-challenge" ], no_proxy_uris_match => [ '^/licen[cs]es?_et_tip(ping)?$', '^/licen[cs]es?_and_tip(ping)?$', '^/licen[cs]es?$', '^/tip(ping)?$', ] } exec { 'Start-apache': command => "/usr/bin/systemctl start httpd", before => Class["::letsencrypt"], unless => "/usr/bin/systemctl is-active httpd", } $letsencrypt_certonly_default = { plugin => "webroot", webroot_paths => ["/srv/http/"], notify => Class['Apache::Service'], require => [Exec['Start-apache'],Apache::Vhost["redirect_no_ssl"],Apache::Custom_config["letsencrypt.conf"]], manage_cron => true, } class { '::letsencrypt': install_method => "package", package_name => "certbot", package_command => "certbot", email => lookup('letsencrypt::email'), } $real_hostname = lookup("base_installation::real_hostname", { "default_value" => undef }) unless empty($real_hostname) { if (lookup("letsencrypt::try_for_real_hostname", { "default_value" => true })) { letsencrypt::certonly { $real_hostname: before => Apache::Vhost["default_ssl"]; default: * => $::profile::apache::letsencrypt_certonly_default; } $ssl_cert = "/etc/letsencrypt/live/$real_hostname/cert.pem" $ssl_key = "/etc/letsencrypt/live/$real_hostname/privkey.pem" $ssl_chain = "/etc/letsencrypt/live/$real_hostname/chain.pem" } else { ssl::self_signed_certificate { $real_hostname: common_name => $real_hostname, country => "FR", days => "3650", organization => "Immae", directory => "/etc/httpd/conf/ssl", before => Apache::Vhost["default_ssl"], } $ssl_key = "/etc/httpd/conf/ssl/$real_hostname.key" $ssl_cert = "/etc/httpd/conf/ssl/$real_hostname.crt" $ssl_chain = undef } apache::vhost { "default_ssl": port => '443', docroot => '/srv/http', servername => $real_hostname, directoryindex => 'index.htm index.html', ssl => true, ssl_key => $ssl_key, ssl_cert => $ssl_cert, ssl_chain => $ssl_chain, priority => 0; default: * => $::profile::apache::apache_vhost_default; } } lookup("letsencrypt::hosts", { "default_value" => [] }).each |$host| { if ($host != $real_hostname) { # Done above already letsencrypt::certonly { $host: ; default: * => $letsencrypt_certonly_default; } } } apache::vhost { "redirect_no_ssl": port => '80', error_log => false, log_level => undef, access_log => false, docroot => false, servername => "", serveraliases => "*", priority => 99, rewrites => [ { rewrite_cond => '"%{REQUEST_URI}" "!^/\.well-known"', rewrite_rule => '^(.+) https://%{HTTP_HOST}$1 [R=301]' } ] } class { 'apache::mod::ssl': ssl_protocol => [ 'all', '-SSLv3' ], # Given by # https://mozilla.github.io/server-side-tls/ssl-config-generator/ ssl_cipher => "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS", # FIXME: need SSLSessionTickets off ssl_stapling => true, ssl_stapling_return_errors => false, # FIXME: SSLStaplingResponderTimeout 5 ssl_ca => '/etc/ssl/certs/ca-certificates.crt', } class { 'apache::mod::alias': } class { 'apache::mod::autoindex': } # Included by ssl # class { 'apache::mod::mime': } class { 'apache::mod::deflate': } class { 'apache::mod::rewrite': } class { 'apache::mod::dir': indexes => ["index.html"] } file { [ "/srv/http", "/srv/http/.well-known"]: ensure => "directory", mode => "0755", owner => "root", group => "root", } file { "/srv/http/index.html": mode => "0644", owner => "root", group => "root", source => "puppet:///modules/profile/apache/index.html", } file { "/srv/http/maintenance_immae.html": mode => "0644", owner => "root", group => "root", source => "puppet:///modules/profile/apache/maintenance_immae.html", } file { "/srv/http/googleb6d69446ff4ca3e5.html": mode => "0644", owner => "root", group => "root", source => "puppet:///modules/profile/apache/googleb6d69446ff4ca3e5.html", } }