view modules/website/manifests/init.pp @ 410:575764c36e16

Setup CSP Nonce on the server
author IBBoard <dev@ibboard.co.uk>
date Sat, 08 Oct 2022 12:08:50 +0100
parents df5ad1612af7
children a08a2f718f9d
line wrap: on
line source

class website(
  Pattern[/^(\/[^\/]+)*$/] $base_dir,
  Pattern[/^(\/[^\/]+)*$/] $cert_dir           = '/etc/pki/custom',
  Stdlib::IP::Address $primary_ip,
  Optional[Stdlib::IP::Address::V6] $proxy_4to6_ip_prefix = undef,
  Optional[Integer] $proxy_4to6_mask = undef,
  Optional[Array] $proxy_upstream = undef,
  String $default_owner,
  String $default_group,
  String $default_tld        = 'com',
  Array $default_extra_tlds = []
  ){

  $basedir = $base_dir
  $certdir = $cert_dir
  $docroot_owner = $default_owner
  $docroot_group = $default_group
  $ca_chain = "/etc/letsencrypt/live/${::fqdn}/chain.pem"
  $tld = $default_tld
  $extra_tlds = $default_extra_tlds
  $htmlphpfragment = "Include conf.extra/html-php.conf"
  $filterfragment = "Include conf.custom/filter.conf"
  $cmsfragment = "Include conf.extra/cms_rewrites.conf"

  $csp_base = {
    "frame-ancestors" => "'none'",
    "base-uri" => "'none'",
    "object-src" => "'none'",
  }
  $csp_report_base = {
    "default-src" => "'none'",
    "img-src" => "'self'",
    "script-src" => "'self' 'nonce-%{CSP_NONCE}e'",
    "style-src" => "'self' 'nonce-%{CSP_NONCE}e'",
    "font-src" => "'self' 'nonce-%{CSP_NONCE}e'"
  }

  if $osfamily == 'RedHat' {
    $apache_base_dir = "/etc/httpd/"
    $vhost_dir = "/etc/httpd/conf.d/vhosts"
    $apache_user = 'apache'
    $apache_group = $apache_user
    $apache_log_group = $apache_user
  }
  elsif $osfamily == 'Debian' {
    $apache_base_dir = "/etc/apache2/"
    $vhost_dir = "/etc/apache2/sites-available"
    $apache_user = 'www-data'
    $apache_group = $apache_user
    $apache_log_group = $apache_user
  }


  class { 'apache':
    vhost_dir => $vhost_dir,
    protocols => ["h2", "http/1.1"],
    default_mods => false,
    default_vhost => false,
    mpm_module => false,
  }
  class { 'apache::mod::dir': indexes => [ 'index.html' ] }
  class { 'apache::mod::event': }
  class { 'apache::mod::http2': }
  class { 'apache::mod::mime': mime_types_config => "${apache_base_dir}mime.types" }
  apache::mod {
    'rewrite':;
    'expires':;
    'env':;
    'setenvif':;
    'headers':;
    'allowmethods':;
  }
  if $osfamily == 'RedHat' {
    # Ubuntu builds the "version" module in, but CentOS doesn't
    apache::mod {
      'version':;
    }
  }

  # Updating the httpd package puts back some configs that we
  # don't load the relevant modules for, so we'll try to make
  # them blank so that RPM/Yum makes ".rpmnew" files instead
  $unused_default_mods = [
    "${::apache::mod_dir}/autoindex.conf",
    "${::apache::mod_dir}/userdir.conf",
    "${::apache::mod_dir}/welcome.conf",
  ]
  file { $unused_default_mods:
    ensure => file,
    content => '',
    require => Class['apache'],
  }

  file { $base_dir:
    ensure => directory;
  }
  file { '/var/log/apache':
    ensure => directory,
    mode   => '0750',
    group  => $apache_log_group,
  }
  file { "${apache_base_dir}conf.extra":
    ensure => directory,
    recurse => true,
    source => "puppet:///modules/website/conf.extra",
    require => Class['apache'],
    notify => Service['httpd'];
  }
  file { "${apache_base_dir}mime.types":
    ensure => present,
    source => "puppet:///modules/website/mime.types",
    require => Class['apache'],
    notify => Service['httpd'];
  }
  file { "${apache_base_dir}conf.d/zzz-custom.conf":
    ensure => absent,
    require => Class['apache'],
    notify => Service['httpd'];
  }
  file { "${apache_base_dir}conf.d/zzz-0-custom.conf":
    ensure => present,
    source => "puppet:///modules/website/zzz-0-custom.conf",
    require => Class['apache'],
    notify => Service['httpd'];
  }
  file { "${apache_base_dir}conf.custom":
    ensure => directory,
    recurse => true,
    source => "puppet:///private/apache/conf.custom",
    require => Class['apache'],
    notify => Service['httpd']; 
  }
  file { $cert_dir:
    ensure => directory;
  }
  firewall { '100 allow https and http':
    destination => $primary_ip,
    dport => [80, 443],
    proto => tcp,
    action => accept,
  }
  if ($proxy_4to6_ip_prefix != undef) and ($proxy_upstream != undef) {
    apache::mod { "remoteip": }
    $proxy_4to6_ip = "$proxy_4to6_ip_prefix:0000/$proxy_4to6_mask"

    $proxy_upstream.each |String $upstream_addr| {
      firewall { "100 limit PROXY protocol to upstream $upstream_addr":
        source => $upstream_addr,
        destination => $proxy_4to6_ip,
        dport => [80, 443],
        proto => tcp,
        action => accept,
      }
    }
    firewall { "101 block all other PROXY protocol access":
      destination => $proxy_4to6_ip,
      dport => [80, 443],
      proto => tcp,
      action => reject,
    }
  }
  if $operatingsystem == 'CentOS' {
    exec { 'set_apache_defaults':
      command => 'semanage fcontext -a -t httpd_sys_content_t "/srv/sites(/.*)?"',
      path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
      require => Package['policycoreutils-python'],
      unless  => 'semanage fcontext --list | grep "/srv/sites\\(/\\.\\*\\)\\?"',
    }
    if versioncmp($operatingsystemrelease, '8') < 0 {
        $certbot_pkg = 'python2-certbot-apache'
    } else {
        $certbot_pkg = 'python3-certbot-apache'
    }
  }
  elsif $operatingsystem == 'Ubuntu' {
    $certbot_pkg = 'certbot'
  }
  cron { 'letsencrypt-renewal':
    command => '/usr/bin/certbot renew --quiet',
    hour => '*/12',
    minute => '21',
  }
  package { $certbot_pkg:
    ensure => installed,
  }
}