Skip to content

Build Your Bundle

A UDS Bundle is a single deployable artifact that captures your environment’s configuration alongside all packages and images. You’ll create two files: a uds-bundle.yaml that defines what to deploy and how to configure it, and a uds-config.yaml that supplies runtime values (credentials, certificates, domain names).


UDS Core is published in multiple flavors that differ in the source registry for container images:

FlavorImage SourceUse Case
upstreamPublic registries (Docker Hub, GHCR)Default; utilizes common upstream container images
registry1IronBank / Registry OneDoD environments requiring hardened, Iron Bank-sourced images
unicornDefense Unicorns private registryFIPS-compliant hardened images; reserved for Defense Unicorns customers

Choose the flavor that matches your environment’s registry access and compliance requirements. The bundle ref encodes the flavor:

Bundle ref format
0.X.Y-upstream # upstream flavor
0.X.Y-registry1 # registry1 flavor
0.X.Y-unicorn # unicorn flavor

Start with a minimal uds-bundle.yaml. You’ll add overrides to this in the sections below.

uds-bundle.yaml
kind: UDSBundle
metadata:
name: my-uds-core
description: Production UDS Core deployment
version: 0.1.0
packages:
# Enables Zarf in your cluster
- name: init
repository: ghcr.io/zarf-dev/packages/init
ref: v0.73.0
- name: core
repository: ghcr.io/defenseunicorns/packages/uds/core
ref: 0.62.0-upstream

Unlike the local demo bundle, the production bundle does not include a uds-k3d package—your cluster already exists and is managed separately.


The example below uses access keys, which work with AWS S3, MinIO, and any S3-compatible provider. For Azure and GCP, the override structure differs — see the Loki cloud deployment guides for provider-specific examples.

uds-bundle.yaml
packages:
- name: core
overrides:
loki:
loki:
variables:
- name: LOKI_CHUNKS_BUCKET
description: "Object storage bucket for Loki chunks"
path: loki.storage.bucketNames.chunks
- name: LOKI_ADMIN_BUCKET
description: "Object storage bucket for Loki admin"
path: loki.storage.bucketNames.admin
- name: LOKI_S3_REGION
description: "Object storage region"
path: loki.storage.s3.region
- name: LOKI_ACCESS_KEY_ID
description: "Object storage access key ID"
path: loki.storage.s3.accessKeyId
sensitive: true
- name: LOKI_SECRET_ACCESS_KEY
description: "Object storage secret access key"
path: loki.storage.s3.secretAccessKey
sensitive: true
values:
- path: loki.storage.type
value: "s3"
- path: loki.storage.s3.endpoint
value: "" # leave empty for AWS; set for MinIO or other S3-compatible providers
uds-config.yaml
variables:
core:
loki_chunks_bucket: "your-loki-chunks-bucket"
loki_admin_bucket: "your-loki-admin-bucket"
loki_s3_region: "us-east-1"
loki_access_key_id: "your-access-key-id"
loki_secret_access_key: "your-secret-access-key"

The example below uses AWS S3. For other providers (Azure, GCP), the override structure and credentials format will differ — see Velero’s supported providers for provider-specific configuration.

uds-bundle.yaml
packages:
- name: core
overrides:
velero:
velero:
variables:
- name: VELERO_CLOUD_CREDENTIALS
description: "Velero cloud credentials file content"
path: credentials.secretContents.cloud
sensitive: true
values:
- path: "configuration.backupStorageLocation"
value:
- name: default
provider: aws
bucket: "<your-velero-bucket>"
config:
region: "<your-region>"
s3ForcePathStyle: true
s3Url: "<your-s3-endpoint>"
credential:
name: "velero-bucket-credentials"
key: "cloud"
uds-config.yaml
variables:
core:
velero_cloud_credentials: |
[default]
aws_access_key_id=your-access-key-id
aws_secret_access_key=your-secret-access-key

Expose the TLS certificate and key for each gateway as bundle variables so they can be supplied at deploy time without hardcoding them in the bundle.

uds-bundle.yaml
packages:
- name: core
overrides:
istio-admin-gateway:
uds-istio-config:
variables:
- name: ADMIN_TLS_CERT
description: "Base64-encoded TLS cert chain for admin gateway"
path: tls.cert
- name: ADMIN_TLS_KEY
description: "Base64-encoded TLS key for admin gateway"
path: tls.key
sensitive: true
istio-tenant-gateway:
uds-istio-config:
variables:
- name: TENANT_TLS_CERT
description: "Base64-encoded TLS cert chain for tenant gateway"
path: tls.cert
- name: TENANT_TLS_KEY
description: "Base64-encoded TLS key for tenant gateway"
path: tls.key
sensitive: true
uds-config.yaml
variables:
core:
admin_tls_cert: "LS0t..." # base64-encoded full cert chain
admin_tls_key: "LS0t..." # base64-encoded private key
tenant_tls_cert: "LS0t..."
tenant_tls_key: "LS0t..."

Disable Keycloak’s embedded dev-mode database and connect it to your external database. The connection details are passed as variables.

uds-bundle.yaml
packages:
- name: core
overrides:
keycloak:
keycloak:
values:
- path: devMode
value: false
variables:
- name: KEYCLOAK_DB_HOST
path: postgresql.host
- name: KEYCLOAK_DB_USERNAME
path: postgresql.username
- name: KEYCLOAK_DB_DATABASE
path: postgresql.database
- name: KEYCLOAK_DB_PASSWORD
path: postgresql.password
sensitive: true
uds-config.yaml
variables:
core:
keycloak_db_host: "your-db-host" # hostname or IP of your database server
keycloak_db_username: "keycloak" # database user created in provision-services step
keycloak_db_database: "keycloak" # database name created in provision-services step
keycloak_db_password: "your-db-password" # password for the database user

Some UDS Core components are disabled by default and must be explicitly enabled:

Enable if your distribution does not include a metrics server (e.g., a bare RKE2 cluster without built-in metrics):

uds-bundle.yaml
packages:
- name: core
optionalComponents:
- metrics-server

With all overrides combined, here are the final files:

uds-bundle.yaml
kind: UDSBundle
metadata:
name: my-uds-core
description: Production UDS Core deployment
version: 0.1.0
packages:
- name: init
repository: ghcr.io/zarf-dev/packages/init
ref: v0.73.0
- name: core
repository: ghcr.io/defenseunicorns/packages/uds/core
ref: 0.62.0-upstream
overrides:
loki:
loki:
variables:
- name: LOKI_CHUNKS_BUCKET
description: "Object storage bucket for Loki chunks"
path: loki.storage.bucketNames.chunks
- name: LOKI_ADMIN_BUCKET
description: "Object storage bucket for Loki admin"
path: loki.storage.bucketNames.admin
- name: LOKI_S3_REGION
description: "Object storage region"
path: loki.storage.s3.region
- name: LOKI_ACCESS_KEY_ID
description: "Object storage access key ID"
path: loki.storage.s3.accessKeyId
sensitive: true
- name: LOKI_SECRET_ACCESS_KEY
description: "Object storage secret access key"
path: loki.storage.s3.secretAccessKey
sensitive: true
values:
- path: loki.storage.type
value: "s3"
- path: loki.storage.s3.endpoint
value: ""
velero:
velero:
variables:
- name: VELERO_CLOUD_CREDENTIALS
description: "Velero cloud credentials file content"
path: credentials.secretContents.cloud
sensitive: true
values:
- path: "configuration.backupStorageLocation"
value:
- name: default
provider: aws
bucket: "<your-velero-bucket>"
config:
region: "<your-region>"
s3ForcePathStyle: true
s3Url: "<your-s3-endpoint>"
credential:
name: "velero-bucket-credentials"
key: "cloud"
istio-admin-gateway:
uds-istio-config:
variables:
- name: ADMIN_TLS_CERT
description: "Base64-encoded TLS cert chain for admin gateway"
path: tls.cert
- name: ADMIN_TLS_KEY
description: "Base64-encoded TLS key for admin gateway"
path: tls.key
sensitive: true
istio-tenant-gateway:
uds-istio-config:
variables:
- name: TENANT_TLS_CERT
description: "Base64-encoded TLS cert chain for tenant gateway"
path: tls.cert
- name: TENANT_TLS_KEY
description: "Base64-encoded TLS key for tenant gateway"
path: tls.key
sensitive: true
keycloak:
keycloak:
values:
- path: devMode
value: false
variables:
- name: KEYCLOAK_DB_HOST
path: postgresql.host
- name: KEYCLOAK_DB_USERNAME
path: postgresql.username
- name: KEYCLOAK_DB_DATABASE
path: postgresql.database
- name: KEYCLOAK_DB_PASSWORD
path: postgresql.password
sensitive: true
uds-config.yaml
shared:
domain: "yourdomain.com"
variables:
core:
# TLS (base64-encoded full cert chains)
admin_tls_cert: "LS0t..."
admin_tls_key: "LS0t..."
tenant_tls_cert: "LS0t..."
tenant_tls_key: "LS0t..."
# Loki object storage
loki_chunks_bucket: "your-loki-chunks-bucket"
loki_admin_bucket: "your-loki-admin-bucket"
loki_s3_region: "us-east-1"
loki_access_key_id: "your-access-key-id"
loki_secret_access_key: "your-secret-access-key"
# Velero backup storage
velero_cloud_credentials: |
[default]
aws_access_key_id=your-access-key-id
aws_secret_access_key=your-secret-access-key
# Keycloak database
keycloak_db_host: "your-db-host" # hostname or IP of your database server
keycloak_db_username: "keycloak" # database user created in provision-services step
keycloak_db_database: "keycloak" # database name created in provision-services step
keycloak_db_password: "your-db-password" # password for the database user

  1. Create the bundle

    Terminal window
    uds create --confirm

    This command pulls all referenced packages and their images, then packages them into a single archive. Depending on network speed and package sizes, this can take several minutes on first run.

    The output is a file named:

    Output
    uds-bundle-<name>-<arch>-<version>.tar.zst
  2. Inspect the bundle (optional)

    Terminal window
    uds inspect uds-bundle-my-uds-core-*.tar.zst

    This lists the packages included in the bundle and their versions, letting you confirm the contents before deploying.