> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-revert-104359-revert-104251-parquet-single.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Platform updates

> Approve the platform bundles ClickHouse Cloud proposes for a managed cluster: what a bundle is, how approval works, and what it grants

export const Image = ({img, alt, size = "lg", background}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  const backgroundColor = background === "white" ? "white" : background === "black" ? "rgb(31 31 28)" : undefined;
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} style={{
    backgroundColor
  }} />
      </Frame>
    </div>;
};

export const PrivatePreviewBadge = () => {
  return <div className="privatePreviewBadge">
            <div className="privatePreviewIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M5.33301 6.66667V4.66667V4.66667C5.33301 3.194 6.52701 2 7.99967 2V2C9.47234 2 10.6663 3.194 10.6663 4.66667V4.66667V6.66667" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path d="M8.00033 9.33337V11.3334" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path fillRule="evenodd" clipRule="evenodd" d="M11.333 14H4.66634C3.92967 14 3.33301 13.4033 3.33301 12.6666V7.99996C3.33301 7.26329 3.92967 6.66663 4.66634 6.66663H11.333C12.0697 6.66663 12.6663 7.26329 12.6663 7.99996V12.6666C12.6663 13.4033 12.0697 14 11.333 14Z" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            {'Private preview'}
        </div>;
};

<PrivatePreviewBadge />

A managed cluster runs a small platform layer that the ClickHouse services depend on. ClickHouse Cloud proposes updates to that layer; the executor applies nothing until you approve each one with your own cluster credentials.

<h2 id="what-a-platform-update-is">
  What a platform update is
</h2>

The platform layer is three components: the snapshot controller, the ClickHouse operator, and the monitoring collectors. They install in that order because each needs the previous one's custom resource definitions. The services use a StorageClass named `gp3-encrypted` (encrypted gp3 volumes) that ships with them.

A platform bundle is the manifest ClickHouse Cloud renders for your environment. It pins the chart and image versions of those components and names the registry they are pulled from. Every bundle is identified by the sha256 of that manifest. ClickHouse Cloud sends it to the executor over the command channel, and the executor stages it for your approval.

A bundle is applied in two halves:

* The **permission half** is everything that grants or shapes access: Namespaces, CustomResourceDefinitions, ServiceAccounts, ClusterRoles and ClusterRoleBindings, Roles and RoleBindings, webhook and admission configurations, PriorityClasses, and the StorageClass. Only you apply it, with your credentials, by running `clicklink clctl platform approve`.
* The **workload half** is what runs: Deployments, Services, ConfigMaps, Secrets, Jobs, and PodDisruptionBudgets. The executor applies it as a dedicated `pcm-platform` identity that can write those kinds and nothing else, and only while the short-lived token your approval minted is valid.

The executor never applies a bundle you have not approved. It refuses a platform sync whose permission half is missing, whose sha256 differs from the approved one, or whose token has expired. The refusal reports that approval is needed and names the sha256 of the staged bundle. A service create that needs a custom resource definition your current platform lacks fails the same way, with the same command to run.

<h2 id="approve-a-platform-update">
  Approve a platform update
</h2>

<Image img="https://mintcdn.com/private-7c7dfe99-revert-104359-revert-104251-parquet-single/FjaG6PmLNcoIR7ck/images/cloud/reference/byoc-connector-platform-approval.svg?fit=max&auto=format&n=FjaG6PmLNcoIR7ck&q=85&s=8f356c94230beb381434e9734a062380" size="lg" alt="ClickHouse Connector platform approval flow" width="1320" height="800" data-path="images/cloud/reference/byoc-connector-platform-approval.svg" />

<h3 id="registry-credentials">
  Registry credentials
</h3>

Registry authentication depends on the image distribution mode registered for your environment:

* **Direct access to ClickHouse's registry.** Run approval on the connector's EC2 VM. Both `approve` and the executor's platform sync assume your environment's read-only ECR puller role with credentials from the EC2 instance metadata service. That role logs in to the chart registry; the executor also uses it to check that the platform images exist. AWS profiles, environment credentials, or SSO credentials on a workstation do not replace the instance profile. Your kubeconfig still supplies the separate cluster-admin credentials that apply the permission half.
* **Charts in another ECR registry, including your own mirror.** Chart login uses the ambient AWS credentials of the process running `approve` or the executor. Those credentials must be allowed to read that registry.

Use the Kubernetes workstation procedure below only for mirrored-registry deployments with Kubernetes platform approval enabled. For direct access, ask your account team to confirm a supported execution environment with the required EC2 instance profile first.

<Steps>
  <Step title="Find the staged bundle" id="find-the-staged-bundle">
    ClickHouse Cloud sends each proposed bundle to the executor first. The executor stages it as the pending bundle and reports its sha256 on the heartbeat. One staged bundle exists at a time; a newer proposal replaces it. The executor then refuses the sync and records a failed command whose result ends with the command to run.

    ```bash theme={null}
    clicklink clctl commands list --status failed --action sync_platform
    ```

    The `result` field ends with `run: clctl platform approve (pending bundle sha <sha256>)`. On Kubernetes the hint reads `run: clctl platform approve --secret-namespace <connector-namespace> (pending bundle sha <sha256>)`. A create that hit a missing custom resource definition carries the same `clctl platform approve` line. It appears in its own failed command and in the error `clicklink clctl instances create --wait` prints. Your account team also tells you when a platform update is proposed.

    Read the staged bundle before you approve it. It holds the manifest and its sha256.

    <Tabs>
      <Tab title="Linux VM" id="inspect-vm">
        The executor stages the bundle as a file next to its access bundles on the connector host:

        ```bash theme={null}
        sudo cat /etc/clicklink/access/executor/platform-pending.json
        ```
      </Tab>

      <Tab title="Kubernetes" id="inspect-kubernetes">
        The executor pod stages the bundle on its state volume and serves it on its local API. Open a port-forward and read it:

        ```bash theme={null}
        CONNECTOR_NAMESPACE='clicklink'   # the connector namespace you chose at init
        kubectl -n "${CONNECTOR_NAMESPACE}" port-forward deployment/clicklink-connector-executor 9999:9999 &
        curl -s http://127.0.0.1:9999/v1/platform/pending
        ```

        The API answers `404` with `no platform bundle is staged` until the first proposal arrives. Leave the port-forward open for the next step.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run approve" id="run-approve">
    `approve` with no flags reads the staged bundle and hashes it, so you approve exactly what the executor received. It renders every chart as the executor will and applies the permission half with the kube context you choose. It creates the `pcm-platform` identity if needed and mints its token. It makes no request to your connector endpoint.

    `approve` needs a kube context with cluster-admin rights on the managed cluster (`--context <name>` when your kubeconfig holds several) and the [registry credentials](#registry-credentials) for your environment's image distribution mode. `--dry-run` renders and lists the permission half without applying or minting anything; it still needs registry access to render the charts.

    <Tabs>
      <Tab title="Linux VM" id="approve-vm">
        Run on the connector host, as root, where the executor staged the bundle:

        ```bash theme={null}
        sudo clicklink clctl platform approve --config /etc/clicklink/config.yaml
        ```

        `approve` writes the token to `/etc/clicklink/access/executor/_platform`, next to the executor's other credentials. It builds the new bundle beside the live one and swaps it in only once its token exists, so a failed approve leaves a still-valid token alone.
      </Tab>

      <Tab title="Kubernetes" id="approve-kubernetes">
        For a mirrored-registry deployment with Kubernetes platform approval enabled, `approve` reads the staged bundle over the port-forward from the previous step. It delivers the token bundle as a Secret in the connector namespace, which the chart mounts into the pod. Run it from a workstation whose kubeconfig reaches the cluster, with a copy of the connector configuration and [registry access](#registry-credentials). The chart renders the configuration into the executor's ConfigMap; `approve` needs it only for the namespace prefix and reads no credentials from it.

        ```bash theme={null}
        CONNECTOR_NAMESPACE='clicklink'   # the connector namespace you chose at init
        kubectl -n "${CONNECTOR_NAMESPACE}" get configmap clicklink-connector-executor \
          -o jsonpath='{.data.config\.yaml}' > clicklink-config.yaml
        clicklink clctl platform approve --config clicklink-config.yaml \
          --secret-namespace "${CONNECTOR_NAMESPACE}"
        ```

        `approve` reads the staged bundle from `http://127.0.0.1:9999` by default; pass `--endpoint` when your port-forward uses another local port. Without a port-forward it stops and prints the `kubectl port-forward` command to open. The bundle lands in the Secret `clicklink-platform-bundle` (`--secret-name` to change it, matching the chart's `executor.platformBundleSecret`). The executor pod sees it once the kubelet refreshes the mount, within about a minute.
      </Tab>
    </Tabs>
  </Step>

  <Step title="Confirm" id="confirm">
    `approve` ends with:

    ```text theme={null}
    Approved: <n> permission object(s) applied, platform token valid until <expiry>.
    The executor may now apply the <n> workload object(s) of this bundle inside <namespaces>.
    ```

    On Kubernetes a third line follows: `Bundle written to Secret <namespace>/<name>; the executor pod sees it once the kubelet refreshes the mount, within about a minute.`

    ClickHouse Cloud re-sends the sync once the executor's next heartbeat shows the approval. It waits up to 20 minutes for a sync already in flight and skips an executor whose last heartbeat is older than 5 minutes. After 3 attempts for one bundle it stops, and your account team re-triggers it. The executor applies the workload half and reports the platform as `synced`. Watch the sync land with:

    ```bash theme={null}
    clicklink clctl commands list --action sync_platform
    ```

    The most recent `sync_platform` command turns `completed`. The executor also reports the platform status and the component versions to ClickHouse Cloud on every heartbeat, so your account team sees the same outcome.
  </Step>
</Steps>

<h2 id="the-approval-window">
  The approval window
</h2>

An approval mints a token for the `pcm-platform` identity, valid for 2 hours by default (`--ttl` changes it). The executor never renews it. Once it expires the executor can no longer touch the platform layer and refuses the next platform sync with the approval message again. This is by design and independent of connectivity: an approval given while the connector is offline still expires on its own clock.

Run `approve` again whenever:

* the token expired before the sync finished;
* ClickHouse Cloud proposes a different bundle. The sha256 you approved is recorded on the `pcm-platform` ServiceAccount, and the executor refuses a sync for any other bundle until you approve that one;
* a service create reports a missing custom resource definition.

Approving the same bundle again is safe and replaces the token. The staged bundle stays in place after the sync, so a repeat approval needs no new proposal.

<h2 id="what-the-approval-grants">
  What the approval grants
</h2>

You apply the permission half, so it carries your authority; the executor applies nothing in it. `approve` stamps it with the bundle's sha256, and before touching anything the executor verifies that every permission object of the bundle it was sent is present and approved.

The executor applies the workload half as `pcm-platform`. That identity can create and update Secrets, ConfigMaps, Services, Deployments, Jobs, and PodDisruptionBudgets, only inside the platform namespaces, which an admission policy enforces. It can read the objects it needs for its preflight (pods, events, namespaces, ServiceAccounts, the permission kinds above). It cannot:

* write any cluster-scoped kind or any RBAC object;
* `escalate`, `bind`, or `impersonate`;
* mint or renew its own token.

The executor's service-lifecycle identity, `pcm-executor`, is separate and confined to the service namespaces. It cannot write to the platform namespaces; its reads are not confined by the prefix guard. For the full listing of both identities, see the [privilege model](/products/bring-your-own-cloud/connector/reference/privilege-model).

<h2 id="resetting-a-test-cluster">
  Resetting a test cluster
</h2>

`clicklink clctl platform reset` exists for test clusters: it uninstalls the platform components so their first installation can be exercised again. Before changing anything it lists the ClickHouse clusters in the namespaces this connector owns and refuses if any service exists.

On an empty cluster it uninstalls the platform releases in reverse dependency order. It then removes the executor's platform token bundle: the local directory on a VM, or the Secret named by `--secret-namespace <connector-namespace>` on Kubernetes. CustomResourceDefinitions, RBAC, and the StorageClass stay in place. Run `approve` again before the next platform sync.

```bash theme={null}
sudo clicklink clctl platform reset --bundle <manifest-file> --config /etc/clicklink/config.yaml --dry-run
```

`reset` takes the rendered platform manifest as a file (`--bundle`); it does not read the staged bundle. `--dry-run` checks for services and prints the plan without changing the cluster.
