Customize Keycloak login page branding
What you’ll accomplish
Section titled “What you’ll accomplish”You’ll replace the default Keycloak login page images (logo, background, footer, favicon) and Terms & Conditions content with custom versions using bundle overrides and Kubernetes ConfigMaps — no image rebuild required.
Prerequisites
Section titled “Prerequisites”- UDS Core deployed
- UDS CLI installed
- Custom image files (PNG format) for whichever assets you want to replace
Before you begin
Section titled “Before you begin”UDS Core supports two layers of branding customization:
| Approach | Use for | Requires image rebuild? |
|---|---|---|
| Bundle overrides + ConfigMap (this guide) | Logo, background, footer, favicon, Terms & Conditions text, show/hide registration form fields | No |
| Custom theme in uds-identity-config image | CSS, layout changes, adding or restructuring registration form fields, new theme pages | Yes |
This guide covers the bundle override approach. For CSS or structural theme changes, see Build and deploy a custom identity config image.
-
Prepare your image files
Create or obtain PNG files for whichever assets you want to replace. Supported asset names:
Key Description background.pngLogin page background image logo.pngOrganization logo displayed on the login form footer.pngFooter image favicon.pngBrowser tab icon You do not need to replace all four — include only the keys you are customizing.
-
Create a ConfigMap with your image assets
Generate a ConfigMap manifest using
uds zarf tools kubectl. Adjust the file paths and include only the images you want to override:Terminal window uds zarf tools kubectl create configmap keycloak-theme-overrides \--from-file=background.png=./background.png \--from-file=logo.png=./logo.png \--from-file=footer.png=./footer.png \--from-file=favicon.png=./favicon.png \-n keycloak --dry-run=client -o yaml > theme-image-cm.yaml -
Deploy the ConfigMap before deploying UDS Core
The ConfigMap must exist in the
keycloaknamespace before UDS Core/Keycloak is deployed or upgraded. The simplest way to package and deploy it is with a small Zarf package:zarf.yaml kind: ZarfPackageConfigmetadata:name: keycloak-theme-overridesversion: 0.1.0components:- name: keycloak-theme-overridesrequired: truemanifests:- name: configmapnamespace: keycloakfiles:- theme-image-cm.yamlBuild and deploy this package prior to deploying or upgrading UDS Core:
Terminal window uds zarf package create .uds zarf package deploy zarf-package-keycloak-theme-overrides-*.zst -
Add
themeCustomizationsto your bundle overrideIn your
uds-bundle.yaml, add thethemeCustomizationsoverride referencing your ConfigMap:uds-bundle.yaml packages:- name: corerepository: registry.defenseunicorns.com/public/coreref: x.x.x-upstreamoverrides:keycloak:keycloak:values:- path: themeCustomizationsvalue:resources:images:- name: background.pngconfigmap:name: keycloak-theme-overrides- name: logo.pngconfigmap:name: keycloak-theme-overrides- name: footer.pngconfigmap:name: keycloak-theme-overrides- name: favicon.pngconfigmap:name: keycloak-theme-overrides -
(Optional) Configure custom Terms & Conditions content
If you want to display a custom Terms & Conditions overlay, prepare your T&C content as a single-line HTML string. First, write your HTML:
terms.html <h4>By logging in you agree to the following:</h4><ul><li>Authorized use only</li><li>Activity may be monitored</li></ul>Convert to a single line (newlines replaced with
\n):Terminal window cat terms.html | sed ':a;N;$!ba;s/\n/\\n/g' > single-line.htmlCreate a ConfigMap from the single-line file:
Terminal window uds zarf tools kubectl create configmap keycloak-tc-overrides \--from-file=text=./single-line.html \-n keycloak --dry-run=client -o yaml > terms-cm.yaml(Recommended) Add
terms-cm.yamlto themanifestslist in thezarf.yamlfrom step 3 and rebuild the Zarf package:Terminal window uds zarf package create --confirmuds zarf package deploy zarf-package-*.tar.zst --confirmOr apply the ConfigMap directly for quick testing:
Terminal window uds zarf tools kubectl apply -f terms-cm.yamlAdd the
termsAndConditionskey to yourthemeCustomizationsoverride and enable T&C inrealmInitEnv:uds-bundle.yaml overrides:keycloak:keycloak:values:- path: realmInitEnvvalue:TERMS_AND_CONDITIONS_ENABLED: "true"- path: themeCustomizationsvalue:termsAndConditions:text:configmap:key: textname: keycloak-tc-overrides -
(Optional) Disable registration form fields
By default, the user registration form includes fields for Affiliation, Pay Grade, and Unit/Organization. To minimize the steps required to register, disable these fields:
uds-bundle.yaml overrides:keycloak:keycloak:values:- path: themeCustomizations.settingsvalue:enableRegistrationFields: falseWhen
enableRegistrationFieldsisfalse, the following fields are hidden from the registration form:- Affiliation
- Pay Grade
- Unit, Organization or Company Name
-
Create and deploy your bundle
Terminal window uds create <path-to-bundle-dir>uds deploy uds-bundle-<name>-<arch>-<version>.tar.zst
Verification
Section titled “Verification”Confirm branding changes are applied:
- Navigate to
sso.<domain>in a browser - Verify the login page shows your custom logo, background, and footer
- Attempt to log in — if T&C is enabled, confirm the overlay appears before access is granted
Iterate quickly during development:
You can update the ConfigMap in-place and cycle the Keycloak pod to preview changes without a full redeploy:
uds zarf tools kubectl apply -f theme-image-cm.yaml -n keycloakuds zarf tools kubectl rollout restart statefulset/keycloak -n keycloakTroubleshooting
Section titled “Troubleshooting”Problem: Custom images do not appear after deploy
Section titled “Problem: Custom images do not appear after deploy”Symptoms: Login page still shows default branding.
Solution: Confirm the ConfigMap exists in the keycloak namespace before UDS Core is deployed or upgraded. Check that the ConfigMap keys exactly match the name values in the themeCustomizations override:
uds zarf tools kubectl get configmap keycloak-theme-overrides -n keycloak -o yamlVerify each expected key (background.png, logo.png, etc.) is present in the output.
Problem: Terms & Conditions overlay does not appear
Section titled “Problem: Terms & Conditions overlay does not appear”Symptoms: Users are not prompted to accept T&C on login.
Solution: Confirm two things:
TERMS_AND_CONDITIONS_ENABLED: "true"is set inrealmInitEnv- The
termsAndConditions.text.configmapentry is present inthemeCustomizations
Problem: T&C content appears malformed
Section titled “Problem: T&C content appears malformed”Symptoms: HTML tags appear as raw text, or layout is broken.
Solution: Verify the T&C file is properly converted to a single-line HTML string — all newlines replaced with the literal \n sequence. Check the ConfigMap data key:
uds zarf tools kubectl get configmap keycloak-tc-overrides -n keycloak \ -o jsonpath='{.data.text}' | head -c 200The output should be a single line with no literal newlines.
Related Documentation
Section titled “Related Documentation”- uds-identity-config repository — source repository with theme assets and FreeMarker templates for deeper customization
Next steps
Section titled “Next steps”These guides and concepts may be useful to explore next: