# HG changeset patch # User IBBoard # Date 1641235036 0 # Node ID df5ad1612af74c9c0d8d083518bfb5565fa77fb0 # Parent 668df47116714557f77c25d0946d21d2c5a6a33c Adapt configs to support Ubuntu This is prep for running a VPS on a Mythic Beasts Raspberry Pi * Switch paths where necessary * Add optional modules that only apply on some OSes * Change usernames and groups * Don't do RPM-based stuff in Ubuntu * Switch to using some of the new modules diff -r 668df4711671 -r df5ad1612af7 manifests/nodes.pp --- a/manifests/nodes.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/manifests/nodes.pp Mon Jan 03 18:37:16 2022 +0000 @@ -15,9 +15,9 @@ firewall_cmd => 'iptables', } } -node 'vpsvm.ibboard.co.uk' { +node 'vpsarm.home' { class { 'ibboardvpsnode': - primary_ip => '2a00:23c4:6b00:c201:73a1:bf9:a379:9825', + primary_ip => '2a00:23c8:a480:3701:5054:ff:fe42:65f9', mailserver => 'mail.ibboard.co.uk', imapserver => 'imap.ibboard.co.uk', firewall_cmd => 'iptables', diff -r 668df4711671 -r df5ad1612af7 manifests/templates.pp --- a/manifests/templates.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/manifests/templates.pp Mon Jan 03 18:37:16 2022 +0000 @@ -30,6 +30,30 @@ version: 5 ", } + + if $operatingsystem == 'Ubuntu' { + file { '/etc/locale.gen': + ensure => present, + content => "en_GB.UTF-8 UTF-8", + notify => Exec['Regen locales'] + } + exec { 'Regen locales': + command => 'locale-gen', + refreshonly => true + } + # Don't waste space with Snap and do everything properly with system packages + [ 'lxd', 'core18', 'core20', 'snapd'].each |$snap| { + exec { "remove $snap snap package": + command => "snap remove $snap", + onlyif => "which snap && snap list $snap", + tag => 'snap', + } + } + Exec<| tag == 'snap' |> -> + package { 'snapd': + ensure => purged, + } + } } class basevpsnode ( @@ -198,7 +222,9 @@ require => Package['unbound'], notify => Service['unbound'], } - + file { '/etc/NetworkManager/conf.d': + ensure => directory + } file { '/etc/NetworkManager/conf.d/local-dns-resolver.conf': ensure => present, content => "[main] @@ -209,7 +235,7 @@ ensure => absent, } file { '/etc/resolv.conf': - ensure => present, + ensure => file, # "ipaddress" key only exists for machines with IPv4 addresses content => has_key($facts, 'ipaddress') ? { true => "nameserver 127.0.0.1", default => "nameserver ::1" }, require => Service['unbound'], @@ -218,39 +244,41 @@ } class repos { - yumrepo { 'epel': - mirrorlist => 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch', - descr => "Extra Packages for Enterprise Linux", - enabled => 1, - failovermethod => absent, - 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' { + yumrepo { 'epel': + mirrorlist => 'https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch', + descr => "Extra Packages for Enterprise Linux", + enabled => 1, + failovermethod => absent, + 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 { @@ -276,16 +304,20 @@ ensure => 'present', version => $python_ver, pip => 'present', - virtualenv => 'present', use_epel => false, } } class tools { - $packages = [ 'sqlite', 'bash-completion', 'nano', 'bzip2', 'mlocate', 'patch', 'tmux', 'wget', 'yum-utils', 'rsync' ] + $packages = [ 'sqlite', 'bash-completion', 'nano', 'bzip2', 'mlocate', 'patch', 'tmux', 'wget', 'rsync' ] package { $packages: ensure => installed; } + if $osfamily == 'RedHat' { + package { 'yum-utils': + ensure => installed + } + } } class logrotate { @@ -297,11 +329,6 @@ 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 { @@ -385,89 +412,106 @@ default_extra_tlds => [ 'com' ], } - $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 => absent, - gpgcheck => 1, - gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi', - } - yumrepo { 'remirepo-php': - mirrorlist => 'http://cdn.remirepo.net/enterprise/8/modular/$basearch/mirror', - descr => 'Remi\'s Modular repository for Enterprise Linux 8 - $basearch', - enabled => 1, - failovermethod => absent, - 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.el8', - tag => 'repo-config', + if $operatingsystem == 'CentOS' { + $php_suffix = '' + $extra_prefix = 'pecl-' + $extra_extra = [ 'process' ] + if 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 => absent, + gpgcheck => 1, + gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi', + } + yumrepo { 'remirepo-php': + mirrorlist => 'http://cdn.remirepo.net/enterprise/8/modular/$basearch/mirror', + descr => 'Remi\'s Modular repository for Enterprise Linux 8 - $basearch', + enabled => 1, + failovermethod => absent, + 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.el8', + tag => 'repo-config', + } + } else { + yumrepo { 'remirepo-safe': + mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/safe/mirror', + descr => "Extra CentOS packages from Remi", + enabled => 1, + failovermethod => absent, + gpgcheck => 1, + gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi', + } + yumrepo { 'remirepo-php': + mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/php74/mirror', + descr => "PHP7.4 for CentOS from Remi", + enabled => 1, + failovermethod => absent, + 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', + tag => 'repo-config', + } } - } else { - yumrepo { 'remirepo-safe': - mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/safe/mirror', - descr => "Extra CentOS packages from Remi", - enabled => 1, - failovermethod => absent, - gpgcheck => 1, - gpgkey => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi', - } - yumrepo { 'remirepo-php': - mirrorlist => 'http://cdn.remirepo.net/enterprise/$releasever/php74/mirror', - descr => "PHP7.4 for CentOS from Remi", - enabled => 1, - failovermethod => absent, - 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', - tag => 'repo-config', - } + } + elsif $operatingsystem == 'Ubuntu' { + $php_suffix = '' + $extra_prefix = '' + $extra_extras = [] } #Configure the PHP version to use class { 'website::php': suffix => $php_suffix, module => ($operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') >= 0) ? { true => 'remi-7.4', default => undef }, - extras => [ 'process', 'intl', 'pecl-imagick', 'bcmath', 'pecl-zip', 'json', 'pecl-apcu', 'gmp', 'enchant' ], + extras => [ 'intl', "${extra_prefix}imagick", 'bcmath', "${extra_prefix}zip", 'json', "${extra_prefix}apcu", 'gmp', 'enchant' ] + $extra_extras, } #Setup MySQL, using (private) templates to make sure that we set non-std passwords and a default user + if $operatingsystem == 'CentOS' { + if versioncmp($operatingsystemrelease, '7') >= 0 { + $mysqlpackage = 'mariadb' + $mysqlsuffix = '' - if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '7') >= 0 { + # 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' + } + } + elsif $operatingsystem == 'Ubuntu' { $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' + fail("No MySQL support for ${operatingsystem}") } class { 'website::mysql': mysqluser => template('defaultusers/mysql-user'), @@ -477,6 +521,11 @@ phpsuffix => $php_suffix, phpmysqlsuffix => 'nd' } + + # Additional supporting directories that aren't served as sites + file { [ '/srv/sites/errorhandling', '/srv/sites/private', '/srv/cms' ]: + ensure => directory, + } } class ibboardvpsnode ( @@ -507,7 +556,9 @@ } # Common modules used by multiple sites (mod_auth_basic is safe because we HTTPS all the things) - $mods = [ 'auth_basic', + $mods = [ + 'auth_basic', + 'authn_core', 'authn_file', 'authz_user', 'deflate', @@ -516,11 +567,6 @@ 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": @@ -545,14 +591,14 @@ } } website::https::redir { 'mail.ibboard.co.uk': - proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:03", default => undef }, + proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:03", default => undef }, redir => 'https://ibboard.co.uk/', docroot => "${website::basedir}/ibboard", letsencrypt_name => 'ibboard.co.uk', separate_log => true, } website::https::redir { 'imap.ibboard.co.uk': - proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:03", default => undef }, + proxy_4to6_ip => $proxy_4to6_ip_prefix != undef ? { true => "$proxy_4to6_ip_prefix:03", default => undef }, redir => 'https://ibboard.co.uk/', docroot => "${website::basedir}/ibboard", letsencrypt_name => 'ibboard.co.uk', @@ -589,14 +635,20 @@ ssl_ca_chain => '', custom_fragment => template("privat/apache/admin.fragment"), } + if $osfamily == 'RedHat' { + $cron_user = 'apache' + } + elsif $osfamily == 'Debian' { + $cron_user = 'www-data' + } cron { 'loadavg': command => '/usr/local/bin/run-loadavg-logger', - user => apache, + user => $cron_user, minute => '*/6' } cron { 'awstats': command => '/usr/local/bin/update-awstats > /srv/sites/admin/awstats.log', - user => apache, + user => $cron_user, hour => '*/6', minute => '0' } @@ -665,43 +717,13 @@ } } 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' - # And mod_wsgi doesn't exist as a "provides" any more - $mod_wsgi_package = 'python3-mod_wsgi' + if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') >= 0 { + $mod_wsgi_prefix = 'run/wsgi/' } else { - $mod_wsgi_lib = undef - $mod_wsgi_package = undef - } - apache::mod { - # mod_wsgi for Python support - 'wsgi': - lib => $mod_wsgi_lib, - package => $mod_wsgi_package, + $mod_wsgi_prefix = undef } - - # 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, + class { 'apache::mod::wsgi': + wsgi_socket_prefix => $mod_wsgi_prefix, } website::https::multitld { 'dev.ibboard': @@ -724,9 +746,15 @@ ssl_ca_chain => '', custom_fragment => template("privat/apache/webmail.fragment"), } + if $osfamily == 'RedHat' { + $pim_user = 'apache' + } + elsif $osfamily == 'Debian' { + $pim_user = 'www-data' + } website::https { 'pim.ibboard.co.uk': proxy_4to6_ip => $proxy_4to6_ip_pim, - docroot_owner => 'apache', + docroot_owner => $pim_user, docroot_group => 'editors', force_no_index => false, lockdown_requests => false, @@ -737,7 +765,7 @@ } cron { 'owncloudcron': command => "/usr/local/bin/owncloud-cron", - user => 'apache', + user => $pim_user, minute => '*/15', } } @@ -768,44 +796,57 @@ } # Unspecified SpamAssassin config dependencies that started # showing up as errors in our logs - package { ['perl-File-MimeInfo']: + if $osfamily == 'RedHat' { + $spamassassin_deps = ['perl-File-MimeInfo'] + $spamassassin_dir = '/etc/mail/spamassassin/' + $amavis_dir = '/etc/amavisd/' + $amavis_service = 'amavisd' + # CentOS has a Clam service, but we call on demand (Ubuntu doesn't have a service) + service { 'clamd@amavisd': + ensure => 'stopped', + enable=> 'mask', + } + } + elsif $osfamily == 'Debian' { + $spamassassin_deps = ['libfile-mimeinfo-perl'] + $spamassassin_dir = '/etc/spamassassin/' + $amavis_dir = '/etc/amavis/' + $amavis_service = 'amavis' + } + package { $spamassassin_deps: ensure => installed, } package { [ 'amavisd-new' ]: ensure => installed, tag => 'av', } - service { 'amavisd': + service { $amavis_service: ensure => 'running', enable => 'true', } - service { 'clamd@amavisd': - ensure => 'stopped', - enable=> 'mask', - } - file { '/etc/amavisd/amavisd.conf': + file { "${amavis_dir}amavisd.conf": ensure => present, source => 'puppet:///private/postfix/amavisd.conf', tag => 'av', } - file { '/etc/mail/spamassassin/local.cf': + file { "${spamassassin_dir}local.cf": ensure => present, source => 'puppet:///private/postfix/spamassassin-local.cf', tag => 'av', } - file { '/etc/mail/spamassassin/ole2macro.cf': + file { "${spamassassin_dir}ole2macro.cf": ensure => present, source => 'puppet:///common/ole2macro.cf', tag => 'av', } - file { '/etc/mail/spamassassin/ole2macro.pm': + file { "${spamassassin_dir}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'], + notify => Service[$amavis_service], } cron { 'Postwhite': command => "/usr/local/bin/postwhite 2>&1| grep -vE '^(Starting|Recursively|Getting|Querying|Removing|Sorting|$)'", diff -r 668df4711671 -r df5ad1612af7 modules/dovecot/manifests/init.pp --- a/modules/dovecot/manifests/init.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/dovecot/manifests/init.pp Mon Jan 03 18:37:16 2022 +0000 @@ -4,13 +4,20 @@ $imapserver_proxy = undef, $proxy_upstream = [], ) { - package { 'dovecot': + if $osfamily == 'RedHat' { + $dovecot_package = 'dovecot' + } + elsif $osfamily == 'Debian' { + $dovecot_package = 'dovecot-imapd' + } + + package { $dovecot_package: ensure => installed, } File { ensure => present, notify => Service['dovecot'], - require => Package['dovecot'], + require => Package[$dovecot_package], } file { '/etc/dovecot/conf.d/99-imap-only.conf': content => epp('dovecot/99-imap-only.conf.epp', @@ -42,8 +49,8 @@ }" } file { '/etc/dovecot/conf.d/99-ssl.conf': - content => "ssl_cert = "ssl_cert = 'puppet:///private/dovecot/99-ssl-extra.conf' @@ -51,20 +58,20 @@ file { '/etc/dovecot/users': source => 'puppet:///private/dovecot/passwd' } - file { "/etc/pki/dovecot/certs/${imapserver}.crt": + file { "/etc/pki/custom/${imapserver}.crt": source => "puppet:///private/pki/custom/${imapserver}.crt" } - file { "/etc/pki/dovecot/certs/${imapserver}.key": + file { "/etc/pki/custom/${imapserver}.key": source => "puppet:///private/pki/custom/${imapserver}.key" } service { 'dovecot': ensure => running, enable => true, - subscribe => Package['dovecot'], + subscribe => Package[$dovecot_package], } exec { 'Dovecot/LetsEncrypt sync restart trigger': command => "/usr/bin/true", - unless => "[ /run/dovecot/master -nt $(readlink -e /etc/pki/dovecot/certs/${imapserver}.crt) ]", + unless => "[ /run/dovecot/master -nt $(readlink -e /etc/pki/custom/${imapserver}.crt) ]", notify => Service['dovecot'], } firewall { '102 allow IMAPS': diff -r 668df4711671 -r df5ad1612af7 modules/fail2ban/files/jail.local --- a/modules/fail2ban/files/jail.local Mon Jan 03 17:16:21 2022 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -# Disable ssh-iptables because some versions auto-enable it -# and we want to use our own version (which may use non-iptables) -[ssh-iptables] -enabled = false - -[ssh-firewall-ban] -enabled = true -filter = sshd -action = firewall-ban[name=SSH,chain=Fail2Ban,port=222] -logpath = /var/log/secure -maxretry = 3 -bantime = 604800 - -[ssh-user-instaban] -enabled = true -filter = ibb-sshd-bad-user -action = firewall-ban[name=SSH-Instaban,chain=Fail2Ban,port=222] -logpath = /var/log/secure -maxretry = 1 -bantime = 604800 - -[ssh-key-ban] -enabled = true -filter = ibb-sshd -action = firewall-ban[name=SSH-Key,chain=Fail2Ban,port=222] -logpath = /var/log/secure -maxretry = 3 -findtime = 604800 -bantime = 604800 - -# Disable badbots - we've not seen it used in a month -[apache-badbots] -enabled = false -filter = apache-badbots -action = firewall-ban[name=ApacheBadBots,chain=Fail2Ban,port="80,443"] -logpath = /var/log/apache/access_*.log -findtime = 604800 -bantime = 604800 - -[apache-instaban] -enabled = true -maxretry = 1 -filter = ibb-apache-exploits-instaban -action = ibb-apache-ip-block -logpath = /var/log/apache/access_*.log -findtime = 86400 -bantime = 86400 - -# Disable auth - we've not seen it used in a month -[apache-auth] -enabled = false -maxretry = 5 -filter = apache-auth -action = firewall-ban[name=ApacheAuth,chain=Fail2Ban,port="80,443"] -logpath = /var/log/apache/error_*.log -findtime = 86400 -bantime = 604800 - -# Repeat offenders only operates on Apache because we're not -# seeing much on anything else anymore (or we can't filter -# because of IPv6-to-v4 proxying) -[repeat-offenders] -enabled = true -maxretry = 2 -filter = ibb-repeat-offender -action = ibb-apache-ip-block[chain=repeat] -logpath = /var/log/fail2ban.log -findtime = 2592000 -bantime = 2592000 - -[repeat-offenders-ssh] -enabled = true -maxretry = 2 -filter = ibb-repeat-offender-ssh -action = firewall-ban[name=RepeatOffendersSSH,chain=Fail2Ban,port="222"] -logpath = /var/log/fail2ban.log -findtime = 2592000 -bantime = 2592000 - -[spam-email] -enabled = true -maxretry = 1 -filter = ibb-postfix-spammers -action = firewall-ban[name=SpamEmail,chain=Fail2Ban,port="465,25"] -logpath = /var/log/maillog -findtime = 604800 -bantime = 604800 - -[mail-abuse] -enabled = true -maxretry = 1 -filter = ibb-postfix-malicious -action = firewall-ban[name=MailAbuse,chain=Fail2Ban,port="465,25"] -logpath = /var/log/maillog -findtime = 604800 -bantime = 604800 - -[mail-rejected] -enabled = false -maxretry = 10 -filter = ibb-postfix -action = firewall-ban[name=MailRejected,chain=Fail2Ban,port="465,25"] -logpath = /var/log/maillog -findtime = 604800 -bantime = 604800 - -[sasl] -enabled = true -maxretry = 10 -filter = postfix[mode=auth] -action = firewall-ban[name=SASLFailures,chain=Fail2Ban,port="465,25"] -logpath = /var/log/maillog -findtime = 604800 -bantime = 604800 - -[shellshock] -enabled = true -maxretry = 1 -filter = ibb-apache-shellshock -action = firewall-ban[name=Shellshock,chain=Fail2Ban,port="80,443"] -logpath = /var/log/apache/access_*.log -findtime = 604800 -bantime = 604800 diff -r 668df4711671 -r df5ad1612af7 modules/fail2ban/manifests/init.pp --- a/modules/fail2ban/manifests/init.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/fail2ban/manifests/init.pp Mon Jan 03 18:37:16 2022 +0000 @@ -16,8 +16,16 @@ file { '/etc/fail2ban/fail2ban.local': source => 'puppet:///modules/fail2ban/fail2ban.local', } + if $osfamily == 'RedHat' { + $ssh_log = '/var/log/secure' + $mail_log = '/var/log/maillog' + } + elsif $osfamily == 'Debian' { + $ssh_log = '/var/log/auth.log' + $mail_log = '/var/log/mail.log' + } file { '/etc/fail2ban/jail.local': - source => 'puppet:///modules/fail2ban/jail.local', + content => epp('fail2ban/jail.local.epp', {'ssh_log' => $ssh_log, 'mail_log' => $mail_log}) } file { '/etc/fail2ban/action.d/apf.conf': source => 'puppet:///modules/fail2ban/apf.conf', @@ -28,10 +36,19 @@ } else { $firewall_ban_cmd = $firewall_cmd } + + if $osfamily == 'RedHat' { + $apache_conf_custom = '/etc/httpd/conf.custom/' + } + elsif $osfamily == 'Debian' { + $apache_conf_custom = '/etc/apache2/conf.custom/' + } + # Create an empty banlist file if it doesn't exist - exec { 'httxt2dbm -i /dev/null -o /etc/httpd/conf.custom/apache_banlist.db': - path => '/usr/bin', - unless => 'test -f /etc/httpd/conf.custom/apache_banlist.db', + exec { "httxt2dbm -i /dev/null -o ${apache_conf_custom}apache_banlist.db": + path => '/sbin:/usr/bin', + unless => "test -f ${apache_conf_custom}apache_banlist.db", + require => Class['website'], before => Service['httpd'], } file { '/tmp/apache_banlist.txt': @@ -39,22 +56,25 @@ seltype => 'httpd_config_t', } # Create an empty repeat banlist file if it doesn't exist - exec { 'httxt2dbm -i /dev/null -o /etc/httpd/conf.custom/apache_repeat_banlist.db': - path => '/usr/bin', - unless => 'test -f /etc/httpd/conf.custom/apache_repeat_banlist.db', + exec { "httxt2dbm -i /dev/null -o ${apache_conf_custom}apache_repeat_banlist.db": + path => '/sbin:/usr/bin', + unless => "test -f ${apache_conf_custom}apache_repeat_banlist.db", + require => Class['website'], before => Service['httpd'], } file { '/tmp/apache_repeat_banlist.txt': ensure => present, seltype => 'httpd_config_t', } - # And let the httxt2dbm process work the rest of the time - file { '/etc/selinux/apache-ip-banlist.pp': - source => 'puppet:///modules/fail2ban/apache-ip-banlist.pp', - } ~> - exec { 'semodule -i /etc/selinux/apache-ip-banlist.pp': - path => '/usr/sbin', - refreshonly => true, + if $operatingsystem == 'CentOS' { + # And let the httxt2dbm process work the rest of the time + file { '/etc/selinux/apache-ip-banlist.pp': + source => 'puppet:///modules/fail2ban/apache-ip-banlist.pp', + } ~> + exec { 'semodule -i /etc/selinux/apache-ip-banlist.pp': + path => '/usr/sbin', + refreshonly => true, + } } file { '/etc/fail2ban/action.d/firewall-ban.conf': ensure => link, diff -r 668df4711671 -r df5ad1612af7 modules/fail2ban/templates/jail.local.epp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/modules/fail2ban/templates/jail.local.epp Mon Jan 03 18:37:16 2022 +0000 @@ -0,0 +1,123 @@ +# Disable ssh-iptables because some versions auto-enable it +# and we want to use our own version (which may use non-iptables) +[ssh-iptables] +enabled = false + +[ssh-firewall-ban] +enabled = true +filter = sshd +action = firewall-ban[name=SSH,chain=Fail2Ban,port=222] +logpath = <%= $ssh_log %> +maxretry = 3 +bantime = 604800 + +[ssh-user-instaban] +enabled = true +filter = ibb-sshd-bad-user +action = firewall-ban[name=SSH-Instaban,chain=Fail2Ban,port=222] +logpath = <%= $ssh_log %> +maxretry = 1 +bantime = 604800 + +[ssh-key-ban] +enabled = true +filter = ibb-sshd +action = firewall-ban[name=SSH-Key,chain=Fail2Ban,port=222] +logpath = <%= $ssh_log %> +maxretry = 3 +findtime = 604800 +bantime = 604800 + +# Disable badbots - we've not seen it used in a month +[apache-badbots] +enabled = false +filter = apache-badbots +action = firewall-ban[name=ApacheBadBots,chain=Fail2Ban,port="80,443"] +logpath = /var/log/apache/access_*.log +findtime = 604800 +bantime = 604800 + +[apache-instaban] +enabled = true +maxretry = 1 +filter = ibb-apache-exploits-instaban +action = ibb-apache-ip-block +logpath = /var/log/apache/access_*.log +findtime = 86400 +bantime = 86400 + +# Disable auth - we've not seen it used in a month +[apache-auth] +enabled = false +maxretry = 5 +filter = apache-auth +action = firewall-ban[name=ApacheAuth,chain=Fail2Ban,port="80,443"] +logpath = /var/log/apache/error_*.log +findtime = 86400 +bantime = 604800 + +# Repeat offenders only operates on Apache because we're not +# seeing much on anything else anymore (or we can't filter +# because of IPv6-to-v4 proxying) +[repeat-offenders] +enabled = true +maxretry = 2 +filter = ibb-repeat-offender +action = ibb-apache-ip-block[chain=repeat] +logpath = /var/log/fail2ban.log +findtime = 2592000 +bantime = 2592000 + +[repeat-offenders-ssh] +enabled = true +maxretry = 2 +filter = ibb-repeat-offender-ssh +action = firewall-ban[name=RepeatOffendersSSH,chain=Fail2Ban,port="222"] +logpath = /var/log/fail2ban.log +findtime = 2592000 +bantime = 2592000 + +[spam-email] +enabled = true +maxretry = 1 +filter = ibb-postfix-spammers +action = firewall-ban[name=SpamEmail,chain=Fail2Ban,port="465,25"] +logpath = <%= $mail_log %> +findtime = 604800 +bantime = 604800 + +[mail-abuse] +enabled = true +maxretry = 1 +filter = ibb-postfix-malicious +action = firewall-ban[name=MailAbuse,chain=Fail2Ban,port="465,25"] +logpath = <%= $mail_log %> +findtime = 604800 +bantime = 604800 + +[mail-rejected] +enabled = false +maxretry = 10 +filter = ibb-postfix +action = firewall-ban[name=MailRejected,chain=Fail2Ban,port="465,25"] +logpath = <%= $mail_log %> +findtime = 604800 +bantime = 604800 + +[sasl] +enabled = true +maxretry = 10 +filter = postfix[mode=auth] +action = firewall-ban[name=SASLFailures,chain=Fail2Ban,port="465,25"] +logpath = <%= $mail_log %> +findtime = 604800 +bantime = 604800 + +[shellshock] +enabled = true +maxretry = 1 +filter = ibb-apache-shellshock +action = firewall-ban[name=Shellshock,chain=Fail2Ban,port="80,443"] +logpath = /var/log/apache/access_*.log +findtime = 604800 +bantime = 604800 diff -r 668df4711671 -r df5ad1612af7 modules/postfix/manifests/init.pp --- a/modules/postfix/manifests/init.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/postfix/manifests/init.pp Mon Jan 03 18:37:16 2022 +0000 @@ -65,7 +65,7 @@ } exec { 'postmap-files': - command => 'for file in helo_whitelist recipient_bcc sender_access valias valias-blacklist virtual vmailbox transport; do postmap $file; done', + command => 'for file in helo_whitelist recipient_bcc sender_access valias valias-blacklist virtual vmailbox; do postmap $file; done', cwd => '/etc/postfix/', provider => 'shell', refreshonly => true, @@ -76,6 +76,12 @@ notify => Exec['postmap-files'], require => Package['postfix'], } + if $osfamily == 'RedHat' { + $policyd_script = '/usr/libexec/postfix/policyd-spf' + } + elsif $osfamily == 'Debian' { + $policyd_script = '/usr/bin/policyd-spf' + } file { '/etc/postfix/main.cf': content => epp('postfix/main.cf.epp', { @@ -93,6 +99,7 @@ 'mailserver_proxy' => $mailserver_proxy, 'lo_ip' => $lo_ip, 'lo_networks' => $lo_networks, + 'policyd_script' => $policyd_script, 'fallback_relays' => $mailrelays, } ), @@ -172,11 +179,19 @@ } #SPF checking - package { 'pypolicyd-spf': + if $osfamily == 'RedHat' { + $pypolicyd_package = 'pypolicyd-spf' + $pypolicyd_config = '/etc/python-policyd-spf/policyd-spf.conf' + } + elsif $osfamily == 'Debian' { + $pypolicyd_package = 'postfix-policyd-spf-python' + $pypolicyd_config = '/etc/postfix-policyd-spf-python/policyd-spf.conf' + } + package { $pypolicyd_package: ensure => installed; } -> - file { '/etc/python-policyd-spf/policyd-spf.conf': + file { $pypolicyd_config: content => epp('postfix/policyd-spf.conf', { 'fallback_relays' => $mailrelays, diff -r 668df4711671 -r df5ad1612af7 modules/postfix/templates/main.cf.epp --- a/modules/postfix/templates/main.cf.epp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/postfix/templates/main.cf.epp Mon Jan 03 18:37:16 2022 +0000 @@ -70,7 +70,6 @@ smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_sender, check_sender_access hash:/etc/postfix/sender_access, reject_unknown_sender_domain, permit smtpd_recipient_restrictions = reject_invalid_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, check_sender_access hash:/etc/postfix/sender_access, reject_unknown_sender_domain, permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, check_recipient_access hash:/etc/postfix/valias-blacklist, check_recipient_access regexp:/etc/postfix/valias-blacklist-regex, check_policy_service unix:private/policy smtpd_data_restrictions = reject_unauth_pipelining -transport_maps = hash:/etc/postfix/transport message_size_limit = 30000000 header_checks = regexp:/etc/postfix/header_checks body_checks = regexp:/etc/postfix/body_checks diff -r 668df4711671 -r df5ad1612af7 modules/postfix/templates/master.cf.epp --- a/modules/postfix/templates/master.cf.epp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/postfix/templates/master.cf.epp Mon Jan 03 18:37:16 2022 +0000 @@ -3,6 +3,7 @@ Optional[Stdlib::IP::Address] $mailserver_proxy = undef, Stdlib::IP::Address $lo_ip, Stdlib::IP::Address $lo_networks, + Stdlib::AbsolutePath $policyd_script, Optional[Array[Stdlib::Host]] $fallback_relays = [] | -%> @@ -151,7 +152,7 @@ # ${nexthop} ${user} policy unix - n n - 0 spawn - user=nobody argv=/usr/libexec/postfix/policyd-spf + user=nobody argv=<%= $policyd_script %> # # spam/virus section diff -r 668df4711671 -r df5ad1612af7 modules/website/files/zzz-0-custom.conf --- a/modules/website/files/zzz-0-custom.conf Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/website/files/zzz-0-custom.conf Mon Jan 03 18:37:16 2022 +0000 @@ -32,7 +32,7 @@ - WSGISocketPrefix run/wsgi +# WSGISocketPrefix run/wsgi BrowserMatch "Mozilla/2" nokeepalive diff -r 668df4711671 -r df5ad1612af7 modules/website/manifests/init.pp --- a/modules/website/manifests/init.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/website/manifests/init.pp Mon Jan 03 18:37:16 2022 +0000 @@ -31,8 +31,24 @@ "font-src" => "'self'" } + 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 => "/etc/httpd/conf.d/vhosts", + vhost_dir => $vhost_dir, protocols => ["h2", "http/1.1"], default_mods => false, default_vhost => false, @@ -41,15 +57,21 @@ 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':; - 'version':; '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 @@ -71,45 +93,33 @@ file { '/var/log/apache': ensure => directory, mode => '0750', - group => 'apache', + group => $apache_log_group, } - file { '/etc/httpd/conf.extra': + file { "${apache_base_dir}conf.extra": ensure => directory, recurse => true, source => "puppet:///modules/website/conf.extra", require => Class['apache'], notify => Service['httpd']; } - file { '/etc/httpd/conf/mime.types': + file { "${apache_base_dir}mime.types": ensure => present, source => "puppet:///modules/website/mime.types", require => Class['apache'], notify => Service['httpd']; } - file { '/etc/php.d/datetime.ini': - ensure => present, - source => "puppet:///modules/website/datetime.ini", - require => Class['apache'], - notify => Service['httpd']; - } - file { '/etc/httpd/conf.d/zzz-custom.conf': + file { "${apache_base_dir}conf.d/zzz-custom.conf": ensure => absent, require => Class['apache'], notify => Service['httpd']; } - file { '/etc/httpd/conf.d/zzz-0-custom.conf': + 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 { '/etc/httpd/conf.d/php.conf': - ensure => present, - source => "puppet:///modules/website/php.conf", - require => Class['apache'], - notify => Service['httpd']; - } - file { '/etc/httpd/conf.custom': + file { "${apache_base_dir}conf.custom": ensure => directory, recurse => true, source => "puppet:///private/apache/conf.custom", @@ -145,25 +155,28 @@ action => reject, } } - if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '7') >= 0 { + 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\\(/\\.\\*\\)\\?"', } - cron { 'letsencrypt-renewal': - command => '/usr/bin/certbot renew --quiet', - hour => '*/12', - minute => '21', - } if versioncmp($operatingsystemrelease, '8') < 0 { $certbot_pkg = 'python2-certbot-apache' } else { $certbot_pkg = 'python3-certbot-apache' } - package { $certbot_pkg: - ensure => installed, - } + } + elsif $operatingsystem == 'Ubuntu' { + $certbot_pkg = 'certbot' + } + cron { 'letsencrypt-renewal': + command => '/usr/bin/certbot renew --quiet', + hour => '*/12', + minute => '21', + } + package { $certbot_pkg: + ensure => installed, } } diff -r 668df4711671 -r df5ad1612af7 modules/website/manifests/mysql.pp --- a/modules/website/manifests/mysql.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/website/manifests/mysql.pp Mon Jan 03 18:37:16 2022 +0000 @@ -6,8 +6,15 @@ $phpmysqlsuffix = '', $mysqlprefix = 'mysql') { + if $osfamily == 'RedHat' { + $client_package_suffix = '' + } + elsif $osfamily == 'Debian' { + $client_package_suffix = '-client' + } + class { 'mysql::client': - package_name => "${mysqlprefix}${mysqlsuffix}", + package_name => "${mysqlprefix}${mysqlsuffix}${client_package_suffix}", bindings_enable => false, #Deal with bindings manually } class { 'mysql::bindings': @@ -28,14 +35,15 @@ 'innodb_file_per_table' => '1', } - if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') >= 0 { - $mysqld_settings = $mysqld_base_settings - } else { + if $operatingsystem == 'CentOS' and versioncmp($operatingsystemrelease, '8') < 0 { $mysqld_settings = $mysqld_base_settings + { 'innodb_file_format' => 'barracuda', 'innodb_large_prefix' => 'true', } } + else { + $mysqld_settings = $mysqld_base_settings + } class { 'mysql::server': diff -r 668df4711671 -r df5ad1612af7 modules/website/manifests/php.pp --- a/modules/website/manifests/php.pp Mon Jan 03 17:16:21 2022 +0000 +++ b/modules/website/manifests/php.pp Mon Jan 03 18:37:16 2022 +0000 @@ -3,6 +3,78 @@ $module = undef, $extras = [], ) { + if $osfamily == 'RedHat' { + $listener_user = 'apache' + $listener_group = 'apache' + # Work around SELinux "denied execmem" warnings from preg_match JITing + $pcre_jit = 0 + } + else { + $listener_user = 'www-data' + $listener_group = 'www-data' + $pcre_jit = 1 + } + class { '::php': + ensure => present, + manage_repos => false, + fpm => true, + fpm_pools => { + 'www' => { + 'listen' => '/run/php-fpm/www.sock', + 'listen_owner' => $listener_user, + 'listen_group' => $listener_group, + 'slowlog' => '/var/log/php-fpm/www-slow.log', + 'security_limit_extensions' => ['.php', '.html'], + 'php_admin_value' => { + 'memory_limit' => '256M', + }, + 'php_value' => { +# 'session.save_path' => '/var/lib/php/session' # Ubuntu uses plural, CentOS uses singular + }, + }, + }, + dev => false, + composer => false, + pear => false, + settings => { + 'PHP/default_charset' => 'UTF-8', + 'PHP/pcre.jit' => $pcre_jit, + # Space isn't scarce these days - increase default sizes + 'PHP/upload_max_filesize' => "8M", + 'PHP/post_max_size' => "8M", + 'Data/date.timezone' => 'UTC', + }, + extensions => { + gd => {}, + mbstring => {}, + opcache => { + settings => { + 'zend_extension' => 'opcache.so', + 'opcache.enable' => 1, + 'opcache.enable_cli' => 1, + 'opcache.interned_strings_buffer' => 8, + 'opcache.max_accelerated_files' => 10000, + 'opcache.memory_consumption' => 128, + 'opcache.save_comments' => 1, + 'opcache.revalidate_freq' => 1, + } + }, + xml => {}, + }, + } + apache::custom_config { "php.conf": + ensure => present, + source => "puppet:///modules/website/php.conf" + } + class { ['apache::mod::proxy', 'apache::mod::proxy_fcgi']:} + + $extras.each |String $extra| { + ::php::extension { $extra: + ensure => present + } + } + +if false { Package <| tag == 'php-package' |> -> File <| tag == 'php-file' |> ~> Service['php-fpm'] ~> Service['httpd'] $php_core = ($module != undef) ? { true => "php", default => "php${suffix}" } @@ -13,7 +85,19 @@ tag => 'php-package', } - package { 'mod_fcgid': + if $osfamily == 'RedHat' { + $php_conf_dir = '/etc/php.d/' + $php_fpm_conf_dir = '/etc/php-fpm.d/' + $mod_fcgid_package = 'mod_fcgid' + } + elsif $osfamily == 'Debian' { + # FIXME: This hard-codes the version number, which isn't great + $php_conf_dir = '/etc/php/7.4/fpm/conf.d/' + $php_fpm_conf_dir = $php_conf_dir + $mod_fcgid_package = 'libapache2-mod-fcgid' + } + + package { $mod_fcgid_package: ensure => installed, } class { ['apache::mod::proxy', 'apache::mod::proxy_fcgi']:} @@ -31,6 +115,12 @@ website::php::extra { $extras: } + file { '/etc/php.d/datetime.ini': + ensure => present, + source => "puppet:///modules/website/datetime.ini", + require => Class['apache'], + notify => Service['httpd']; + } file { '/etc/php-fpm.d/www.conf': ensure => present, source => 'puppet:///modules/website/php-fpm-www.conf', @@ -63,3 +153,4 @@ tag => 'php-file', } } +}