Skip to content
Snippets Groups Projects
Lyle Hanson's avatar
Lyle Hanson authored
5e049612
History
Name Last commit Last update
src
.gitignore
Readme.md
pom.xml

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