https://github.com/unidata/tomcat-docker
Security-hardened Tomcat container for thredds-docker and ramadda-docker
https://github.com/unidata/tomcat-docker
Last synced: 3 months ago
JSON representation
Security-hardened Tomcat container for thredds-docker and ramadda-docker
- Host: GitHub
- URL: https://github.com/unidata/tomcat-docker
- Owner: Unidata
- License: bsd-3-clause
- Created: 2016-09-09T15:27:05.000Z (over 9 years ago)
- Default Branch: latest
- Last Pushed: 2024-07-30T17:06:24.000Z (over 1 year ago)
- Last Synced: 2025-03-24T02:12:39.473Z (10 months ago)
- Language: Shell
- Homepage: https://hub.docker.com/r/unidata/tomcat-docker/
- Size: 107 KB
- Stars: 66
- Watchers: 10
- Forks: 70
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
- [Unidata Tomcat Docker](#h-C944C5F1)
- [Introduction](#h-1411CF81)
- [Security Hardening Measures](#h-6C9EE33A)
- [Introduction](#h-F5641083)
- [web.xml Enhancements](#h-76CE835C)
- [CORS](#h-6D53D9B2)
- [server.xml Enhancements](#h-8027E0B0)
- [Digested Passwords](#h-4CE92D2E)
- [CVEs](#h-C1DF14EF)
- [Versions](#h-6C0AB867)
- [Prerequisites](#h-61809CB7)
- [Installation](#h-FB3558BB)
- [Usage](#h-B602CE28)
- [Configuration](#h-AFA7F4DC)
- [Configurable Tomcat UID and GID](#h-E4632DC9)
- [HTTPS](#h-D725A36E)
- [Self-signed Certificates](#h-C24884FC)
- [Certificate from CA](#h-B5E124BB)
- [Force HTTPS](#h-787A700F)
- [Testing](#h-32889858)
# Unidata Tomcat Docker
A security-hardened Tomcat container for [thredds-docker](https://github.com/Unidata/thredds-docker) and [ramadda-docker](https://github.com/Unidata/ramadda-docker).
## Introduction
This repository contains files necessary to build and run a security hardened Tomcat Docker container, based off of a canonical [Tomcat base image](https://hub.docker.com/_/tomcat/). The Unidata Tomcat Docker images associated with this repository are [available on Docker Hub](https://hub.docker.com/r/unidata/tomcat-docker/). All default web applications have been expunged from this container so it will primarily serve as a base image for other containers.
### Security Hardening Measures
#### Introduction
This Tomcat container was security hardened according to [OWASP recommendations](https://www.owasp.org/index.php/Securing_tomcat). Specifically,
- Eliminated default Tomcat web applications
- Run Tomcat with unprivileged user `tomcat` (via `entrypoint.sh`)
- Start Tomcat via Tomcat Security Manager (via `entrypoint.sh`)
- All files in `CATALINA_HOME` are owned by user `tomcat` (via `entrypoint.sh`)
- Files in `CATALINA_HOME/conf` are read only (`400`) by user `tomcat` (via `entrypoint.sh`)
- Container-wide `umask` of `007`
#### web.xml Enhancements
The following changes have been made to [web.xml](./web.xml) from the out-of-the-box version:
- Added `SAMEORIGIN` anti-clickjacking option
- HTTP header security filter (`httpHeaderSecurity`) uncommented/enabled
- Cross-origin resource sharing (CORS) filtering (`CorsFilter`) added/enabled (see below to disable)
- Stack traces are not returned to user through `error-page` element.
##### CORS
This image enables the [Apache Tomcat CORS filter](https://tomcat.apache.org/tomcat-8.5-doc/config/filter.html#CORS_Filter) by default. To disable it (maybe you want to handle CORS uniformly in a proxying webserver?), set environment variable `DISABLE_CORS` to `1`.
#### server.xml Enhancements
The following changes have been made to [server.xml](./server.xml) from the out-of-the-box version:
- Server version information is obscured to user via `server` attribute for all `Connector` elements
- `secure` attribute set to `true` for all `Connector` elements
- Shutdown port disabled
- Digested passwords. See next section.
The active `Connector` has `relaxedPathChars` and `relaxedQueryChars` attributes. This change may not be optimal for security, but must be done [to accommodate DAP requests](https://github.com/Unidata/thredds-docker/issues/209) which THREDDS and RAMADDA must perform.
#### Digested Passwords
This container has a `UserDatabaseRealm`, `Realm` element in `server.xml` with a default `CredentialHandler` `algorithm` of `sha-512`. This modification is an improvement over the clear text password default that comes with the parent container (`tomcat:8.5-jdk11`). Passwords defined in `tomcat-users.xml` must use digested passwords in the `password` attributes of the `user` elements. Generating a digested password is simple. Here is an example for the `sha-512` digest algorithm:
```sh
docker run tomcat /usr/local/tomcat/bin/digest.sh -a "sha-512" mysupersecretpassword
```
This command will yield something like:
```sh
mysupersecretpassword:94e334bc71163a69f2e984e73741f610e083a8e11764ee3e396f6935c3911f49$1$a5530e17501f83a60286f6363a8647a277c9cfdb
```
The hash after the `:` is what you will use for the `password` attribute in `tomcat-users.xml`.
More information about this topic is available in the [Tomcat documentation](https://tomcat.apache.org/tomcat-8.5-doc/realm-howto.html#Digested_Passwords).
#### CVEs
We strive to maintain the security of this project's DockerHub images by updating them with the latest upstream security improvements. If you have any security concerns, please email us at [security@unidata.ucar.edu](mailto:security@unidata.ucar.edu) to bring them to our attention.
## Versions
See tags listed [on dockerhub](https://hub.docker.com/r/unidata/tomcat-docker/tags). Note, these versions are not necessarily static and will evolve due to upstream image changes. It's recommended to check regularly to ensure you have the latest image.
## Prerequisites
Before you begin using this Docker container project, make sure your system has Docker installed. Docker Compose is optional but recommended.
## Installation
You can either pull the image from DockerHub with:
```sh
docker pull unidata/tomcat-docker:
```
Or you can build it yourself with:
1. ****Clone the repository****: `git clone https://github.com/Unidata/tomcat-docker.git`
2. ****Navigate to the project directory****: `cd tomcat-docker`
3. ****Build the Docker image****: `docker build -t tomcat-docker:` .
## Usage
Note that this project is meant to serve as a base image for other containerized Docker Tomcat web applications. Refer to the image created by this project in your Dockerfile. For example:
```sh
FROM unidata/tomcat-docker:8.5-jdk11
```
Sometimes it is useful to enter this container via bash and poke around, just to see what is there. For example,
```sh
docker run -it unidata/tomcat-docker:8.5-jdk11 bash
```
## Configuration
### Configurable Tomcat UID and GID
The problem with mounted Docker volumes and UID/GID mismatch headaches is best explained here: .
This container allows the possibility of controlling the UID/GID of the `tomcat` user inside the container via `TOMCAT_USER_ID` and `TOMCAT_GROUP_ID` environment variables. If not set, the default UID/GID is `1000/1000`. For example,
```sh
docker run --name tomcat \
-e TOMCAT_USER_ID=`id -u` \
-e TOMCAT_GROUP_ID=`getent group $USER | cut -d':' -f3` \
-v `pwd`/logs:/usr/local/tomcat/logs/ \
-v /path/to/your/webapp:/usr/local/tomcat/webapps \
-d -p 8080:8080 unidata/tomcat-docker:
```
where `TOMCAT_USER_ID` and `TOMCAT_GROUP_ID` have been configured with the UID/GID of the user running the container. If using `docker-compose`, see `compose.env` to configure the UID/GID of user `tomcat` inside the container.
This feature enables greater control of file permissions written outside the container via mounted volumes (e.g., files contained within the Tomcat logs directory such as `catalina.out`).
Note that containers that inherit this container and have overridden `entrypoint.sh` will have to take into account user `tomcat` is no longer assumed in the `Dockerfile`. Rather the `tomcat` user is now created within the `entrypoint.sh` and those overriding `entrypoint.sh` should take this fact into account. Also note that this UID/GID configuration option will not work on operating systems where Docker is not native (e.g., macOS).
### HTTPS
This Tomcat container can support HTTPS for either self-signed certificates which can be useful for experimentation or certificates from a CA for a production server. For a complete treatment on this topic, see .
#### Self-signed Certificates
This Tomcat container can support HTTP over SSL. For example, generate a self-signed certificate with `openssl` (or better yet, obtain a real certificate from a certificate authority):
```sh
openssl req -new -newkey rsa:4096 -days 3650 -nodes -x509 -subj \
"/C=US/ST=Colorado/L=Boulder/O=Unidata/CN=tomcat.example.com" -keyout \
./ssl.key -out ./ssl.crt
```
Then augment the `server.xml` from this repository with this additional XML snippet for [Tomcat SSL capability](https://tomcat.apache.org/tomcat-8.0-doc/ssl-howto.html):
```xml
```
Mount over the existing `server.xml` and add the SSL certificate and private key with:
```sh
docker run -it -d -p 80:8080 -p 443:8443 \
-v /path/to/server.xml:/usr/local/tomcat/conf/server.xml \
-v /path/to/ssl.crt:/usr/local/tomcat/conf/ssl.crt \
-v /path/to/ssl.key:/usr/local/tomcat/conf/ssl.key \
unidata/tomcat-docker:
```
or if using `docker-compose` the `docker-compose.yml` will look like:
```yaml
unidata-tomcat:
image: unidata/tomcat-docker:
ports:
- "80:8080"
- "443:8443"
volumes:
- /path/to/ssl.crt:/usr/local/tomcat/conf/ssl.crt
- /path/to/ssl.key:/usr/local/tomcat/conf/ssl.key
- /path/to/server.xml:/usr/local/tomcat/conf/server.xml
```
#### Certificate from CA
First, obtain a certificate from a certificate authority (CA). This process will yield a `.key` and `.crt` file. To meet enhanced security guidelines you, will want to serve a certificate with the intermediate and root certificates present in the `ssl.crt` file. For Tomcat to serve the certificate chain, you have to put your `.key` and `.crt` (containing the intermediate and root certificates) in a Java keystore. The [Keystore Explorer](https://keystore-explorer.org/) tool is a helpful app to assist you in building a valid certificate chain as well as exploring Java keystores.
First put the `.key` and `.crt` in a `.p12` file:
```sh
openssl pkcs12 -export -in ssl.crt.fullchain -inkey ssl.key -out ssl.p12 -name \
mydomain.com
```
Then add the `.p12` file to the keystore:
```
keytool -importkeystore -destkeystore keystore.jks -srckeystore ssl.p12 \
-srcstoretype PKCS12
```
When prompted for passwords in the two steps above, consider reusing the same password to reduce cognitive load. If you see the following message
```
Warning: The JKS keystore uses a proprietary format. It is recommended to
migrate to PKCS12 which is an industry standard format using "keytool
-importkeystore -srckeystore keystore.jks -destkeystore keystore.jks
-deststoretype pkcs12".
```
ignore it.
You'll then refer to that keystore in your `server.xml`:
```xml
```
Note there are a few differences with the `Connector` described for the self-signed certificate above. These additions are made according to enhanced security guidelines.
Mount over the existing `server.xml` and add the SSL certificate and private key with:
```sh
docker run -it -d -p 80:8080 -p 443:8443 \
-v /path/to/server.xml:/usr/local/tomcat/conf/server.xml \
-v /path/to/ssl.jks:/usr/local/tomcat/conf/ssl.jks \
unidata/tomcat-docker:
```
or if using `docker-compose` the `docker-compose.yml` will look like:
```yaml
unidata-tomcat:
image: unidata/tomcat-docker:
ports:
- "80:8080"
- "443:8443"
volumes:
- /path/to/ssl.jks:/usr/local/tomcat/conf/ssl.jks
- /path/to/server.xml:/usr/local/tomcat/conf/server.xml
```
#### Force HTTPS
Once you have your certificates in order, make HTTPS mandatory. Add this snippet as the final element in `web.xml`. Mount over the `web.xml` inside the container with this enhanced `web.xml` in the same manner we have been doing to `server.xml` as discussed herein.
```xml
Protected Context
/*
CONFIDENTIAL
```
## Testing
If you would like to do a small test to ensure the Unidata Tomcat Docker image is working:
```sh
mkdir -p /tmp/test
wget -O /tmp/test/sample.war https://tomcat.apache.org/tomcat-8.5-doc/appdev/sample/sample.war
docker run --name tomcat -e TOMCAT_USER_ID=1000 -e TOMCAT_GROUP_ID=1000 -v /tmp/test/:/usr/local/tomcat/webapps -d -p 8080:8080 unidata/tomcat-docker:
curl http://127.0.0.1:8080/sample/index.html
```
This should yield some HTML that starts like this:
```html
Sample "Hello, World" Application
...
```