> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 管理数据库服务账号

> 本页介绍管理员如何添加数据库服务账号

数据库服务账号可以很简单，比如只是一个使用单独密码或证书进行身份验证的用户。较高级的用户可能希望设置此类账号，使其权限范围可通过 SET ROLE 动态调整，从而无需注销或重新加载内容，即可在不同 profile 之间快速切换。

<div id="overview">
  ## 概述
</div>

[SET ROLE](/docs/zh/reference/statements/set-role) 可用于在会话期间动态限定服务账号的权限范围。其原理是将用户的有效权限限制为仅限于已激活角色所授予的权限。这种方法有几个优点：

* 服务账号可以被分配多个角色，但只需激活特定查询所需的那个角色。
* 如果服务账号被攻破，攻击者也只能使用当前激活角色的权限。
* 单个账号可以通过切换角色来执行不同任务，而不必为每项任务分别使用单独的凭据。
* 只需修改一个角色，而无需逐个更新用户，即可为整类服务账号更新权限。
* 日志可以记录查询期间具体激活的是哪个角色，从而为安全审计提供更清晰的上下文。

在实践中，你需要：

1. 设计用于定义允许范围边界的角色 (如 read\_only、maintenance 等)
2. 将这些角色授予服务账号
3. 在建立连接时，通过 `SET ROLE` (或 role 参数) 选择激活的角色，从而限制该会话可执行的操作

<div id="setup-service-roles">
  ## 设置服务角色
</div>

<Steps>
  <Step title="将角色授予服务账号" id="grant-roles-to-service-account">
    首先，创建具有所需特权/设置的角色，然后将其授予服务账号。

    ```sql theme={null}
    CREATE ROLE read_only_role;
    GRANT SELECT ON db1.* TO read_only_role;

    CREATE ROLE maint_role;
    GRANT SELECT, INSERT, ALTER on db1.* TO maint_role;

    GRANT read_only_role, maint_role TO service_user;
    ```
  </Step>

  <Step title="使用 SET ROLE 定义权限边界" id="define-permission-boundaries">
    在会话开始时，服务账号可以选择激活哪些角色：

    ```sql theme={null}
    -- 此会话仅启用只读权限
    SET ROLE read_only_role;
    ```

    或：

    ```sql theme={null}
    -- 启用所有已授予角色（完整权限）
    SET ROLE ALL;
    ```

    `SET ROLE` 会为当前用户启用角色；生效的特权是所有激活角色特权的并集，再加上直接授予该用户的任何特权。

    你也可以禁用所有角色：

    ```sql theme={null}
    SET ROLE NONE;
    ```

    或启用多个角色：

    ```sql theme={null}
    SET ROLE read_only_role, maint_role;
    ```

    当前激活角色可通过 `system.current_roles` 查看。
  </Step>

  <Step title="为服务账号设置默认角色" id="set-default-role">
    为确保服务账号始终以受限模式启动，请配置默认角色：

    ```sql theme={null}
    SET DEFAULT ROLE read_only_role TO service_user;
    ```

    或

    ```sql theme={null}
    SET DEFAULT ROLE ALL EXCEPT maint_role TO service_user;
    ```
  </Step>

  <Step title="通过 HTTP / 以编程方式使用 SET ROLE" id="use-set-role-programmatically">
    如果服务账号通过 HTTP 连接，则不能将 SET ROLE; SELECT ... 作为多条语句发送。应改为将角色作为查询参数传递：

    ```shell theme={null}
    curl "https://host:8123?user=service_user&password=...&role=read_only_role" \
     --data-binary "SELECT * FROM db1.table1"
    ```

    `?role=`... 等同于在该语句之前执行 `SET ROLE read_only_role`。多个角色参数的行为类似于 `SET ROLE role 1, role 2`。

    一些驱动程序 (例如用于 Python 的 ClickHouse Connect) 也提供角色设置，并会随每个请求一并发送，服务器会将其用作会话角色。
  </Step>
</Steps>
