Skip to content
Skillv1.0.0

clickhouse-enterprise-rbac

Configure ClickHouse enterprise RBAC — SQL-based users, roles, row policies, column-level grants, and quota management. Use when setting up multi-user access control, implementing tenant isolation, or

by jukeyman(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from jukeyman/jukeyman-skills (skills/saas-packs--clickhouse-pack--clickhouse-enterprise-rbac/SKILL.md). Install upstream with npx skills add jukeyman/jukeyman-skills --skill saas-packs--clickhouse-pack--clickhouse-enterprise-rbac. Copyright stays with the author (MIT).

ClickHouse Enterprise RBAC

Overview

Implement enterprise-grade role-based access control in ClickHouse using SQL-based user management, hierarchical roles, row-level policies, and quotas.

Prerequisites

  • ClickHouse with access_management = 1 enabled (default in Cloud)
  • Admin user with GRANT OPTION

Instructions

Step 1: Create Users with Authentication

-- SHA256 password (standard)
CREATE USER app_backend
    IDENTIFIED WITH sha256_password BY 'strong-password-here'
    DEFAULT DATABASE analytics
    HOST IP '10.0.0.0/8'           -- Restrict to VPC
    SETTINGS max_memory_usage = 10000000000,   -- 10GB per query
             max_execution_time = 60;          -- 60s timeout

-- Double SHA1 (MySQL wire protocol compatible)
CREATE USER legacy_app
    IDENTIFIED WITH double_sha1_password BY 'password'
    DEFAULT DATABASE analytics;

-- bcrypt (strongest, slowest — use for admin accounts)
CREATE USER admin_user
    IDENTIFIED WITH bcrypt_password BY 'admin-password';

-- Verify user was created
SHOW CREATE USER app_backend;
SELECT name, host_ip, default_database FROM system.users;

Step 2: Create Role Hierarchy

-- Base roles (leaf-level permissions)
CREATE ROLE data_reader;
GRANT SELECT ON analytics.* TO data_reader;

CREATE ROLE data_writer;
GRANT INSERT ON analytics.* TO data_writer;

CREATE ROLE schema_manager;
GRANT CREATE TABLE, ALTER TABLE, DROP TABLE ON analytics.* TO schema_manager;

-- Composite roles (inherit from base roles)
CREATE ROLE analyst;
GRANT data_reader TO analyst;
-- Analysts can also create temporary tables for ad-hoc work
GRANT CREATE TEMPORARY TABLE ON *.* TO analyst;

CREATE ROLE developer;
GRANT data_reader, data_writer TO developer;

CREATE ROLE platform_admin;
GRANT data_reader, data_writer, schema_manager TO platform_admin;
GRANT SYSTEM RELOAD, SYSTEM FLUSH LOGS ON *.* TO platform_admin;

-- Assign roles to users
GRANT analyst TO app_backend;         -- Read-only
GRANT developer TO app_backend;       -- Read + write
GRANT platform_admin TO admin_user;   -- Full access

-- Set default role (active when user connects)
SET DEFAULT ROLE developer TO app_backend;

-- Verify the full permission chain
SHOW GRANTS FOR app_backend;
SHOW ACCESS;  -- All users, roles, policies

Step 3: Row-Level Security

-- Multi-tenant isolation: each user sees only their tenant's data
CREATE USER tenant_acme
    IDENTIFIED WITH sha256_password BY 'pass'
    DEFAULT DATABASE analytics;

CREATE USER tenant_globex
    IDENTIFIED WITH sha256_password BY 'pass'
    DEFAULT DATABASE analytics;

-- Row policy: restrict by tenant_id
CREATE ROW POLICY acme_isolation ON analytics.events
    FOR SELECT
    USING tenant_id = 1
    TO tenant_acme;

CREATE ROW POLICY globex_isolation ON analytics.events
    FOR SELECT
    USING tenant_id = 2
    TO tenant_globex;

-- Admin sees all rows (permissive policy)
CREATE ROW POLICY admin_all ON analytics.events
    FOR SELECT
    USING 1 = 1                     -- No filter
    TO platform_admin;

-- Verify: this user only sees tenant_id = 1
-- (connect as tenant_acme)
SELECT tenant_id, count() FROM analytics.events GROUP BY tenant_id;
-- Returns only rows where tenant_id = 1

-- List all row policies
SELECT * FROM system.row_policies;

Step 4: Column-Level Grants

-- Grant SELECT on specific columns only (hide PII)
GRANT SELECT(event_id, event_type, created_at) ON analytics.events TO analyst;
-- Analyst cannot SELECT email, user_id, ip_address

-- Grant INSERT on specific columns (prevent metadata injection)
GRANT INSERT(event_type, user_id, properties) ON analytics.events TO data_writer;

-- Verify column-level grants
SHOW GRANTS FOR analyst;

Step 5: Quotas (Resource Limits per User)

-- Limit query resources per time interval
CREATE QUOTA analyst_quota
    FOR INTERVAL 1 HOUR
        MAX queries = 1000,
        MAX result_rows = 10000000,        -- 10M result rows
        MAX read_rows = 1000000000,        -- 1B rows read
        MAX execution_time = 1800          -- 30 minutes total
    FOR INTERVAL 1 DAY
        MAX queries = 10000,
        MAX read_rows = 10000000000
    TO analyst;

-- Check quota usage
SELECT
    quota_name, quota_key,
    interval_duration,
    queries, max_queries,
    result_rows, max_result_rows,
    round(queries / max_queries * 100, 1) AS usage_pct
FROM system.quota_usage;

-- Override quota for specific user
CREATE QUOTA power_user_quota
    FOR INTERVAL 1 HOUR MAX queries = 10000
    TO developer;

Step 6: Settings Profiles

-- Create a restrictive profile for external analysts
CREATE SETTINGS PROFILE analyst_profile
    SETTINGS
        readonly = 1,                            -- Read-only mode
        max_memory_usage = 5000000000 MIN 0 MAX 10000000000,  -- 5GB, can request up to 10GB
        max_execution_time = 120,                -- 2 min timeout
        max_threads = 4,                         -- 4 threads per query
        max_result_rows = 1000000,               -- 1M result rows
        max_concurrent_queries_for_user = 5,     -- 5 parallel queries
        use_uncompressed_cache = 0               -- Don't pollute cache
    TO analyst;

-- Create a profile for ETL / ingestion users
CREATE SETTINGS PROFILE writer_profile
    SETTINGS
        max_memory_usage = 10000000000,
        max_execution_time = 300,
        max_insert_block_size = 1000000,
        async_insert = 1,
        async_insert_busy_timeout_ms = 5000
    TO developer;

Step 7: Application-Level RBAC Wrapper

import { createClient } from '@clickhouse/client';

// Create per-role clients
function createRoleClient(role: 'reader' | 'writer' | 'admin') {
  const credentials = {
    reader: { user: 'app_reader', pass: process.env.CH_READER_PASS! },
    writer: { user: 'app_writer', pass: process.env.CH_WRITER_PASS! },
    admin:  { user: 'app_admin',  pass: process.env.CH_ADMIN_PASS! },
  };

  const cred = credentials[role];
  return createClient({
    url: process.env.CLICKHOUSE_HOST!,
    username: cred.user,
    password: cred.pass,
  });
}

// Use the appropriate client for each operation
const readerClient = createRoleClient('reader');
const writerClient = createRoleClient('writer');

// Read operations use the reader client
async function queryEvents() {
  return readerClient.query({ query: 'SELECT * FROM events LIMIT 100', format: 'JSONEachRow' });
}

// Write operations use the writer client
async function insertEvents(events: Record<string, unknown>[]) {
  return writerClient.insert({ table: 'events', values: events, format: 'JSONEachRow' });
}

Access Control Audit

-- Who has access to what?
SELECT
    user_name, role_name, granted_role_name,
    access_type, database, table, column
FROM system.grants
ORDER BY user_name, role_name;

-- Track authentication failures
SELECT event_time, user, client_hostname, exception
FROM system.query_log
WHERE exception_code = 516  -- AUTHENTICATION_FAILED
ORDER BY event_time DESC
LIMIT 20;

-- Track privilege denials
SELECT event_time, user, exception, substring(query, 1, 200)
FROM system.query_log
WHERE exception_code = 497  -- ACCESS_DENIED
ORDER BY event_time DESC
LIMIT 20;

Error Handling

Error Code Name Solution
497 ACCESS_DENIED SHOW GRANTS FOR user, add missing GRANT
516 AUTHENTICATION_FAILED Verify password, check HOST restriction
164 READONLY User has readonly=1, grant write if needed
497 Not enough privileges to execute GRANT Use admin user with GRANT OPTION

Resources

Next Steps

For schema migrations, see clickhouse-migration-deep-dive.

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/jukeyman-jukeyman-skills-saas-packs-clickhouse-pack-clic-793013/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

jukeyman-jukeyman-skills-saas-packs-clickhouse-pack-clic-793013.ocm.jsonjson
{
  "ocm": "1",
  "id": "jukeyman-jukeyman-skills-saas-packs-clickhouse-pack-clic-793013",
  "kind": "skill",
  "name": "clickhouse-enterprise-rbac",
  "description": "Configure ClickHouse enterprise RBAC — SQL-based users, roles, row policies, column-level grants, and quota management. Use when setting up multi-user access control, implementing tenant isolation, or configuring enterprise security for ClickHouse. Trigger: \"clickhouse RBAC\", \"clickhouse roles\", \"clickhouse permissions\", \"clickhouse row policy\", \"clickhouse enterprise access\", \"clickhouse GRANT\".",
  "publisher": "jukeyman",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding",
      "data_analysis"
    ],
    "tags": [
      "skill-md",
      "saas",
      "database",
      "analytics",
      "clickhouse",
      "olap",
      "github"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Configure ClickHouse enterprise RBAC — SQL-based users, roles, row policies, column-level grants, and quota management. Use when setting up multi-user access control, implementing tenant isolation, or configuring enterprise security for ClickHouse. Trigger: \"clickhouse RBAC\", \"clickhouse roles\", \"clickhouse permissions\", \"clickhouse row policy\", \"clickhouse enterprise access\", \"clickhouse GRANT\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "github",
      "repository": "https://github.com/jukeyman/jukeyman-skills",
      "path": "skills/saas-packs--clickhouse-pack--clickhouse-enterprise-rbac/SKILL.md",
      "ref": "99825ad3f3bcc6597ddcc7294a14e6e922f2b67b",
      "url": "https://github.com/jukeyman/jukeyman-skills/blob/99825ad3f3bcc6597ddcc7294a14e6e922f2b67b/skills/saas-packs--clickhouse-pack--clickhouse-enterprise-rbac/SKILL.md",
      "key": "jukeyman/jukeyman-skills/skills/saas-packs--clickhouse-pack--clickhouse-enterprise-rbac/SKILL.md"
    },
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit"
    ],
    "license": "MIT"
  },
  "instructions": "# ClickHouse Enterprise RBAC\n\n## Overview\n\nImplement enterprise-grade role-based access control in ClickHouse using SQL-based\nuser management, hierarchical roles, row-level policies, and quotas.\n\n## Prerequisites\n\n- ClickHouse with `access_management = 1` enabled (default in Cloud)\n- Admin user with `GRANT OPTION`\n\n## Instructions\n\n### Step 1: Create Users with Authentication\n\n```sql\n-- SHA256 password (standard)\nCREATE USER app_backend\n    IDENTIFIED WITH sha256_password BY 'strong-password-here'\n    DEFAULT DATABASE analytics\n    HOST IP '10.0.0.0/8'           -- Restrict to VPC\n    SETTINGS",
  "cost": {
    "context_tokens": 2020
  }
}

Fetch it by URL: GET /api/v1/registry/jukeyman-jukeyman-skills-saas-packs-clickhouse-pack-clic-793013/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.