view manifests/templates.pp @ 284:9431aec4d998

Switch to using IPv6 prefix and IP per site This is because the proxy seems to break SNI, so we need an IP per SSL cert. We're not short of IPv6 addresses, though! Also corrected to "4to6" naming, because we're letting IPv4 access an IPv6 site
author IBBoard <dev@ibboard.co.uk>
date Sun, 16 Feb 2020 12:07:35 +0000
parents af7df930a670
children 61e90445c899
line wrap: on
line source

# Make sure packages come after their repos
File<| tag == 'repo-config' |> -> YumRepo<| |> -> Package<| |>

# Make sure all files are in  place before starting services
File<| tag != 'post-service' |> -> Service<| |>

# Set some shortcut variables
#$os = $operatingsystem
$osver = $operatingsystemmajrelease
$server = ''


class basenode {
	include sudo

	include defaultusers
	include logwatch

	file { '/etc/puppet/hiera.yaml':
		ensure => present,
		content => "
# Let the system set defaults
version: 5
",
	}
}

class basevpsnode (
	$primary_ip,
	$proxy_4to6_ip_prefix = undef,
	$proxy_upstream = undef,
	$mailserver,
	$imapserver,
	$firewall_cmd = 'iptables',
	) {

	if $firewall_cmd == 'iptables' {
		class { 'vpsfirewall':
			fw_protocol => $primary_ip =~ Stdlib::IP::Address::V6 ? { true => 'IPv6', default => 'IPv4'},
		}
	}

	#VPS is a self-mastered Puppet machine, so bodge a Hosts file
	file { '/etc/hosts':
		ensure => present,
		content => "127.0.0.1   localhost
$primary_ip ${fqdn}",
	}

	require repos
	include basenode
	include privat
	include dnsresolver
	include ssh::server
	include vcs::server
	include vcs::client
	class { 'webserver':
		primary_ip => $primary_ip,
		proxy_4to6_ip_prefix => $proxy_4to6_ip_prefix,
		proxy_upstream => $proxy_upstream,
	}
	include cronjobs
	include logrotate
	class { 'fail2ban':
		firewall_cmd => $firewall_cmd,
	}
	include tools
	class { 'email':
		mailserver => $mailserver,
		imapserver => $imapserver,
	}
}

## Classes to allow facet behaviour using preconfigured setups of classes

class vpsfirewall ($fw_protocol) {
	resources { "firewall":
		purge => false,
	}
	class { "my_fw":
		ip_version => $fw_protocol,
	}
	# Control what does and doesn't get pruned in the main filter chain
	firewallchain { "INPUT:filter:$fw_protocol":
		purge => true,
		ignore => [
			'-j f2b-[^ ]+$',
			'^(:|-A )f2b-',
			'--comment "Great Firewall of China"',
			'--comment "Do not purge',
			],
	}
	if ($fw_protocol != "IPv6") {
		firewall { '010 Whitelist Googlebot':
			source => '66.249.64.0/19',
			dport => [80,443],
			proto => tcp,
			action => accept,
		}
		# Block a spammer hitting our contact forms (also on StopForumSpam list A LOT)
		firewall { '099 Blacklist spammers 1':
			source => '107.181.78.172',
			dport => [80, 443],
			proto => tcp,
			action => 'reject',
		}
		firewall { '099 Blacklist IODC bot':
			# IODC bot makes too many bad requests, and contact form is broken
			# They don't publish a robots.txt name, so firewall it!
			source => '86.153.145.149',
			dport => [ 80, 443 ],
			proto => tcp,
			action => 'reject',
		}
		firewall { '099 Blacklist Baidu Brazil':
			#Baidu got a Brazilian netblock and are hitting us hard
			#Baidu doesn't honour "crawl-delay" in robots.txt
			#Baidu gets firewalled
			source => '131.161.8.0/22',
			dport => [ 80, 443 ],
			proto => tcp,
			action => 'reject',
		}
	}
	firewallchain { "GREATFIREWALLOFCHINA:filter:$fw_protocol":
		ensure => present,
	}
	firewall { '050 Check our Great Firewall Against China':
		chain => 'INPUT',
		jump => 'GREATFIREWALLOFCHINA',
	}
	firewallchain { "Fail2Ban:filter:$fw_protocol":
		ensure => present,
	}
	firewall { '060 Check Fail2Ban':
		chain => 'INPUT',
		jump => 'Fail2Ban',
	}
	firewall { '101 allow SMTP':
		dport => [25, 465],
		proto => tcp,
		action => accept,
	}
	firewall { '102 allow IMAPS':
		dport => 993,
		proto => tcp,
		action => accept,
	}
	# Note: SSH port will be managed separately as we 
	# put it on a different port to hide from script kiddy noise
}

class dnsresolver {
	package { 'bind':
		ensure => present,
	}

	service { 'named':
		ensure => running,
		enable => true,
		require => Package['bind'],
	}

	file { '/etc/named.conf':
		ensure => present,
		source => [
                        "puppet:///common/named.conf-${::hostname}",
                        "puppet:///common/named.conf",
                ],
		group => 'named',
		require => Package['bind'],
		notify => Service['named'],
	}

	file { '/etc/NetworkManager/conf.d/local-dns-resolver.conf':
		ensure => present,
		content => "[main]
dns=none",
	}

	file { '/etc/sysconfig/named':
		ensure => present,
		source => [
			"puppet:///common/sysconfig-named-${::hostname}",
			"puppet:///common/sysconfig-named",
		],
		require => Package['bind'],
	}

	file { '/etc/resolv.conf':
		ensure => present,
		content => "nameserver 127.0.0.1",
		require => Service['named'],
		tag => 'post-service',
	}
}

class repos {
	yumrepo { 'epel':
		mirrorlist => 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch',
		descr => "Extra Packages for Enterprise Linux",
		enabled => 1,
		failovermethod => 'priority',
		gpgcheck => 1,
		gpgkey => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$osver",
	}
	file { "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-$osver":
		ensure => present,
		source => "puppet:///common/RPM-GPG-KEY-EPEL-$osver",
		tag => 'repo-config',
	}
	yumrepo { 'ibboard':
		baseurl => 'https://download.opensuse.org/repositories/home:/IBBoard:/server/CentOS_$releasever/',
		descr => 'Extra packages from IBBoard',
		enabled => 1,
		gpgcheck => 1,
		gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ibboard',
	}
	file { '/etc/pki/rpm-gpg/RPM-GPG-KEY-ibboard':
		ensure => present,
		source => 'puppet:///common/RPM-GPG-KEY-ibboard',
		tag => 'repo-config',
	}
	yumrepo { 'webtatic':
		ensure => absent,
	}
	file { '/etc/pki/rpm-gpg/RPM-GPG-KEY-webtatic-andy':
		ensure => absent,
	}
	file { '/etc/pki/rpm-gpg/RPM-GPG-KEY-webtatic-el7':
		ensure => absent,
	}

	if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') >= 0 {
		$python_ver = 'python3'
	} else {
		$python_ver = 'system'
	}

	class { 'python':
		ensure => 'present',
		version => $python_ver,
		pip => 'present',
		virtualenv => 'present',
		use_epel => false,
	}
}

class tools {
	$packages = [ 'sqlite', 'bash-completion', 'nano', 'bzip2', 'mlocate', 'patch', 'tmux', 'wget' ]
	package { $packages:
		ensure => installed;
	}
}

class logrotate {
	package { 'logrotate':
		ensure => installed;
	}
	file { '/etc/logrotate.d/httpd':
		ensure => present,
		source => 'puppet:///common/logrotate-httpd',
		require => Package['logrotate'],
	}
	file { '/etc/logrotate.d/trac':
		ensure => present,
		source => 'puppet:///common/logrotate-trac',
		require => Package['logrotate'],
	}
}

class logwatch {
	package { 'logwatch':
		ensure => installed;
	}
	File {
		ensure => present,
		require => Package['logwatch'],
	}
	file { '/etc/cron.daily/0logwatch':
		source => 'puppet:///common/0logwatch';
	}
	file { '/etc/logwatch/scripts/shared/':
		ensure => directory,
	}
	file { '/etc/logwatch/scripts/services/fail2ban':
		source => 'puppet:///common/logwatch/services-fail2ban',
	}
	file { '/etc/logwatch/scripts/services/named':
		source => 'puppet:///common/logwatch/named',
	}
	file { '/etc/logwatch/scripts/services/http-error':
		source => 'puppet:///common/logwatch/http-error',
	}
	file { '/etc/logwatch/scripts/services/php':
		source => 'puppet:///common/logwatch/scripts_php',
	}
	file { '/etc/logwatch/scripts/services/mysql':
		source => 'puppet:///common/logwatch/scripts_mysql',
	}
	file { '/etc/logwatch/scripts/services/dovecot':
		source => 'puppet:///common/logwatch/dovecot',
	}
	file { '/etc/logwatch/scripts/services/postfix':
		source => 'puppet:///common/logwatch/postfix',
	}
	file { '/etc/logwatch/scripts/shared/applyhttperrordate':
		source => 'puppet:///common/logwatch/applyhttperrordate',
	}
	file { '/etc/logwatch/conf/logwatch.conf':
		content => 'Detail = Med',
	}
	file { '/etc/logwatch/conf/logfiles/http.conf':
		content => 'LogFile = apache/access_*.log',
	}
	file { '/etc/logwatch/conf/logfiles/http-error-24.conf':
		source => 'puppet:///common/logwatch/log-http-error.conf',
	}
	file { '/etc/logwatch/conf/logfiles/http-error.conf':
		ensure=> absent,
	}
	file { '/etc/logwatch/conf/services/http-error.conf':
		source => 'puppet:///common/logwatch/services-http-error.conf',
	}
	file { '/etc/logwatch/conf/logfiles/php.conf':
		source => 'puppet:///common/logwatch/logfiles_php.conf',
	}
	file { '/etc/logwatch/conf/services/php.conf':
		source => 'puppet:///common/logwatch/services_php.conf',
	}
	file { '/etc/logwatch/conf/logfiles/mysql.conf':
		source => 'puppet:///common/logwatch/logfiles_mysql.conf',
	}
	file { '/etc/logwatch/conf/services/mysql.conf':
		source => 'puppet:///common/logwatch/services_mysql.conf',
	}
}

class fail2ban (
	$firewall_cmd,
	) {
	package { 'fail2ban':
		ensure => installed,
	}
	service { 'fail2ban':
		ensure => running,
		enable => true
	}
	File {
		ensure => present,
		require => Package['fail2ban'],
		notify => Service['fail2ban'],
	}
	file { '/etc/fail2ban/fail2ban.local':
		source => 'puppet:///common/fail2ban/fail2ban.local',
	}
	file { '/etc/fail2ban/jail.local':
		source => 'puppet:///common/fail2ban/jail.local',
	}
	file { '/etc/fail2ban/action.d/apf.conf':
		source => 'puppet:///common/fail2ban/apf.conf',
	}

	if $firewall_cmd == 'iptables' {
		$firewall_ban_cmd = 'iptables-multiport'
	} else {
		$firewall_ban_cmd = $firewall_cmd
	}

	file { '/etc/fail2ban/action.d/firewall-ban.conf':
		ensure => link,
		target => "/etc/fail2ban/action.d/${firewall_ban_cmd}.conf",
	}
	file { '/etc/fail2ban/filter.d/ibb-apache-exploits-instaban.conf':
		source => 'puppet:///common/fail2ban/ibb-apache-exploits-instaban.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-apache-shellshock.conf':
		source => 'puppet:///common/fail2ban/ibb-apache-shellshock.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-repeat-offender.conf':
		source => 'puppet:///common/fail2ban/ibb-repeat-offender.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-repeat-offender-ssh.conf':
		source => 'puppet:///common/fail2ban/ibb-repeat-offender-ssh.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-postfix-spammers.conf':
		source => 'puppet:///common/fail2ban/ibb-postfix-spammers.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-postfix-malicious.conf':
		source => 'puppet:///common/fail2ban/ibb-postfix-malicious.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-postfix.conf':
		source => 'puppet:///common/fail2ban/ibb-postfix.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-sshd.conf':
		source => 'puppet:///common/fail2ban/ibb-sshd.conf',
	}
	file { '/etc/fail2ban/filter.d/ibb-sshd-bad-user.conf':
		source => 'puppet:///common/fail2ban/ibb-sshd-bad-user.conf',
	}
	# Because one of our rules checks fail2ban's log, but the service dies without the file
	file { '/var/log/fail2ban.log':
		ensure => present,
		owner => 'root',
		group => 'root',
		mode => '0600',
	}
}

#Our web server with our configs, not just a stock one
class webserver (
	$primary_ip,
	$proxy_4to6_ip_prefix = undef,
	$proxy_upstream = undef,
	) {

	if $proxy_4to6_ip_prefix == undef {
		$ipv6_addresses = []
	}
	else {
		$ipv6_addresses = [1, 2, 3, 4, 5, 6, 7, 8, 9].map |$octet| { "$proxy_4to6_ip_prefix:$octet" }
	}

	#Setup base website parameters
	class { 'website':
		base_dir => '/srv/sites',
		primary_ip => $primary_ip,
		proxy_4to6_ip_prefix => $proxy_4to6_ip_prefix,
		proxy_4to6_mask => 124,
		proxy_4to6_addresses => $ipv6_addresses,
		proxy_upstream => $proxy_upstream,
		default_owner => $defaultusers::default_user,
		default_group => $defaultusers::default_user,
		default_tld => 'co.uk',
		default_extra_tlds => [ 'com' ],
	}

	# Use Remi's PHP 7.3 for now - 7.4 is still VERY new
	$php_suffix = ''
	if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') >= 0 {
		yumrepo { 'remirepo-safe':
			mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/safe/$basearch/mirror',
			descr => "Extra CentOS packages from Remi",
			enabled => 1,
			failovermethod => 'priority',
			gpgcheck => 1,
			gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
		}
		yumrepo { 'remirepo-php':
			mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/php73/$basearch/mirror',
			descr => "PHP7.3 for CentOS from Remi",
			enabled => 1,
			failovermethod => 'priority',
			gpgcheck => 1,
			gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
		}
	} else {
		yumrepo { 'remirepo-safe':
			mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/safe/mirror',
			descr => "Extra CentOS packages from Remi",
			enabled => 1,
			failovermethod => 'priority',
			gpgcheck => 1,
			gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
		}
		yumrepo { 'remirepo-php':
			mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/php73/mirror',
			descr => "PHP7.3 for CentOS from Remi",
			enabled => 1,
			failovermethod => 'priority',
			gpgcheck => 1,
			gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
		}
	}
	file { '/etc/pki/rpm-gpg/RPM-GPG-KEY-remi':
		ensure => present,
		source => 'puppet:///common/RPM-GPG-KEY-remi',
		before => YumRepo['remirepo-php'],
	}

	#Configure the PHP version to use
	class { 'website::php':
		suffix => $php_suffix, 
		opcache => 'opcache',
		extras => [ 'process', 'intl', 'pecl-imagick', 'bcmath', 'pecl-zip' ],
	}

	#Setup MySQL, using (private) templates to make sure that we set non-std passwords and a default user

	if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '7') >= 0 {
		$mysqlpackage = 'mariadb'
		$mysqlsuffix = ''

		# Required for SELinux rule setting/status checks
		if versioncmp($operatingsystemrelease, '8') >= 0 {
			$semanage_package_name = 'policycoreutils-python-utils'
		} else {
			$semanage_package_name = 'policycoreutils-python'
		}

		package { 'policycoreutils-python':
			name => $semanage_package_name,
			ensure => present,
		}

		$extra_packages = [
			'perl-Sys-Syslog', #Required for Perl SPF checking
		]

		package { $extra_packages:
			 ensure => installed
		}
	}
	else {
		$mysqlpackage = 'mysql'
		$mysqlsuffix = '55w'
	}
	class { 'website::mysql':
		mysqluser => template('defaultusers/mysql-user'),
		mysqlpassword => template('defaultusers/mysql-password'),
		mysqlprefix => $mysqlpackage,
		mysqlsuffix => $mysqlsuffix,
		phpsuffix => $php_suffix,
		phpmysqlsuffix => 'nd'
	}
}

class ibboardvpsnode (
	$primary_ip,
	$proxy_4to6_ip_prefix = undef,
	$proxy_upstream = undef,
	$mailserver,
	$imapserver,
	$firewall_cmd = 'iptables',
	){
	class { 'basevpsnode':
		primary_ip => $primary_ip,
		proxy_4to6_ip_prefix => $proxy_4to6_ip_prefix,
		proxy_upstream => $proxy_upstream,
		mailserver => $mailserver,
		imapserver => $imapserver,
		firewall_cmd => $firewall_cmd,
	}

	# Set timezone to something sensible
	file { "/etc/localtime":
		ensure => 'link',
		target => '/usr/share/zoneinfo/Europe/London',
	}

	# Common modules used by multiple sites (mod_auth_basic is safe because we HTTPS all the things)
	$mods = [ 'auth_basic',
		'authn_file',
		'authz_user',
		'deflate',
		'xsendfile'
		]
	apache::mod {
		$mods:;
	}
	if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '7') >= 0 {
		apache::mod {
			'authn_core':;
		}
	}

	#Configure our sites, using templates for the custom fragments where the extra content is too long
	class { "devsite":
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:01", default => undef }
	}
	class { "adminsite":
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:02", default => undef }
	}
	website::https::multitld { 'www.ibboard':
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:03", default => undef },
		custom_fragment => template("privat/apache/ibboard.fragment"),
		letsencrypt_name => 'ibboard.co.uk',
		csp_override => {
			"report-uri" => "https://ibboard.report-uri.com/r/d/csp/enforce",
			"default-src" => "'none'",
			"img-src" => "'self' https://live.staticflickr.com/",
			"script-src" => "'self'",
			"style-src" => "'self'",
			"font-src" => "'self'",
			"form-action" => "'self'",
			"connect-src" => "'self'",
		}
	}
	class { "hiveworldterrasite":
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:04", default => undef }
	}
	class { "bdstrikesite":
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:05", default => undef }
	}
	website::https::multitld { 'www.abiknight':
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:06", default => undef },
		custom_fragment => "$website::htmlphpfragment
	ErrorDocument 404 /error.php",
		letsencrypt_name => 'abiknight.co.uk',
	}
	website::https::multitld { 'www.warfoundry':
		proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:07", default => undef },
		letsencrypt_name => 'warfoundry.co.uk',
		custom_fragment => template("privat/apache/warfoundry.fragment"),
	}
	class { "webmailpimsite":
		proxy_4to6_ip_pim => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:08", default => undef },
		proxy_4to6_ip_webmail => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:09", default => undef },
	}
}

class adminsite ($proxy_4to6_ip) {
	apache::mod { 'info':; 'status':; 'cgi':; }
	website::https::multitld { 'admin.ibboard':
		proxy_4to6_ip => $proxy_4to6_ip,
		force_no_index => false,
		ssl_ca_chain => '',
		custom_fragment => template("privat/apache/admin.fragment"),
	}
	cron { 'loadavg':
		command => '/usr/local/bin/run-loadavg-logger',
		user => apache,
		minute => '*/6'
	}
	cron { 'awstats':
		command => '/usr/local/bin/update-awstats > /srv/sites/admin/awstats.log',
		user => apache,
		hour => '*/6',
		minute => '0'
	}
}

class hiveworldterrasite ($proxy_4to6_ip) {
	website::https::multitld { 'www.hiveworldterra':
		proxy_4to6_ip => $proxy_4to6_ip,
		force_no_www => false,
		letsencrypt_name => 'hiveworldterra.co.uk',
		custom_fragment => template("privat/apache/hwt.fragment"),
	}
	website::https::multitld { 'forums.hiveworldterra': 
		proxy_4to6_ip => $proxy_4to6_ip,
		letsencrypt_name => 'hiveworldterra.co.uk',
		custom_fragment => template("privat/apache/forums.fragment"),
	}
	website::https::multitld { 'skins.hiveworldterra':
		proxy_4to6_ip => $proxy_4to6_ip,
		letsencrypt_name => 'hiveworldterra.co.uk',
		custom_fragment => template("privat/apache/skins.fragment"),
	}
	website::https::redir { 'hiveworldterra.ibboard.co.uk':
		proxy_4to6_ip => $proxy_4to6_ip,
		redir => 'https://www.hiveworldterra.co.uk/',
		docroot => "${website::basedir}/hiveworldterra",
		letsencrypt_name => 'hiveworldterra.co.uk',
		separate_log => true,
	}
}
class bdstrikesite ($proxy_4to6_ip) {
	website::https::multitld { 'www.bdstrike': 
		proxy_4to6_ip => $proxy_4to6_ip,
		docroot_owner => $defaultusers::secondary_user,
		docroot_group => 'editors',
		letsencrypt_name => 'bdstrike.co.uk',
		custom_fragment => template("privat/apache/bdstrike.fragment"),
		csp_override => {"frame-ancestors" => "'self'"},
		csp_report_override => {
			"font-src" => "'self' https://fonts.gstatic.com/",
			"img-src" => "'self' https://secure.gravatar.com/",
			"style-src" => "'self' https://fonts.googleapis.com/"
		},
	}
	$aliases = [
		'strikecreations.co.uk',
		'strikecreations.com',
		'www.strikecreations.com' ]

	website::https::redir { 'www.strikecreations.co.uk':
		proxy_4to6_ip => $proxy_4to6_ip,
		redir => 'https://bdstrike.co.uk/',
		serveraliases => $aliases,
		docroot => "${website::basedir}/bdstrike",
		docroot_owner => $defaultusers::secondary_user,
		docroot_group => 'editors',
		letsencrypt_name => 'bdstrike.co.uk',
		separate_log => true,
	}
	cron { 'wordpress_cron':
		# Run "php -f wp-cron.php" on a schedule so that we can auto-update
		# without giving Apache full write access!
		command => "/usr/local/bin/bdstrike-cron",
		user => $defaultusers::default_user,
		minute => '*/15',
	}
}
class devsite ($proxy_4to6_ip) {
	if versioncmp($operatingsystemrelease, '8') >= 0 {
		# Apache::Mod doesn't map this correctly for CentOS 8 yet
		$mod_wsgi_lib = 'mod_wsgi_python3.so'
	} else {
		$mod_wsgi_lib = undef
	}
	apache::mod {
		# mod_wsgi for Python support
		'wsgi':
		  lib => $mod_wsgi_lib,
	}

	# Create Python virtualenvs for the dev site apps
	file {
		"/srv/rhodecode":
			ensure => 'directory';
		"/srv/trac":
			ensure => 'directory';
	} ->
	python::virtualenv {
		# Distribute is described as "simple compatibility layer that installs Setuptools 0.7+"
		# and leads to 'module "importlib._bootstrap" has no attribute "SourceFileLoader"'
		"/srv/rhodecode/virtualenv":
			distribute => false,
			version => '3';
		"/srv/trac/virtualenv":
			distribute => false,
			version => '3';
	}

	# Graphviz for Trac "master ticket" graphs
	package { 'graphviz':
		ensure => installed,
	}

	website::https::multitld { 'dev.ibboard':
		proxy_4to6_ip => $proxy_4to6_ip,
		#Make sure we're the first one hit for the tiny fraction of "no support" cases we care about (potentially Python for Mercurial!)
		# http://en.wikipedia.org/wiki/Server_Name_Indication#No_support
		priority => 1,
		letsencrypt_name => 'dev.ibboard.co.uk',
		custom_fragment => template("privat/apache/dev.fragment"),
		proxy_fragment => template("privat/apache/dev-proxy.fragment"),
		force_no_index => false,
	}
}

class webmailpimsite ($proxy_4to6_ip_pim, $proxy_4to6_ip_webmail) {
	# Webmail and Personal Information Management (PIM) sites
	website::https { 'webmail.ibboard.co.uk':
		proxy_4to6_ip => $proxy_4to6_ip_webmail,
		force_no_index => false,
		ssl_ca_chain => '',
		custom_fragment => template("privat/apache/webmail.fragment"),
	}
	website::https { 'pim.ibboard.co.uk':
		proxy_4to6_ip => $proxy_4to6_ip_pim,
		docroot_owner => 'apache',
		docroot_group => 'editors',
		force_no_index => false,
		lockdown_requests => false,
		ssl_ca_chain => '',
		csp => false,
		csp_report => false,
		custom_fragment => template("privat/apache/pim.fragment"),
	}
	cron { 'owncloudcron':
		command => "/usr/local/bin/owncloud-cron",
		user => 'apache',
		minute => '*/15',
	}
}

class email (
	$mailserver,
	$imapserver,
	){
	class { 'postfix':
		mailserver => $mailserver,
		protocols  => 'ipv4',
	}
	class { 'dovecot':
		imapserver => $imapserver,
	}
	# Unspecified SpamAssassin config dependencies that started
	# showing up as errors in our logs
	package { ['perl-File-MimeInfo']:
		ensure => installed,
	}
	package { [ 'amavisd-new' ]:
		ensure => installed,
		tag => 'av',
	}
	service { 'amavisd':
		ensure => 'running',
		enable => 'true',
	}
	service { 'clamd@amavisd':
		ensure => 'stopped',
		enable=> 'mask',
	}
	file { '/etc/amavisd/amavisd.conf':
		ensure => present,
		source => 'puppet:///private/postfix/amavisd.conf',
		tag => 'av',
	}
	file { '/etc/mail/spamassassin/local.cf':
		ensure => present,
		source => 'puppet:///private/postfix/spamassassin-local.cf',
		tag => 'av',
	}
	file { '/etc/mail/spamassassin/ole2macro.cf':
		ensure => present,
		source => 'puppet:///common/ole2macro.cf',
		tag => 'av',
	}
	file { '/etc/mail/spamassassin/ole2macro.pm':
		ensure => present,
		source => 'puppet:///common/spamassassin-vba-macro-master/ole2macro.pm',
		tag => 'av',
	}
	Package<| tag == 'av' |> -> File<| tag == 'av' |>
	File<| tag == 'av' |> {
		notify => Service['amavisd'],
	}
	cron { 'Postwhite':
		command => "/usr/local/bin/postwhite 2>&1| grep -vE '^(Starting|Recursively|Getting|Querying|Removing|Sorting|$)'",
		user => 'root',
		weekday => 0,
		hour => 2,
		minute => 0,
	}
}

class cronjobs {
	# Add Mutt for scripts that send emails, but stop it clogging the disk by keeping copies of emails
	package { 'mutt':
		ensure => installed,
	}
	file { '/etc/Muttrc.local':
		content => 'set copy = no',
		require => Package['mutt'],
	}

	# General server-wide cron jobs
	Cron { user => 'root' }
	cron { 'backupalldbs':
		command => "/usr/local/bin/backupalldbs",
		monthday => "*/2",
		hour => "4",
		minute => "9"
	}
	cron { 'greatfirewallofchina':
		command => '/usr/local/bin/update-great-firewall-of-china',
		hour => 3,
		minute => 30
	}
	cron { 'permissions':
		command => '/usr/local/bin/set-permissions',
		hour => 3,
		minute => 2
	}
	# Since we're only managing the local server, use our script that wraps "puppet apply" instead of PuppetMaster
	cron { 'puppet':
		command => '/usr/local/bin/puppet-apply | grep -v "Compiled catalog for\|Finished catalog run in\|Applied catalog in"',
		hour => '*/6',
		minute => 5
	}
	cron { 'purgecaches':
		command => "/usr/local/bin/purge-caches",
		hour => '4',
		minute => '15',
		weekday => '1',
	}
	# Notify of uncommitted files
	cron { 'check-mercurial-committed':
		command => "/usr/local/bin/check-hg-status",
		hour => '4',
		minute => '20',
		weekday => '0-6/3', #Sunday, Wednesday and Saturday morning
	}
	# Notify of available updates
	cron { 'check-yum-updates':
		command => '/usr/bin/yum check-updates | tail -2 | grep -Ev "^ \* [[:alnum:]-]+: [[:alnum:]\.]+$"',
		hour => '4',
		minute => '30',
		weekday => '0-6/3', #Sunday, Wednesday and Saturday morning
	}
	# And check whether anything needs restarting
	cron { 'check-needs-restarting':
		command => '/usr/bin/needs-restarting|grep -v "/usr/lib/systemd\|/usr/sbin/lvmetad\|/usr/lib/polkit-1/polkitd"',
		hour => '4',
		minute => '45',
		weekday => '0-6/3', #Sunday, Wednesday and Saturday morning
	}
}