Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

Configuration

This page covers the configuration changes you are most likely to make after installing the ClickHouse Connector. For every key with its default and meaning, see the configuration reference; for command flags, see the CLI reference.

Configuration surfaces

The connector has one configuration surface per install target.

clicklink clctl init stages a values overlay named clicklink-values.yaml in the working directory and deploys the clicklink-connector chart with it. The overlay is the durable record of your deployment: re-running init keeps it unless you pass --force, so your edits survive re-runs and recovery.

Edit the overlay, then apply it:

CONNECTOR_NAMESPACE='clicklink'   # the connector namespace you chose at init
CHART_VERSION="$(helm get metadata clicklink-connector -n "${CONNECTOR_NAMESPACE}" | awk '/^VERSION:/{print $2}')"
helm upgrade clicklink-connector clicklink-connector \
  --repo https://releases.clicklink.clickhouse.com/charts \
  --version "${CHART_VERSION}" \
  --namespace "${CONNECTOR_NAMESPACE}" \
  -f clicklink-values.yaml

The block reapplies your edited values at the chart version already installed, so a configuration change never doubles as an unplanned upgrade; moving to a new version is a deliberate step covered in operations. On a mirrored install that uses a chart repository, swap --repo for your mirror.

An install from a direct chart reference (oci://, a URL, or a local archive or directory, see private mirrors) has no repository to resolve against. Rerun the upgrade with the reference you installed from:

helm upgrade clicklink-connector <same-chart-reference> \
  --version "${CHART_VERSION}" \
  -n "${CONNECTOR_NAMESPACE}" \
  -f clicklink-values.yaml

Adding or changing ClickHouse instances

Each entry under instances names a ClickHouse native-protocol endpoint the connector reads from: host, port, database, secure, plus namespace and cluster on Kubernetes. Credentials never live in the configuration; each component resolves its read-only ClickHouse user from the access bundle that provisioning creates.

Add the instance to both component maps in clicklink-values.yaml, and add its namespace to networkPolicy.clickhouseNamespaces (matched by the namespace’s kubernetes.io/metadata.name label):

scraper:
  instances:
    analytics:
      host: "clickhouse-analytics.clickhouse.svc.cluster.local"
      port: 9440
      database: "default"
      secure: true
      namespace: "clickhouse"
      cluster: "default"

troubleshooter:
  instances:
    analytics:
      host: "clickhouse-analytics.clickhouse.svc.cluster.local"
      port: 9440
      database: "default"
      secure: true
      namespace: "clickhouse"
      cluster: "default"

networkPolicy:
  clickhouseNamespaces:
    - "clickhouse"

Provision read-only access for each component from your workstation. --apply-ch-grants applies the generated ClickHouse grants in-pod via kubectl exec; without it the command creates the Kubernetes side only and leaves ch-grants.sql on disk for you to apply. When the admin user has a password, add --ch-admin-password-stdin and pipe it in.

CONNECTOR_NAMESPACE='clicklink'   # the connector namespace you chose at init
clicklink clctl scraper access provision --target helm \
  --target-namespace "${CONNECTOR_NAMESPACE}" \
  --instance analytics --instance-namespace clickhouse \
  --server <kubernetes-api-server-url> \
  --apply-ch-grants --ch-pod <clickhouse-pod-or-label-selector> --ch-pod-namespace clickhouse
clicklink clctl troubleshoot access provision --target helm \
  --target-namespace "${CONNECTOR_NAMESPACE}" \
  --instance analytics --instance-namespace clickhouse \
  --server <kubernetes-api-server-url> \
  --apply-ch-grants --ch-pod <clickhouse-pod-or-label-selector> --ch-pod-namespace clickhouse

For an operator-managed instance with no SQL-capable admin, swap --apply-ch-grants for --ch-user-via cr (the pod-selection flags stay); see the CLI reference. Then wire the Secret and ServiceAccount pair each command creates into the matching accessBundles map and run the helm upgrade shown above:

scraper:
  accessBundles:
    analytics:
      secretName: clicklink-connector-scraper-access-analytics
      serviceAccountName: pcm-scraper-analytics

troubleshooter:
  accessBundles:
    analytics:
      secretName: clicklink-connector-troubleshooter-access-analytics
      serviceAccountName: pcm-troubleshooter-analytics

Operator allowlist

Gateway-managed sessions are gated by an allowlist of operator email addresses: every request to the session gateway must carry a short-lived OIDC ID token whose attested email is on the list. An empty allowlist closes the gateway, so nobody can open a session through it. On a VM, root on the host can additionally manage sessions directly through the local session file; the allowlist governs the gateway path only. See support sessions for the full trust model.

The allowlist lives in the overlay and is rendered into a ConfigMap. To change it, edit the list and run helm upgrade:

clctl:
  gateway:
    enabled: true
    allowedOperators:
      - "oncall@example.com"
      - "dba@example.com"

Network policy and egress

On Kubernetes the chart ships a default-deny NetworkPolicy with an egress allowlist (networkPolicy.enabled: true). NetworkPolicy objects only take effect when your CNI enforces them; under an enforcing CNI the connector has no egress at all until allowEgressCIDRs names the CIDRs behind your connector API endpoint.

networkPolicy:
  enabled: true
  # CIDRs behind your connector API endpoint. Required under an enforcing CNI.
  allowEgressCIDRs:
    - "203.0.113.0/24"
  # Ports opened to allowEgressCIDRs.
  allowEgressPorts:
    - 443
  # Namespaces of your ClickHouse Services, matched by the
  # kubernetes.io/metadata.name label. Empty allows no in-cluster
  # ClickHouse access.
  clickhouseNamespaces:
    - "clickhouse"
  # Kubernetes API server CIDRs. On managed Kubernetes the API server sits
  # outside the cluster network, so it cannot be matched with a selector.
  apiserverCIDRs:
    - "172.16.0.0/28"

Two rules deserve special attention:

  • apiserverCIDRs: when empty, the chart emits no API server egress rule. The daemons then fail their first Kubernetes token request with a network error, which is the signal to set it. On managed Kubernetes, use the cluster’s API server endpoint CIDR(s).
  • clctl.gateway.jwksEgressCIDRs: when the session gateway is enabled, the troubleshooter fetches your identity provider’s JWKS to validate operator tokens. Under a default-deny posture, leaving this empty blocks every token check:
clctl:
  gateway:
    jwksEgressCIDRs:
      - "199.36.153.8/30"

The example is the private.googleapis.com range, which covers a Google identity provider reached over Private Google Access; for any other identity provider, supply that provider’s range (or the CIDR of the egress proxy that fronts it).

Two further ingress knobs: metricsScrapeSelector restricts metrics-scrape ingress to a specific Prometheus namespace by label, and kubeletProbeCIDRs admits kubelet health probes explicitly in environments with strict default-deny. See the configuration reference for the full key list.

Redaction patterns

Troubleshooter output is redacted before it leaves your boundary. Built-in patterns cover ipv4, ipv6, bearer-token, aws-access-key, email, jwt, ssh-private-key, and connection-string-credentials. You can add your own patterns in a YAML file; your patterns run first, in file order, then the built-ins, and an entry that reuses a built-in’s name replaces that built-in.

Each pattern takes name (required, unique), regex (required, Go RE2 syntax), replace (default [REDACTED], supports $1 capture references), and case_insensitive (default false):

version: 1
patterns:
  - name: internal-hostname
    regex: '\b[a-z0-9-]+\.corp\.example\.com\b'
    replace: '[REDACTED:internal-host]'

  # Reusing a built-in name replaces the built-in pattern.
  - name: ipv4
    regex: '\b(?:\d{1,3}\.){3}\d{1,3}\b'
    replace: '[REDACTED:ip]'

On a VM the file is /etc/clicklink/redaction-patterns.yaml; the installer lays down a commented default and preserves your version across upgrades. On Kubernetes, put the YAML in a ConfigMap under the key redaction-patterns.yaml and set troubleshooter.redaction.patternsConfigMap to its name; the chart mounts it at the same path.

Private mirrors and in-boundary endpoints

The published chart pre-sets image.repository to the public, multi-arch, cosign-signed connector image, so plain installs need no image values. To inspect the published defaults:

CLICKLINK_VERSION="$(curl -fsSL https://releases.clicklink.clickhouse.com/latest-version.txt)"
helm show values clicklink-connector \
  --repo https://releases.clicklink.clickhouse.com/charts \
  --version "${CLICKLINK_VERSION#v}"

To pull through your own registry, override the repository in the overlay:

image:
  repository: "registry.example.com/mirrors/clicklink"

To install the chart itself from a mirror, init accepts --chart as a chart name resolved in --chart-repo, or as a direct oci:// reference, URL, or local archive or directory. --chart-version defaults to the CLI’s own version so the binary and chart move together:

clicklink clctl init --handoff handoff.yaml --target helm \
  --chart oci://registry.example.com/charts/clicklink-connector

When your connector API endpoint sits behind a private CA inside your boundary, pass --api-private-ca to init: it stages api.tls.caFile: /etc/clicklink/secrets/mtls/ca.crt, so the endpoint is verified against the CA chain from your enrollment bundle instead of the system roots. On a VM the equivalent is api.tls.ca_file in /etc/clicklink/config.yaml; init installs the bundle chain at /etc/clicklink/tls/ca.crt, and it is added to the system roots for verification. For fully air-gapped enrollment and certificate signing, see onboarding.

Storage

The troubleshooter keeps its state on a PersistentVolumeClaim, so session state and the audit trail survive pod rescheduling:

persistence:
  enabled: true
  storageClass: "gp3"
  size: 5Gi

An empty storageClass uses the cluster’s default StorageClass. When the cluster marks no default, init requires one, via the prompt or --storage-class.

Navigation