This document describes how the kommonitor/keycloak image is hardened at build time
and the controls an operator must apply at run time.
Scope: this repository controls the image and its build/publish pipeline. Host, network, orchestration and organizational requirements remain the operator's responsibility and are listed as pointers below.
| Control | Where |
|---|---|
Base images pinned to immutable @sha256 digests |
Dockerfile |
| Official, identifiable sources (quay.io/keycloak, Docker Hub library/maven) | Dockerfile |
Runs as non-root user 1000:0, files --chowned |
Dockerfile |
Health & metrics endpoints compiled in (/health/ready etc. on port 9000) |
Dockerfile |
| One service per container (Keycloak only) | Dockerfile |
--optimized start (no build/write at runtime) |
Dockerfile |
| OCI metadata labels (title/source/version/…) | Dockerfile + CI |
No secrets in image/build context; minimal context via .dockerignore |
.dockerignore |
| Vulnerability scanning (Trivy, SARIF → Security tab) | CI workflows |
| SBOM + build provenance attestations | CI workflows |
| Keyless image signing (cosign) | CI workflows |
| Actions pinned to commit SHAs; Dependabot for images/actions/deps | CI + dependabot.yml |
The image ships secure defaults but cannot enforce host-level isolation. Run the container with at least the following:
services:
keycloak:
image: kommonitor/keycloak:<version>-postgres
user: "1000:0"
read_only: true
tmpfs:
- /tmp
- /opt/keycloak/data
cap_drop: [ ALL ]
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: "2"
memory: 2g
pids: 2048
healthcheck:
test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/localhost/9000 && echo -e 'GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n' >&3 && grep -q '\"status\": \"UP\"' <&3"]
interval: 30s
timeout: 5s
retries: 5
# secrets/DB/TLS/hostname env as aboveThe above docker-compose snippet does not cover all aspects for running Keycloak for production. Also take into account the documentation on how to set up Keycloak for production: https://www.keycloak.org/server/configuration-production
As a starting point, you may use the production-ready template from our Docker repository: https://github.com/KomMonitor/docker/tree/master/prod/keycloak
Verify the signature before deploying:
cosign verify kommonitor/keycloak:<tag> \
--certificate-identity-regexp '^https://github.com/kommonitor/keycloak-extensions/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com- The Keycloak image is based on Red Hat UBI9-micro: minimal, with no package manager and no curl/wget
- It does include bash (the
kc.shentrypoint is a bash script) - A curl-based Dockerfile
HEALTHCHECKwon't work (no curl), but the bash/dev/tcpprobe above does. - Under an orchestrator, prefer a native HTTP readiness probe against
http://<host>:9000/health/ready. Keep port 9000 internal-only. - Keep container logs on stdout/stderr so the host collects them via the logging driver; never write logs to files inside the container.