# 如何用内置的认证与授权保护 Manticore Search

了解如何启用 Manticore 认证、创建第一位管理员、创建最小权限用户、使用 SQL 与 HTTP 凭据，并验证允许与拒绝的访问。

搜索常常被当作基础设施来对待。但在生产环境里，它更像一个应用 API：接收用户流量、暴露业务数据、支撑仪表盘，而且常常紧挨着那些不该对网络上所有客户端开放的记录。

自 [27.1.5](http://localhost:1313/blog/manticore-search-27-1-5/) 版本起，Manticore Search 现在已为通过 MySQL 协议的 SQL、HTTP/HTTPS 端点以及与复制相关的操作内置了认证和授权。

认证回答“是谁在调用”，授权回答“这个用户能做什么”。

已经在使用 Manticore 的用户可以在保持熟悉工作流不变的情况下使用这些新功能。现有的 SQL 和 HTTP 客户端仍然保留原有的连接方式。应用程序只需要做很少的改动。

## Manticore 新增的内容

- 使用 `mysql_native_password` 的 SQL/MySQL 密码认证。
- 使用相同用户名和密码的 HTTP Basic 认证。
- HTTP Bearer token，适合不希望每次请求都发送密码的客户端。
- 五种清晰的权限：`read`、`write`、`schema`、`replication` 和 `admin`。
- 目标对象，例如 `products`、`logs_*`、`posts` 和 `*`。
- 用于管理用户、token 和权限的 SQL 命令。
- 认证日志，级别包括 `disabled`、`error`、`warning`、`info`、`all` 和 `trace`，默认是 `info`。

这个访问模型有意设计得很小。你只需创建用户，授予他们所需的操作权限，更新应用以发送凭据，并测试被拒绝的操作确实会被拒绝。

## 启用认证

认证由 `searchd` 段中的 `auth` 设置控制。

在 [RT 模式](https://manual.manticoresearch.com/Read_this_first#Real-time-mode-vs-plain-mode) 中，使用 `auth = 1`。Manticore 会将认证数据存储在 `data_dir` 下的 `auth.json` 中。

```ini
searchd {
    data_dir = /var/lib/manticore
    auth = 1
    auth_log_level = info
}
```

要在 RT 模式下显式关闭认证，使用 `auth = 0` 或移除该设置。

在 plain 模式下，把 `auth` 设为认证文件的路径：

```ini
searchd {
    auth = /var/lib/manticore/auth.json
    auth_log_level = info
}
```

当密码或 bearer token 需要跨网络传输时，SQL 连接请使用 SSL，HTTP 客户端请使用 HTTPS。

认证文件要保管好，不要让无关人员读取。在首次引导之前，Manticore 可能会创建一个空的认证文件；引导完成后，该文件会存放认证数据和凭据哈希。

## 创建第一位管理员

启用 `auth` 之后，启动 `searchd`，再用同一个配置文件创建第一位管理员：

```bash
searchd --config /etc/manticoresearch/manticore.conf --auth
```

自动化场景下，使用非交互式引导模式：

```bash
printf 'admin\nStrongPass#2026\nStrongPass#2026\n' | \
  searchd --config /etc/manticoresearch/manticore.conf --auth-non-interactive
```

引导需要一个正在运行的守护进程。它会创建第一个管理员并授予该用户所有操作权限。

引导过程不会返回 bearer token。如果管理员用户需要 HTTP Bearer 访问权限，请以该管理员身份连接后执行 `TOKEN`，或者调用 HTTP 的 `POST /token` 端点。

## 创建用户

初始化管理员后，你可以用这个账号通过 SQL 命令管理用户和权限。不过，不要在应用程序中使用它。相反，应为特定任务创建独立用户。

例如，一个只从 `products` 读取数据的搜索前端只需要 `read`，不需要 `write`、`schema`、`replication` 或 `admin`：

```sql
CREATE USER 'app_read' IDENTIFIED BY 'ReadPass#2026';
GRANT read ON 'products' TO 'app_read';
```

`CREATE USER` 会为新用户返回一个原始 bearer token。请立即妥善保存，Manticore 之后不会再显示原始 token。

之后需要创建或轮换 bearer token 时：

```sql
TOKEN 'app_read';
```

`TOKEN 'app_read'` 会返回一个可直接使用的新的原始令牌。`SHOW TOKEN` 显示的是已存储的令牌哈希，而不是要在 HTTP 请求中发送的令牌。这对验证和审计很有用：你可以在不暴露原始密钥的情况下，确认令牌是否存在，或在轮换后是否发生了变化：

```sql
SHOW TOKEN FOR 'app_read';
```

`SET PASSWORD` 会更改用于 SQL/MySQL 和 HTTP Basic 认证的密码：

```sql
SET PASSWORD 'NewReadPass#2026' FOR 'app_read';
```

它不会撤销现有的 bearer 令牌。要轮换 Bearer 访问权限，请使用 `TOKEN` 或 `POST /token` 创建新令牌：

```sql
TOKEN 'app_read';
```

数据写入管道可以只获得 `write`，而不需要其他权限：

```sql
CREATE USER 'app_ingest' IDENTIFIED BY 'IngestPass#2026';
GRANT write ON 'products' TO 'app_ingest';
```

表结构迁移任务可以获取 `schema`：

```sql
CREATE USER 'schema_job' IDENTIFIED BY 'SchemaPass#2026';
GRANT schema ON 'products' TO 'schema_job';
```

认证管理员可以获得 `admin` 权限：

```sql
CREATE USER 'security_admin' IDENTIFIED BY 'AdminPass#2026';
GRANT admin ON * TO 'security_admin';
```

`admin` 权限只管理认证和授权状态。它们并不意味着拥有 `read`、`write`、`schema` 或 `replication` 权限。如果同一个用户确实需要这些权限，请分别授予。

## 通过 SQL 与 HTTP 连接

mysql 客户端使用 Manticore 用户名和密码进行认证：

```bash
MYSQL_PWD=ReadPass#2026 \
  mysql -h127.0.0.1 -P9306 -uapp_read \
  -e "SELECT * FROM products LIMIT 10"
```

HTTP/HTTPS 客户端可以使用 Basic 认证：

```bash
curl -u app_read:ReadPass#2026 \
  http://127.0.0.1:9308/sql?mode=raw \
  -d "SELECT * FROM products LIMIT 10"
```

它们也可以使用 `CREATE USER`、`TOKEN` 或 `POST /token` 命令返回的 bearer 令牌：

```bash
curl -H "Authorization: Bearer <app_read_token>" \
  http://127.0.0.1:9308/sql?mode=raw \
  -d "SELECT * FROM products LIMIT 10"
```

`Basic` 和 `Bearer` 认证方案不区分大小写。用户名区分大小写。

两种方式的权限校验相同：客户端完成认证后，Manticore 识别出用户，再把请求的操作与该用户的权限进行比对。

## 启用认证后进行测试

提示：在为 Manticore 启用访问控制时，不要只验证启用认证后客户端能够连接。还要测试被拒绝的访问，以及你的应用对此的响应。

`app_read` 用户应该能从 `products` 读取：

```bash
curl -H "Authorization: Bearer <app_read_token>" \
  http://127.0.0.1:9308/sql?mode=raw \
  -d "SELECT * FROM products LIMIT 10"
```

同一个用户应该不能向 `products` 写入：

```bash
curl -H "Authorization: Bearer <app_read_token>" \
  http://127.0.0.1:9308/sql?mode=raw \
  -d "INSERT INTO products(id,title) VALUES(1,'test')"
```

该错误是预期行为。通过 HTTP，具有有效用户但没有权限的请求会得到 `403 Forbidden`。通过 SQL/MySQL，Manticore 会返回带有权限拒绝信息的 `ERROR 1045`。

## Manticore 如何判断允许与拒绝

Manticore 的权限是“操作 + 目标”形式的规则。如果没有任何规则允许在请求的目标上执行请求的操作，访问就会被拒绝。

简而言之：

- 规则只针对所请求的操作进行匹配。`admin` 不能满足 `read`、`write`、`schema` 或 `replication`。
- `WITH ALLOW 0` 创建一条显式拒绝规则。
- 任何匹配的显式拒绝都会胜出，即使存在更具体的允许规则。
- 如果没有匹配的允许规则，访问被拒绝。

举个例子：

```sql
CREATE USER 'analyst' IDENTIFIED BY 'AnalystPass#2026';
GRANT read ON * TO 'analyst';
GRANT read ON 'private_logs' TO 'analyst' WITH ALLOW 0;
```

`analyst` 用户可以读其他表，但不能读 `private_logs`。

带通配符的拒绝无法与精确允许一起作为例外模式使用。只要拒绝匹配了请求，它就仍然优先生效。

## 在现有部署中逐步启用访问控制

对于已有的 Manticore 部署，应将认证作为分阶段上线来处理，而不是一次性全部切换：

1. 梳理所有连接到 Manticore 的 SQL 和 HTTP 客户端。
2. 选择认证文件路径：RT 模式下放在 `data_dir` 下的 `auth.json`，plain 模式下使用显式路径。
3. 先在 staging 环境启用认证。
4. 创建第一位管理员。
5. 为搜索、写入、表结构变更、复制和认证管理分别创建最小权限用户。
6. 更新应用的 SQL 连接代码，以发送用户名和密码。
7. 更新 HTTP/HTTPS 连接代码，改用 Basic 认证或 Bearer 令牌。
8. 对每个应用用户分别验证预期的成功与预期的拒绝。
9. 配置合适的认证日志级别，并确保该日志与其他运维日志一起被安全存储。
10. 逐步发布，在切换后轮换凭据，以获得额外的安全性，并再做一次测试和培训。

分布式表还需要多做一项检查。Remote-agent 查询以当前会话用户身份进行认证，因此远程守护进程上需要有该用户的匹配认证数据，该用户也要具备远程目标表的相应权限。

复制集群使用 `replication` 操作。启用认证后，集群加入可能会用来自捐赠集群的认证数据替换本地认证数据，因此在加入之前要确保各节点之间的认证材料保持一致。在处理集群时，要谨慎对待认证日志（默认是 `searchd.log.auth` 文件），因为其中可能包含盐值和凭据哈希。

## 完整参考

该手册页覆盖了新功能的完整命令集和运维细节，包括密码策略、认证日志级别、`SHOW USERS`、`SHOW PERMISSIONS`、`RELOAD AUTH`、分布式远程代理以及复制集群：

[认证与授权手册](https://manual.manticoresearch.com/Security/Authentication_and_authorization)

但对大多数应用来说，路径很直接：启用认证，初始化管理员，创建最小权限用户，更新客户端，并验证正确的请求被允许，而错误的请求被拒绝。
