-
Notifications
You must be signed in to change notification settings - Fork 82
feat: add rootless image #428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
Is anyone available to take a look at this and offer feedback? There are several issues discussing the need for a rootless image. Our team is working on several Hyperledger and OpenWallet Foundation projects utilizing Caddy server as a reverse proxy. |
|
Sorry for the wait. Thanks for this, I think it's the way we should go (separate tagged variant for rootless), rather than try to force the main one to support rootless (which is what prior discussion has always suggested). There's still some things I think won't work well though, like the I want to get @hairyhenderson's thoughts on this before moving ahead with it though. |
|
Overall I'm supportive of this - @francislavoie and I have chatted about this and I'll let him make a few comments and get this merged. Thanks for your patience, @i5okie! |
caf8dc1 to
d9685cb
Compare
francislavoie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Looks good to me. We'll need to generate the 2.11 ones as well (but I can do that after merge, that's fine)
Just as a last sanity check, @tianon do you have any objections to us adding another image variant for rootless usage? It's tricky with a webserver cause low ports as well as filesystem permissions, so I think this is the best of both worlds instead of trying to support both root and rootless in one image.
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
Signed-off-by: Ivan P <2119240+i5okie@users.noreply.github.com>
d9685cb to
7e724d4
Compare
|
I rebased on |
|
My knee-jerk reaction is definitely that this is weird (both it being a whole separate variant and it being a complete copy not just a few configuration/metadata tweaks) 😅 However, I clearly need to dig in to the details more to make sure I understand how we ended up here so I can provide more meaningful thoughts 🙇 ❤️ |
|
Heh, moby/moby#8460 -- this issue haunts me forever 😂 The privileged ports problem in Docker itself was fixed in moby/moby#41030, way back in Docker 20.10 😅 See also kubernetes/kubernetes#102612 for where Kubernetes has spent a lot of time discussing this same change. More relevantly, containerd enabled this by default in containerd/containerd#9348, which is containerd 2.0+ (and I believe that applies transitively to Kubernetes deployments using containerd also). Regarding the filesystem access, saying that users who want to run as non-root need to deal with filesystem permissions is really reasonable, but pre-seeding with directories at mode 1777 is extremely reasonable, and I think mostly solves the problem in a way that's reasonably safe (as I noted over in #287 (comment) 😅). Just to illustrate, here's an example of me running $ docker run -it --rm --pull=always --user 1234:5678 --security-opt no-new-privileges --tmpfs /data:mode=1777 --tmpfs /config:mode=1777 caddy
latest: Pulling from library/caddy
Digest: sha256:2adb640cdc0ce1d8870887c30af1e21edfb3cdfd8433431b2a15f40119a7d654
Status: Image is up to date for caddy:latest
2026/01/23 23:43:19.569 INFO maxprocs: Leaving GOMAXPROCS=16: CPU quota undefined
2026/01/23 23:43:19.569 INFO GOMEMLIMIT is updated {"package": "github.com/KimMachineGun/automemlimit/memlimit", "GOMEMLIMIT": 60335316172, "previous": 9223372036854775807}
2026/01/23 23:43:19.569 INFO using config from file {"file": "/etc/caddy/Caddyfile"}
2026/01/23 23:43:19.570 INFO adapted config to JSON {"adapter": "caddyfile"}
2026/01/23 23:43:19.570 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//[::1]:2019", "//127.0.0.1:2019", "//localhost:2019"]}
2026/01/23 23:43:19.570 WARN http.auto_https server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server {"server_name": "srv0", "http_port": 80}
2026/01/23 23:43:19.571 WARN http HTTP/2 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/23 23:43:19.571 WARN http HTTP/3 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2026/01/23 23:43:19.571 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2026/01/23 23:43:19.571 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc0003f5480"}
2026/01/23 23:43:19.571 INFO autosaved config (load with --resume flag) {"file": "/config/caddy/autosave.json"}
2026/01/23 23:43:19.571 INFO serving initial configuration
2026/01/23 23:43:19.571 INFO tls cleaning storage unit {"storage": "FileStorage:/data/caddy"}
2026/01/23 23:43:19.571 INFO tls finished cleaning storage units |
Add rootless Docker images for enhanced security and Kubernetes/OpenShift compatibility
Purpose
This PR adds rootless variant of the Caddy Docker images that run as a non-root user (UID 1001), making them suitable for security-constrained environments like Kubernetes and OpenShift, while remaining a drop-in replacement for the alpine images.
Why rootless?
Security best practices: Running containers as root is discouraged in production environments. Non-root containers provide defense-in-depth by limiting the impact of potential container breakouts or exploits.
Kubernetes/OpenShift requirements: Many Kubernetes clusters enforce Pod Security Standards that prohibit root containers. OpenShift, in particular, assigns arbitrary UIDs to containers by default and requires image to support this pattern.
Port restrictions: Non-root users cannot bind to privileged ports (< 1024). Using ports 80 and 443 in Kubernetes is problematic anyway since:
What's included
New image variant:
caddy:rootless- Rootless runtime image (ports 8080, 8443, 2019)Key features:
Implementation details:
The rootless templates are based on the standard
alpinetemplates with these modifications:setcapcapability (not needed for non-privileged ports)adduser -D -u 1001 -g 0chown 1001:0) and group permissions (chmod g+w) on all Caddy directoriessedto replace:80with:{$CADDY_HTTP_PORT:8080}CADDY_HTTP_PORT=8080andCADDY_HTTPS_PORT=8443environment variablesUSER 1001directive to run as non-rootTesting
Built and tested locally - serves the welcome page on port 8080 as expected. The image runs without root privileges and properly serves static content.