Si
Application Infrastructure Azure

Shibboleth Identity Provider 5 on Ubuntu 24.04 LTS on Azure User Guide

| Product: Shibboleth Identity Provider 5 on Ubuntu 24.04 LTS on Azure

Overview

This guide covers the deployment and verification of Shibboleth Identity Provider 5.2.3 on Microsoft Azure using cloudimg's pre configured virtual machine image from the Azure Marketplace.

Shibboleth Identity Provider is the SAML 2.0 identity provider used across research and education federations worldwide, and widely in the public sector. It authenticates your users against your own directory and issues signed SAML assertions to the services they sign in to, so a single sign in works across every service you federate with. It is open source, published under the Apache License 2.0 by the Shibboleth Consortium.

Shibboleth is a registered trademark of Internet2. cloudimg is not affiliated with, endorsed by, or sponsored by Internet2 or the Shibboleth Consortium. The name is used here only to identify the software this image runs.

Every secret on this image is generated on your own virtual machine, at first boot. That matters more for an identity provider than for almost any other kind of software. An identity provider signs assertions with a private key, and any service that trusts your identity provider trusts that key. If the key were baked into the image, every customer who deployed it would hold the same one, and any of them could forge assertions for any other. So this image does not ship an installed identity provider at all. It ships the pinned upstream distribution, and your first boot runs Shibboleth's own installer, which mints this machine's signing key, encryption key, back channel keystore, sealer keystore and published metadata. Nothing under /opt/shibboleth-idp exists in the image before you launch it.

Signing and encryption keys, minted on this VM at first boot

What's included:

  • Shibboleth Identity Provider 5.2.3, released 18 June 2026, installed from the official distribution tarball with its SHA-256 pinned and verified at build time
  • Eclipse Jetty 12.1.13 as the servlet container, pinned and verified from Maven Central. Shibboleth 5.2's web application declares Jakarta Servlet 6.1, so it needs a Jakarta EE 11 container: Jetty 12.0 and Tomcat 10.1 are both too old
  • OpenJDK 21 LTS from Ubuntu main
  • nginx terminating TLS on port 443 with a certificate generated on your machine at first boot
  • OpenLDAP as a co located directory on the loopback interface, holding one test user so you can prove a sign in works within a minute of the machine booting
  • A self test service provider registered out of the box, and shibboleth-idp-roundtrip.py, which drives a complete SAML 2.0 sign in and checks the assertion that comes back
  • Ubuntu 24.04 LTS, fully patched at build time, with unattended security upgrades enabled

Exposed ports: 22 and 443, and nothing else. The directory listens on 127.0.0.1:389 and Jetty on 127.0.0.1:8080; neither is reachable from outside the machine. There is deliberately no port 80 listener.

Exposed ports and the per-VM details file

Before you deploy: choose your hostname

A SAML identity provider has an entity ID, and it is a permanent identifier. Every service provider you federate with records it, and the endpoints in your published metadata are built from your hostname. Changing it later means re keying and re registering with every service provider you have.

If you already know the DNS name this identity provider will answer on, set it before the first boot by passing cloud init user data when you create the VM:

#cloud-config
write_files:
  - path: /etc/cloudimg/shibboleth-idp.conf
    permissions: '0644'
    content: |
      IDP_HOSTNAME=idp.example.ac.uk
      IDP_SCOPE=example.ac.uk
      IDP_ENTITY_ID=https://idp.example.ac.uk/idp/shibboleth

If you do not, the first boot uses the machine's public IP address for all three, which is fine for evaluation. Step 6 shows how to move to a real hostname afterwards.

IDP_SCOPE is the domain your scoped attributes are suffixed with, for example eduPersonPrincipalName becomes alice@example.ac.uk. It is normally your organisation's domain.

Step 1: Deploy the Virtual Machine

Option A: Azure Portal

  1. Sign in to the Azure Portal and choose Create a resource
  2. Search for Shibboleth Identity Provider 5 on Ubuntu 24.04 LTS by cloudimg and select it
  3. Choose your subscription, resource group and region
  4. Choose a VM size. Standard_B2ms (2 vCPU, 8 GiB) is the recommended minimum; the Java heap is set to 1280 MB
  5. Set the administrator username to azureuser and upload your SSH public key
  6. Under Inbound port rules, allow SSH (22) and HTTPS (443)
  7. Review and create

Option B: Azure CLI

az vm create \
  --resource-group my-resource-group \
  --name my-shibboleth-idp \
  --image cloudimg:shibboleth-idp-ubuntu-24-04:default:latest \
  --size Standard_B2ms \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard \
  --custom-data cloud-init.yaml

# then open the two ports you need
az vm open-port --resource-group my-resource-group --name my-shibboleth-idp --port 443 --priority 900

Step 2: Wait for the first boot to finish

The first boot creates the directory, runs the Shibboleth installer, mints every key and generates your metadata. It takes about a minute. SSH in and confirm it completed:

ssh azureuser@<vm-ip>
sudo test -f /var/lib/cloudimg/shibboleth-idp-firstboot.done && echo "first boot complete"

Then check the services and the published metadata:

systemctl is-active slapd shibboleth-idp nginx
curl -sk -o /dev/null -w '%{http_code}\n' https://localhost/idp/shibboleth

Expected output:

active
active
active
200

Shibboleth IdP 5.2.3 - services and published metadata

The details generated for your machine are in a root only file:

sudo cat /root/shibboleth-idp-credentials.txt

It contains your entity ID, your metadata URL, the directory's administrator distinguished name and password, and the test user's username and password. Keep it on the machine; it is mode 0600 and owned by root.

Step 3: Prove a user can sign in

The image ships a self test service provider and a prover that drives a complete SAML 2.0 browser sign in against it. Run it:

sudo bash -c 'CLOUDIMG_IDP_PW="$(sed -n "s/^IDP_TEST_PASSWORD=//p" /root/shibboleth-idp-credentials.txt)" \
  python3 /usr/local/sbin/shibboleth-idp-roundtrip.py 127.0.0.1 shibtest'

Expected output:

  PASS  a login form was presented and submitted
  PASS  SAML status is Success urn:oasis:names:tc:SAML:2.0:status:Success
  PASS  an Assertion was issued
  PASS  the response is signed
  PASS  an AuthnStatement is present
  PASS  the Issuer is this IdP https://<your-host>/idp/shibboleth
  PASS  a NameID was issued
  PASS  the audience is the requesting SP https://selftest.cloudimg.local/sp
SHIBBOLETH_SAML_LOGIN_OK

A real sign-in: the signed SAML 2.0 assertion this IdP issued

The exit status alone is not the contract — check for the SHIBBOLETH_SAML_LOGIN_OK line. Shibboleth's own aacli exits zero even when it is refused, so this prover follows the same discipline it asks of you: read the output, not the status.

You can also sign in with a browser. Visit:

https://<vm-ip>/idp/profile/SAML2/Unsolicited/SSO?providerId=https://selftest.cloudimg.local/sp

Your browser will warn about the certificate, because the one generated at first boot is self signed — Step 6 covers replacing it. Accept the warning and sign in with the test username and password from the credentials file.

The sign-in page

The service you are signing in to is the built in self test service provider, which is why it is named on the page. After signing in, the identity provider posts a signed assertion to that service's assertion consumer URL, which is on the loopback interface and does not answer — so your browser will show a connection error. That is expected: the assertion was issued, and the prover above is what reads it.

Visit https://<vm-ip>/idp/profile/Logout to end the session. The page lists the services you accessed during it.

The sign-out page

Step 4: Give your metadata to a service provider

Your published metadata is what a service provider needs in order to trust you. It is served, unauthenticated, at:

https://<your-host>/idp/shibboleth
curl -sk https://localhost/idp/shibboleth | head -20

It carries your entity ID, your scope, your single sign on endpoints and the signing and encryption certificates minted on this machine.

Published SAML metadata

To register a service provider with your identity provider, add its metadata to conf/metadata-providers.xml. Save the service provider's metadata to a file and add a provider entry before the closing tag:

sudo tee /opt/shibboleth-idp/metadata/my-service.xml >/dev/null <<'EOF'
<!-- paste the service provider's EntityDescriptor here -->
EOF
sudo chown shibboleth:shibboleth /opt/shibboleth-idp/metadata/my-service.xml

Then edit /opt/shibboleth-idp/conf/metadata-providers.xml and add, immediately before the final </MetadataProvider>:

<MetadataProvider id="MyService" xsi:type="FilesystemMetadataProvider"
    metadataFile="/opt/shibboleth-idp/metadata/my-service.xml"/>

Reload the metadata service without restarting:

sudo -u shibboleth /opt/shibboleth-idp/bin/reload-service.sh \
  -u http://127.0.0.1:8080/idp -id shibboleth.MetadataResolverService

reload-service.sh defaults to http://localhost/idp — port 80, which this image does not listen on — so pass -u pointing at Jetty on the loopback interface. That also avoids the script having to trust the self signed certificate.

For a federation, use an HTTPMetadataProvider with a SignatureValidationFilter pointing at your federation's signing certificate instead — never trust remote metadata without validating its signature.

Remove the self test service provider

Once your own service providers are registered, remove the self test one. It exists only so the machine can prove itself on first boot:

sudo rm /opt/shibboleth-idp/metadata/cloudimg-selftest-sp.xml

Then delete the CloudimgSelfTestSP entries from conf/metadata-providers.xml and conf/relying-party.xml, and restart:

sudo systemctl restart shibboleth-idp

Step 5: Point the identity provider at your own directory

The image ships OpenLDAP on 127.0.0.1:389 with one test user, so the machine works out of the box. In production you will point it at your own directory instead.

Edit /opt/shibboleth-idp/conf/ldap.properties as the shibboleth user. Set your own server, base DN and bind account, and turn StartTLS back on — it is disabled here only because the shipped directory is on the loopback interface:

idp.authn.LDAP.authenticator = bindSearchAuthenticator
idp.authn.LDAP.ldapURL       = ldaps://ldap.example.ac.uk:636
idp.authn.LDAP.useStartTLS   = false
idp.authn.LDAP.baseDN        = ou=people,dc=example,dc=ac,dc=uk
idp.authn.LDAP.userFilter    = (uid={user})
idp.authn.LDAP.bindDN        = cn=shibboleth,ou=services,dc=example,dc=ac,dc=uk
idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt

The bind password goes in idp.authn.LDAP.bindDNCredential inside /opt/shibboleth-idp/credentials/secrets.properties, never in ldap.properties. Restart once both files are in place:

sudo systemctl restart shibboleth-idp

Once your own directory is in use, stop and disable the local one:

sudo systemctl disable --now slapd

Step 6: Production hardening

Replace the self signed TLS certificate

The certificate generated at first boot is self signed. Replace both files with your own, keeping the paths:

sudo install -m 0644 -o root -g root fullchain.pem /etc/cloudimg/tls/idp.crt
sudo install -m 0640 -o root -g www-data privkey.pem /etc/cloudimg/tls/idp.key
sudo nginx -t && sudo systemctl reload nginx

This certificate is for browsers only. It is deliberately unrelated to the identity provider's own signing and encryption keys, which are never used for TLS.

Move to a real hostname

If you deployed without setting a hostname and now want a real one, the entity ID and every endpoint in your metadata must change, so re run the installer. Do this before you register with any service provider — afterwards it means re registering with all of them.

sudo systemctl stop shibboleth-idp
sudo tee /etc/cloudimg/shibboleth-idp.conf >/dev/null <<'EOF'
IDP_HOSTNAME=idp.example.ac.uk
IDP_SCOPE=example.ac.uk
IDP_ENTITY_ID=https://idp.example.ac.uk/idp/shibboleth
EOF
sudo rm -f /var/lib/cloudimg/shibboleth-idp-firstboot.done
sudo /usr/local/sbin/shibboleth-idp-firstboot.sh
sudo systemctl start shibboleth-idp

This mints a completely new key set and new metadata. Anyone who already trusts the old keys must be given the new metadata.

Administrative endpoints

Shibboleth's administrative endpoints under /idp/profile/admin/ are gated only by an IP access control policy that trusts the loopback address. resolvertest discloses a user's resolved attributes and dumpconfig discloses configuration, so this image refuses them at nginx outright and sets X-Forwarded-For from the real client address rather than appending to whatever the caller sent. Without that, a remote caller could send X-Forwarded-For: 127.0.0.1 and be read as loopback.

To use them, run them on the machine itself against Jetty directly:

curl -s "http://127.0.0.1:8080/idp/profile/admin/resolvertest?requester=https://selftest.cloudimg.local/sp&principal=shibtest"

/idp/status remains reachable over HTTPS but the identity provider's own policy allows it only from the loopback address, so a remote request receives 403.

Branding the sign in pages

The sign in and sign out pages are plain by design: the upstream placeholder logo, footer text and dead help links are removed at first boot. Add your own in /opt/shibboleth-idp/messages/messages.properties:

idp.logo = /images/my-logo.png
idp.logo.alt-text = Example University
idp.footer = Contact the IT Service Desk on 0123 456 7890.
idp.url.password.reset = https://accounts.example.ac.uk/reset
idp.url.helpdesk = https://help.example.ac.uk/

Put the image in /opt/shibboleth-idp/edit-webapp/images/, then rebuild the web application and restart:

sudo -u shibboleth /opt/shibboleth-idp/bin/build.sh
sudo systemctl restart shibboleth-idp

Step 7: Monitoring and patching

/idp/status reports version, uptime and the enabled modules:

curl -sk https://localhost/idp/status | head -12

IdP status

nginx serves an unauthenticated health endpoint for load balancer probes:

curl -sk https://localhost/healthz

Logs are in /opt/shibboleth-idp/logs/: idp-process.log for the identity provider, idp-warn.log for warnings and errors, and idp-audit.log for one line per authentication.

Ubuntu security updates are applied automatically by unattended-upgrades. Apply everything and reboot on your own schedule:

sudo apt-get update && sudo apt-get -y dist-upgrade
sudo reboot

Shibboleth releases are separate from the operating system. Watch the Shibboleth announce list and upgrade with bin/update.sh from a newer distribution when one is published.

Troubleshooting

Sign in is refused for a user you know exists. Check idp-warn.log and confirm the user is under the configured base DN and that the bind account can search for them:

sudo tail -30 /opt/shibboleth-idp/logs/idp-warn.log
sudo ldapsearch -x -H ldap://127.0.0.1:389 -b "ou=people,dc=cloudimg,dc=local" "(uid=shibtest)" dn

A service provider rejects your assertion. Almost always the metadata it holds is stale, or your hostname changed after you gave it to them. Compare the certificate it has against the one you publish now:

curl -sk https://localhost/idp/shibboleth | grep -o 'entityID="[^"]*"'
sudo openssl x509 -in /opt/shibboleth-idp/credentials/idp-signing.crt -noout -fingerprint -sha256

The identity provider will not start after you rotated a key by hand. Rotating the sealer or the back channel keystore without updating credentials/secrets.properties fails at start up with a DataSealerKeyStrategy error rather than an obvious wrong password message. Re run the first boot script from Step 6 instead of rotating keys individually.

/idp/status returns 403 from your laptop. That is correct. The policy allows the loopback address only; run it on the machine.

Support

cloudimg provides 24/7 support for this image. Raise a ticket at www.cloudimg.co.uk with your Azure subscription ID and the output of:

sudo systemctl is-active slapd shibboleth-idp nginx
sudo tail -40 /opt/shibboleth-idp/logs/idp-warn.log

Support covers the image, its configuration and its deployment. Questions about SAML federation policy belong with your federation operator, and Shibboleth software questions with the Shibboleth community lists.

Licence

Shibboleth Identity Provider is published under the Apache License, Version 2.0. The licence text ships on the image, copied from the distribution at build time:

cat /usr/share/doc/shibboleth-idp/LICENSE.txt | head -3

Third party component licences from the distribution are alongside it in the same directory. Shibboleth is a registered trademark of Internet2; cloudimg is not affiliated with Internet2 or the Shibboleth Consortium, and this image does not use the Shibboleth logo.