GRANT in ClickHouse

ClickHouse e' un potente Columnar Database SQL, Open Source con ottime prestazioni sulle attivita' OLAP (On-Line Analytical Processing).
In questa pagina descriviamo i comandi RBAC (role-based access control) ovvero i comandi di sicurezza che definiscono gli accessi agli oggetti del database da parte degli utenti e dei ruoli.
In effetti il titolo esatto di questa pagina avrebbe dovuto essere RBAC con ClickHouse, ma poiche' la clausola SQL piu' importante e' il GRANT abbiamo utilizzato questo titolo ed in effetti non e' l'unica liberta' che ci siamo concessi :)

Questa pagina si riferisce alla versione 20.2 o successive di ClickHouse perche' in tale versione sono stati inserite le clausole SQL di GRANT e REVOKE. Ma conviene anche controllare cosa e' disponibile dalla versione 20.4: continuate a leggere...

Ho fretta!

Vediamo un semplice esempio che presenta le principali clausole SQL:

:) CREATE USER scott IDENTIFIED BY 'tiger'; CREATE USER scott IDENTIFIED WITH sha256_hash BY 'F1...69' Ok. :) GRANT show ON demo.* TO scott; :) GRANT select ON demo.* TO scott; :) GRANT select ON sample.emp TO scott; Ok. :) SHOW GRANTS FOR scott; ┌─GRANTS FOR scott────────────────────┐ │ GRANT SELECT ON demo.* TO scott │ │ GRANT SELECT ON sample.emp TO scott │ └─────────────────────────────────────┘ ^D clickhouse-client --user=scott --ask-password :) SELECT count(*) from sample.emp; ┌─count()─┐ │ 17 │ └─────────┘ :) SELECT count(*) from sample.dept; Received exception from server (version 20.2.69): Code: 497. DB::Exception: Received from localhost:9000. DB::Exception: scott: Not enough privileges. To execute this query it's necessary to have the grant SELECT(deptno, deptname, ...) ON sample.dept.

Tutto chiaro, vero?

Abbiamo creato un utente e gli abbiamo assegnato alcuni GRANT, quindi ci siamo connessi con il nuovo utente. Risultano visibili solo i database su cui sono stati assegnati i GRANT corretti ma gli accessi alle tabelle singole sono comunque permessi purche' correttamente autorizzati. Naturalmente se si accede ad un oggetto verso il quale non si hanno sufficienti privilegi ClickHouse restituisce un errore.

La sintassi ricorda quella MySQL (eg. SHOW GRANTS) anche se sono presenti differenze...
Nel seguito vedremo con maggior dettaglio le clausole SQL disponibili in ClickHouse.

Utenti

Gli utenti vengono definti con uno specifico statement DCL:

CREATE USER [IF NOT EXISTS | OR REPLACE] name
       [IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}]
       [HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
       [DEFAULT ROLE role [,...]]
       [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]

Naturalmente sono presenti un analogo comando di ALTER USER ed il comando di DROP USER.

La password puo' essere indicata in chiaro o crittografata. In ogni caso verra' memorizzata in forma crittografata. L'hash si ottiene con:
 echo -n "MyPass" | sha256sum | tr -d '-'
 echo -n "MyPass" | sha1sum | tr -d '-'| xxd -r -p | sha1sum | tr -d '-'

E' possibile limitare l'accesso di un utente a seconda della provenienza impostando la clausola HOST.

La modalita' classica in ClickHouse per definire le utenze era quella di configurarle nel file /etc/clickhouse-server/users.xml indicando il nome dell'utente, la password, l'assegnazione di un profilo (eg. default, readonly) ed eventualmente l'allow_databases per limitare l'accesso ad alcuni database.

L'RBAC implementato con i GRANT e' molto piu' flessibile della modalita' precedente su ClickHouse oltre ad essere uno standard SQL.

Autorizzazioni

Agli utenti vengono assegnate o revocate specifiche autorizzazioni con le clausole:

GRANT access_type[(column_name [,...])]  ON {db.table|db.*|*.*|table|*} TO user_name  [WITH GRANT OPTION]
REVOKE access_type[(column_name [,...])]  ON {db.table|db.*|*.*|table|*} FROM user_name

I privilegi assegnabili (access_type) sono molto dettagliati, vediamo i principali. NONE, ALL assegnano nessuno o tutti i diritti; SELECT, INSERT consentono di selezionare ed inserire dati in una tabella/colonna; UPDATE, DELETE sono leggermente differenti in ClickHouse poiche' non sono DML ma DDL; CREATE_TABLE, ADD_COLUMN, COMMENT_COLUMN sono alcuni dei molti GRANT per la creazione della struttura del database; CREATE_USER, SHUTDOWN, STOP_MERGES, RESTART_REPLICA sono alcune delle molte funzioni di amministrazione che e' possibile controllare...

Alcuni privilegi sono particolari: per eseguire una USE e' necessario il grant di SHOW; per eseguire una RENAME sono necessari: SELECT, CREATE TABLE, INSERT e DROP TABLE!

Per i piu' curiosi la sintassi completa e tutti gli access_type (cfr. codice sorgente)...

GRANT access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} TO {user_name | CURRENT_USER} [,...] [WITH GRANT OPTION]
REVOKE access_type[(column_name [,...])] [,...] ON {db.table|db.*|*.*|table|*} FROM {user_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | CURRENT_USER} [,...]

Access Type:
    NONE,  /// no access
    ALL,   /// full access

    SHOW_DATABASES,    /// allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE <database>
    SHOW_TABLES,       /// allows to execute SHOW TABLES, EXISTS <table>, CHECK <table>
    SHOW_COLUMNS,      /// allows to execute SHOW CREATE TABLE, DESCRIBE
    SHOW_DICTIONARIES, /// allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS <dictionary>
    SHOW,              /// allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE

    SELECT,
    INSERT,
    UPDATE,  /// allows to execute ALTER UPDATE
    DELETE,  /// allows to execute ALTER DELETE

    ADD_COLUMN,
    DROP_COLUMN,
    MODIFY_COLUMN,
    COMMENT_COLUMN,
    CLEAR_COLUMN,
    ALTER_COLUMN,       /// allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN

    ALTER_ORDER_BY,
    ADD_INDEX,
    DROP_INDEX,
    MATERIALIZE_INDEX,
    CLEAR_INDEX,
    INDEX,              /// allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX

    ADD_CONSTRAINT,
    DROP_CONSTRAINT,
    ALTER_CONSTRAINT,   /// allows to execute ALTER {ADD|DROP} CONSTRAINT

    MODIFY_TTL,          /// allows to execute ALTER MODIFY TTL
    MATERIALIZE_TTL,     /// allows to execute ALTER MATERIALIZE TTL
    MODIFY_SETTING,      /// allows to execute ALTER MODIFY SETTING

    MOVE_PARTITION,
    FETCH_PARTITION,
    FREEZE_PARTITION,

    ALTER_TABLE,        /// allows to execute ALTER TABLE ...

    REFRESH_VIEW,       /// allows to execute ALTER LIVE VIEW REFRESH
    MODIFY_VIEW_QUERY,  /// allows to execute ALTER TABLE MODIFY QUERY
    ALTER_VIEW,         /// allows to execute ALTER LIVE VIEW REFRESH, ALTER TABLE MODIFY QUERY

    ALTER,              /// allows to execute ALTER {TABLE|LIVE VIEW} ...

    CREATE_DATABASE,        /// allows to execute {CREATE|ATTACH} DATABASE
    CREATE_TABLE,           /// allows to execute {CREATE|ATTACH} TABLE
    CREATE_VIEW,            /// allows to execute {CREATE|ATTACH} VIEW
    CREATE_DICTIONARY,      /// allows to execute {CREATE|ATTACH} DICTIONARY
    CREATE_TEMPORARY_TABLE, /// allows to create and manipulate temporary tables and views.
    CREATE,                 /// allows to execute {CREATE|ATTACH} [TEMPORARY] {DATABASE|TABLE|VIEW|DICTIONARY}

    DROP_DATABASE,
    DROP_TABLE,
    DROP_VIEW,
    DROP_DICTIONARY,
    DROP,               /// allows to execute DROP {DATABASE|TABLE|VIEW|DICTIONARY}

    TRUNCATE_TABLE,
    TRUNCATE_VIEW,
    TRUNCATE,           /// allows to execute TRUNCATE {TABLE|VIEW}
    OPTIMIZE,           /// allows to execute OPTIMIZE TABLE
    KILL_QUERY,         /// allows to kill a query started by another user (anyone can kill his own queries)

    CREATE_USER,
    ALTER_USER,
    DROP_USER,
    CREATE_ROLE,
    ALTER_ROLE,
    DROP_ROLE,
    CREATE_POLICY,
    ALTER_POLICY,
    DROP_POLICY,
    CREATE_QUOTA,
    ALTER_QUOTA,
    DROP_QUOTA,
    CREATE_SETTINGS_PROFILE,
    ALTER_SETTINGS_PROFILE,
    DROP_SETTINGS_PROFILE,

    ROLE_ADMIN,         /// allows to grant and revoke any roles.

    SYSTEM,                  /// allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...}
    SHUTDOWN,
    DROP_CACHE,
    RELOAD_CONFIG,
    RELOAD_DICTIONARY,
    STOP_MERGES,
    STOP_TTL_MERGES,
    STOP_FETCHES,
    STOP_MOVES,
    STOP_DISTRIBUTED_SENDS,
    STOP_REPLICATED_SENDS,
    STOP_REPLICATION_QUEUES,
    SYNC_REPLICA,
    RESTART_REPLICA,
    FLUSH_DISTRIBUTED,
    FLUSH_LOGS,

    dictGet,                 /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
    dictHas,                 /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
    dictGetHierarchy,        /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
    dictIsIn,                /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn

    addressToLine,           /// allows to execute function addressToLine
    addressToSymbol,         /// allows to execute function addressToSymbol
    demangle,                /// allows to execute function demangle
    INTROSPECTION,           /// allows to execute functions addressToLine, addressToSymbol, demangle

    TABLE_FUNCTIONS,  /// allows to execute any table function
    file,
    url,
    input,
    values,
    numbers,
    zeros,
    merge,
    remote,
    mysql,
    odbc,
    jdbc,
    hdfs,
    s3,

[NdA link alla documentazione ufficiale]

Ruoli

I ruoli consentono una gestione a gruppi dei privilegi degli utenti. Vengono creati con un comando simile

CREATE ROLE [IF NOT EXISTS | OR REPLACE] name
       [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]

SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]

GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION]
REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]

La gestione dei ruoli rende molto flessibile l'assegnazione e la revoca dei GRANT. E' per esempio possibile definire ruoli per funzioni specifiche (operatore, backup, monitoraggio, applicazione, power user, ...) con definizioni anche molto complesse ed assegnarli agli utenti in modo molto semplice.

Profili e settings

Un utente ClickHouse ha sempre un profile. Il profilo di default (che e' fantasiosamente 'default') e' tipicamente molto libero ma e' possibile creare profile per definire un insieme molto ampio di impostazioni (setting) [NdA anzi gli insiemi sono due].

Con l'impostazione di un profilo e' possibile limitare la complessita' delle richieste sulle singole query per ogni tipologia di utente.

Quota

Per default il quota registra solo l'utilizzo di risorse (eg. durata) per un'ora senza limitarne l'utilizzo. E' tuttavia possibile definire un periodo di tempo diverso e limiti per risorsa.
Le risorse possono essere:

Le clausole SQL sono:

SHOW QUOTAS
SHOW QUOTA USAGE [CURRENT | ALL]

Policy

Le ROW POLICY consentono di limitare gli accessi ai dati agli utenti.

Si tratta di una funzionalita' specifica di ClickHouse (anche se vi sono implementazioni simili in altri database quali Virtual Private Database, Label Security, Data Redaction, ...) che permette di limitare la visibilita' dei dati a seconda degli utenti che vengono utilizzati.

CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
       [AS {PERMISSIVE | RESTRICTIVE}]
       [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
       [USING condition]
       [WITH CHECK condition] [,...]
       [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]

Data Dictionary

In ClickHouse e' disponibile un completo Data Dictionary, nel database system, che contiene gli oggetti definiti (eg. tables, columns, parts), le attivita' (eg. processes, merges), ...
L'accesso in lettura al database system e' disponibile per tutti gli utenti.

Per quanto riguarda l'RBAC... continuate a leggere!

April the 1st

Questo documento e' stato pubblicato il 1 Aprile... L'RBAC non e' documentato, il ChangeLog non lo riporta, solo la Roadmap lo prevede (ed in effetti lo fa da un po').

I GRANT non esistono! ... pero' funzionano gia'.
Lo so perche' li ho trovati ravanando (perdonate l'inglesismo :) nel codice, ovviamente li ho provati e quindi li ho documentati in questa paginetta.
C'e' solo un piccolo difetto. Vengono eseguiti in memoria da ClickHouse e mantenuti a sistema attivo: se si effettua un riavvio si perde tutto. Se si cerca di modificare i privilegi ad un utente definito in modo classico nel file users.xml viene restituito l'errore:

:) GRANT SELECT ON sample.* TO smith Received exception from server (version 20.2.69): Code: 495. DB::Exception: Received from localhost:9000. DB::Exception: Cannot update User `smith` in users.xml because this storage is readonly.

E' il 1 Aprile... era l'unico modo per pubblicare per primo un articolo su questo argomento :)

Grants!

Jokes are only funny for a while! ClickHouse 20.4 with RBAC available now (2020-05-12).

Da oggi sono disponibili i GRANT in modo permanente e non solo in memoria. Ora l'RBAC e' documentato, utilizzabile e consigliato!

Dalla versione 20.4 e' disponibile sia la modalita' classica di configurazione degli utenti che quella basata sui GRANT. Per abilitare questa seconda modalita' di gestione e' sufficiente impostare access_management=1 su almeno un utente definito nel file users.xml (eg. default o un'utenza amministrativa):

<default> ... <!-- User can create other users and grant rights to them. --> <access_management>1</access_management> </default>

Se ClickHouse era gia' installato e' possibile che non sia presente il path dove sono appoggiate le definizioni che va configurato nel file config.xml:

<access_control_path>/var/lib/clickhouse/access/</access_control_path>

Ora e' possibile creare gli utenti, concedere GRANT, definire un nuovo superuser con:
 GRANT ALL ON *.* WITH GRANT OPTION TO root; ...

Buon divertimento!

Varie ed eventuali

Il documento Introduzione a ClickHouse contiene una presentazione sulle funzioni di base, il documento Architettura ClickHouse riporta i principali aspetti dell'architettura mentre DBA scripts contiene alcuni dei comandi piu' utili per il DBA.

Sono certo che l'RBAC sara' disponibile in una versione stable e documentato molto presto!
[NdE in effetti e' passato poco piu' di un mese ed ora la versione 20.4 supporta i GRANT in modo completo]


Titolo: GRANT in ClickHouse
Livello: Medio (2/5)
Data: 1 Aprile 2020 🐟
Versione: 1.0.1 - 12 Maggio 2020
© Autore: mail [AT] meo.bogliolo.name