LDEV-5882 non-root user and read-only rootfs support for Lucee 6.2+#107
Open
justincarter wants to merge 1 commit into
Open
LDEV-5882 non-root user and read-only rootfs support for Lucee 6.2+#107justincarter wants to merge 1 commit into
justincarter wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add non-root user and read-only root filesystem support (Lucee 6.2+)
This PR adds opt-in support for running Lucee Docker images as a non-root user and with a read-only root filesystem. Both features target Lucee 6.2+ / Tomcat 11+ images (and 7.x). Earlier Lucee minors (5.x, 6.0, 6.1) are unchanged and continue to run as root with a writable filesystem.
Motivation
Modern container deployment environments (Kubernetes pod security standards, AWS ECS task hardening, internal security policies) increasingly require — or strongly prefer — containers that run as non-root and with a read-only root filesystem. These changes give Lucee users the ability to meet those requirements without forking the base image, while keeping default container behavior unchanged for users who don't opt in.
What's changed
Image-level capabilities (all opt-in; defaults unchanged):
luceesystem user is created (uid 999) on Lucee 6.2+ / Tomcat 11+ images. Opt in viaUSER luceein a downstream Dockerfile,--user luceeon the CLI,user: "lucee"in docker-compose,securityContext.runAsUser: 999in Kubernetes, or"user": "lucee"in an ECS task definition./usr/local/tomcat/{logs,temp,work},/opt/lucee/server-runtime,/tmp, plus nginx-specific paths) are declared as anonymous volumes sodocker run --read-onlyworks out of the box. Kubernetes and ECS Fargate still require explicitemptyDir/ volume entries — this is documented in the README.docker-entrypoint.shhandles theLUCEE_RUNTIME_DIRenv var: when set, it seeds a writable copy of the Lucee server context from the read-only image at container start, then re-points Lucee to use the runtime directory. Without this seed step, Lucee can't write to its server context under a read-only filesystem.prewarm.shchowns the writable Tomcat and Lucee directories to theluceeuser after warmup, so files produced by root during prewarm don't leave theluceeuser unable to overwrite them at runtime (this avoidscatalina.YYYY-MM-DD.logpermission errors).Configuration changes:
config/tomcat/11.0/web.xml: thelucee-server-directoryandlucee-web-directoryinit-params in theCFMLServletdefinition are commented out. Lucee now resolves these from theLUCEE_SERVER_DIRandLUCEE_WEB_DIRenv vars (set in the Dockerfile). Tomcat 9.0 and 10.1 web.xml files are NOT modified, so 5.x / 6.0 / 6.1 continue to use the hardcoded init-param values.Gating:
The new RUN block in
Dockerfileis gated on Tomcat major version ≥ 11, matching the existing pattern at line 49. Since Lucee 6.2 / 7.0 / 7.1 are the only minors on Tomcat 11.0 in the build matrix, this scopes the feature to exactly the in-scope versions without requiring per-Lucee-minor logic.Testing
tests/test-readonly-filesystem.shand can be run manually against any locally-built or published Lucee image..github/workflows/test-readonly-filesystem.yml) is included for ad-hoc verification of published Docker Hub images. It does NOT run automatically on push or pull request — main build times are unaffected.Files changed
DockerfileENV LUCEE_SERVER_DIR/LUCEE_WEB_DIR; conditional RUN for Tomcat 11+ (creates pinned uid 999luceeuser, chowns runtime dirs, creates server-runtime dir, locks down lucee.jar perms);VOLUMEdeclarations;ENTRYPOINT+ restoredCMDDockerfile.nginxid luceefor nginx chowns + libcap2-bin / setcap; nginx-specificVOLUMEdeclarationsconfig/tomcat/11.0/web.xmllucee-server-directoryandlucee-web-directoryinit-params commented outsupporting/prewarm.sh/usr/local/tomcat/{logs,temp,work}and/var/wwwsupporting/docker-entrypoint.shLUCEE_RUNTIME_DIRfromLUCEE_SERVER_DIRwhen settests/test-readonly-filesystem.sh.github/workflows/test-readonly-filesystem.ymlworkflow_dispatchonly)README.mdLUCEE_RUNTIME_DIRdocumentedNotable behavior changes for existing 6.2+ users
docker runwithout--rmwill now create anonymous volumes for the declared paths. These accumulate on disk over time on dev / CI machines if not pruned. The README documents this and the available cleanup options (--rm,docker volume prune, named volumes in compose withdocker compose down -v). Production deployments using explicit volumes are unaffected.luceeuser (uid 999) is now created in the image but is not used unless explicitly opted in via--user lucee/USER lucee/ etc. Default container behavior is still root.ENTRYPOINTis nowdocker-entrypoint.sh. It is a no-op whenLUCEE_RUNTIME_DIRis unset, and forwards to the inheritedCMD(catalina.sh runorsupervisord …) viaexec "$@". Behavior for default users is identical.