Tomcat File Property Source
This is an implementation of org.apache.tomcat.util.IntrospectionUtils.PropertySource
which
allows Tomcat to resolve property placeholders in configuration files such as server.xml
at startup,
sourcing properties from a file path indicated by either the system property or environment variable
(in that order of preference) named TOMCAT_PROPERTIES_FILE
.
Why?
It's undesirable and fragile to maintain individual copies of Tomcat configurations across multiple hosts for the same application. It doesn't scale well operationally and adds opportunity for misconfiguration or subtle differences between Tomcat instances. Externalizing sensitive and environment-specific configuration properties (such as keystore or database credentials) allows the application to be deployed identically across multiple hosts while minimizing the amount individual configuration required.
It also makes a customized Tomcat deployment self-contained for easy packaging with Docker.
Usage
The artifact produced by this project is a fat JAR which is simply copied into your Tomcat lib/
directory.
In order to register as a property source which Tomcat will consult on startup, the following needs to be
included in conf/catalina.properties
:
org.apache.tomcat.util.digester.PROPERTY_SOURCE=edu.wisc.services.tomcat.FilePropertySource
At Tomcat startup, if a valid file path is found in the environment or system properties under the
TOMCAT_PROPERTIES_FILE
key, those properties may be used as placeholders in Tomcat config files.
Example
To build a Docker image containing a customized Tomcat configuration with externalized properties, here's an outline of the setup you'd do.
In your project's pom.xml
:
<build>
<plugins>
<plugin>
<!-- Copy the tomcat-file-property-source JAR from Maven into our build directory -->
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-tomcat-property-source</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>edu.wisc.services.tomcat</groupId>
<artifactId>tomcat-file-property-source</artifactId>
<version>${tomcat-file-property-source-version}</version>
<outputDirectory>${project.build.directory}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- Include the tomcat-file-property-source JAR in our docker build directory
when "mvn docker:build" is run -->
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<imageName>tomcat_endpoint</imageName>
<dockerDirectory>docker</dockerDirectory>
<resources>
<resource>
<targetPath>/</targetPath>
<directory>${project.build.directory}</directory>
<include>tomcat-file-property-source-${tomcat-file-property-source-version}.jar</include>
</resource>
</resources>
</configuration>
</plugin>
<!-- ... -->
</plugins>
</build>
To build a Docker image with mvn docker:build
, you'd include a Dockerfile
containing the following in your docker/
directory:
FROM tomcat:8.0.32-jre8
# Set up our custom property resolver for credential placeholders in Tomcat config files
ENV TOMCAT_PROPERTIES_FILE=/my/properties/file
RUN echo "org.apache.tomcat.util.digester.PROPERTY_SOURCE=edu.wisc.services.tomcat.FilePropertySource" >> /usr/local/tomcat/conf/catalina.properties
COPY tomcat-file-property-source-1.0.jar /usr/local/tomcat/lib
# Install custom Tomcat configuration with property placeholders
COPY server.xml /usr/local/tomcat/conf/
That server.xml might include placeholders like so:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="http-executor-8443"
URIEncoding="UTF-8"
SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2,SSLv2Hello"
maxKeepAliveRequests="300"
keystoreFile="${keystore.file}"
keystorePass="${keystore.password}" />
Those keystore.*
placeholders will be resolved from your properties file specified in the TOMCAT_PROPERTIES_FILE
and
exposed to the Docker image via the usual means, such as VOLUME.
Properties:
keystore.file=/path/to/my/keystore.jks
keystore.password=t0ps3cr3t