Bootstrap a Connected Deployment
This procedure is idempotent. Replace every angle-bracket placeholder and use an explicit Kubernetes context so commands cannot land on the wrong cluster.
1. Verify prerequisites
export KUBE_CONTEXT=<customer-cluster-context>
export PRETORIN_NAMESPACE=pretorin
kubectl --context "${KUBE_CONTEXT}" version
flux version --client
flux --context "${KUBE_CONTEXT}" check --pre
helm version
pretorin version
Use the pinned Flux CLI v2.9.4. Install its bundled controllers once if the
cluster does not already satisfy the prerequisite:
flux --context "${KUBE_CONTEXT}" install
flux --context "${KUBE_CONTEXT}" check
flux check must pass before continuing.
2. Install read-only registry credentials
Log in using a temporary Docker configuration so unrelated credentials are not copied into the cluster. The password is read from stdin and is not placed on the command line.
export REGISTRY_HOST=<registry.example.com>
export REGISTRY_USER=<read-only-service-account>
read -rsp "Registry password: " REGISTRY_PASSWORD; echo
REGISTRY_CONFIG_DIR="$(mktemp -d)"
trap 'rm -rf "${REGISTRY_CONFIG_DIR}"' EXIT
printf '%s' "${REGISTRY_PASSWORD}" | \
docker --config "${REGISTRY_CONFIG_DIR}" login "${REGISTRY_HOST}" \
--username "${REGISTRY_USER}" --password-stdin
unset REGISTRY_PASSWORD
kubectl --context "${KUBE_CONTEXT}" create namespace flux-system \
--dry-run=client -o yaml | kubectl --context "${KUBE_CONTEXT}" apply -f -
kubectl --context "${KUBE_CONTEXT}" --namespace flux-system \
create secret generic pretorin-registry-credentials \
--type=kubernetes.io/dockerconfigjson \
--from-file=.dockerconfigjson="${REGISTRY_CONFIG_DIR}/config.json" \
--dry-run=client -o yaml | kubectl --context "${KUBE_CONTEXT}" apply -f -
Confirm only the Secret name and type—not its contents:
kubectl --context "${KUBE_CONTEXT}" --namespace flux-system \
get secret pretorin-registry-credentials \
-o custom-columns=NAME:.metadata.name,TYPE:.type
3. Create the persistent deployment identity
pretorin deployment identity ensure \
--context "${KUBE_CONTEXT}" --namespace "${PRETORIN_NAMESPACE}"
Back up pretorin-deployment-identity with the cluster’s encrypted backup
process. Never regenerate it during upgrades or disaster recovery.
Create the non-secret license request and send it through the approved Pretorin support channel:
pretorin deployment license request \
--context "${KUBE_CONTEXT}" --namespace "${PRETORIN_NAMESPACE}" \
--customer-id <contract-customer-id> \
--customer-name "<customer-name>" \
--max-systems <licensed-system-count> \
--duration-days <licensed-duration> \
--output license-request.json
4. Install core Secrets; the license may follow
Follow the standard bundle’s secret worksheet and run
scripts/customer/create-customer-secrets.sh. The helper preserves the existing
deployment identity and any license resources already installed.
If the license handoff is complete, provide these optional file inputs:
export PRETORIN_LICENSE_FILE="$PWD/license.jwt"
export PRETORIN_LICENSE_TRUST_BUNDLE_FILE="$PWD/license-trust.json"
export KUBECTL_CONTEXT="${KUBE_CONTEXT}"
export NAMESPACE="${PRETORIN_NAMESPACE}"
scripts/customer/create-customer-secrets.sh
If Pretorin is still processing license-request.json, omit
PRETORIN_LICENSE_FILE. The trust bundle may be installed independently, or
both license inputs may be omitted. Do not create a placeholder token. The Auth
and web workloads start normally, Auth reports the redacted missing state,
and the bootstrap owner can log in. License pending appears to owners and
administrators, and only new system creation is blocked.
After the signed files arrive, install or renew them independently:
pretorin deployment license install \
--context "${KUBE_CONTEXT}" --namespace "${PRETORIN_NAMESPACE}" \
--license-file ./license.jwt \
--trust-bundle ./license-trust.json
The command never prints the token, requests no Helm reconciliation, and does not restart a workload. The running Auth Pod observes the projected-file update.
The signed token contains the deployment-wide positive max_systems ceiling
and validity window. It does not meter users, framework packages, storage,
exports, or calls to the customer-managed LLM; those dimensions come from the
default Enterprise profile and remain unlimited. The application rereads the
projected token during entitlement checks, so a renewal takes effect without a
chart change or rollout.
5. Bootstrap verified reconciliation
Use the neutral values-customer.yaml from the standard chart package. Copy it
and replace registry, DNS, TLS, storage, identity, and AI-provider placeholders.
Do not put secret values or a license token in this file.
pretorin deployment flux bootstrap \
--context "${KUBE_CONTEXT}" --namespace "${PRETORIN_NAMESPACE}" \
--customer-values ./values-customer.install.yaml \
--chart-registry "${REGISTRY_HOST}/pretorin/charts" \
--release-repository "${REGISTRY_HOST}/pretorin/releases/pretorin" \
--release-public-key ./pretorin-release.pub \
--update-mode approval \
--channel stable
Use --dry-run first in change-controlled environments. It prints ConfigMaps,
public trust material, and controllers; it does not print Kubernetes Secrets or
the license token.
6. Verify
pretorin --json deployment flux status
kubectl --context "${KUBE_CONTEXT}" --namespace "${PRETORIN_NAMESPACE}" \
get pods,jobs,helmreleases
In approval mode, review the resolved release digest and then continue:
pretorin deployment flux resume --context "${KUBE_CONTEXT}"
After the public API is reachable, authenticate the CLI and verify license state:
pretorin config set platform_api_base_url https://<platform-host>/api/v1/public
pretorin --json deployment license status
In the web application, open Settings → Plan & Usage. Before delivery,
confirm the redacted state is missing and the owner/admin banner says
License pending. After installation, confirm:
- Current Plan is
Enterprise; - Deployment License is
validand shows the expected system maximum; - Members, Storage, AI Requests, and AI Tokens show
Unlimited; and - the available framework packages include Custom Frameworks.