diff --git a/conf/adminer b/conf/adminer index 3df8d007..76f8ca3b 100755 --- a/conf/adminer +++ b/conf/adminer @@ -10,7 +10,26 @@ ln -sf $ADMINER_DIR/designs/nette/adminer.css $STATIC_DIR/default.css ln -sf /etc/adminer/adminer.css /usr/share/adminer/adminer/adminer.css -# ensure www-data has read access to php files in /etc/adminer +# Ensure www-data has read access to php files in /etc/adminer +chown -R root:adm /etc/adminer chown root:www-data /etc/adminer /etc/adminer/tkl-*.php /etc/adminer/adminer.css chmod 755 /etc/adminer chmod 644 /etc/adminer/tkl-*.php /etc/adminer/adminer.css + +# Set up custom Adminer specific logging (config in relevant webserver vhosts) +mkdir -p /var/log/adminer +touch /var/log/adminer/{access.log,error.log} +chown -R www-data:www-data /var/log/adminer +chmod 755 /var/log/adminer +chmod 644 /var/log/adminer/*.log + +# Configure fail2ban protection for Adminer +cat >> /etc/fail2ban/jail.local < fail2ban.patch <(?P\S+)|(?:(?! from ).)*? from %(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) - # consider failed publickey for valid users too (don't need RE, see cmnfailed): --cmnfailre-failed-pub-any = -+cmnfailre-failed-pub-any = ^Failed publickey for (?P\S+)|(?:(?! from ).)*? from %(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$) - # same as invalid, but consider failed publickey for valid users too, just as no failure (helper to get IP and user-name only, see cmnfailed): --cmnfailre-failed-pub-nofail = -+cmnfailre-failed-pub-nofail = - # don't consider failed publickey as failures (don't need RE, see cmnfailed): - cmnfailre-failed-pub-ignore = - -EOF -git apply fail2ban.patch -rm fail2ban.patch - cat > /etc/cron.weekly/fail2ban <> $CONF - fi -} - -update_or_add port 12321 -update_or_add listen 12321 -update_or_add keyfile /etc/ssl/private/cert.pem -update_or_add certfile -update_or_add cipher_list_def 0 -update_or_add error_handler_401 401.cgi -update_or_add error_handler_404 404.cgi -update_or_add error_handler_403 403.cgi -update_or_add nolog '\/stats\.cgi\?xhr\-stats\=general' -update_or_add no_tls1 1 -update_or_add no_tls1_1 1 -update_or_add no_tls1_2 -update_or_add extracas -update_or_add ssl_hsts 0 diff --git a/conf/turnkey.d/webmin-conf-logging b/conf/turnkey.d/webmin-conf-logging new file mode 100755 index 00000000..c3467647 --- /dev/null +++ b/conf/turnkey.d/webmin-conf-logging @@ -0,0 +1,51 @@ +#!/bin/bash -e + +CONF=/etc/webmin/miniserv.conf +LOG_DIR=/var/log/webmin + +update_or_add() { + key=$1 + value=$2 + if grep -q "$key" "$CONF"; then + sed -i "s|$key=.*|$key=$value|" "$CONF" + else + echo "$key=$value" >> "$CONF" + fi +} + +update_or_add port 12321 +update_or_add listen 12321 +update_or_add keyfile /etc/ssl/private/cert.pem +update_or_add certfile +update_or_add cipher_list_def 0 +update_or_add error_handler_401 401.cgi +update_or_add error_handler_404 404.cgi +update_or_add error_handler_403 403.cgi +update_or_add nolog '\/stats\.cgi\?xhr\-stats\=general' +update_or_add no_tls1 1 +update_or_add no_tls1_1 1 +# TODO: Disable TLSv1.2 in a future release (i.e. append '1': 'no_tls1_2 1') +update_or_add no_tls1_2 +update_or_add extracas +update_or_add ssl_hsts 1 +update_or_add ssl_enforce 2 # force with hsts - '1' forces ssl but not hsts +update_or_add ssl_redirect 1 +update_or_add session_timeout 1800 # 30 minutes +# update logfile location +update_or_add logfile "$LOG_DIR/miniserv.log" +update_or_add errorlog "$LOG_DIR/miniserv.error" + +# Note: Updating Webmin config for it's own log file as below does not actually +# work (continues to log to /var/webmin/webmin.log) but we'll work around that +# via symlinks and update the config file to point to the actual log file +# anyway. +CONF=/etc/webmin/config +update_or_add logfile "$LOG_DIR/webmin.log" + +# Prime log files and set permissions +mkdir -p "$LOG_DIR" +touch "$LOG_DIR"/{miniserv.log,miniserv.error,webmin.log} +chmod 750 "$LOG_DIR" +chmod 640 "$LOG_DIR"/*.log +rm -f /var/webmin/webmin.log +ln -sf /var/log/webmin/webmin.log /var/webmin/webmin.log diff --git a/conf/turnkey.d/webmin-fw b/conf/turnkey.d/webmin-fw index e1619a6b..854facaf 100755 --- a/conf/turnkey.d/webmin-fw +++ b/conf/turnkey.d/webmin-fw @@ -1,10 +1,34 @@ -#!/bin/sh -e +#!/bin/bash -e -set ${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321} +# TODO: drop use of iptables-legacy and use nftables directly -CONF=/etc/iptables.up.rules +set "${WEBMIN_FW_TCP_INCOMING:=22 80 443 12321}" -cat > $CONF < "$conf" <> $CONF -done - -if [ "$WEBMIN_FW_UDP_INCOMING" ]; then - for port in $WEBMIN_FW_UDP_INCOMING; do - echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> $CONF + for port in "${WEBMIN_FW_TCP_INCOMING[@]}"; do + echo "-A INPUT -p tcp -m tcp --dport $port -j ACCEPT" >> "$conf" done -fi -if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then - for port in $WEBMIN_FW_TCP_INCOMING_REJECT; do - echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> $CONF - done -fi + if [[ "$WEBMIN_FW_UDP_INCOMING" ]]; then + readarray -t WEBMIN_FW_UDP_INCOMING \ + < <(tr ' ' '\n' <<< "$WEBMIN_FW_UDP_INCOMING" | sort -un) + for port in "${WEBMIN_FW_UDP_INCOMING[@]}"; do + echo "-A INPUT -p udp -m udp --dport $port -j ACCEPT" >> "$conf" + done + fi -echo "COMMIT" >> $CONF + if [ "$WEBMIN_FW_TCP_INCOMING_REJECT" ]; then + readarray -t WEBMIN_FW_TCP_INCOMING_REJECT \ + < <(tr ' ' '\n' <<< "$WEBMIN_FW_TCP_INCOMING_REJECT" | sort -un) + for port in "${WEBMIN_FW_TCP_INCOMING_REJECT[@]}"; do + echo "-A INPUT -p tcp -m tcp --dport $port -j REJECT" >> "$conf" + done + fi -sed -i "/^$/d" $CONF + echo "COMMIT" >> "$conf" + sed -i "/^$/d" "$conf" +done -# As of Buster, Debian uses nftables for firewall; but webmin only supports legacy -# iptables - see https://github.com/webmin/webmin/issues/1097 +# Debian has been using nftables for firewall for some time; but historically +# Webmin only supported legacy iptables. Webmin now supports nftables so as per +# TODO at top of this file TKL should migrate to nftables, but for now we'll +# continue to leverage legacy iptables functionality via 'iptables-legacy'. +# +# See https://github.com/webmin/webmin/issues/1097 update-alternatives --set iptables /usr/sbin/iptables-legacy update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy diff --git a/conf/turnkey.d/webmin-handy-log b/conf/turnkey.d/webmin-handy-log deleted file mode 100755 index 20354494..00000000 --- a/conf/turnkey.d/webmin-handy-log +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -# set up convenience links to Webmin log files - -WEBMIN_VAR=/var/webmin -WEBMIN_LOG=/var/log/webmin - -mkdir -p $WEBMIN_LOG - -files=(miniserv.error webmin.log) -for f in "${files[@]}"; do - ln -s "$WEBMIN_VAR/$f" "$WEBMIN_LOG/$f" -done diff --git a/conf/turnkey.d/webmin-lets-enc b/conf/turnkey.d/webmin-lets-enc index a19d84ed..2ae13e0e 100755 --- a/conf/turnkey.d/webmin-lets-enc +++ b/conf/turnkey.d/webmin-lets-enc @@ -3,5 +3,7 @@ # Disable Webmin Let's Encrypt config - via patch cd /usr/share/webmin/webmin +# test patch first; --check exits non-zero if doesn't apply cleanly +git apply --check /usr/local/src/webmin.patch git apply /usr/local/src/webmin.patch rm /usr/local/src/webmin.patch diff --git a/overlays/adminer/etc/adminer/apache.conf b/overlays/adminer/etc/adminer/apache.conf index 3e170e6f..2500e7ba 100644 --- a/overlays/adminer/etc/adminer/apache.conf +++ b/overlays/adminer/etc/adminer/apache.conf @@ -6,6 +6,9 @@ Alias /adminer/static /usr/share/adminer/adminer/static Alias /externals /usr/share/adminer/externals Alias /editor /usr/share/adminer/editor + + CustomLog /var/log/adminer/access.log combined + ErrorLog /var/log/adminer/error.log diff --git a/overlays/adminer/etc/adminer/lighttpd.conf b/overlays/adminer/etc/adminer/lighttpd.conf index 8d483033..f3a92906 100644 --- a/overlays/adminer/etc/adminer/lighttpd.conf +++ b/overlays/adminer/etc/adminer/lighttpd.conf @@ -8,33 +8,26 @@ var.alias_redirects = ( "/externals/" => "/usr/share/adminer/externals/" ) -# Map tkl-index.php URL to the actual file in /etc/adminer/ -$HTTP["url"] == "/tkl-index.php" { - fastcgi.server = ( - ".php" => (( - "socket" => "/run/php/php-fpm.sock", # may need adjustment? - "check-local" => "disable", - "bin-environment" => ( - "SCRIPT_FILENAME" => "/etc/adminer/tkl-index.php" - ) - )) - ) -} - -index-file.names += ( "tkl-index.php" ) - # IPv4 $SERVER["socket"] == "0.0.0.0:12322" { ssl.engine = "enable" server.document-root = "/usr/share/adminer/adminer/" + index-file.names = ( "tkl-index.php", "index.php" ) alias.url = alias_redirects follow-symlink = "enable" + + accesslog.filename = "/var/log/adminer/access.log" + server.errorlog = "/var/log/adminer/error.log" } # IPv6 $SERVER["socket"] == "[::]:12322" { ssl.engine = "enable" server.document-root = "/usr/share/adminer/adminer/" + index-file.names = ( "tkl-index.php", "index.php" ) alias.url = alias_redirects follow-symlink = "enable" + + accesslog.filename = "/var/log/adminer/access.log" + server.errorlog = "/var/log/adminer/error.log" } diff --git a/overlays/adminer/etc/adminer/nginx.conf b/overlays/adminer/etc/adminer/nginx.conf index 53915003..5d08e819 100644 --- a/overlays/adminer/etc/adminer/nginx.conf +++ b/overlays/adminer/etc/adminer/nginx.conf @@ -5,7 +5,9 @@ server { listen [::]:12322 ssl; include /etc/nginx/snippets/ssl.conf; root /usr/share/adminer/adminer/; - error_log /var/log/nginx/adminer-error.log; + + access_log /var/log/adminer/access.log; + error_log /var/log/adminer/error.log; location / { index tkl-index.php index.php; @@ -14,9 +16,10 @@ server { # Route tkl-index.php to /etc/adminer/ location = /tkl-index.php { + include /etc/nginx/snippets/fastcgi-php.conf; fastcgi_param HTTPS on; fastcgi_param SCRIPT_FILENAME /etc/adminer/tkl-index.php; - include /etc/nginx/snippets/php-fpm.conf; + fastcgi_pass unix:/run/php/php-fpm.sock; } location ~ \.php$ { diff --git a/overlays/adminer/etc/fail2ban/filter.d/adminer-auth.conf b/overlays/adminer/etc/fail2ban/filter.d/adminer-auth.conf new file mode 100644 index 00000000..e071e2b2 --- /dev/null +++ b/overlays/adminer/etc/fail2ban/filter.d/adminer-auth.conf @@ -0,0 +1,12 @@ +# Fail2Ban filter for adminer +# +# Provided by TurnKey GNU/Linux +# Works for Apache2, LigHTTPd & Nginx access logs + +[INCLUDES] +before = common.conf + +[Definition] +failregex = ^ .* "POST /adminer\.php.*" (200|302) .*$ + +ignoreregex = diff --git a/overlays/adminer/etc/logrotate.d/adminer b/overlays/adminer/etc/logrotate.d/adminer new file mode 100644 index 00000000..479404e0 --- /dev/null +++ b/overlays/adminer/etc/logrotate.d/adminer @@ -0,0 +1,23 @@ +/var/log/adminer/access.log +/var/log/adminer/error.log { + weekly + rotate 4 + compress + missingok + notifempty + sharedscripts + postrotate + # Apache + if systemctl is-active --quiet apache2; then + systemctl reload apache2 + fi + # Nginx + if systemctl is-active --quiet nginx; then + systemctl reload nginx + fi + # Lighttpd + if systemctl is-active --quiet lighttpd; then + systemctl reload lighttpd + fi + endscript +} diff --git a/overlays/lighttpd/etc/lighttpd/ssl-params.conf b/overlays/lighttpd/etc/lighttpd/ssl-params.conf index 3349834c..33b88cc7 100644 --- a/overlays/lighttpd/etc/lighttpd/ssl-params.conf +++ b/overlays/lighttpd/etc/lighttpd/ssl-params.conf @@ -5,7 +5,6 @@ ssl.pemfile = "/etc/ssl/private/cert.pem" ssl.privkey = "/etc/ssl/private/cert.key" -ssl.dh-file = "/etc/ssl/private/dhparams.pem" ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.2") # lighttpd 1.4.79 TLS default appends X448 @@ -15,7 +14,7 @@ ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.2") # See https://wiki.lighttpd.net/Docs_SSL # Uncomment to better match the less restricted Mozilla intermediate spec. # (TKL Ciphers set by common/conf/turnkey.d/zz-ssl-ciphers) -#ssl.openssl.ssl-conf-cmd += ("CipherString" => "ZZ_SSL_CIPHERS") +ssl.openssl.ssl-conf-cmd += ("CipherString" => "ZZ_SSL_CIPHERS") # HSTS config + additional hardening server.modules += ("mod_redirect") diff --git a/overlays/nginx/etc/nginx/sites-available/tkl-default b/overlays/nginx/etc/nginx/sites-available/tkl-default index 9938d683..8a02b446 100644 --- a/overlays/nginx/etc/nginx/sites-available/tkl-default +++ b/overlays/nginx/etc/nginx/sites-available/tkl-default @@ -18,14 +18,18 @@ ## # Default server configuration -# + +# HTTP server { listen 80 default_server; listen [::]:80 default_server; - + server_name _; # temporary redirect to https - update to permanent (308) for production return 307 https://$host$request_uri; +} +# HTTPS +server { # SSL configuration listen 443 ssl default_server; listen [::]:443 ssl default_server; @@ -33,8 +37,8 @@ server { root /var/www; - # Ensure index.php is at the end of this list if using php-fpm - index index.html index.htm; + # index.php can be removed from the end of this list when not using php-fpm + index index.html index.htm index.php; server_name _; @@ -44,8 +48,8 @@ server { try_files $uri $uri/ =404; } - # Uncomment to enable PHP-FPM - #include snippets/php-fpm.conf; + # Comment to disable PHP-FPM + include snippets/php-fpm.conf; # Deny access to all dot files location ~ /\. { diff --git a/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local b/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local index 28eb775e..ccd1b765 100644 --- a/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local +++ b/overlays/turnkey.d/fail2ban/etc/fail2ban/jail.local @@ -9,8 +9,8 @@ [DEFAULT] ignoreip = 127.0.0.1/8 ::1 bantime = 3600 -findtime = 10 -maxretry = 2 +findtime = 600 # 10 minutes +maxretry = 3 backend = systemd [sshd] diff --git a/overlays/turnkey.d/webmin/usr/local/src/webmin.patch b/overlays/turnkey.d/webmin/usr/local/src/webmin.patch index cf76bcbb..d27ce764 100644 --- a/overlays/turnkey.d/webmin/usr/local/src/webmin.patch +++ b/overlays/turnkey.d/webmin/usr/local/src/webmin.patch @@ -1,19 +1,25 @@ diff --git a/edit_ssl.cgi b/edit_ssl.cgi -index dd98182..1a4cd77 100755 +index a8b6274..f552dbb 100755 --- a/edit_ssl.cgi +++ b/edit_ssl.cgi -@@ -259,13 +259,14 @@ print ui_tabs_end_tab(); - print ui_tabs_start_tab("mode", "lets"); - print "$text{'ssl_letsdesc'}

\n"; +@@ -261,19 +261,15 @@ print ui_tabs_end_tab(); + # Let's Encrypt form + print ui_tabs_start_tab("mode", "lets"); -my $err = &check_letsencrypt(); +my $err = 1; - if ($err) { -- print "",&text('ssl_letserr', $err),"

\n"; -- print &get_letsencrypt_install_message( -- "/$module_name/edit_ssl.cgi?mode=lets", $text{'ssl_title'}); -- print "

\n"; -- print &text('ssl_letserr2', "../config.cgi?$module_name"),"

\n"; + print $text{'ssl_letsdesc'}; + if (!$err) { +- print &ui_tag('span', +- &ui_details({ +- 'class' => 'inline inlined', +- 'title' => '', +- 'content' => $text{'ssl_letsdesc2'}, +- }))."\n". +- &ui_tag('style', +- ".ui--span>details.inline>summary+span {\n". +- "margin-top: 0;\n". +- "}\n"); + print "Unfortunately the Webmin Let's Encrypt module currrently clashes"; + print " with TurnKey's SSL conf and has been disabled

\n"; + print "

To use Let's Encrypt, please use "; + print "Let's Encrypt plugin docs.

"; } - else { - # Show form to create a cert + print "

\n"; + diff --git a/plans/turnkey/base b/plans/turnkey/base index e805ed45..634b3cab 100644 --- a/plans/turnkey/base +++ b/plans/turnkey/base @@ -62,7 +62,9 @@ ncurses-term /* support additional $TERM values */ webmin webmin-authentic-theme -webmin-net +// webmin-net causing issues so excluded for now +// see https://github.com/turnkeylinux/tracker/issues/2118 +//webmin-net webmin-software webmin-useradmin webmin-passwd @@ -82,6 +84,7 @@ libfile-mimeinfo-perl /* webmin-filemin requires to extract archives */ logrotate iptables +iptables-persistent webmin-firewall webmin-firewall6 fail2ban