, ,

Zero Trust for ClickHouse: Securing Pod Access with Kubernetes RBAC and Keycloak OIDC

Gayathri avatar
Zero Trust for ClickHouse: Securing Pod Access with Kubernetes RBAC and Keycloak OIDC

ClickHouse Kubernetes RBAC with Keycloak provides a secure, identity-driven way to control access to ClickHouse pods in Kubernetes. By combining Keycloak OIDC authentication with Kubernetes RBAC, teams can enforce least-privilege access and follow Zero Trust security principles.

1. Introduction

In Kubernetes environments, databases like ClickHouse are often the backbone of analytical workloads. While Kubernetes simplifies deployment, controlling operational access regarding who can actually execute into a pod or view logs is frequently overlooked.

By default, Kubernetes access often relies on static kubeconfig files. This lacks centralized management and identity-based control. In this guide, we will implement a professional-grade security layer using:

  • Keycloak: For centralized OpenID Connect (OIDC) authentication.
  • Kubernetes RBAC: For fine-grained authorization.
  • Minikube: To simulate a local production-like environment.

2. What We Are Building

We are establishing a “Zero Trust” approach for platform engineers and DBAs.

The Goal:

  • Authenticate via Keycloak (Identity Provider).
  • Authorize via Kubernetes RBAC (Role-Based Access Control).
  • Restrict Access: Only users in the clickhouse-admins group can access ClickHouse pods in the analytics namespace.

Note: This guide covers Infrastructure Access (Kubernetes level). It does not cover ClickHouse SQL-level users or query permissions.

3. Architecture Overview

The flow follows the standard OIDC integration pattern:

  1. User initiates login via the kubectl oidc-login plugin.
  2. Keycloak authenticates the user and issues an ID Token containing group membership.
  3. Kubernetes API Server validates the token using Keycloak’s public key.
  4. RBAC checks if the user’s group has a RoleBinding to perform actions on ClickHouse pods.

4. Environment and Prerequisites

This setup was implemented on a local Kubernetes environment to demonstrate secure, production-aligned access control.

Environment

  • Operating System: Linux
  • Kubernetes Cluster: Minikube (local single-node cluster)
  • Container Runtime: Docker
  • Database: ClickHouse (deployed as a Kubernetes pod)
  • Identity Provider: Keycloak
  • Authentication Protocol: OpenID Connect (OIDC)

Required Tools

  • Minikube for running a local Kubernetes cluster
  • kubectl for interacting with the Kubernetes API
  • Docker for container image management

Starting the Kubernetes Cluster

Before deploying any components, ensure that the Minikube cluster is running:

minikube start --driver=kvm2 --kubernetes-version=v1.33.0

Verify the cluster:

kubectl get nodes

After the cluster is ready, ClickHouse and Keycloak can be deployed and configured.

5. Deploying ClickHouse on Kubernetes

Create a dedicated namespace for analytics:

kubectl create namespace analytics

Deploy ClickHouse using a Kubernetes manifest:

kubectl apply -f clickhouse.yaml

Clickhouse.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: clickhouse
  namespace: analytics
spec:
  replicas: 1
  selector:
    matchLabels:
      app: clickhouse
  template:
    metadata:
      labels:
        app: clickhouse
    spec:
      containers:
      - name: clickhouse
        image: clickhouse/clickhouse-server:latest
        ports:
        - containerPort: 8123
        - containerPort: 9000

Note: For production environments, ClickHouse should typically run as a StatefulSet with persistent volumes. A Deployment is used here for simplicity.

Verify that the pod is running:

kubectl -n analytics get pods

6. Deploying Keycloak on Kubernetes

Create a namespace for Keycloak and run the pod:

kubectl create namespace keycloak

kubectl -n keycloak run keycloak \
  --image=quay.io/keycloak/keycloak:26.5.1 \
  --env=KEYCLOAK_ADMIN=admin \
  --env=KEYCLOAK_ADMIN_PASSWORD=admin123 \
  --port=8080 \
  --command -- start-dev

Expose and port-forward the service:

kubectl -n keycloak expose pod keycloak --port=8080
kubectl -n keycloak port-forward svc/keycloak 8081:8080

Access the Keycloak console at: http://localhost:8081

Screenshot: Keycloak login page

7. Configuring Keycloak for Kubernetes Authentication

7.1 Creating a Realm

Create a new realm named k8s. This realm is dedicated to Kubernetes authentication.

7.2 Creating a Kubernetes Client

Create a client with:

  • Client ID: kubernetes
  • Client authentication: Off
  • Standard Flow: On
  • Direct Access Grants: On
  • Valid Redirect URIs: http://localhost/* and http://127.0.0.1/*

The client does not require a secret because kubectl acts as a public OIDC client.

7.3 Creating Groups and Users

Create a group: Name it clickhouse-admins.

Create User: Create user gayathri, set a password, and join the clickhouse-admins group.

Screenshot: Create user and Set a password for user credential.

8. Configuring Kubernetes RBAC for ClickHouse

8.1 Defining the RBAC Role

Create a role scoped to the analytics namespace that allows controlled access to ClickHouse pods.

clickhouse-admin-role.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: clickhouse-admin
  namespace: analytics
rules:
- apiGroups: [""]
  resources:
    - pods
  verbs:
    - get
    - list
    - watch

- apiGroups: [""]
  resources:
    - pods/log
  verbs:
    - get

- apiGroups: [""]
  resources:
    - pods/exec
  verbs:
    - create
    - get

Apply the role:

kubectl apply -f clickhouse-admin-role.yaml

8.2 Binding Keycloak Groups to RBAC

Bind the Keycloak group to the Kubernetes role:

clickhouse-admin-binding.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: clickhouse-admins-binding
  namespace: analytics
subjects:
- kind: Group
  name: clickhouse-admins
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: clickhouse-admin
  apiGroup: rbac.authorization.k8s.io

Apply the binding:

kubectl apply -f clickhouse-admin-binding.yaml

9. Authenticating to Kubernetes Using Keycloak

Install the OIDC login plugin and authenticate via the browser:

kubectl krew install oidc-login

kubectl oidc-login get-token \
  --oidc-issuer-url=http://localhost:8081/realms/k8s \
  --oidc-client-id=kubernetes

After successful authentication, kubectl uses the OIDC token for subsequent API requests.

Screenshot: “Authenticated” confirmation page

10. Verifying Access Control

Authorized User (Positive Scenario)

Check permissions for the user in the correct group:

kubectl auth can-i create pods/exec -n analytics \
  --as=gayathri \
  --as-group=clickhouse-admins

Output: yes

Access ClickHouse:

kubectl -n analytics exec -it clickhouse-  -- bash

Screenshot: Successful exec into ClickHouse pod

Unauthorized User (Negative Scenarios)

User not authenticated:

kubectl auth can-i create pods/exec -n analytics \
  --as=unauthorized-user

Output: no

Authenticated user without correct group:

kubectl auth can-i create pods/exec -n analytics \
  --as=gayathri \
  --as-group=developers

Output: no

11. Final Thoughts on ClickHouse Kubernetes RBAC

With this setup:

  • Authentication is centralized via Keycloak
  • Authorization is enforced using Kubernetes RBAC
  • ClickHouse pod access is fully identity-driven
  • Static kubeconfigs and shared credentials are eliminated

This Zero Trust for ClickHouse approach aligns with modern platform security standards and scales cleanly across teams.

Conclusion

This hands-on implementation demonstrates how centralized identity management can be effectively integrated with Kubernetes to secure ClickHouse operations. By combining Keycloak-based authentication with Kubernetes RBAC authorization, teams can enforce least-privilege access, simplify operational workflows, and strengthen overall security posture.

Although this guide focuses on ClickHouse, the same architecture applies to any Kubernetes-hosted database or sensitive service that requires controlled, identity-driven access.

References