⚠️ 此页面为自动翻译,翻译可能不完美。
blog-post

Manticore Search 生产环境认证上线检查清单

在生产环境中,“打开开关就完事”几乎从来行不通。对于单机节点,技术步骤很短:启用 auth,重启 Manticore,创建管理员用户,然后更新客户端。带有分布式表或复制集群的拓扑还需要额外准备,因为节点之间也必须相互认证。

把这次上线当成一次小版本发布来处理。先盘点客户端和节点,准备认证数据,为你的拓扑演练流程,然后再切换。预演可以在维护窗口之前暴露故障。

这份清单适用于计划启用认证并希望在现有系统中尽可能安全上线的用户。请记住,在配置 auth 之前认证是关闭的;切换后,仍然省略凭据的客户端会失败。

请按拓扑选择流程:

拓扑迁移要求
独立节点启用 auth 后引导创建第一位管理员
分布式表和远程代理在开始带认证的远程查询之前分发一份统一的认证存储
复制集群启动前准备好持久化的集群用户和认证存储,然后按受控顺序恢复集群

第 1 阶段:在变更前盘点

先列出所有连接到 Manticore Search 的客户端,包括每个应用以及独立部署的应用组件。编辑配置之前先做这一步。

需要检查的常见项:

  • 应用搜索前端
  • 导入工作进程
  • 定时任务
  • 仪表板和 BI 工具
  • 支持或管理工具
  • 模式变更/更新脚本
  • 备份和维护脚本
  • 手动运行的本地脚本

为每个客户端记录如下信息:

客户端协议表或集群需要的操作备注
产品搜索应用HTTPproductsread将使用 Bearer token
目录导入工作进程SQLproductswrite使用密码认证
模式迁移任务SQLproductsschema仅在部署期间运行
访问管理员SQL*admin管理用户和权限

然后确认部署基础信息:

  • 这是单机节点、分布式表拓扑、复制集群,还是它们的组合?
  • 你运行的是 RT 模式还是普通模式?
  • 在普通模式下,认证文件应该放在哪里?
  • 配置里是否设置了 pid_file?引导创建需要它。
  • 所有参与节点是否都运行支持同一认证协议的版本?
  • SQL 客户端是否会使用 SSL,而 HTTP 客户端在凭据跨网络传输时是否会使用 HTTPS?
  • 凭据,包括临时 Bearer token,将安全存放在哪里?
  • 谁可以看到第一个管理员密码?

如果存在复制,也要记录每个集群名称,以及每个节点 <data_dir>/manticore.json 中持久化的 user。在演练前先备份完整的数据目录、配置以及任何现有认证存储,并在正式切换前再备份一次。

不要跳过凭据处理相关问题。CREATE USER 会返回一个原始 Bearer token;TOKEN 会为指定用户生成一个新 token。之后 SHOW TOKEN 显示的是已存储 token 的哈希,而不是原始 token。如果原始 token 丢失了,就用 TOKEN 轮换它,并在你的应用中更新该 token。

第 2 阶段:设置最小权限用户

应根据具体工作负载创建用户,而不是按别人“以后可能需要什么”来授予权限。

可以使用下面这样的小矩阵:

工作负载用户权限
搜索前端app_readGRANT read ON 'products' TO 'app_read'
导入工作进程app_ingestGRANT write ON 'products' TO 'app_ingest'
模式迁移任务schema_jobGRANT schema ON 'products' TO 'schema_job'
认证操作员security_adminGRANT admin ON * TO 'security_admin'
复制操作员cluster_replGRANT replication ON 'posts' TO 'cluster_repl'

请记住,admin 是一个范围很窄的权限。它只允许管理认证和授权状态;它并不意味着拥有 readwriteschemareplication

这很重要,因为管理凭据的人不一定需要读取业务数据。搜索商品的服务不需要写入文档。迁移任务也不需要管理用户。

同时也要规划负向权限测试。对于你创建的每个用户,至少选一项它应该能做的事,以及一项它不应该能做的事。

例如:

  • app_read 可以搜索 products
  • app_read 不能向 products 插入。
  • app_ingest 可以向 products 写入。
  • app_ingest 不能管理认证。
  • schema_job 可以更改 products 的模式。
  • schema_job 不能读取表,除非你授予 read

第 3 阶段:在预发环境测试

使用预发环境演练你计划在生产中执行的步骤顺序。

在 RT 模式下:

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

要在 RT 模式下显式关闭认证:

searchd {
    data_dir = /var/lib/manticore
    auth = 0
    ...
}

在普通模式下:

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

请将认证文件妥善保密。首次引导创建前,Manticore 可能会创建一个空的认证文件。引导完成后,该文件会保存认证数据和凭据哈希。

这套引导流程适用于单机节点,也适用于准备多个节点认证数据的隔离临时守护进程。绝不要用空认证存储启动一个已有的复制数据目录。这样会丢失其持久化的集群用户,Manticore 可能会跳过集群描述符。

启动 searchd,然后引导创建第一位管理员:

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

脚本化设置:

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

⚠️ 警告:上面的命令把密码以明文形式包含在内。在生产自动化中,应从你的密钥管理系统通过标准输入提供这三行输入。

引导会创建第一位拥有全部操作权限的管理员,包括 replication;不需要额外授权。该命令不会返回 bearer token。如果管理员需要 HTTP Bearer 访问,可以用该用户连接后运行 TOKEN,或者使用 HTTP POST /token 端点。

对于多节点部署,只创建一次认证存储。使用一个带有自己空数据目录、PID 文件和监听器的临时守护进程。引导管理员和共享服务用户,然后干净地停止该守护进程。在启用节点间认证流量之前,将生成的认证存储复制到所有参与节点。不要分别独立创建相同用户:即使名称和密码一致,存储的认证材料也可能不同。

接着,根据前面各阶段的记录创建预发用户。例如:

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

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

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

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

把返回的 Bearer token 安全保存到受保护的存储中。请记住:原始 token 绝不能留在日志、shell 历史或未加保护的文件里。如果需要轮换其中一个,请使用:

TOKEN 'app_read';

SHOW TOKEN 不能用来恢复原始 token:

SHOW TOKEN FOR 'app_read';

检查用户和权限:

SHOW USERS;
SHOW PERMISSIONS;
SHOW PERMISSIONS FOR 'app_read';

对每个用户都执行一次允许和一次拒绝测试。对于只读用户:

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

然后验证未授权操作会被拒绝:

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,权限拒绝会返回带有 permission-denied 信息的 ERROR 1045

SQL 客户端应使用 Manticore 用户名和密码连接。Manticore 中的 SQL/MySQL 协议支持 mysql_native_password

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

HTTP 客户端可以使用 Basic 认证或 Bearer token:

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

HTTP 认证方案(BasicBearer)不区分大小写;用户名区分大小写。

如果你在维护期间在守护进程外编辑了认证文件,请重新加载它:

RELOAD AUTH;

第 4 阶段:生产上线检查清单

对每次部署都使用这份清单,然后再按你的拓扑执行对应流程。

  • 确认你有当前的配置和数据目录备份。
  • 分别备份 manticore.json 和现有的认证存储。
  • 确认现有网络防护措施保持不变。
  • 确认配置中已设置 pid_file
  • 确认认证文件将在哪儿创建或从哪里加载。
  • 确认密码和 token 的存储已准备好。
  • 确认所有参与节点都运行兼容的 Manticore 版本。
  • 在预发环境中按相同拓扑和重启顺序演练。
  • 为跨节点共享的用户准备一份统一的认证存储。
  • 选择下面的单机、分布式或复制流程。
  • 在计划好的维护窗口中启用认证。
  • 预期未认证客户端在认证启用后会失败。
  • token 一经发放就立即存入受保护的 secrets 存储中。不要把原始 token 存到文件、shell 历史或日志里。
  • 更新 SQL 连接代码以发送用户名和密码。
  • 更新 HTTP 连接代码以使用 Basic 认证或 Bearer token。
  • 运行预发环境中的允许和拒绝测试。
  • 在部署包含远程代理或复制时,验证节点间内部操作。
  • 检查认证日志。
  • 运行覆盖搜索、导入、仪表板和维护脚本的应用压力测试。
  • 轮换任何临时的上线凭据。
  • 不要让第一个管理员凭据参与常规应用使用。

独立节点

对于独立节点,直接引导流程就足够了:

  1. 干净地停止 Manticore 并做最终备份。
  2. 配置 auth 并启动 searchd
  3. 使用 searchd --config <path> --auth 引导创建第一位管理员。
  4. 创建生产用户和权限。
  5. 更新客户端,并运行计划好的允许和拒绝测试。
  6. 确认现有表和已知行仍然可用。

分布式表和远程代理

分布式查询会把远程代理请求作为当前会话用户发出。每个远程节点都必须为该用户拥有相同的已存储认证材料,并在远程表上授予所需权限。

对于跨分布式节点的新上线:

  1. 在第 3 阶段的隔离引导守护进程中一次性创建共享用户。
  2. 为协调切换停止受影响的代理和主节点。
  3. 配置 auth,并将同一份统一的认证存储放到每个参与节点上。保留严格的属主和权限,并对校验和进行比对。
  4. 先启动远程代理,再启动查询它们的主节点。
  5. 先在每个代理上测试一条直接的认证查询,再通过主节点测试等价的分布式查询。
  6. 只有在共享流量正常后才创建节点本地用户,并在共享用户的密码、token 或权限发生变化时保持其记录同步。

共享用户只应创建一次。即使名称和密码相同,独立创建的账户也可能拥有不同的已存储认证材料。

现有复制集群

将现有未认证复制集群迁移到认证模式,需要协调重启。不要在现有集群数据上启用 auth 并引导创建第一个用户。空存储不包含持久化的集群用户,因此 Manticore 可能会跳过集群描述符。

按以下顺序执行:

  1. 在未认证集群仍然健康时,选择其未来的复制身份并将其持久化:

    ALTER CLUSTER products UPDATE user 'cluster_repl';
    

    UPDATE user 会把名称写入集群元数据。此时认证仍然关闭,因此 Manticore 既不会创建也不会检查该账户。请在第 3 步中创建它,并在任何真实的、启用认证的集群节点重启之前完成。

    确认每个节点的 <data_dir>/manticore.json 现在都为该集群存储了 "user": "cluster_repl"。如果一个节点承载多个集群,请把每个集群更新为在新认证存储中会存在的用户,或者在切换前创建并授予每个持久化用户。

  2. 干净地停止所有集群节点,并利用复制状态选择安全主节点。干净关机后,通常最后停止的节点就是它,其 <data_dir>/grastate.dat 中会有 safe_to_bootstrap: 1。参见 Restarting a cluster

  3. 在隔离的临时守护进程中,将 cluster_repl 引导创建为第一位管理员。第一位管理员已经拥有全部操作权限,包括 replication,因此不需要额外授权。如果集群将使用单独的最小权限身份,请一次性创建它并在分发存储前授予 replication

  4. 停止临时守护进程。在每个真实集群节点上配置 auth,并将完全相同的生成认证存储复制到每个节点。保持文件私密且字节级一致。在该存储就位之前,不要启动真实集群节点。

  5. 按以下顺序重启一个双节点集群:

    1. 先正常启动非主对等节点,只需等待其守护进程监听器即可。此时它的集群可以显示为 closed;不要向其写入。
    2. 使用 --new-cluster 启动记录下来的安全主节点,或者使用相应的 manticore_new_cluster 服务操作。
    3. 等待安全主节点报告 cluster_products_status=primarycluster_products_node_state=synced
    4. 干净地停止第一个对等节点,然后再次正常启动它。等待该节点上出现相同的 primarysynced 值。绝不要在它上面使用 --new-cluster

    安全主节点在启动期间会从一个描述符对等节点读取持久化的集群用户,因此初始对等节点必须已经在监听。即使认证存储正确,单独启动安全主节点也可能失败并报 failed to fetch donor user from any node。对于更大的集群,请在预发环境中演练这个顺序。先用一个非主节点作为初始元数据对等节点,建立安全主节点,然后再正常启动或重启其余对等节点。

  6. 在每个节点上检查集群组件是否为 primary、本地节点是否已同步,以及迁移前的数据是否存在:

    SHOW STATUS LIKE 'cluster_products_status';
    SHOW STATUS LIKE 'cluster_products_node_state';
    SELECT COUNT(*) FROM products:existing_table;
    

    在把节点视为可写之前,先等待这两个状态值分别变为 primarysynced

  7. 在恢复流量之前,创建一个可丢弃的单行表并将其加入已恢复的集群:

    CREATE TABLE migration_control (id bigint, body text);
    INSERT INTO migration_control VALUES (1, 'post-auth control');
    ALTER CLUSTER products ADD migration_control;
    

    确认对等节点从 products:migration_control 返回一行。如果在前述迁移前数据检查都通过后这一步失败,请排查表传输,而不是迁移本身。

集群健康后,创建剩余的管理员用户,必要时再创建一个专用的最小权限复制用户。只有在新用户及其认证数据在每个节点上都可见之后,才更改存储的集群身份:

CREATE USER 'repluser' IDENTIFIED BY '<strong-secret>';
GRANT replication ON * TO 'repluser';
ALTER CLUSTER products UPDATE user 'repluser';

在另一个管理员以及最终复制身份都已验证之前,不要删除引导管理员。

当节点加入一个带认证的集群时,捐赠节点的认证数据会覆盖加入节点本地的认证数据。在 info 或更详细的认证日志级别下,Manticore 会把之前的数据写入 searchd.log.auth 作为备份。日志可能包含 salt 和凭据哈希,因此共享前请限制访问并进行脱敏。

切换期间的认证日志

启用认证后,认证事件会写入单独的认证日志。如果守护进程日志是 /var/log/manticore/searchd.log,那么认证日志就是 /var/log/manticore/searchd.log.auth

auth_log_level 的取值有:

  • disabled
  • error
  • warning
  • info
  • all
  • trace

默认值是 info。除非你有理由减少或增加日志细节,否则从这里开始。只有在排障时才使用 trace;它也会包含所有成功的内部认证流量。

有用的清理和维护命令:

SET PASSWORD 'NewReadPass#2026' FOR 'app_read';
REVOKE read ON 'products' FROM 'app_read';
DROP USER 'app_read';

SET PASSWORD 会修改 SQL/MySQL 和 HTTP Basic 认证所用的密码。它不会吊销现有 bearer token。要轮换 Bearer 访问,请用 TOKENPOST /token 创建新 token,并更新客户端。

第 5 阶段:回滚与故障排查

对于单机节点,恢复之前的配置和网络限制,重启 Manticore,并在必要时回退客户端配置。

把所有通信节点一起回滚。认证和未认证节点混在一起是无法工作的。在每个节点上恢复相同的配置和认证状态,然后先启动远程代理,再启动它们的主节点。

为每个复制集群保留切换前的 manticore.json 备份。如果某个节点在持久化集群用户存在之前就已启用认证启动,先停止它并将当前描述符与备份比较。一次干净停止可能已经保存了被跳过的状态,但没有保存集群描述符;在重试前恢复备份的描述符。不要重新创建集群表,也不要删除其数据。

不要删除这份上线记录。它通常是最快找出哪个客户端已更新、哪个 token 存放在哪、以及创建了哪些权限的方式。

症状可能原因检查项
SQL 访问被拒绝用户错误、密码错误,或客户端认证不匹配检查已配置的用户,并确认客户端可以使用 mysql_native_password
HTTP 401缺少或无效的凭据检查 Authorization 头,以及客户端使用的是 Basic 认证还是 Bearer token 认证。
HTTP 403用户已认证,但没有权限检查 SHOW PERMISSIONS FOR '<user>'
Bearer token 不工作token 丢失、复制错误,或已被撤销运行 TOKEN '<user>',保存返回的 token,并更新客户端。
用户权限比预期更少缺少动作授权检查该操作是否需要 readwriteschemareplicationadmin
用户权限比预期更多作用范围过大或缺少显式拒绝检查通配符授权、精确目标授权,以及任何 WITH ALLOW 0 规则。
分布式查询在远程被拒绝共享用户缺失、不同,或在代理节点上没有权限对比主节点和代理节点上的认证存储与权限。
启动时跳过了已有集群持久化的集群用户不在认证存储中,或没有 replication重启前检查 manticore.jsonSHOW PERMISSIONS 以及切换前备份。
failed to fetch donor user from any node没有可用的描述符对等节点,或者守护进程之间的认证失败检查重启顺序、对等节点可用性,以及两边的 searchd.log.auth

权限规则由动作类型决定。当规则冲突时,显式拒绝始终优先于允许,即使允许规则更具体也是如此。如果没有匹配的允许规则,访问将被拒绝。

最终检查

在宣布上线完成前,请确认:

  • 你使用了适合该部署拓扑的流程。
  • 系统中每个独立使用 Manticore Search 的部分都有自己的用户。
  • 每个用户都只拥有它需要的操作权限。
  • 跨节点共享的用户具有相同的已存储认证材料。
  • Bearer token 已存入受保护的 secrets 存储中;原始 token 没有在受控环境之外保存。
  • 运维团队知道 SHOW TOKEN 不会返回原始 token,而是显示其哈希;要获取新 token,请使用 TOKEN 或 HTTP 端点。
  • SQL 和 HTTP 客户端都已更新。
  • 已测试预期中的拒绝场景。
  • 适用时,你已经测试了分布式查询或复制操作。
  • 每个已迁移的复制集群都处于 synced 状态,并且其现有数据在每个节点上都存在。
  • 认证日志可见。
  • 回滚流程清晰且有文档记录。

祝你的认证与授权上线顺利!

安装Manticore Search

在 Linux 或 macOS 上用一条命令安装 Manticore Search:

curl https://manticoresearch.com | sh

有关高级安装选项,请参阅完整安装指南手册

安装Manticore Search