git: 0c01423b48aa - main - www/caddy: Secure the default admin API endpoint

From: Adam Weinberger <adamw_at_FreeBSD.org>
Date: Thu, 12 Oct 2023 02:38:56 UTC
The branch main has been updated by adamw:

URL: https://cgit.FreeBSD.org/ports/commit/?id=0c01423b48aa7b63e795601c64af03322a594cae

commit 0c01423b48aa7b63e795601c64af03322a594cae
Author:     Thomas Hurst <tom@hur.st>
AuthorDate: 2023-10-12 02:32:01 +0000
Commit:     Adam Weinberger <adamw@FreeBSD.org>
CommitDate: 2023-10-12 02:38:40 +0000

    www/caddy: Secure the default admin API endpoint
    
    Caddy's default of localhost:2019, particularly combined with the port
    defaulting to root:wheel, can be a significant security risk.
    
    Mitigate this by setting the default to /var/run/caddy/caddy.sock, which
    will be protected by filesystem permissions.  Prior behaviour can be
    restored with 'sysrc caddy_admin=localhost:2019'
    
    Additionally, help users prepare for a change to running Caddy as
    www:www by default using the new security/portacl-rc port in an update
    message, and by extending the comments in the rc script.
---
 www/caddy/Makefile             |  3 ++
 www/caddy/files/caddy.in       | 35 ++++++++++++++++--
 www/caddy/files/pkg-message.in | 80 +++++++++++++++++++++++++++++++++++++++---
 3 files changed, 110 insertions(+), 8 deletions(-)

diff --git a/www/caddy/Makefile b/www/caddy/Makefile
index 78ebc97e544d..cc999d13b787 100644
--- a/www/caddy/Makefile
+++ b/www/caddy/Makefile
@@ -14,6 +14,9 @@ LICENSE_FILE=	${WRKSRC}/LICENSE
 USES=		cpe go:modules
 CPE_VENDOR=	caddyserver
 
+USERS=		www
+GROUPS=		www
+
 USE_RC_SUBR=	caddy
 SUB_FILES=	Caddyfile.sample caddy pkg-message
 
diff --git a/www/caddy/files/caddy.in b/www/caddy/files/caddy.in
index 8e46cd93aae9..37babe7889d3 100644
--- a/www/caddy/files/caddy.in
+++ b/www/caddy/files/caddy.in
@@ -4,14 +4,39 @@
 # REQUIRE: LOGIN DAEMON NETWORKING
 # KEYWORD: shutdown
 
-# To enable caddy, add 'caddy_enable="YES"' to /etc/rc.conf or
-# /etc/rc.conf.local
+# To enable caddy:
+#
+# - Edit %%ETCDIR%%/Caddyfile
+#   See https://caddyserver.com/docs/
+# - Run 'service enable caddy'
+#
+# Note while Caddy currently defaults to running as root:wheel, it is strongly
+# recommended to run the server as an unprivileged user, such as www:www.
+#
+# - Use security/portacl-rc to enable privileged port binding:
+#
+#   # pkg install security/portacl-rc
+#   # sysrc portacl_users+=www
+#   # sysrc portacl_user_www_tcp="http https"
+#   # sysrc portacl_user_www_udp="https"
+#   # service portacl enable
+#   # service portacl start
+#
+# - Configure caddy to run as www:www
+#
+#   # sysrc caddy_user=www caddy_group=www
+#
+# - Note if Caddy has been started as root previously, files in
+#   /var/log/caddy, /var/db/caddy, and /var/run/caddy may require their ownership
+#   changing manually.
 
 # Optional settings:
 # caddy_command (string):     Full path to the caddy binary
 # caddy_config (string):      Full path to caddy config file
 #                             (%%ETCDIR%%/Caddyfile)
 # caddy_adapter (string):     Config adapter type (caddyfile)
+# caddy_admin (string):       Default administration endpoint
+#                             (unix//var/run/caddy/caddy.sock)
 # caddy_directory (string):   Root for caddy storage (ACME certs, etc.)
 #                             (/var/db/caddy)
 # caddy_extra_flags (string): Extra flags passed to caddy start
@@ -40,6 +65,7 @@ load_rc_config $name
 : ${caddy_enable:=NO}
 : ${caddy_adapter:=caddyfile}
 : ${caddy_config:="%%ETCDIR%%/Caddyfile"}
+: ${caddy_admin:="unix//var/run/${name}/${name}.sock"}
 : ${caddy_command:="%%PREFIX%%/bin/${name}"}
 : ${caddy_directory:=/var/db/caddy}
 : ${caddy_extra_flags:=""}
@@ -53,6 +79,9 @@ load_rc_config $name
 : ${XDG_DATA_HOME:="${caddy_directory}/data"}
 export XDG_CONFIG_HOME XDG_DATA_HOME
 
+# Default admin interface
+export CADDY_ADMIN="${caddy_admin}"
+
 command="${caddy_command}"
 pidfile="/var/run/${name}/${name}.pid"
 
@@ -116,7 +145,7 @@ caddy_prestop()
 
     echo -n "Stopping caddy... "
 
-    result="$(caddy_execute stop 2>&1)"
+    result="$(caddy_execute stop ${caddy_flags} 2>&1)"
     if [ ${?} -eq 0 ]; then
         echo "done"
         exit 0
diff --git a/www/caddy/files/pkg-message.in b/www/caddy/files/pkg-message.in
index 661e81dde602..321e6b87bc36 100644
--- a/www/caddy/files/pkg-message.in
+++ b/www/caddy/files/pkg-message.in
@@ -6,22 +6,41 @@ To enable caddy:
 
 - Edit %%ETCDIR%%/Caddyfile
   See https://caddyserver.com/docs/
-- Add caddy_enable="YES" to /etc/rc.conf
+- Run 'service enable caddy'
+
+Note while Caddy currently defaults to running as root:wheel, it is strongly
+recommended to run the server as an unprivileged user, such as www:www --
+
+- Use security/portacl-rc to enable privileged port binding:
+
+  # pkg install security/portacl-rc
+  # sysrc portacl_users+=www
+  # sysrc portacl_user_www_tcp="http https"
+  # sysrc portacl_user_www_udp="https"
+  # service portacl enable
+  # service portacl start
+
+- Configure caddy to run as www:www
+
+  # sysrc caddy_user=www caddy_group=www
+
+- Note if Caddy has been started as root previously, files in
+  /var/log/caddy, /var/db/caddy, and /var/run/caddy may require their ownership
+  changing manually.
 
 %%PREFIX%%/etc/rc.d/caddy has the following defaults:
 
 - Server log: /var/log/caddy/caddy.log
   (runtime messages, NOT an access.log)
 - Automatic SSL certificate storage: /var/db/caddy/data/caddy/
-- Runs as root:wheel (you can run as another user, like www,
-  but caddy will be unable to bind to low-numbered ports,
-  including 80 and 443)
+- Administration endpoint: //unix/var/run/caddy/caddy.sock
+- Runs as root:wheel (this will change to www:www in the future)
 
 INSTALL
 }
 {
   type: upgrade
-  maximum_version: 2.3.0
+  maximum_version: "2.3.0"
   message: <<UPGRADE
 The default locations for caddy runtime files have changed!
 
@@ -36,6 +55,57 @@ The default locations for caddy runtime files have changed!
 
 You can change these defaults. See %%PREFIX%%/etc/rc.d/caddy
 
+UPGRADE
+}
+{
+  type: upgrade
+  maximum_version: "2.7.4_2"
+  message: <<UPGRADE
+The default Caddy administration endpoint location has been changed from
+localhost:2019 to a protected Unix domain socket located in
+/var/run/caddy/caddy.sock
+
+This can be overridden with the `caddy_admin` rc variable, or by specifiying
+an alternative in the Caddyfile `admin` section, documented here:
+
+  https://caddyserver.com/docs/caddyfile/options#admin
+
+The previous default, particularly paired with the server running as root,
+may have serious security implications for shared machines with untrusted
+users.
+
+UPGRADE
+}
+{
+  type: upgrade
+  message: <<UPGRADE
+It is STRONGLY RECOMMENDED to run Caddy as an unprivileged user, such as
+www:www, rather than the current default of root:wheel.
+
+If you have relied upon earlier defaults:
+
+- Use security/portacl-rc to enable privileged port binding:
+
+  # pkg install security/portacl-rc
+  # sysrc portacl_users+=www
+  # sysrc portacl_user_www_tcp="http https"
+  # sysrc portacl_user_www_udp="https"
+  # service portacl enable
+  # service portacl start
+
+- Stop the server, and update ownership on Caddy runtime files:
+
+  # service caddy stop
+  # chown -r www:www /var/db/caddy /var/log/caddy /var/run/caddy
+
+Other changes may be necessary depending on your exact Caddy
+configuration.
+
+- Change the default runtime user, and restart the server:
+
+  # sysrc caddy_user=www caddy_group=www
+  # service caddy start
+
 UPGRADE
 }
 ]