Skip to main content
This page is the security reference for the ClickHouse Connector: its identities, connections, exact privileges, structural limits, and how every action is attributed. For how the pieces fit together, see architecture.

Identities

  • The connector’s mTLS client certificate, with your organization ID as its common name, authenticates every daemon to your connector endpoint. clicklink clctl instances create uses the same certificate and HMAC key when it calls the endpoint.
  • pcm_scraper and pcm_troubleshooter are the read-only ClickHouse users the scraper and troubleshooter connect as. The executor has no ClickHouse user.
  • Troubleshooter ServiceAccounts, one per provisioned deployment, carry the read-only Kubernetes views a support session can use.
  • pcm-executor is the executor’s Kubernetes ServiceAccount for the lifecycle of managed services. A ValidatingAdmissionPolicy confines its writes to service namespaces.
  • pcm-platform is the executor’s identity for platform updates. Your clicklink clctl platform approve mints its token for 2 hours and never renews it; between approvals the executor has no write access to the platform layer.
  • The per-service IAM role (CH-S3-<service>-<region>-00-Role by default) is created by clicklink clctl executor prepare with your credentials. It is scoped to that service’s data and backup buckets and trusted only by that service’s Kubernetes ServiceAccount, so neither the executor nor ClickHouse can assume it.
  • The connector EC2 VM’s instance profile assumes your environment’s read-only ECR puller role for direct platform access, for both chart login and image checks. The approval CLI uses the same instance-profile path; workstation AWS profiles or SSO credentials do not replace it. Other ECR chart registries use ambient AWS credentials. Image pulls happen on your nodes under their own pull role. The executor holds no credentials for your buckets or IAM and makes no S3 or IAM calls. See registry credentials.
  • Your own credentials apply every grant: the executor’s access grant at init --managed, the buckets and role at prepare, the permission half of every platform update at approve, and the cleanup at teardown.

What the connector can do

Outbound connections

Every connection the connector opens originates inside your environment. The complete list: Inbound, each daemon exposes one local health port, which also serves its Prometheus metrics, plus the opt-in session gateway. The executor’s local command API binds to loopback only. Nothing else listens. ClickHouse Cloud never connects into your environment: it can only answer the two outbound WebSockets.

ClickHouse grants

Provisioning creates one read-only user per observing component. The users are created with IDENTIFIED WITH bcrypt_hash, so only a salted bcrypt hash exists in the provisioning SQL. The plaintext password lives only in the credential file the daemon reads at runtime. The ALTER USER line after each CREATE USER rotates the hash on --force. The executor has no ClickHouse user and never connects to ClickHouse. The grants are exactly these, with the default table sets:
READ ON REMOTE is needed because scrape queries wrap each system table in clusterAllReplicas(). SYSTEM FLUSH LOGS is the one system-level grant. It makes the *_log system tables persist entries they already buffer so scrapes see current data; it can neither read nor modify anything. ClickHouse accepts that privilege only at global scope and honors it only for log tables, so the grant is broader than the capability.
The system.user_directories grant on both users serves one diagnostic. clicklink clctl preflight runs with the connector’s own credentials and checks whether the instance stores its ClickHouse users replicated or locally. The table holds user-storage configuration metadata, not user data. Neither the scrape set nor the session table allowlist includes it, so no scrape or session output path reads it. Without the grant, that preflight check reports itself skipped and everything else proceeds. There are no INSERT, DDL, user-management, settings, or process-control grants. When a second connector deployment shares an instance, its users carry a suffix (pcm_scraper_<suffix>) with the same grant sets.

Kubernetes RBAC

Scraper and troubleshooter

The scraper and troubleshooter have no ClusterRole or ClusterRoleBinding. The chart creates namespace-scoped Roles in the connector namespace, and each per-instance access bundle creates a Role in that instance’s ClickHouse or service namespace.

Executor

In managed mode, clicklink clctl init --managed (or clicklink clctl executor access grant --cluster followed by apply --cluster) applies the executor’s grant with your credentials. The grant is the pcm-executor ServiceAccount (in the connector namespace on Kubernetes, in clicklink-system on a VM install), one ClusterRole bound to it, and the pcm-executor-prefix-guard ValidatingAdmissionPolicy. The verbs are granted cluster-wide because RBAC cannot express a namespace prefix. The admission policy then denies every write from pcm-executor that targets a namespace outside the service prefix (ns- by default). Its home namespace admits three writes: its own token renewal, the clicklink-instance-registry ConfigMap the scraper reads, and, on Kubernetes, the renewed client certificate written back to the clicklink-mtls Secret. The policy applies to that ServiceAccount alone and uses failurePolicy: Fail and validationActions: [Deny]. The ClusterRoleBinding is applied last, after the policy and its binding, so a partially applied grant leaves the executor with no permissions rather than unguarded ones. On a VM, clicklink clctl executor prepare also applies a per-service bundle. The bundle is a pcm-executor ServiceAccount inside ns-<name>, a Role carrying the same resource families, and a ClusterRole pinned to get and delete on that one namespace. The executor uses that bundle for the service when present and the cluster-wide grant otherwise. On Kubernetes the pod always acts as the connector-namespace pcm-executor ServiceAccount. Admission does not run on get, list, or watch, so the executor’s reads of these resource families are not confined to the prefix.

Platform identity

clicklink clctl platform approve applies the permission half of a platform update with your credentials: Namespaces, CustomResourceDefinitions, ServiceAccounts, ClusterRoles and ClusterRoleBindings, Roles and RoleBindings, webhook and admission configurations, PriorityClasses, and the StorageClass. It then applies the pcm-platform ServiceAccount, its ClusterRole, the pcm-platform-scope-guard ValidatingAdmissionPolicy, and the binding, and mints a bound token valid for 2 hours. With that token the executor may write only deployments, services, configmaps, secrets, jobs, and poddisruptionbudgets, and only in the platform namespaces the scope guard allows. It may read pods, events, namespaces, serviceaccounts, CustomResourceDefinitions, RBAC objects, webhook configurations, StorageClasses, and PriorityClasses to check that the permission half is in place before it applies anything. It never holds escalate, bind, or impersonate, never writes a cluster-scoped kind or an RBAC object, and cannot mint or renew its own token. The token authorizes exactly one bundle: the digest you approved is recorded on the ServiceAccount, and the executor refuses any other.

What the connector cannot do

  • No writes to ClickHouse data or state. The grants above contain no INSERT, no DDL, and no user-management, settings, or process-control privileges. The single system-class grant, the scraper’s SYSTEM FLUSH LOGS, only makes log tables persist what they already buffer. The executor has no ClickHouse user. No component can modify data, schemas, users, or settings through ClickHouse.
  • No exec. No RBAC contains pods/exec; no component can run commands in your pods.
  • No writes outside service and platform namespaces. The scraper and troubleshooter hold no delete or patch. Their only mutations are the exact-name update on the connector’s own mTLS Secret and create on serviceaccounts/token, which mints short-lived tokens for their own ServiceAccounts and modifies no stored object. Admission denies the executor’s writes outside the service prefix, and its platform writes exist only while a token you minted is valid.
  • No permission to grant permissions. Your credentials apply the platform’s Namespaces, CRDs, ServiceAccounts, RBAC, webhook and admission configurations, PriorityClasses, and StorageClass during approve. The executor’s platform identity cannot escalate, bind, or impersonate. Inside a service namespace the executor can create only Roles that grant permissions it already holds.
  • No credentials for your buckets or IAM. clicklink clctl executor prepare creates the buckets and the per-service role, and clicklink clctl executor teardown removes them, both under your credentials. The role is assumable only by that service’s pods. For direct platform access, the executor uses the connector EC2 VM’s instance profile to assume the read-only ECR puller role for both chart login and image checks. Other ECR chart registries use ambient AWS credentials; see identities. Its only cloud API calls go to ECR and STS; it cannot read or delete your data.
  • No knowledge of your default user password. clicklink clctl executor prepare generates it on your side and shows it once (or clicklink clctl instances create does, when you pass the inputs as flags). Only its hashes are submitted, so neither the connector nor ClickHouse Cloud can recover it.
  • Nothing inbound. ClickHouse Cloud never opens a connection into your environment. The only command paths are the two outbound WebSockets. The troubleshooter refuses every command unless a support session you enabled is active. The executor accepts lifecycle commands only for the services you asked ClickHouse to manage, within the scopes above. Even during a session the troubleshooter is bounded on both sides. ClickHouse queries are limited to the table allowlist, which refuses query_log and text_log, so those are never granted. Kubernetes access is limited to the read-only views and pod logs the namespace-scoped Roles grant.

What requires your action

  • Enabling managed mode. The executor runs, and its Kubernetes grant exists, only after you enable managed mode at init; the grant is applied with cluster admin. See managed services.
  • Creating a service. clicklink clctl executor prepare runs with your AWS credentials to create the buckets and the IAM role, and clicklink clctl instances create submits the definition. ClickHouse Cloud cannot create a service in your cluster without both. See create a service.
  • Platform updates. Each update to the platform components is applied only after you run clicklink clctl platform approve for that exact bundle; the token it mints expires after 2 hours and is never renewed. See platform updates.
  • Cleaning up after a delete. Deleting a service removes its Kubernetes resources only. clicklink clctl executor teardown, run with your credentials, removes the IAM role and, only with explicit flags, the data and backups. See delete a service.
  • Support sessions. Interactive troubleshooting happens only inside a session you enable, time-boxed to 4 hours by default and 24 hours at most. Disabling takes effect immediately. See support sessions.
  • The operator allowlist. Every gateway request must carry an OIDC token whose attested email is on your allowlist. An empty allowlist is closed. You manage the list; see the configuration guide.
  • Gateway exposure. The session gateway is off unless you enable it, and reachable only by port-forward unless you opt into an Ingress. On a VM, each operator must fingerprint-pin its self-signed certificate, or verify it with a CA bundle passed as --gateway-ca, before the session commands talk to it.
  • Network egress. Under an enforcing CNI, no daemon reaches your connector endpoint until you list its CIDRs in networkPolicy.allowEgressCIDRs. The executor also needs the Kubernetes API server CIDRs (networkPolicy.apiserverCIDRs), which init --managed derives from the cluster’s VPC. If platform charts come from Amazon ECR, add the ECR and STS ranges too.

How access is attributed

  • Deployment identity. The mTLS client certificate’s common name is your org ID, and its single DNS name is bound to your endpoint host. That makes every API connection attributable to your org. Renewal is automatic and in-daemon; no operator handles the key material.
  • Request integrity. Every API request also carries an HMAC-SHA256 signature (Authorization: HMAC-SHA256 AccessKey=..., Signature=..., Timestamp=...) over the method, path, timestamp, and body hash, using the key pair issued at enrollment.
  • Operator identity. Gateway calls are attributed to the email attested by the operator’s OIDC ID token, verified against your identity provider’s JWKS. A self-reported name is never trusted where a token is available.
  • Lifecycle commands. The executor records every command it receives in its local store with its origin (ClickHouse Cloud or a local clicklink clctl call), its stage, and its result. It reports the result back over the command channel. Read the record with clicklink clctl commands list and clicklink clctl commands get; see the CLI reference.
  • Platform approvals. The digest of the bundle you approved is recorded on the pcm-platform ServiceAccount. Every object your credentials applied carries a content hash, which the executor verifies before it writes anything. A bundle with any other digest is refused.
  • Audit trail. Every session command, accepted or blocked, is appended to the NDJSON audit log with the org identity from the command channel. Gateway calls are logged as structured clctl.gateway lines in the troubleshooter log with the attested operator email. VM local session changes record the host user in session.json. Read the audit log with clicklink clctl troubleshoot audit tail; see the CLI reference.

Data minimization defaults

  • query_log is excluded from scrapes by default. Its columns carry raw SQL with literal values, which can contain personal data or secrets. It does not leave your boundary unless you add it.
  • The troubleshooter reads only allowlisted tables. query_log and text_log are refused in the allowlist configuration itself, so they are never granted and query history is never readable. The default allowlist does include system.processes (live query text); trim it (troubleshooter.allowedTables on Kubernetes, troubleshooter.allowed_tables on a VM) if that must stay hidden during sessions.
  • All troubleshooter output is redacted with built-in patterns plus any you define. The built-ins cover IPv4 and IPv6 addresses, bearer tokens, AWS access keys, emails, JWTs, SSH private keys, and connection-string credentials. The daemon refuses to start with an invalid patterns file rather than run unredacted.
  • Managed service status is metadata only. The executor reports a service’s state, replica counts, versions, and command outcomes. It never reads the service’s tables or buckets.
  • Credentials are minimized at rest. Provisioning SQL contains bcrypt hashes, never plaintext passwords. A managed service’s default user password is shown once and leaves only as hashes. The enrollment token is never written to the command line, disk, or logs. Keys live in Kubernetes Secrets or files with mode 0600.
Last modified on September 22, 2026