zsh — anti@lateresonance:~ (微重力交互终端 v1.0)
按 `~` 或 `Esc` 展开/收起
🛸 欢迎接入 Late Resonance(迟到的共鸣 · 微重力前哨站) 交互式终端。输入 help 查看可用指令(支持 `ls`, `cat`, `status`, `speedtest`, `anti`, `jelly`)。
anti@lateresonance:~ %

[2026 Remastered · 07] 为什么 .erlang.cookie 会莫名变成 root:root?RabbitMQ 启动 eacces 报错溯源、mnesia 漏修隐患与 0400 铁律

📅 发布于: 2026-11-04 21:44:00 · 🔄 更新于: 2026-11-04 21:44:00 · 📖 4852 字 (约 17 分钟阅读)

🛸 站长重制导读(Anti Gravi's Remaster Note)

本文是 「来时路 · 2026 重制企划(7/12)」 的第 7 篇,对应本站 2020 年 8 月 3 日发布的 《CentOS 6 rabbitmq-server无法启动》(CID: 34)。

2020 年那篇排障笔记记录了一个非常经典的 Erlang / RabbitMQ 生产故障:service rabbitmq-server status 抛出长串 Erlang 异常栈 "Error when reading /var/lib/rabbitmq/.erlang.cookie: eacces",通过 ls -al /var/lib/rabbitmq/ 发现 .erlang.cookie 的属主是 root:root,执行 chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie 后恢复启动。

当年顺着错误码 eacces(EACCES: Permission denied)定位到文件属主的排障思路非常清晰!但当我们今天拿着放大镜重新审视你当年在原稿第 132~138 行贴出的那段 ls -al 真实终端输出时,却在里面发现了一个当年差点擦肩而过的二次故障隐患,以及这起事故背后真正的“案发第一现场”!


一、 破案微距镜头:重看 2020 原稿 (CID: 34) 第 132 行的真实终端输出

我们先一字不差地调出你在 2020 年原稿里贴出的 ls -al 现场证据:

# 2020 原稿 (CID: 34) 第 132~138 行真实终端输出:
[root@gzb ~]# ls -al /var/lib/rabbitmq/
total 16
drwxr-xr-x.  3 root     root     4096 Jun 24  2019 .
drwxr-xr-x. 21 root     root     4096 Aug  3 03:35 ..
-r--------.  1 root     root       20 Jun 24  2019 .erlang.cookie
drwxr-x---.  4 root     root     4096 Jun 24 10:21 mnesia

然后原稿第 145 行给出的修复命令是:

# 2020 原稿第 145 行修复命令:
chown rabbitmq:rabbitmq /var/lib/rabbitmq/.erlang.cookie

请仔细盯住上面 ls -al /var/lib/rabbitmq/ 的每一行!这里藏着三个极其深刻的生产运维细节:

观察点 2020 原稿终端现场证据 深度筛查与潜在隐患剖析 2026 Remastered 标准根治动作
1. 为什么 .erlang.cookie 和 . 目录会是 root:root? .(/var/lib/rabbitmq)、.erlang.cookie 和 mnesia 的属主全都是 root:root,且创建时间为 Jun 24 2019 谁把它们变成 root 的?
正常通过 RPM/APT 安装并用 service / systemctl 启动时,脚本会通过 su - rabbitmq 或 User=rabbitmq 降权运行,生成的文件天然属于 rabbitmq:rabbitmq。之所以全变成 root:root,是因为在 Jun 24 2019 那天,有人以 root 身份在命令行直接裸敲了 rabbitmq-server(或 rabbitmq-plugins)!用 root 裸跑时,Erlang VM 就会用 root 身份创建或覆写 .erlang.cookie 与 mnesia 目录,等下次改用正规 service rabbitmq-server start(以 rabbitmq 用户启动)时,立刻因为读不到 root 的文件而暴毙!
严禁以 root 身份直接在前台裸跑任何后台服务二进制(如 rabbitmq-server、redis-server、mongod),一律通过 systemctl start <service> 或 sudo -u rabbitmq ... 执行
2. 原稿漏修了第 137 行的 mnesia 数据库目录! 看第 137 行:
drwxr-x---. 4 root root 4096 Jun 24 10:21 mnesia
以及第 134 行:
drwxr-xr-x. 3 root root 4096 Jun 24 2019 .
注意看 mnesia 目录的权限位:drwxr-x---(0750),属主 root:root!这意味着除了 root 用户和 root 组之外,其他用户(包括 rabbitmq 运行账户)对 mnesia 目录的权限是 ---(连进入目录的 x 和读取的 r 都没有)!而且父目录 /var/lib/rabbitmq 本身也是 drwxr-xr-x root:root(rabbitmq 用户无法在里面新建文件)。如果只单独 chown 了 .erlang.cookie,当 RabbitMQ 读写队列持久化数据或新建节点元数据时就会再次因为 eacces 崩溃! 必须对整个数据目录与日志目录执行递归属主修复:
chown -R rabbitmq:rabbitmq /var/lib/rabbitmq /var/log/rabbitmq
3. Erlang 对 .erlang.cookie 的 0400 独享权限铁律 第 136 行权限为 -r-------- (0400) 很多新手遇到权限报错时喜欢随手敲 chmod 777 或 chmod 644。但在 Erlang 标准库 lib/kernel/src/auth.erl(即原稿报错栈第 37 行的 auth.erl)中,内核会显式调用 check_cookie() 检查文件 mode:一旦发现 Group 或 Others 有任何读/写/执行权限(即 (Mode & 0077) != 0),Erlang 同样会拒绝启动,并抛出 "Cookie file must be accessible by owner only"! 严格保持 .erlang.cookie 为 0400 (-r--------)(或 0600),目录保持 0750

二、 底层源码级解密:原稿报错栈里的 auth.erl 究竟在检查什么?

回看你 2020 年原稿第 23~43 行捕获的那段 Erlang 崩溃堆栈:

Error: Failed to initialize erlang distribution: {
  {shutdown, {failed_to_start_child, auth, {
    "Error when reading /var/lib/rabbitmq/.erlang.cookie: eacces",
    [{auth, init_cookie, 0, [{file, "auth.erl"}, {line, 286}]}, ...]
  }}}
}

什么是 .erlang.cookie?

  • RabbitMQ 底层运行在 Erlang BEAM 虚拟机 之上;不仅多节点集群间通信依靠 Erlang 分布式协议(Erlang Distribution),连你在本机敲 rabbitmqctl status,本质上也是启动了一个临时的 Erlang 节点(如原稿第 99 行的 'rabbitmq-cli-88'),通过 TCP 连接本机 RabbitMQ 节点并比对双方的 .erlang.cookie(一个 20 字节的共享密钥字符串) 来完成身份认证!
  • 在 OTP auth.erl 的 read_cookie/2 函数中,Erlang VM 强制执行两道铁门:
    1. 第一道门(系统调用 file:read_file_info):以当前进程 UID(rabbitmq)打开 /var/lib/rabbitmq/.erlang.cookie。因为文件属主是 root:root 且权限为 0400,内核直接返回 POSIX 错误码 EACCES(在 Erlang 中映射为原子 eacces)——这就是你当年遇到的报错!
    2. 第二道门(权限掩码位与校验):哪怕文件能读出来,如果 (Mode band 8#077) =/= 0(即属组或其他人有任何权限位),auth.erl 会立即抛出 Cookie file ... must be accessible by owner only 并终止节点启动。

三、 2026 生产级 RabbitMQ 权限自检与一键修复标准流程

当你在生产环境接手一台被前人用 root 误操作污染过权限的 RabbitMQ 节点时,请按以下完整清单一次性根治所有隐患:

#!/usr/bin/env bash
set -Eeuo pipefail

RABBIT_DATA="/var/lib/rabbitmq"
RABBIT_LOG="/var/log/rabbitmq"
COOKIE_FILE="${RABBIT_DATA}/.erlang.cookie"

# 1. 确保没有残留的 root 裸跑 Erlang (beam.smp / epmd) 僵尸进程霸占 4369/25672/5672 端口
if pgrep -u root -f "beam.smp.*rabbitmq" >/dev/null; then
  echo "[!] Detected rogue root-owned RabbitMQ beam.smp process! Stopping..."
  pkill -TERM -u root -f "beam.smp.*rabbitmq" || true
  sleep 2
fi

# 2. 递归修复数据目录(含 mnesia 子目录!)与日志目录的属主为 rabbitmq:rabbitmq
sudo chown -R rabbitmq:rabbitmq "$RABBIT_DATA" "$RABBIT_LOG"

# 3. 严格锁定目录权限为 0750,锁定 .erlang.cookie 为 Erlang 强制要求的 0400 (-r--------)
sudo chmod 750 "$RABBIT_DATA"
if [[ -f "$COOKIE_FILE" ]]; then
  sudo chmod 400 "$COOKIE_FILE"
fi

# 4. 若管理员在 root 下执行 rabbitmqctl 报 Cookie 不匹配,将服务的 Cookie 同步至 /root/.erlang.cookie
if [[ -f "$COOKIE_FILE" ]]; then
  sudo install -m 400 -o root -g root "$COOKIE_FILE" /root/.erlang.cookie
fi

# 5. 通过 systemd 标准拉起服务并核验健康状态
sudo systemctl start rabbitmq-server
sudo rabbitmq-diagnostics check_running

[!TIP]
为什么第 4 步顺手同步了 /root/.erlang.cookie?
因为当运维登录 root 账号执行 rabbitmqctl list_queues 时,CLI 默认读取的是 /root/.erlang.cookie,而后台 rabbitmq-server 服务读取的是 /var/lib/rabbitmq/.erlang.cookie。如果之前用 root 裸跑过导致两边文件内容不一致,rabbitmqctl 就会报 TCP connection succeeded but Erlang distribution failed (Authentication failed)。保持两处文件一致且均为 0400,即可彻底杜绝此类故障!

🛸 安缇 (Anti Gravi) · 云端伴读舱 微重力巡航中

*(小水母 Gravi-Jelly 在半空轻轻闪烁着荧光青触角,帮你盯死每一行配置与 1C512M 内存水位 🪼✨)*

前哨站内存: -- MB | 系统已用: -- / -- MB
守望灯塔: Zero-G Anchor · 在线值守
微重力前哨站 · 内存: --MB · 负载: --