From cc918cbf3e4c5bc0805e232a0f79812b59998495 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 11:17:35 -0700 Subject: [PATCH 01/14] Document preflight checks in platform deployment guide Implements documentation for issue #1067: - Add "Run preflight checks" section covering the shipped Preflight CR - Cover CLI plugin install, running against real values, and all checks - Document advisory-by-default behavior and preflight.enforce=true - Note the RBAC and CRD-collision gaps preflight cannot verify --- .../enterprise-platform/deployment.mdx | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 09c22a96..8b444dce 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -82,6 +82,153 @@ examples, so substitute your own namespaces as you follow them. ::: +## Run preflight checks + +Before you authenticate and install, run the platform's **preflight** spec +against your target cluster. The umbrella chart ships a `Preflight` custom +resource as a labeled Secret, so rendering the chart and piping it to the +`kubectl-preflight` plugin analyzes real prerequisites automatically. It catches +the misconfigurations that cause the most opaque install failures, a Kubernetes +version below the chart floor, tight node capacity, an unreachable OIDC issuer, +a missing signing-key Secret, before they surface later as failed pods or a +stuck rollout. + +### Install the CLI plugin + +Install the pinned binary release directly from +[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases), +the same version Stacklok validates the spec against: + +```bash +PREFLIGHT_VERSION=v0.131.1 +os=$(uname -s | tr '[:upper:]' '[:lower:]') +arch=$(uname -m); [ "$arch" = "x86_64" ] && arch=amd64 +curl -fsSL -o preflight.tar.gz \ + "https://github.com/replicatedhq/troubleshoot/releases/download/${PREFLIGHT_VERSION}/preflight_${os}_${arch}.tar.gz" +tar -xzf preflight.tar.gz preflight +sudo install -m 0755 preflight /usr/local/bin/kubectl-preflight +``` + +:::note[Alternative: krew] + +`kubectl krew install preflight` is a quicker one-time setup, but krew always +resolves to whatever version its index currently serves. It has no version-pin +flag, so it can silently drift ahead of the version this spec was last validated +against. If you hit unexpected preflight behavior on a krew-installed CLI, +compare `kubectl preflight version` against the pinned version above. + +::: + +### Run it against your real values + +Use the `values.yaml` you build in [Step 3](#3-configure-values), not an empty +or minimal render. The opt-in analyzers (OIDC issuer, signing-key Secret, +registry database) only render when their corresponding values are set, so +preflighting against an empty file silently skips them, a `pass` result that +verified less than your real install will. + +```bash +helm template stacklok-enterprise \ + oci://oci.stacklok.com/stacklok-enterprise//stacklok-enterprise-platform \ + --version \ + --values values.yaml \ + | kubectl preflight - +``` + +`helm template` prompts for the same registry credentials as +[Step 1](#1-authenticate-to-the-replicated-registry): your license email as the +username and your **License ID** as the password. + +### What it checks + +| Check | Renders when | Outcome | +| ------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | +| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | +| Distribution | Always | `warn` on OpenShift OCP | +| Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | +| Registry database reachability | `registryServer.enabled` and a run-time `preflightDatabaseUri` is supplied | `fail` if unreachable | +| OIDC issuer reachability | `enterpriseManager.enabled=true` and `idpConfig.issuer` is set | `fail` if unreachable or misconfigured | +| Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `signingConfig.existingSecret` is missing | + +:::warning[Registry database credential] + +The registry database check needs a DB URI that includes a password. Supply it +as a one-off flag at preflight time, never in a permanent or GitOps-tracked +values file: + +```bash +helm template stacklok-enterprise \ + --set registryServer.enabled=true \ + --set 'toolhive-registry-server.preflightDatabaseUri=postgres://user:pass@host:5432/db?sslmode=require' \ + | kubectl preflight - +``` + +The preflight spec ships as a Kubernetes Secret. A persistently configured URI +leaves the database password in-cluster indefinitely, readable with +`kubectl get secret ... -o yaml`, rather than existing only for the duration of +one preflight run. + +::: + +### Preflight is advisory by default + +On the Helm CLI install path, `kubectl preflight` can't block `helm install`. A +`fail` result is a signal you act on yourself, not an automatic gate: don't +proceed to [Step 4](#4-install-the-chart) while any check reports `fail`. Fix +the underlying cluster condition first. + +### Optional: real enforcement with preflight.enforce + +Set `--set preflight.enforce=true` in your values to opt into an in-cluster +pre-install and pre-upgrade Helm hook Job that runs the same spec and genuinely +fails `helm install` or `helm upgrade` on a `fail` outcome, real blocking, not +advisory. + +This is off by default because it carries cost you should accept deliberately: + +- The Job needs `global.replicated.dockerconfigjson` set. It pulls a + license-gated `preflight-runner` image before the Replicated SDK provisions + the ordinary pull secret; without it, the Job's pod can't pull its image and + the install hangs. +- The Job runs under its own ServiceAccount with cluster-scoped read RBAC + (nodes, namespaces, storage classes, CRDs), plus a namespaced read on the + signing-key Secret when `enterpriseManager.enabled` is set. + +If enforcement blocks an install, read the Job's log to see why: + +```bash +kubectl logs job/stacklok-enterprise-preflight-check -n stacklok-system +``` + +To bypass a known false positive for one run, re-run the same `helm` command +with `--set preflight.enforce=false`. + +### What preflight can't check + +Two prerequisites need manual verification; troubleshoot.sh has no analyzer for +either: + +- **Installer RBAC rights.** No `SelfSubjectAccessReview`-style analyzer exists. + Verify against the same kubeconfig context you install with: + + ```bash + kubectl auth can-i create customresourcedefinitions.apiextensions.k8s.io + kubectl auth can-i create clusterroles.rbac.authorization.k8s.io + kubectl auth can-i create clusterrolebindings.rbac.authorization.k8s.io + kubectl auth can-i '*' '*' -n stacklok-system + ``` + + Each must print `yes`. If any prints `no`, `helm install` fails partway + through with a CRD, RBAC, or namespaced-resource creation error instead of + upfront. + +- **CRD collisions with a prior install.** No CRD analyzer ships, since + troubleshoot's `customResourceDefinition` analyzer can only express present as + pass or absent as fail, not "already present is a problem." If you're + reinstalling over a previous release, check + `kubectl get crd | grep toolhive.stacklok.dev` for version conflicts by hand. + ## Deploy with Helm ### 1. Authenticate to the Replicated registry From ad366b7845ec2ba288a1852669edf2ab05010190 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 11:17:46 -0700 Subject: [PATCH 02/14] Document preflight checks for air-gapped installs Implements documentation for issue #1067: - Add a subsection under "Step 5: Install and verify" showing that the default preflight spec runs entirely offline - Show templating the locally transferred chart instead of oci:// - Note mirroring the CLI plugin release asset for the transfer workstation --- .../enterprise-platform/airgap-install.mdx | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index e565c820..cdf3a447 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -501,6 +501,26 @@ Verify the platform comes up the same way as in the [standard deployment](./deployment.mdx#5-verify-the-install): confirm every pod in `stacklok-system` reaches `Running` and the ToolHive CRDs registered. +### Run preflight checks against the mirrored chart + +The default preflight spec runs entirely offline, no cluster egress, so it works +unchanged in an air-gapped install. Template the chart directory you +transferred, rather than an `oci://` reference, and pipe it to the +`kubectl-preflight` plugin the same way as the +[standard deployment](./deployment.mdx#run-preflight-checks): + +```bash +helm template stacklok-enterprise ./stacklok-enterprise-platform \ + --values values.yaml \ + | kubectl preflight - +``` + +If the transfer workstation needs the CLI plugin itself, mirror the +`preflight__.tar.gz` release asset from +[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases) +alongside the chart and image transfer in +[Step 1](#step-1-get-your-license-and-image-list). + In an air-gapped install, the failure mode to watch for is a pod stuck in `ImagePullBackOff`. It almost always means an image the chart references wasn't mirrored, or the pull secret can't authenticate. Recheck the pod's image against From 965284593e112b85e2540846854a8b232e64d1e5 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 11:22:11 -0700 Subject: [PATCH 03/14] Address review feedback on preflight checks section Follow-up for issue #1067: - Prefix idpConfig.issuer and signingConfig.existingSecret with the enterprise-manager subchart key, matching the rest of the page - Rephrase the enforcement heading to plain English --- .../enterprise-platform/deployment.mdx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 8b444dce..58420752 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -141,15 +141,15 @@ username and your **License ID** as the password. ### What it checks -| Check | Renders when | Outcome | -| ------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------- | -| Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | -| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | -| Distribution | Always | `warn` on OpenShift OCP | -| Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | -| Registry database reachability | `registryServer.enabled` and a run-time `preflightDatabaseUri` is supplied | `fail` if unreachable | -| OIDC issuer reachability | `enterpriseManager.enabled=true` and `idpConfig.issuer` is set | `fail` if unreachable or misconfigured | -| Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `signingConfig.existingSecret` is missing | +| Check | Renders when | Outcome | +| ------------------------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | +| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | +| Distribution | Always | `warn` on OpenShift OCP | +| Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | +| Registry database reachability | `registryServer.enabled` and a run-time `preflightDatabaseUri` is supplied | `fail` if unreachable | +| OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured | +| Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `enterprise-manager.signingConfig.existingSecret` is missing | :::warning[Registry database credential] @@ -178,7 +178,7 @@ On the Helm CLI install path, `kubectl preflight` can't block `helm install`. A proceed to [Step 4](#4-install-the-chart) while any check reports `fail`. Fix the underlying cluster condition first. -### Optional: real enforcement with preflight.enforce +### Optional: enforce preflight checks in-cluster Set `--set preflight.enforce=true` in your values to opt into an in-cluster pre-install and pre-upgrade Helm hook Job that runs the same spec and genuinely From 86d379748102940d71ce9e7ce24355b56c054314 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 11:26:55 -0700 Subject: [PATCH 04/14] Fix remaining review feedback on preflight docs Follow-up for issue #1067, iteration 2: - Qualify preflightDatabaseUri with the toolhive-registry-server prefix in the checks table, matching the other conditional rows - Distinguish the preflight.enforce values-file form from the --set flag - Restructure two run-on sentences for clarity --- .../enterprise-platform/deployment.mdx | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 58420752..d38afb6c 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -88,10 +88,9 @@ Before you authenticate and install, run the platform's **preflight** spec against your target cluster. The umbrella chart ships a `Preflight` custom resource as a labeled Secret, so rendering the chart and piping it to the `kubectl-preflight` plugin analyzes real prerequisites automatically. It catches -the misconfigurations that cause the most opaque install failures, a Kubernetes -version below the chart floor, tight node capacity, an unreachable OIDC issuer, -a missing signing-key Secret, before they surface later as failed pods or a -stuck rollout. +misconfigurations before they surface later as failed pods or a stuck rollout: a +Kubernetes version below the chart floor, tight node capacity, an unreachable +OIDC issuer, a missing signing-key Secret. ### Install the CLI plugin @@ -124,8 +123,8 @@ compare `kubectl preflight version` against the pinned version above. Use the `values.yaml` you build in [Step 3](#3-configure-values), not an empty or minimal render. The opt-in analyzers (OIDC issuer, signing-key Secret, registry database) only render when their corresponding values are set, so -preflighting against an empty file silently skips them, a `pass` result that -verified less than your real install will. +preflighting against an empty file silently skips them, and a `pass` result +verifies less than your real install actually needs. ```bash helm template stacklok-enterprise \ @@ -141,15 +140,15 @@ username and your **License ID** as the password. ### What it checks -| Check | Renders when | Outcome | -| ------------------------------ | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | -| Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | -| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | -| Distribution | Always | `warn` on OpenShift OCP | -| Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | -| Registry database reachability | `registryServer.enabled` and a run-time `preflightDatabaseUri` is supplied | `fail` if unreachable | -| OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured | -| Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `enterprise-manager.signingConfig.existingSecret` is missing | +| Check | Renders when | Outcome | +| ------------------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | +| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | +| Distribution | Always | `warn` on OpenShift OCP | +| Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | +| Registry database reachability | `registryServer.enabled` and a run-time `toolhive-registry-server.preflightDatabaseUri` is supplied | `fail` if unreachable | +| OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured | +| Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `enterprise-manager.signingConfig.existingSecret` is missing | :::warning[Registry database credential] @@ -180,9 +179,10 @@ the underlying cluster condition first. ### Optional: enforce preflight checks in-cluster -Set `--set preflight.enforce=true` in your values to opt into an in-cluster -pre-install and pre-upgrade Helm hook Job that runs the same spec and genuinely -fails `helm install` or `helm upgrade` on a `fail` outcome, real blocking, not +Set `preflight.enforce: true` in your values (or pass +`--set preflight.enforce=true`) to opt into an in-cluster pre-install and +pre-upgrade Helm hook Job that runs the same spec and genuinely fails +`helm install` or `helm upgrade` on a `fail` outcome, real blocking, not advisory. This is off by default because it carries cost you should accept deliberately: From 61fe89103bc769a54cc799f8d7299dd049a8e3dc Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 13:57:35 -0700 Subject: [PATCH 05/14] Address Copilot review feedback on preflight docs Follow-up for issue #1067 / PR #1068: - Fix the CLI download URL to match real Troubleshoot release assets (darwin ships a single universal binary, not per-arch ones) - Reword two awkward sentences flagged in review --- .../enterprise-platform/airgap-install.mdx | 4 ++-- docs/platform/enterprise-platform/deployment.mdx | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index cdf3a447..422f5032 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -503,8 +503,8 @@ in `stacklok-system` reaches `Running` and the ToolHive CRDs registered. ### Run preflight checks against the mirrored chart -The default preflight spec runs entirely offline, no cluster egress, so it works -unchanged in an air-gapped install. Template the chart directory you +The default preflight spec runs entirely offline, without cluster egress, so it +works unchanged in an air-gapped install. Template the chart directory you transferred, rather than an `oci://` reference, and pipe it to the `kubectl-preflight` plugin the same way as the [standard deployment](./deployment.mdx#run-preflight-checks): diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index d38afb6c..7f3034e9 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -101,9 +101,14 @@ the same version Stacklok validates the spec against: ```bash PREFLIGHT_VERSION=v0.131.1 os=$(uname -s | tr '[:upper:]' '[:lower:]') -arch=$(uname -m); [ "$arch" = "x86_64" ] && arch=amd64 +if [ "$os" = "darwin" ]; then + asset="preflight_darwin_all.tar.gz" +else + arch=$(uname -m); [ "$arch" = "x86_64" ] && arch=amd64 + asset="preflight_${os}_${arch}.tar.gz" +fi curl -fsSL -o preflight.tar.gz \ - "https://github.com/replicatedhq/troubleshoot/releases/download/${PREFLIGHT_VERSION}/preflight_${os}_${arch}.tar.gz" + "https://github.com/replicatedhq/troubleshoot/releases/download/${PREFLIGHT_VERSION}/${asset}" tar -xzf preflight.tar.gz preflight sudo install -m 0755 preflight /usr/local/bin/kubectl-preflight ``` @@ -173,9 +178,9 @@ one preflight run. ### Preflight is advisory by default On the Helm CLI install path, `kubectl preflight` can't block `helm install`. A -`fail` result is a signal you act on yourself, not an automatic gate: don't -proceed to [Step 4](#4-install-the-chart) while any check reports `fail`. Fix -the underlying cluster condition first. +`fail` result is a signal to act on, not an automatic gate: don't proceed to +[Step 4](#4-install-the-chart) while any check reports `fail`. Fix the +underlying cluster condition first. ### Optional: enforce preflight checks in-cluster From f2c258140b74ad34cba340d1d83c6eaf63668fd0 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:03:13 -0700 Subject: [PATCH 06/14] Lead with krew for preflight CLI install Match how the docs already treat third-party tool versions (helm, cosign): a minimum/compatible version, not a pin tied to Stacklok's internal CI. krew becomes the primary install path; the pinned release download moves to a fallback for air-gapped or krew-less setups, without claiming to match a CI-validated version. --- .../enterprise-platform/deployment.mdx | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 7f3034e9..749ea9b0 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -94,9 +94,22 @@ OIDC issuer, a missing signing-key Secret. ### Install the CLI plugin -Install the pinned binary release directly from -[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases), -the same version Stacklok validates the spec against: +Install the `preflight` plugin with [krew](https://krew.sigs.k8s.io/), the +`kubectl` plugin manager: + +```bash +kubectl krew install preflight +``` + +Any recent release works; the chart's `Preflight` spec doesn't depend on a +specific CLI version. + +:::note[Alternative: install a specific release directly] + +If you don't use krew, or need a specific release (for example, in an air-gapped +environment with no krew index access), download the binary from +[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases) +instead: ```bash PREFLIGHT_VERSION=v0.131.1 @@ -113,13 +126,8 @@ tar -xzf preflight.tar.gz preflight sudo install -m 0755 preflight /usr/local/bin/kubectl-preflight ``` -:::note[Alternative: krew] - -`kubectl krew install preflight` is a quicker one-time setup, but krew always -resolves to whatever version its index currently serves. It has no version-pin -flag, so it can silently drift ahead of the version this spec was last validated -against. If you hit unexpected preflight behavior on a krew-installed CLI, -compare `kubectl preflight version` against the pinned version above. +Check the [releases page](https://github.com/replicatedhq/troubleshoot/releases) +for the current version rather than assuming `v0.131.1` above is still latest. ::: From d155dc694b14d9e4e49f9a1ded1c6b3c0b4889bf Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:07:28 -0700 Subject: [PATCH 07/14] Use placeholders in the preflight DB URI example Match the placeholder convention used elsewhere on this page instead of a literal-looking connection string. --- docs/platform/enterprise-platform/deployment.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 749ea9b0..0b5c7ed4 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -172,7 +172,7 @@ values file: ```bash helm template stacklok-enterprise \ --set registryServer.enabled=true \ - --set 'toolhive-registry-server.preflightDatabaseUri=postgres://user:pass@host:5432/db?sslmode=require' \ + --set 'toolhive-registry-server.preflightDatabaseUri=postgres://:@:5432/?sslmode=require' \ | kubectl preflight - ``` From 1b2190340ea955e14d5f66a80ab26ba18b8d33ff Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:14:40 -0700 Subject: [PATCH 08/14] Clarify placeholders in the preflight commands - Explain and at first use, since the preflight section now runs before Step 1 where they were previously introduced - Replace the vague placeholder with the concrete oci:// reference --- docs/platform/enterprise-platform/deployment.mdx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 0b5c7ed4..a4ef4cb3 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -147,7 +147,10 @@ helm template stacklok-enterprise \ | kubectl preflight - ``` -`helm template` prompts for the same registry credentials as +`` and `` are the channel slug and chart version the install +portal at [install.stacklok.com](https://install.stacklok.com) generates for +your release, in its **Existing cluster with Helm** instructions. +`helm template` prompts for the same registry credentials you use in [Step 1](#1-authenticate-to-the-replicated-registry): your license email as the username and your **License ID** as the password. @@ -170,7 +173,9 @@ as a one-off flag at preflight time, never in a permanent or GitOps-tracked values file: ```bash -helm template stacklok-enterprise \ +helm template stacklok-enterprise \ + oci://oci.stacklok.com/stacklok-enterprise//stacklok-enterprise-platform \ + --version \ --set registryServer.enabled=true \ --set 'toolhive-registry-server.preflightDatabaseUri=postgres://:@:5432/?sslmode=require' \ | kubectl preflight - From a681098d96d4fcecb902bc6f265c167607102b16 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:33:34 -0700 Subject: [PATCH 09/14] Run air-gapped preflight checks before install, not after Preflight is meant to catch problems before helm install, but the prior placement ran it after install already succeeded and pods were verified Running, defeating the point. Move "Run preflight checks" ahead of "Install and verify" within Step 5, and rename the step to "Preflight, install, and verify" to reflect both subsections. --- .../enterprise-platform/airgap-install.mdx | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index 422f5032..97aa2d8d 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -483,27 +483,12 @@ enterprise-ai-gateway-operator: Persistence is enabled by default with a 1Gi claim, so you only need to set the class. -## Step 5: Install and verify - -Install the chart from your registry with the merged values. Reference the chart -by its `oci://` URL rather than a Helm repo alias: - -```bash -helm install stacklok-enterprise \ - oci://$ECR_HOST/$ECR_PREFIX/stacklok-enterprise-platform \ - --version \ - --namespace stacklok-system \ - --create-namespace \ - --values values.yaml -``` - -Verify the platform comes up the same way as in the -[standard deployment](./deployment.mdx#5-verify-the-install): confirm every pod -in `stacklok-system` reaches `Running` and the ToolHive CRDs registered. +## Step 5: Preflight, install, and verify ### Run preflight checks against the mirrored chart -The default preflight spec runs entirely offline, without cluster egress, so it +Before you install, run the platform's **preflight** spec against your target +cluster. The default spec runs entirely offline, without cluster egress, so it works unchanged in an air-gapped install. Template the chart directory you transferred, rather than an `oci://` reference, and pipe it to the `kubectl-preflight` plugin the same way as the @@ -521,6 +506,24 @@ If the transfer workstation needs the CLI plugin itself, mirror the alongside the chart and image transfer in [Step 1](#step-1-get-your-license-and-image-list). +### Install and verify + +Install the chart from your registry with the merged values. Reference the chart +by its `oci://` URL rather than a Helm repo alias: + +```bash +helm install stacklok-enterprise \ + oci://$ECR_HOST/$ECR_PREFIX/stacklok-enterprise-platform \ + --version \ + --namespace stacklok-system \ + --create-namespace \ + --values values.yaml +``` + +Verify the platform comes up the same way as in the +[standard deployment](./deployment.mdx#5-verify-the-install): confirm every pod +in `stacklok-system` reaches `Running` and the ToolHive CRDs registered. + In an air-gapped install, the failure mode to watch for is a pod stuck in `ImagePullBackOff`. It almost always means an image the chart references wasn't mirrored, or the pull secret can't authenticate. Recheck the pod's image against From abe746a516e65665122acefe12952f57e28a8d7a Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:50:23 -0700 Subject: [PATCH 10/14] Fix editorial issues in preflight checks section - Add the missing --values values.yaml flag to the registry database credential example; without it, copying that block standalone drops the real values file and silently skips every other analyzer - Reword the "Step 4" cross-reference, since no numbered steps are visible from the preflight section itself --- docs/platform/enterprise-platform/deployment.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index a4ef4cb3..93c4a9a1 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -170,12 +170,14 @@ username and your **License ID** as the password. The registry database check needs a DB URI that includes a password. Supply it as a one-off flag at preflight time, never in a permanent or GitOps-tracked -values file: +values file. Add these flags to the command above, alongside your real +`--values values.yaml`: ```bash helm template stacklok-enterprise \ oci://oci.stacklok.com/stacklok-enterprise//stacklok-enterprise-platform \ --version \ + --values values.yaml \ --set registryServer.enabled=true \ --set 'toolhive-registry-server.preflightDatabaseUri=postgres://:@:5432/?sslmode=require' \ | kubectl preflight - @@ -191,9 +193,9 @@ one preflight run. ### Preflight is advisory by default On the Helm CLI install path, `kubectl preflight` can't block `helm install`. A -`fail` result is a signal to act on, not an automatic gate: don't proceed to -[Step 4](#4-install-the-chart) while any check reports `fail`. Fix the -underlying cluster condition first. +`fail` result is a signal to act on, not an automatic gate: don't +[install the chart](#4-install-the-chart) while any check reports `fail`. Fix +the underlying cluster condition first. ### Optional: enforce preflight checks in-cluster From 4ba750143ba0ad999aeea9b5e7e616890b67cfe4 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 16:59:00 -0700 Subject: [PATCH 11/14] Explain unclear artifacts in preflight sections - deployment.mdx: explain where global.replicated.dockerconfigjson comes from (injected by the registry at pull time, not hand-set), verified against stacklok-enterprise-platform's appendix-b-helm- distribution.md and troubleshoot.md - airgap-install.mdx: fix the preflight template command to reference the actual .tgz this flow produces, not an invented unpacked directory that never exists in this walkthrough --- docs/platform/enterprise-platform/airgap-install.mdx | 9 +++++---- docs/platform/enterprise-platform/deployment.mdx | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index 97aa2d8d..4cbdb6d9 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -489,13 +489,14 @@ class. Before you install, run the platform's **preflight** spec against your target cluster. The default spec runs entirely offline, without cluster egress, so it -works unchanged in an air-gapped install. Template the chart directory you -transferred, rather than an `oci://` reference, and pipe it to the -`kubectl-preflight` plugin the same way as the +works unchanged in an air-gapped install. Template the local `.tgz` you pulled +in [Step 3](#step-3-mirror-the-chart-and-images), rather than an `oci://` +reference, and pipe it to the `kubectl-preflight` plugin the same way as the [standard deployment](./deployment.mdx#run-preflight-checks): ```bash -helm template stacklok-enterprise ./stacklok-enterprise-platform \ +helm template stacklok-enterprise \ + stacklok-enterprise-platform-.tgz \ --values values.yaml \ | kubectl preflight - ``` diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 93c4a9a1..9642d489 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -210,7 +210,11 @@ This is off by default because it carries cost you should accept deliberately: - The Job needs `global.replicated.dockerconfigjson` set. It pulls a license-gated `preflight-runner` image before the Replicated SDK provisions the ordinary pull secret; without it, the Job's pod can't pull its image and - the install hangs. + the install hangs. On this standard (non-air-gapped) install path, you don't + set this value by hand: the Replicated registry injects it into `values.yaml` + automatically when you pull the chart with `helm pull` or `helm template` + after [authenticating](#1-authenticate-to-the-replicated-registry). Confirm + it's present in your pulled `values.yaml` rather than adding it yourself. - The Job runs under its own ServiceAccount with cluster-scoped read RBAC (nodes, namespaces, storage classes, CRDs), plus a namespaced read on the signing-key Secret when `enterpriseManager.enabled` is set. From c0713150d63249759f442567dc6738f81b0cd1d0 Mon Sep 17 00:00:00 2001 From: glageju Date: Wed, 29 Jul 2026 17:07:43 -0700 Subject: [PATCH 12/14] Correct preflight authentication ordering claim "Before you authenticate and install" was wrong: helm template against an oci:// reference is itself a registry pull, so it needs the same authentication as helm install. Verified against Replicated's own docs and the upstream install-helm.md, which orders preflight right after authentication, not before it. Fix the framing to point the reader at Step 1 and Step 3 first, rather than claiming preflight runs before authenticating. --- .../enterprise-platform/deployment.mdx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 9642d489..91f60533 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -84,13 +84,18 @@ examples, so substitute your own namespaces as you follow them. ## Run preflight checks -Before you authenticate and install, run the platform's **preflight** spec -against your target cluster. The umbrella chart ships a `Preflight` custom -resource as a labeled Secret, so rendering the chart and piping it to the -`kubectl-preflight` plugin analyzes real prerequisites automatically. It catches -misconfigurations before they surface later as failed pods or a stuck rollout: a -Kubernetes version below the chart floor, tight node capacity, an unreachable -OIDC issuer, a missing signing-key Secret. +Before you install, run the platform's **preflight** spec against your target +cluster. The umbrella chart ships a `Preflight` custom resource as a labeled +Secret, so rendering the chart and piping it to the `kubectl-preflight` plugin +analyzes real prerequisites automatically. It catches misconfigurations before +they surface later as failed pods or a stuck rollout: a Kubernetes version below +the chart floor, tight node capacity, an unreachable OIDC issuer, a missing +signing-key Secret. + +Running the check itself requires the same registry access and `values.yaml` you +use to install: complete [Step 1](#1-authenticate-to-the-replicated-registry) +and [Step 3](#3-configure-values) below first, then come back here before +[Step 4](#4-install-the-chart). ### Install the CLI plugin From 4c7a90ac7461fdda33c03104e9b5db47fa7d0a9a Mon Sep 17 00:00:00 2001 From: glageju Date: Thu, 30 Jul 2026 14:33:14 -0700 Subject: [PATCH 13/14] Lead with pinned preflight CLI install Restore the pinned direct-download as the primary CLI install path, with krew demoted from a note to its own subsection. This matches the upstream recommendation in stacklok-enterprise-platform's docs/replicated/troubleshoot.md, which is version-gated by CI against PREFLIGHT_CLI_VERSION in build/replicated/Taskfile.yml. Neither install method belonged in an admonition, so both are now real subsections. The air-gapped page points at the pinned path explicitly, since krew needs index access an air-gapped host doesn't have. Also promote the registry-database check to its own subsection so its command is primary content rather than living inside a credential warning, widen the CRD-collision grep to cover the AI Gateway CRDs (ai-gateway.stacklok.dev), and state the concrete node-capacity thresholds (4 cores, 6Gi). Co-Authored-By: Claude Opus 5 (1M context) --- .../enterprise-platform/airgap-install.mdx | 9 ++- .../enterprise-platform/deployment.mdx | 72 +++++++++++-------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index 4cbdb6d9..3f243fd6 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -501,11 +501,14 @@ helm template stacklok-enterprise \ | kubectl preflight - ``` -If the transfer workstation needs the CLI plugin itself, mirror the -`preflight__.tar.gz` release asset from +If the transfer workstation needs the CLI plugin itself, mirror the release +asset for your platform (`preflight_linux_.tar.gz`, or +`preflight_darwin_all.tar.gz` on macOS) from [replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases) alongside the chart and image transfer in -[Step 1](#step-1-get-your-license-and-image-list). +[Step 1](#step-1-get-your-license-and-image-list). Use the +[pinned version](./deployment.mdx#install-the-cli-plugin) rather than krew here, +since krew needs index access an air-gapped host doesn't have. ### Install and verify diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 91f60533..669dccb2 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -99,22 +99,9 @@ and [Step 3](#3-configure-values) below first, then come back here before ### Install the CLI plugin -Install the `preflight` plugin with [krew](https://krew.sigs.k8s.io/), the -`kubectl` plugin manager: - -```bash -kubectl krew install preflight -``` - -Any recent release works; the chart's `Preflight` spec doesn't depend on a -specific CLI version. - -:::note[Alternative: install a specific release directly] - -If you don't use krew, or need a specific release (for example, in an air-gapped -environment with no krew index access), download the binary from -[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases) -instead: +Install the pinned `preflight` release that Stacklok validates the spec against. +Download it from +[replicatedhq/troubleshoot releases](https://github.com/replicatedhq/troubleshoot/releases): ```bash PREFLIGHT_VERSION=v0.131.1 @@ -131,10 +118,27 @@ tar -xzf preflight.tar.gz preflight sudo install -m 0755 preflight /usr/local/bin/kubectl-preflight ``` -Check the [releases page](https://github.com/replicatedhq/troubleshoot/releases) -for the current version rather than assuming `v0.131.1` above is still latest. +Pinning matters because the CLI and the spec move independently. Stacklok tests +this spec against the version above, so a CLI that drifts ahead of it can report +behavior the spec was never exercised with. -::: +### Alternative: install with krew + +[krew](https://krew.sigs.k8s.io/), the `kubectl` plugin manager, is a quicker +one-time setup: + +```bash +kubectl krew install preflight +``` + +The tradeoff is that krew always resolves to whatever version its index +currently serves, and it has no version-pin flag, so a krew install can drift +ahead of the validated version silently. If you hit unexpected preflight +behavior on a krew-installed CLI, compare `kubectl preflight version` against +the pinned version above before opening a support case. + +krew also needs index access, so use the pinned download in an air-gapped +environment. ### Run it against your real values @@ -164,18 +168,17 @@ username and your **License ID** as the password. | Check | Renders when | Outcome | | ------------------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | Kubernetes version | Always | `fail` below 1.28 (the chart's floor) | -| Node capacity (CPU and memory) | Always | `warn` if tight, evaluated on the smallest node | +| Node capacity (CPU and memory) | Always | `warn` below 4 allocatable cores or 6Gi, evaluated on the smallest node | | Distribution | Always | `warn` on OpenShift OCP | | Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | | Registry database reachability | `registryServer.enabled` and a run-time `toolhive-registry-server.preflightDatabaseUri` is supplied | `fail` if unreachable | | OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured | | Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `enterprise-manager.signingConfig.existingSecret` is missing | -:::warning[Registry database credential] +### Check registry database reachability -The registry database check needs a DB URI that includes a password. Supply it -as a one-off flag at preflight time, never in a permanent or GitOps-tracked -values file. Add these flags to the command above, alongside your real +The registry database check needs a connection URI, which the chart doesn't +ship. To exercise it, add these flags to the command above, alongside your real `--values values.yaml`: ```bash @@ -188,10 +191,19 @@ helm template stacklok-enterprise \ | kubectl preflight - ``` -The preflight spec ships as a Kubernetes Secret. A persistently configured URI -leaves the database password in-cluster indefinitely, readable with -`kubectl get secret ... -o yaml`, rather than existing only for the duration of -one preflight run. +The check reports `fail` if the database is unreachable. This is the only check +that touches a credential; the rest read capability metadata such as the +Kubernetes version, node capacity, and distribution. + +:::warning[Pass the URI as a one-off flag] + +Supply `preflightDatabaseUri` with `--set` at preflight time, never in a +permanent or GitOps-tracked values file. The preflight spec ships as a +Kubernetes Secret, so a persistently configured URI leaves the database password +in-cluster indefinitely, readable with `kubectl get secret ... -o yaml`, rather +than existing only for the duration of one preflight run. + +Don't commit or upload the rendered output either, since it carries the URI. ::: @@ -256,7 +268,9 @@ either: troubleshoot's `customResourceDefinition` analyzer can only express present as pass or absent as fail, not "already present is a problem." If you're reinstalling over a previous release, check - `kubectl get crd | grep toolhive.stacklok.dev` for version conflicts by hand. + `kubectl get crd | grep -E 'aigateway|toolhive'` for version conflicts by + hand. The pattern covers the AI Gateway CRDs as well, which install separately + when `aiGateway.enabled` is set. ## Deploy with Helm From fd2d22f8748e61dedefde5ed9a700ff6e39bc824 Mon Sep 17 00:00:00 2001 From: glageju Date: Thu, 30 Jul 2026 14:47:26 -0700 Subject: [PATCH 14/14] Fix accuracy gaps in preflight documentation Correct three claims that contradicted the tooling or the upstream source, and document two failure modes the sections omitted: - helm template has no interactive credential prompt. It accepts --username/--password and otherwise reuses the helm registry login from Step 1, so a reader waited on a prompt that never appears. - The dockerconfigjson guidance told readers to confirm the value in a "pulled values.yaml", but Step 3 has them hand-author that file and no step pulls one. Describe the license injection without pointing at an artifact the guide never produces. - Note that the OIDC check probes the issuer from wherever the CLI runs, so a cluster-internal issuer can fail from a workstation while the Enterprise Manager pod reaches it fine. Without this, the "don't install while anything reports fail" rule blocks a valid install. - Enabling enforcement on the air-gapped path needs more than a mirrored image: preflight.image.repository defaults to a Stacklok-hosted host an air-gapped cluster can't reach, and the hook Job renders its pull secret from global.replicated.dockerconfigjson, which is still required even though that path sets replicated.enabled: false. - Enforcement also widens the preflightDatabaseUri exposure into the long-lived release Secret, not just the hook-deleted one. Also link preflight checks from the platform deployment sequence, which had no inbound reference to the new section. Co-Authored-By: Claude Opus 5 (1M context) --- .../enterprise-platform/airgap-install.mdx | 29 +++++++++ .../enterprise-platform/deployment.mdx | 59 ++++++++++++++----- docs/platform/enterprise-platform/index.mdx | 4 +- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/docs/platform/enterprise-platform/airgap-install.mdx b/docs/platform/enterprise-platform/airgap-install.mdx index 3f243fd6..5a2dea78 100644 --- a/docs/platform/enterprise-platform/airgap-install.mdx +++ b/docs/platform/enterprise-platform/airgap-install.mdx @@ -510,6 +510,35 @@ alongside the chart and image transfer in [pinned version](./deployment.mdx#install-the-cli-plugin) rather than krew here, since krew needs index access an air-gapped host doesn't have. +The advisory workflow above needs nothing in your registry, only the CLI binary. + +:::note[Enabling in-cluster enforcement] + +The optional +[enforcement mode](./deployment.mdx#optional-enforce-preflight-checks-in-cluster) +runs the same checks as a pre-install hook Job that blocks a failing install. +Enabling it on this path takes three things: + +- Confirm the `preflight-runner` image reached your registry. It's on the + portal's image list, so [Step 3](#step-3-mirror-the-chart-and-images) mirrors + it like any other image, but it's easy to skip as an optional component's + image. +- Repoint `preflight.image.repository` at your registry, the same way you + repoint every other component in + [Step 4](#step-4-point-the-install-at-your-registry). It defaults to a + Stacklok-hosted host that an air-gapped cluster can't reach, and the chart has + no global registry override to do this for you. +- Set `global.replicated.dockerconfigjson` to credentials for your registry. The + Job renders its own hook-ordered pull secret from that value, and it can't use + the `stacklok-enterprise-pull` secret you created above, because a pre-install + hook runs before ordinary chart resources exist. This value is still required + even though you set `replicated.enabled: false`. + +Because the Job runs before anything else installs, missing any of these hangs +the install rather than surfacing as an `ImagePullBackOff` later. + +::: + ### Install and verify Install the chart from your registry with the merged values. Reference the chart diff --git a/docs/platform/enterprise-platform/deployment.mdx b/docs/platform/enterprise-platform/deployment.mdx index 669dccb2..356fef7b 100644 --- a/docs/platform/enterprise-platform/deployment.mdx +++ b/docs/platform/enterprise-platform/deployment.mdx @@ -119,8 +119,9 @@ sudo install -m 0755 preflight /usr/local/bin/kubectl-preflight ``` Pinning matters because the CLI and the spec move independently. Stacklok tests -this spec against the version above, so a CLI that drifts ahead of it can report -behavior the spec was never exercised with. +this spec against the version above, so a newer CLI can grade a check +differently than Stacklok validated it, giving you a `pass` or `fail` that +doesn't reflect your cluster's real state. ### Alternative: install with krew @@ -158,10 +159,11 @@ helm template stacklok-enterprise \ `` and `` are the channel slug and chart version the install portal at [install.stacklok.com](https://install.stacklok.com) generates for -your release, in its **Existing cluster with Helm** instructions. -`helm template` prompts for the same registry credentials you use in -[Step 1](#1-authenticate-to-the-replicated-registry): your license email as the -username and your **License ID** as the password. +your release, in its **Existing cluster with Helm** instructions. Templating an +`oci://` reference pulls the chart, so it reuses the `helm registry login` +credentials from [Step 1](#1-authenticate-to-the-replicated-registry). There's +no credential prompt: if that login is missing or expired, `helm template` fails +with an authorization error. Log in again and rerun. ### What it checks @@ -172,9 +174,24 @@ username and your **License ID** as the password. | Distribution | Always | `warn` on OpenShift OCP | | Egress reachability | `preflight.checkEgress=true` | `warn` only; off by default, always fails in air gap | | Registry database reachability | `registryServer.enabled` and a run-time `toolhive-registry-server.preflightDatabaseUri` is supplied | `fail` if unreachable | -| OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured | +| OIDC issuer reachability | `enterpriseManager.enabled=true` and `enterprise-manager.idpConfig.issuer` is set | `fail` if unreachable or misconfigured (see the note below) | | Signing-key Secret exists | `enterpriseManager.enabled=true` | `fail` if the Secret named in `enterprise-manager.signingConfig.existingSecret` is missing | +:::note[A cluster-internal OIDC issuer can fail from your workstation] + +The OIDC check probes the issuer from wherever you run `kubectl preflight`, not +from inside the cluster. If your issuer is only reachable on the cluster +network, the check reports `fail` from a workstation even though the Enterprise +Manager pod would reach it fine. + +That's a difference in network vantage point, not a misconfiguration. Confirm it +by running the check from inside the cluster, which is what +[enforcement mode](#optional-enforce-preflight-checks-in-cluster) does. For a +publicly reachable issuer, treat a `fail` as real: it usually means a typo in +the issuer URL. + +::: + ### Check registry database reachability The registry database check needs a connection URI, which the chart doesn't @@ -219,29 +236,43 @@ the underlying cluster condition first. Set `preflight.enforce: true` in your values (or pass `--set preflight.enforce=true`) to opt into an in-cluster pre-install and pre-upgrade Helm hook Job that runs the same spec and genuinely fails -`helm install` or `helm upgrade` on a `fail` outcome, real blocking, not -advisory. +`helm install` or `helm upgrade` on a `fail` outcome. This is real blocking +rather than advisory. This is off by default because it carries cost you should accept deliberately: - The Job needs `global.replicated.dockerconfigjson` set. It pulls a license-gated `preflight-runner` image before the Replicated SDK provisions the ordinary pull secret; without it, the Job's pod can't pull its image and - the install hangs. On this standard (non-air-gapped) install path, you don't - set this value by hand: the Replicated registry injects it into `values.yaml` - automatically when you pull the chart with `helm pull` or `helm template` - after [authenticating](#1-authenticate-to-the-replicated-registry). Confirm - it's present in your pulled `values.yaml` rather than adding it yourself. + the install hangs. On this standard (non-air-gapped) install path, Replicated + injects this value from your license when Helm pulls the chart, so you + normally don't set it by hand. If enforcement fails on an image pull, get the + value from the install portal's **Existing cluster with Helm** instructions + and set it explicitly. - The Job runs under its own ServiceAccount with cluster-scoped read RBAC (nodes, namespaces, storage classes, CRDs), plus a namespaced read on the signing-key Secret when `enterpriseManager.enabled` is set. +If you also set `toolhive-registry-server.preflightDatabaseUri` persistently, +enforcement widens the credential exposure described in +[Check registry database reachability](#check-registry-database-reachability): +the password renders into the long-lived `stacklok-enterprise-preflight` Secret, +not just the Job's own Secret, which is deleted when the hook finishes. Keep +passing the URI as a one-off `--set`. + +Enabling this on the [air-gapped path](./airgap-install.mdx) takes extra setup, +since the Job's image defaults to a Stacklok-hosted registry. See +[Run preflight checks against the mirrored chart](./airgap-install.mdx#run-preflight-checks-against-the-mirrored-chart). + If enforcement blocks an install, read the Job's log to see why: ```bash kubectl logs job/stacklok-enterprise-preflight-check -n stacklok-system ``` +The Job and both Secrets are named after your Helm release, so substitute your +own release name if it isn't `stacklok-enterprise`. + To bypass a known false positive for one run, re-run the same `helm` command with `--set preflight.enforce=false`. diff --git a/docs/platform/enterprise-platform/index.mdx b/docs/platform/enterprise-platform/index.mdx index ed79cc34..05f99996 100644 --- a/docs/platform/enterprise-platform/index.mdx +++ b/docs/platform/enterprise-platform/index.mdx @@ -70,7 +70,9 @@ its detailed guide. 1. **Deploy the platform.** Install the umbrella chart, wiring in the identity values from the previous step. The chart deploys the ToolHive operator, the Enterprise Manager, the Enterprise Cloud UI, and the Registry Server as - subcharts. See [Deploy the platform](./deployment.mdx). + subcharts. See [Deploy the platform](./deployment.mdx). Before you install, + [run preflight checks](./deployment.mdx#run-preflight-checks) to catch + cluster problems that would otherwise surface partway through the release. 1. **Configure policies.** Use the Enterprise Manager to pin the registry, control non-registry servers, standardize telemetry, and shape the client experience. See [Configure policies](../enterprise-manager/policies/).