Minimal tomcat container based on alpine meant for production use. TLS is assumed to be provided externally by a load balancer.
- Tomcat 9 running on openjdk11
- JRE by default but JDK available by Docker build arg.
- Configuration split between
CATALINA_HOME
andCATALINA_BASE
.
- Docker practices
- Minimal alpine image.
- Final image size is 187MB.
- Compatible with both AMD64 and ARM architectures.
- PID 1 init program to handle process signals and child processes.
- Application starts as a normal system user instead of
root
. - Web server starts in foreground.
- Web server logs to stdout and stderr to be handled by Docker instead of writing logs to disk.
- Minimal alpine image.
- Security hardened
- CIS Apache Tomcat 9 Benchmark; v1.1.0 - 12-18-2020
- Default tomcat apps removed.
- Tomcat security manager enabled with a sane initial security policy.
- Access restricted to tomcat user for configuration files
unpackWARs
andautoDeploy
is disabled.- Printing stack traces on error is disabled.
- TRACE HTTP method disabled.
- LockOutRealm is configured.
- Shutdown port is disabled.
- Shutdown command is randomized on boot.
- Connector security configured for HTTP
- Autodeployment on startup is disabled and
/webapps/ROOT
is defined for manual deployment context inserver.xml
. - Connection timeout set to 60 seconds.
The tomcat base image can be viewed in Dockerfile
.
docker build -t tomcat .
/webapps/ROOT
- Extract your application WAR here./data
- If your app requires persistent data then/data
is the location assumed.
Security policy grants your app unconstrained access to the following locations.
/data
/dev/shm
/home/tomcat
/tmp
/var/tmp
/webapps/ROOT
Other locations will require a policy update.
Modify JVM behavior through the following environment variables.
CATALINA_OPTS
JAVA_OPTS
An example application Dockerfile has also been provided.
Due to hardening automatic application deployment is disabled. You must extract your war files as part of Docker image building.
Note: The application Dockerfile uses
java xf *.war
to extract an application into/webapps/ROOT
. This folder is the ROOT context for tomcat.
It is recommended to keep tomcat security hardening in place. By default a very broad policy is applied which allows most actions within reason.
If you wish to overwrite this policy then overwrite the following policy file in the tomcat container.
/tomcat/conf/catalina.policy
(see also Tomcat docs).
You can enable more debug logs for security manager with the following environment variable.
docker run -e CATALINA_OPTS=-Djava.security.debug=access ...
If you want to disable sandboxing entirely you can add the following line to the
end of your application Dockerfile removing -security
option.
CMD ["/opt/tomcat/bin/catalina.sh", "run"]
All logs should push to stdout.
If your application has special logging enabled, then don't write to a file. Instead, write the log to stdout and add a log prefix to differentiate instead.
- Logs with no prefix are assumed to be tomcat and its deployed application.
- Access logs are prefixed with
ACCESS:
followed by standard tomcat format.
For a stdout
example, see AccessLogValve
in
/tomcat/conf/server.xml
.
A filesystem layout has been generated highlighting the parts for tomcat excluding Java.
docker run -u root tomcat /bin/sh -c \
'apk add --no-cache tree &> /dev/null; \
rm -rf /var/cache/*; \
tree /home/tomcat /tmp /var/cache /var/tmp /webapps /tomcat /opt/tomcat' \
> example/filesystem-layout.txt
You can try this out with Jenkins. At the root of this repository download Jenkins.
curl -sSfLO https://get.jenkins.io/war-stable/2.361.3/jenkins.war
Build all prerequisite docker images.
docker build --build-arg java=jdk --build-arg all=true -t tomcat .
docker build -t sample -f example/Dockerfile .
Run Jenkins webapp in hardened tomcat container.
mkdir ../jenkins_home
JENKINS_HOME="$(cd ../jenkins_home; pwd)"
docker run -v "${JENKINS_HOME}:/data \
-e JENKINS_HOME=/jenkins --rm -p 8080:8080 sample
Visit http://localhost:8080/ to see your example app running. Use CTRL+C
to
exit.