Skip to content
Unified Defense StackUnified Defense Stack

Customize UDS Portal app tiles

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.

  • UDS CLI installed
  • Access to a Kubernetes cluster with UDS Core deployed, including the Identity & Authorization and Portal layers
  • An application deployed with a Package CR that has an sso section and at least one network.expose entry

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:

The rest of this guide covers only the Portal-specific tile settings: title, icon, and endpoint visibility.

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:

PrioritySourceScopeExample key
1 (highest)portal.uds.dev/* per-endpoint annotationSingle expose entryportal.uds.dev/title
2uds.dev/* per-endpoint annotationSingle expose entryuds.dev/title
3Zarf package metadata annotationAll endpoints in the packagedev.uds.title
4 (lowest)Auto-generatedAll endpoints in the packageFormatted 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:

Keyuds.dev/ variantportal.uds.dev/ variantDefault
Titleuds.dev/titleportal.uds.dev/titleFormatted package name
Iconuds.dev/iconportal.uds.dev/iconDefault Portal logo
Visibilityuds.dev/visibleportal.uds.dev/visibleVisible (annotation absent)
  1. Set per-endpoint title and icon

    Add uds.dev/title and uds.dev/icon to the annotations map on an expose entry in the Package CR. These annotations control how that specific endpoint appears as a tile in the Portal.

    chart/templates/uds-package.yaml
    spec:
    network:
    expose:
    - service: my-app
    selector:
    app.kubernetes.io/name: my-app
    gateway: admin
    host: my-app
    port: 80
    annotations:
    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.title annotation, then to a formatted version of the package name (for example, uds-registry becomes UDS Registry). If no icon annotation is set, the Portal shows a default logo.

  2. (Optional) Hide specific exposed endpoints

    To hide an endpoint from the Portal, set uds.dev/visible to "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-internal
    selector:
    app.kubernetes.io/name: my-app
    gateway: tenant
    host: my-app-internal
    port: 8080
    annotations:
    uds.dev/visible: "false"

    Expose entries with a wildcard host (for example, *.pages) are always excluded automatically.

  3. (Optional) Set package-level title and icon

    To set a default title and icon for all endpoints in a package, add dev.uds.title and dev.uds.icon to the Zarf package metadata.annotations in zarf.yaml. Per-endpoint annotations on the Package CR override these values.

    zarf.yaml
    kind: ZarfPackageConfig
    metadata:
    name: my-app
    annotations:
    dev.uds.title: My Application
    dev.uds.icon: "data:image/svg+xml;base64,<base64-encoded-svg>"
  4. (Optional) Override upstream defaults at the bundle level

    Bundle authors can override upstream package annotations by using the portal.uds.dev/* namespace on the Package CR. 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/title through a Zarf variable targeting exposeAnnotations, and it would take precedence over uds.dev/title.

  5. Deploy your application

    Include the updated zarf.yaml and Package CR in your Zarf package, then create and deploy it. See Packaging applications for general packaging guidance.

    Terminal window
    uds zarf package create --confirm
    uds zarf package deploy zarf-package-*.tar.zst --confirm

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.

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.

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.

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.