API hardening: Limit access

Hello everyone,

1. The problem I’m having:

I don’t really have a problem. I just want to understand concepts of caddy better.

I understand that caddy uses an API. I am free to disable this API by using

{
  admin off
}

If I do so, the command systemctl reload caddy will fail, because the unit file describes that command as:

/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force

and this seems to use the API.

But here begins my problem: I got different users on a system. All of these users can login using ssh and, even if I limit the caddy port using the firewall, edit the caddy config using the API.

This is, of course, something I want to prevent.

What would be the best way to:

  • Allow the usage of systemctl reload caddy
  • Limit the usage of the API in order to forbid other users than the root or caddy user to modify the config

3. Caddy version:

caddy version
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=

4. How I installed and ran Caddy:

From package

a. System environment:

Ubuntu 24.04

c. Service/unit/compose file:

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

You can configure the admin endpoint to listen on a unix socket, which allows you to control which users can access it via the file system ACL. This is mentioned in the admin section on the Caddyfile Global options page, which I’ve linked to directly in the below.

2 Likes

Thanks. That’s a good finding, thanks.

So I’d assume that Caddy will take care of creating that socket on service start.

Once I restart caddy, I am getting this error:

Oct 01 04:52:53 server1 caddy[54892]: Error: loading initial config: loading new config: starting caddy administration endpoint: listen unix /run/caddy-admin.sock: bind: permission denied

Okay. /run is owned by root and caddy is using a separate user, so I guess, caddy cannot create that socket. So I changed it to:

  admin unix//etc/caddy/socket/caddy-admin.sock
}

which is writeable for that user:

drwxr-xr-x   2 caddy caddy 4.0K Oct  1 05:03 socket

But still it’s having it’s troubles:

Oct 01 05:03:31 server1 caddy[54982]: Error: loading initial config: loading new config: starting caddy administration endpoint: unable to set permissions (--w-------) on /etc/caddy/socket/caddy-admin.sock: chmod /etc/caddy/socket/caddy-admin.sock: no such file or directory

The standard systemd unit file shipped with Caddy uses ProtectSystem=full, which makes most directories inaccessible except for selected few. Systemd documentation elaborates more on this config.

https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#ProtectSystem=

You can use the systemd ReadWritePaths directive to override the restriction for selected paths.

https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#ReadWritePaths=

We document here how to override some of the systemd configuration we ship with Caddy.

When configuring Caddy with a unix socket, you can customize the permission bits set on the socket.

Conventions — Caddy Documentation.

2 Likes