This project represents my personal deployment of the Shibboleth v5 Identity Provider software using the Docker container technology.
If you find something useful here you're welcome to take advantage of it. However, there's no guarantee that anything here actually works and I can't really offer support. If you're starting out with the Shibboleth IdP and are looking for a container deployment, I'd recommend looking at Internet2's TIER "Standalone" Shibboleth-IdP instead. Far more people are using that these days, so you will find it easier to get assistance.
This Docker build is normally based on Amazon Corretto, an OpenJDK distribution with long term support. This is produced by Amazon and used for many of their own production services.
Right now, i'm using the Alpine variant of Java 21, the most recent version with long-term support.
If you want to replace this with another Java distribution, change the definition
of JAVA_VERSION in VERSIONS. Note that the Dockerfile assumes that an Alpine
Linux variant of the base container is available and can be referenced by adding
-alpine to the base image's version. If that's not the case, you will need to
tweak the Dockerfile accordingly.
Any JDK from Java 17 onwards will probably work, see the system requirements for the IdP.
You should execute the ./fetch-jetty script to pull down a copy of the Jetty distribution
into jetty-dist/dist. The variables JETTY_VERSION and JETTY_DATE in the VERSIONS file
control the version acquired.
Some minimal validation is performed of the downloaded file using a locally compiled collection
of PGP keys referenced in the Jetty project's KEYS.txt file.
Prior to 2020-02-04, the Jetty configuration used was part of the IdP installation mounted into the running container. The actual configuration used was derived from the Jetty base used by the Shibboleth project's Windows installer, and then locally edited. One advantage of this setup was that the keystore passwords were not made part of the container image. One disadvantage is that the installer mechanisms used to do this were not part of the supported API.
In the current iteration, the Jetty configuration has been moved inside the container image.
As part of the build, the appropriate jetty-base-xxx directory in this repository is copied to /opt/jetty-base
in the image. This is still derived from the same source, but no longer depends on undocumented
features of the Shibboleth installer and comes pre-customised for the container environment.
Additionally, it lives outside the /opt/shibboleth-idp directory, which gives a cleaner
separation between Jetty and the IdP.
This default configuration uses default keystore passwords as follows.
In jetty-base-xxx/start.d/idp.ini:
## Keystore password
jetty.sslContext.keyStorePassword=changeit
## Truststore password
jetty.sslContext.trustStorePassword=changeit
## KeyManager password
jetty.sslContext.keyManagerPassword=changeit
In jetty-base-xxx/start.d/idp-backchannel.ini:
## Backchannel keystore password
# idp.backchannel.keyStorePassword=changeit
Arguably, there's little point in changing these values in the obvious way, as whatever you do will end up on disk and additionally in a container image. I do want to use Docker secrets, or Vault, or some other secrets management system to acquire and inject secrets like this. Until I get round to that, though, I'd be delighted to get a pull request in this area.
If you do want to change these or other values, or make any other local customisations to the
Jetty configuration, you can of course just make a private branch of this repository and change
the files in jetty-base-xxx directly. I have also provided an overlay system to make this a
bit cleaner.
If you create, for example, overlay/jetty-base-12.1/start.d/idp.ini, then that file will overwrite
the one taken from jetty-base-12.1. Anything under overlay is ignored by Git so it can be a local
repository unconnected with this one. I have also made it possible for overlay/jetty-base-12.1 to be
a symbolic link so that it can link to somewhere inside another local repository.
See overlay/README.md for more detail on the overlay system.
Execute the ./build script to build a new container image. This new image will be
tagged as shibboleth-idp and incorporate the Jetty distribution fetched earlier,
the jetty-base from this repository and any overlay/jetty-base you have created.
It will not include
the contents of shibboleth-idp; instead, they will be mounted into the container at /opt/shibboleth-idp when
a container is run from the image.
One important result of this approach is that the container image does not incorporate any secrets that are part of the Shibboleth configuration, such as passwords. On the other hand, the container image doesn't really contain much of the IdP, just a tailored environment for it.
Note: If a new version of Jetty is released and you wish to incorporate it, simply change the
version components in VERSIONS, and then execute ./fetch-jetty to acquire the new version.
Then, either use ./build and terminate and re-create your container manually, or use ./new-jetty to
perform those steps. You don't need to reinstall Shibboleth for this, as it's
not part of the image.
You should execute the ./fetch-shib script to pull down a copy of the Shibboleth IdP distribution
into fetched/shibboleth-dist. A variable at the top of the script controls the version acquired.
Some minimal validation is performed of the downloaded file using a file of PGP keys published by the Shibboleth project and included here to avoid taking a complete "leap of faith" approach.
Before attempting the next step, you should edit the install-idp script to change the critical
parameters at the top:
TSPASSandSEALERPASSare passwords to use if the trust fabric credentials or data sealer keystores, respectively, need to be generated. It's arguable whether changing the defaultchangeitvalues really adds any security given that the values are just put in the clear in property files anyway. I recommend leaving the values at their defaults.SCOPEshould be your organizational scope.HOSTis built fromSCOPEby prependingidp2., which probably won't suit you.ENTITYIDis built fromHOST. The default here is the same as the interactive install would suggest.
Executing the ./install script will now run the Shibboleth install process in a container based on the
configured Docker Java image. If you do not have a shibboleth-idp directory, this will act like a first-time
install using the parameters you set before, resulting in a basic installation in that directory.
If shibboleth-idp already exists, ./install will act to upgrade it to the latest distribution. This should
be idempotent; you should be able to just run ./install at any time without changing the results. In this
case, the variables set at the top of the install script won't have any effect as the appropriate values
are already frozen into the configuration.
A rudimentary mechanism is provided to allow configuration of the scripts provided to interact with the Docker
container. Each relevant script defers configuration to script-functions, which sets defaults and then in turn
invokes CONFIG (if present) to override those defaults. An example CONFIG file is provided as
CONFIG.example.
By default, the container's port 443 is bound to the Docker host's same-numbered port on all
available interfaces. This is probably the right choice for most people. If you need to override this, you
can set IPADDR to a specific IP address in the CONFIG file.
Setting IPADDR=127.0.0.1, for example, might be useful to allow access to the IdP from only the
Docker host itself during testing. Another use for IPADDR would be to single out a specific host
interface on a multi-homed host.
An IdP deployment uses a number of cryptographic credentials. We've already talked about some of these, but for clarity here's a summary of each along with details to allow you to get started.
The browser-facing credential, often referred to as the user-facing or front channel credential, is used in the form of a TLS certificate presented to the user's browser.
In this deployment, the browser-facing credential is entirely the concern of
the Jetty configuration, which assumes that a PKCS#12 keystore exists at
.../credentials/idp-userfacing.p12.
As described earlier, jetty-base-xxx/start.d/idp.ini assumes a default
password of changeit for this keystore, and I don't recommend changing this.
The idp-userfacing.p12 keystore is not created by the process described
above, and the container will fail to start up properly until one is provided.
There are several ways to create this credential:
-
If you're just testing, or if you're not planning to use front-channel TLS access because your IdP is behind a reverse proxy of some kind, you can generate a dummy keystore using the
./gen-selfsigned-certscript. You may need to edit the script to generate a certificate with appropriate subject fields. The password you provide at the end of the./gen-selfsigned-certprocess must match the one injetty-base-xxx/start.d/idp.ini. -
If you already have a commercial or in-house-issued credential for the IdP's domain name, you can convert that to a
.p12file using the instructions at the end of this document and use that. -
You can use something like certbot with Let's Encrypt to create and maintain a valid short-lived certificate. The scripts
docker-certbot-initialanddocker-certbot-renewdo this, but I no longer use them in my configuration.If you want to try these:
- Edit both files to use your domain name, not mine.
- Create the three directories under
/srvthat they expect (seescript-functionsfor defaults, or override them in aCONFIGfile). - Run
./docker-certbot-initialto create the initial certificate. - Every few days, run
./docker-certbot-renewto acquire a new certificate and swap it into place if necessary.
Start a randomly named container from the image using the ./test script. This is set up to be an interactive
container; you will see a couple of lines of logging and then it will appear to pause. Use ^C to stop the
container; it will be automatically removed when you do so.
All state, such as logs, will appear at appropriate locations in the shibboleth-idp directory tree.
Also included are:
./runis a more conventional script to start a container calledshibboleth-idpfrom the image and run it in the background../stopstops theshibboleth-idpcontainer../terminatestops theshibboleth-idpcontainer and removes the container. This is useful if you want to build and run another container version../consolewill give you abashprompt inside the running container, with the current directory set to the IdP's home directory (/opt/shibboleth-idp)../cleanupcan be used at any time to remove orphaned containers and images, which Docker tends to create in abundance during development. Use./cleanup -nto "dry run" and see what it would remove. Docker has got a fair bit better at doing this itself over time, but you may still want to run this once in a while to clear out dead wood.docker-deploy-stackdeploys a container as part of a Docker "swarm mode" stack, defined instack.yml. This is what I currently use "in production". In this deployment, the container runs behind a Traefik reverse proxy which terminates the TLS connection and manages Let's Encrypt certificates.docker-remove-stackremoves the deployed stack.- For IdP V4.1 and later,
pluginandmodulerun thebin/plugin.shandbin/module.shcommands to manipulate IdP plugins and modules respectively. These commands require that the IdP is not already running, and run up an independent Docker container to perform their operations. - The
versionscript runs thebin/version.shcommand inside the container, and requires that the container is running.
You will often find that you have keys and certificates in a format other than the one you'd like. Here are some recipes I've found useful in this work.
If you have a pair of PEM files (normally a self-signed certificate and the corresponding private key) and need them in PKCS12 form for use with Jetty, you can try something like this:
$ openssl pkcs12 -export -out X.p12 -inkey X.key -in X.crt
You'll be prompted for the output password, and the input password if one is required.
If you have a certificate from a commercial CA, it will normally come with a bundle of intermediates which need to be presented by the server in addition to the end entity certificate. If you need to convert a private key, certificate and bundle to PKCS12 form for use with Jetty, try this:
$ openssl pkcs12 -export -out X.p12 -inkey X.key -in X.crt -certfile chain.pem
Again, you'll be prompted for any relevant passwords.
The entire package is Copyright (C) 2014–2025, Ian A. Young.
Licensed 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.