Merge pull request #39 from ahennr/tomcat-hardening-cis
Docker image and Tomcat configuration hardeningpull/44/head
commit
3727938ec0
63
Dockerfile
63
Dockerfile
|
|
@ -30,25 +30,28 @@ ENV CATALINA_OPTS="\$EXTRA_JAVA_OPTS \
|
|||
|
||||
# init
|
||||
RUN apt update \
|
||||
&& apt -y upgrade \
|
||||
&& apt install -y --no-install-recommends openssl unzip gdal-bin wget curl openjdk-11-jdk gettext \
|
||||
&& apt clean \
|
||||
&& rm -rf /var/cache/apt/* \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& apt -y upgrade \
|
||||
&& apt install -y --no-install-recommends openssl unzip gdal-bin wget curl openjdk-11-jdk gettext \
|
||||
&& apt clean \
|
||||
&& rm -rf /var/cache/apt/* \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /opt/
|
||||
|
||||
RUN wget -q https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz \
|
||||
&& tar xf apache-tomcat-${TOMCAT_VERSION}.tar.gz \
|
||||
&& rm apache-tomcat-${TOMCAT_VERSION}.tar.gz \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/ROOT \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/docs \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/examples
|
||||
&& tar xf apache-tomcat-${TOMCAT_VERSION}.tar.gz \
|
||||
&& rm apache-tomcat-${TOMCAT_VERSION}.tar.gz \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/ROOT \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/docs \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/examples \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/host-manager \
|
||||
&& rm -rf /opt/apache-tomcat-${TOMCAT_VERSION}/webapps/manager
|
||||
|
||||
# cleanup
|
||||
RUN apt purge -y \
|
||||
&& apt autoremove --purge -y \
|
||||
&& rm -rf /tmp/*
|
||||
&& apt autoremove --purge -y \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& rm -rf /tmp/*
|
||||
|
||||
FROM tomcat as download
|
||||
|
||||
|
|
@ -61,10 +64,10 @@ ENV GEOSERVER_BUILD=$GS_BUILD
|
|||
WORKDIR /tmp
|
||||
|
||||
RUN echo "Downloading GeoServer ${GS_VERSION} ${GS_BUILD}" \
|
||||
&& wget -q -O /tmp/geoserver.zip $WAR_ZIP_URL \
|
||||
&& unzip geoserver.zip geoserver.war -d /tmp/ \
|
||||
&& unzip -q /tmp/geoserver.war -d /tmp/geoserver \
|
||||
&& rm /tmp/geoserver.war
|
||||
&& wget -q -O /tmp/geoserver.zip $WAR_ZIP_URL \
|
||||
&& unzip geoserver.zip geoserver.war -d /tmp/ \
|
||||
&& unzip -q /tmp/geoserver.war -d /tmp/geoserver \
|
||||
&& rm /tmp/geoserver.war
|
||||
|
||||
FROM tomcat as install
|
||||
|
||||
|
|
@ -118,11 +121,35 @@ COPY $ADDITIONAL_FONTS_PATH /usr/share/fonts/truetype/
|
|||
RUN rm -rf /tmp/*
|
||||
|
||||
# Add default configs
|
||||
ADD config $CONFIG_DIR
|
||||
COPY config $CONFIG_DIR
|
||||
|
||||
# Apply CIS Apache tomcat recommendations regarding server information
|
||||
# * Alter the advertised server.info String (2.1 - 2.3)
|
||||
RUN cd $CATALINA_HOME/lib \
|
||||
&& jar xf catalina.jar org/apache/catalina/util/ServerInfo.properties \
|
||||
&& sed -i 's/Apache Tomcat\/'"${TOMCAT_VERSION}"'/i_am_a_teapot/g' org/apache/catalina/util/ServerInfo.properties \
|
||||
&& sed -i 's/'"${TOMCAT_VERSION}"'/x.y.z/g' org/apache/catalina/util/ServerInfo.properties \
|
||||
&& sed -i 's/^server.built=.*/server.built=/g' org/apache/catalina/util/ServerInfo.properties \
|
||||
&& jar uf catalina.jar org/apache/catalina/util/ServerInfo.properties \
|
||||
&& rm -rf org/apache/catalina/util/ServerInfo.properties
|
||||
|
||||
# copy scripts
|
||||
COPY *.sh /opt/
|
||||
RUN chmod +x /opt/*.sh
|
||||
|
||||
# CIS Docker benchmark: Remove setuid and setgid permissions in the images to prevent privilege escalation attacks within containers.
|
||||
RUN find / -perm /6000 -type f -exec chmod a-s {} \; || true
|
||||
|
||||
# GeoServer user => restrict access to $CATALINA_HOME and GeoServer directories
|
||||
# See also CIS Docker benchmark and docker best practices
|
||||
RUN chmod +x /opt/*.sh \
|
||||
&& groupadd geoserver \
|
||||
&& useradd --no-log-init -u 2000 -r -g geoserver geoserver \
|
||||
&& chown -R geoserver:geoserver $CATALINA_HOME \
|
||||
&& chmod g-w,o-rwx $CATALINA_HOME \
|
||||
&& chown -R geoserver:geoserver $GEOSERVER_DATA_DIR \
|
||||
&& chown -R geoserver:geoserver $GEOSERVER_LIB_DIR
|
||||
|
||||
USER geoserver
|
||||
|
||||
ENTRYPOINT ["/opt/startup.sh"]
|
||||
|
||||
|
|
|
|||
20
README.md
20
README.md
|
|
@ -144,8 +144,23 @@ To enable a PostgreSQL JNDI resource, provide the following environment variable
|
|||
|
||||
In geoserver, you can then reference this JNDI resource using the name `java:comp/env/jdbc/postgres` (if using default).
|
||||
|
||||
For advanced customization of the connection pool, you can provide your own customized "context.xml"
|
||||
file to Apache Tomcat by mounting it to the container at ``/opt/config_overrides/context.xml``.
|
||||
## How to use custom (tomcat) configuration files
|
||||
|
||||
This image provides default (tomcat) configurations that are located in the `./config/` subdir.
|
||||
|
||||
* `context.xml` (see/compare JNDI feature from above)
|
||||
* `server.xml` (security hardened version by default)
|
||||
|
||||
In case you want to fully overwrite such a config file, you can do so by mounting it to the `/opt/config_overrides/` directory of a container.
|
||||
The `startup.sh` script will then copy (and overwrite) these files to the catalina conf directory before starting tomcat.
|
||||
|
||||
Example:
|
||||
|
||||
```shell
|
||||
docker run -it -p 80:8080 \
|
||||
--mount src="/path/to/my/server.xml",target=/opt/config_overrides/server.xml,type=bind \
|
||||
docker.osgeo.org/geoserver:2.24.1
|
||||
```
|
||||
|
||||
## How to use the docker-compose demo?
|
||||
|
||||
|
|
@ -192,7 +207,6 @@ The following values cannot really be safely changed (as they are used to downlo
|
|||
| GEOSERVER_VERSION | Geoserver version (used internally) | `2.24-SNAPSHOT`|
|
||||
| GEOSERVER_BUILD | Geosever build (used internally) | `1628` |
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### How to watch geoserver.log from host?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,187 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!-- Note: A "Server" is not itself a "Container", so you may not
|
||||
define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/server.html
|
||||
-->
|
||||
<Server port="8005" shutdown="SHUTDOWN">
|
||||
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
|
||||
<!-- Security listener. Documentation at /docs/config/listeners.html
|
||||
<Listener className="org.apache.catalina.security.SecurityListener" />
|
||||
-->
|
||||
<!-- APR library loader. Documentation at /docs/apr.html -->
|
||||
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
|
||||
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
|
||||
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
|
||||
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
|
||||
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
|
||||
|
||||
<!-- Global JNDI resources
|
||||
Documentation at /docs/jndi-resources-howto.html
|
||||
-->
|
||||
<GlobalNamingResources>
|
||||
<!-- Editable user database that can also be used by
|
||||
UserDatabaseRealm to authenticate users
|
||||
-->
|
||||
<Resource name="UserDatabase" auth="Container"
|
||||
type="org.apache.catalina.UserDatabase"
|
||||
description="User database that can be updated and saved"
|
||||
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
|
||||
pathname="conf/tomcat-users.xml" />
|
||||
</GlobalNamingResources>
|
||||
|
||||
<!-- A "Service" is a collection of one or more "Connectors" that share
|
||||
a single "Container" Note: A "Service" is not itself a "Container",
|
||||
so you may not define subcomponents such as "Valves" at this level.
|
||||
Documentation at /docs/config/service.html
|
||||
-->
|
||||
<Service name="Catalina">
|
||||
|
||||
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
|
||||
<!--
|
||||
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
|
||||
maxThreads="150" minSpareThreads="4"/>
|
||||
-->
|
||||
|
||||
|
||||
<!-- A "Connector" represents an endpoint by which requests are received
|
||||
and responses are returned. Documentation at :
|
||||
Java HTTP Connector: /docs/config/http.html
|
||||
Java AJP Connector: /docs/config/ajp.html
|
||||
APR (HTTP/AJP) Connector: /docs/apr.html
|
||||
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
|
||||
-->
|
||||
<!--
|
||||
# 2.6 Turn off TRACE
|
||||
-->
|
||||
<Connector
|
||||
port="8080"
|
||||
protocol="HTTP/1.1"
|
||||
connectionTimeout="20000"
|
||||
redirectPort="8443"
|
||||
maxParameterCount="1000"
|
||||
allowTrace="false"
|
||||
xpoweredBy="false"
|
||||
/>
|
||||
<!-- A "Connector" using the shared thread pool-->
|
||||
<!--
|
||||
<Connector executor="tomcatThreadPool"
|
||||
port="8080" protocol="HTTP/1.1"
|
||||
connectionTimeout="20000"
|
||||
redirectPort="8443"
|
||||
maxParameterCount="1000"
|
||||
/>
|
||||
-->
|
||||
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
|
||||
This connector uses the NIO implementation. The default
|
||||
SSLImplementation will depend on the presence of the APR/native
|
||||
library and the useOpenSSL attribute of the AprLifecycleListener.
|
||||
Either JSSE or OpenSSL style configuration may be used regardless of
|
||||
the SSLImplementation selected. JSSE style configuration is used below.
|
||||
-->
|
||||
<!--
|
||||
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
|
||||
maxThreads="150" SSLEnabled="true"
|
||||
maxParameterCount="1000"
|
||||
>
|
||||
<SSLHostConfig>
|
||||
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
|
||||
type="RSA" />
|
||||
</SSLHostConfig>
|
||||
</Connector>
|
||||
-->
|
||||
<!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
|
||||
This connector uses the APR/native implementation which always uses
|
||||
OpenSSL for TLS.
|
||||
Either JSSE or OpenSSL style configuration may be used. OpenSSL style
|
||||
configuration is used below.
|
||||
-->
|
||||
<!--
|
||||
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
|
||||
maxThreads="150" SSLEnabled="true"
|
||||
maxParameterCount="1000"
|
||||
>
|
||||
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
|
||||
<SSLHostConfig>
|
||||
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
|
||||
certificateFile="conf/localhost-rsa-cert.pem"
|
||||
certificateChainFile="conf/localhost-rsa-chain.pem"
|
||||
type="RSA" />
|
||||
</SSLHostConfig>
|
||||
</Connector>
|
||||
-->
|
||||
|
||||
<!-- Define an AJP 1.3 Connector on port 8009 -->
|
||||
<!--
|
||||
<Connector protocol="AJP/1.3"
|
||||
address="::1"
|
||||
port="8009"
|
||||
redirectPort="8443"
|
||||
maxParameterCount="1000"
|
||||
/>
|
||||
-->
|
||||
|
||||
<!-- An Engine represents the entry point (within Catalina) that processes
|
||||
every request. The Engine implementation for Tomcat stand alone
|
||||
analyzes the HTTP headers included with the request, and passes them
|
||||
on to the appropriate Host (virtual host).
|
||||
Documentation at /docs/config/engine.html -->
|
||||
|
||||
<!-- You should set jvmRoute to support load-balancing via AJP ie :
|
||||
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
|
||||
-->
|
||||
<Engine name="Catalina" defaultHost="localhost">
|
||||
|
||||
<!--For clustering, please take a look at documentation at:
|
||||
/docs/cluster-howto.html (simple how to)
|
||||
/docs/config/cluster.html (reference documentation) -->
|
||||
<!--
|
||||
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
|
||||
-->
|
||||
|
||||
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
|
||||
via a brute-force attack -->
|
||||
<Realm className="org.apache.catalina.realm.LockOutRealm">
|
||||
<!-- This Realm uses the UserDatabase configured in the global JNDI
|
||||
resources under the key "UserDatabase". Any edits
|
||||
that are performed against this UserDatabase are immediately
|
||||
available for use by the Realm. -->
|
||||
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
|
||||
resourceName="UserDatabase"/>
|
||||
</Realm>
|
||||
|
||||
<Host name="localhost" appBase="webapps"
|
||||
unpackWARs="true" autoDeploy="true">
|
||||
|
||||
<!-- SingleSignOn valve, share authentication between web applications
|
||||
Documentation at: /docs/config/valve.html -->
|
||||
<!--
|
||||
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
|
||||
-->
|
||||
|
||||
<!-- Access log processes all example.
|
||||
Documentation at: /docs/config/valve.html
|
||||
Note: The pattern used is equivalent to using pattern="common" -->
|
||||
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
|
||||
prefix="localhost_access_log" suffix=".txt"
|
||||
pattern="%h %l %u %t "%r" %s %b" />
|
||||
|
||||
</Host>
|
||||
</Engine>
|
||||
</Service>
|
||||
</Server>
|
||||
39
startup.sh
39
startup.sh
|
|
@ -1,6 +1,20 @@
|
|||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
echo "Welcome to GeoServer $GEOSERVER_VERSION"
|
||||
|
||||
# function that can be used to copy a custom config file to the catalina conf dir
|
||||
function copy_custom_config() {
|
||||
CONFIG_FILE=$1
|
||||
# Use a custom "${CONFIG_FILE}" if the user mounted one into the container
|
||||
if [ -d "${CONFIG_OVERRIDES_DIR}" ] && [ -f "${CONFIG_OVERRIDES_DIR}/${CONFIG_FILE}" ]; then
|
||||
echo "Installing configuration override for ${CONFIG_FILE} with substituted environment variables"
|
||||
envsubst < "${CONFIG_OVERRIDES_DIR}"/"${CONFIG_FILE}" > "${CATALINA_HOME}/conf/${CONFIG_FILE}"
|
||||
else
|
||||
# Otherwise use the default
|
||||
echo "Installing default ${CONFIG_FILE} with substituted environment variables"
|
||||
envsubst < "${CONFIG_DIR}"/"${CONFIG_FILE}" > "${CATALINA_HOME}/conf/${CONFIG_FILE}"
|
||||
fi
|
||||
}
|
||||
|
||||
## Skip demo data
|
||||
if [ "${SKIP_DEMO_DATA}" = "true" ]; then
|
||||
unset GEOSERVER_REQUIRE_FILE
|
||||
|
|
@ -101,15 +115,20 @@ if [ "${POSTGRES_JNDI_ENABLED}" = "true" ]; then
|
|||
fi
|
||||
|
||||
# Use a custom "context.xml" if the user mounted one into the container
|
||||
if [ -d "${CONFIG_OVERRIDES_DIR}" ] && [ -f "${CONFIG_OVERRIDES_DIR}/context.xml" ]; then
|
||||
echo "Installing configuration override for context.xml with substituted environment variables"
|
||||
envsubst < "${CONFIG_OVERRIDES_DIR}"/context.xml > "${CATALINA_HOME}/conf/context.xml"
|
||||
else
|
||||
# Otherwise use the default
|
||||
echo "Installing default context.xml with substituted environment variables"
|
||||
envsubst < "${CONFIG_DIR}"/context.xml > "${CATALINA_HOME}/conf/context.xml"
|
||||
fi
|
||||
copy_custom_config context.xml
|
||||
fi
|
||||
|
||||
# Use a custom "server.xml" if the user mounted one into the container
|
||||
copy_custom_config server.xml
|
||||
|
||||
# start the tomcat
|
||||
exec $CATALINA_HOME/bin/catalina.sh run
|
||||
# CIS - Tomcat Benchmark recommendations:
|
||||
# * Turn off session facade recycling
|
||||
# * Set a nondeterministic Shutdown command value
|
||||
if [ ! "${ENABLE_DEFAULT_SHUTDOWN}" = "true" ]; then
|
||||
REPLACEMENT="$(echo $RANDOM | md5sum | head -c 10)"
|
||||
sed -i 's/SHUTDOWN/'"$REPLACEMENT"'/g' "$CATALINA_HOME/conf/server.xml"
|
||||
REPLACEMENT=
|
||||
fi
|
||||
|
||||
exec $CATALINA_HOME/bin/catalina.sh run -Dorg.apache.catalina.connector.RECYCLE_FACADES=true
|
||||
|
|
|
|||
Loading…
Reference in New Issue