Customize UDS Portal app tiles
What you’ll accomplish
Section titled “What you’ll accomplish”The UDS Portal is the landing page where users discover the applications they can access in a UDS environment. This guide covers the tile settings you configure for an application: its title, its icon, and which of its exposed endpoints appear.
Prerequisites
Section titled “Prerequisites”- UDS CLI installed
- Access to a Kubernetes cluster with UDS Core deployed, including the Identity & Authorization and Portal layers
- An application deployed with a
PackageCR that has anssosection and at least onenetwork.exposeentry
How the Portal builds tiles
Section titled “How the Portal builds tiles”The Portal builds its app list from Package CRs in the cluster, creating one tile per network.expose entry. A package must define an sso section or it produces no tiles, even when it exposes services.
The Portal has no access controls of its own. It reflects each application’s SSO authorization, so a user sees a tile only for an app they can access. That access is governed by the app’s Package CR through spec.sso[].groups.anyOf: list groups to restrict the app, or omit it to allow all authenticated users. You configure access on the SSO client, not in the Portal:
- Register and customize SSO clients - define an application’s SSO client.
- Enforce group-based access controls - restrict which Keycloak groups can access an app, which in turn controls its tile visibility.
The rest of this guide covers only the Portal-specific tile settings: title, icon, and endpoint visibility.
Annotation precedence
Section titled “Annotation precedence”The Portal resolves tile title, icon, and visibility from multiple annotation sources. When the same property is set at more than one level, the Portal uses the first value it finds in this order:
| Priority | Source | Scope | Example key |
|---|---|---|---|
| 1 (highest) | portal.uds.dev/* per-endpoint annotation | Single expose entry | portal.uds.dev/title |
| 2 | uds.dev/* per-endpoint annotation | Single expose entry | uds.dev/title |
| 3 | Zarf package metadata annotation | All endpoints in the package | dev.uds.title |
| 4 (lowest) | Auto-generated | All endpoints in the package | Formatted package name |
Per-endpoint annotations are set on spec.network.expose[].annotations in the Package CR. Zarf package metadata annotations are set on metadata.annotations in zarf.yaml.
This layering lets upstream package authors set sensible defaults with uds.dev/*, while bundle authors can override specific endpoints with portal.uds.dev/* when the chart exposes annotation values.
The following per-endpoint annotation keys are supported:
| Key | uds.dev/ variant | portal.uds.dev/ variant | Default |
|---|---|---|---|
| Title | uds.dev/title | portal.uds.dev/title | Formatted package name |
| Icon | uds.dev/icon | portal.uds.dev/icon | Default Portal logo |
| Visibility | uds.dev/visible | portal.uds.dev/visible | Visible (annotation absent) |
-
Set per-endpoint title and icon
Add
uds.dev/titleanduds.dev/iconto theannotationsmap on anexposeentry in thePackageCR. These annotations control how that specific endpoint appears as a tile in the Portal.chart/templates/uds-package.yaml spec:network:expose:- service: my-appselector:app.kubernetes.io/name: my-appgateway: adminhost: my-appport: 80annotations:uds.dev/title: "My Application"uds.dev/icon: "data:image/svg+xml;base64,<base64-encoded-svg>"If neither per-endpoint title annotation is set, the title falls back to the Zarf package
dev.uds.titleannotation, then to a formatted version of the package name (for example,uds-registrybecomesUDS Registry). If no icon annotation is set, the Portal shows a default logo. -
(Optional) Hide specific exposed endpoints
To hide an endpoint from the Portal, set
uds.dev/visibleto"false"on the expose entry. Expose entries without this annotation are visible by default.chart/templates/uds-package.yaml spec:network:expose:- service: my-app-internalselector:app.kubernetes.io/name: my-appgateway: tenanthost: my-app-internalport: 8080annotations:uds.dev/visible: "false"Expose entries with a wildcard
host(for example,*.pages) are always excluded automatically. -
(Optional) Set package-level title and icon
To set a default title and icon for all endpoints in a package, add
dev.uds.titleanddev.uds.iconto the Zarf packagemetadata.annotationsinzarf.yaml. Per-endpoint annotations on thePackageCR override these values.zarf.yaml kind: ZarfPackageConfigmetadata:name: my-appannotations:dev.uds.title: My Applicationdev.uds.icon: "data:image/svg+xml;base64,<base64-encoded-svg>" -
(Optional) Override upstream defaults at the bundle level
Bundle authors can override upstream package annotations by using the
portal.uds.dev/*namespace on thePackageCR. These annotations take highest precedence.This requires the upstream chart to expose a Helm value for additional expose annotations so the bundle can inject overrides via Zarf variables. For example, if the chart templates its annotations like this:
chart/templates/uds-package.yaml annotations:uds.dev/title: "Upstream Title"{{- with .Values.exposeAnnotations }}{{- toYaml . | nindent 10 }}{{- end }}A bundle could then set
portal.uds.dev/titlethrough a Zarf variable targetingexposeAnnotations, and it would take precedence overuds.dev/title. -
Deploy your application
Include the updated
zarf.yamlandPackageCR in your Zarf package, then create and deploy it. See Packaging applications for general packaging guidance.Terminal window uds zarf package create --confirmuds zarf package deploy zarf-package-*.tar.zst --confirm
Verification
Section titled “Verification”Log in to the Portal at https://portal.<your-domain> (for example, https://portal.uds.dev) and confirm the tile appears with the expected title and icon, and that any hidden endpoints are absent.
Troubleshooting
Section titled “Troubleshooting”Problem: Title or icon does not update
Section titled “Problem: Title or icon does not update”Symptom: The tile shows the default title or logo despite setting annotations.
Solution: Check that annotations are on the correct resource at the correct level. Per-endpoint annotations (uds.dev/title, uds.dev/icon) go on spec.network.expose[].annotations in the Package CR. Package-level annotations (dev.uds.title, dev.uds.icon) go on metadata.annotations in zarf.yaml. Mixing these up has no effect. For Zarf-level changes, repackage and redeploy.
Problem: App tile does not appear
Section titled “Problem: App tile does not appear”Symptom: Your application is deployed and exposed, but no tile shows up.
Solution: Confirm the Package CR has an sso section; a package without one produces no tiles. If the app restricts access with groups.anyOf, a missing tile is expected for users outside the allowed groups. See Enforce group-based access controls.
Problem: Hidden endpoint still shows
Section titled “Problem: Hidden endpoint still shows”Symptom: An endpoint with uds.dev/visible: "false" still appears as a tile.
Solution: Verify that "false" is quoted as a string in the YAML. An unquoted false is parsed as a boolean, not a string, and may not be recognized. Also confirm the annotation is on the correct expose entry, not on the Package CR metadata.annotations.
Related documentation
Section titled “Related documentation”PackageCR reference - all availablespec.ssoandnetwork.exposefields- Package metadata - Zarf package metadata annotations (
dev.uds.title,dev.uds.icon, and others) - Enforce group-based access controls - restrict which Keycloak groups can access an app, which in turn controls its tile visibility
- Register and customize SSO clients - configure SSO clients and Keycloak groups
- Functional Layers - how the Portal layer fits into UDS Core and which flavors include it
- UDS Portal repository - source and additional configuration details