跳转至

SOP — 凭据隔离落地(env-inventory)

变更日期:2026-09-29(2026-10-13 增补 GLM、DSK 凭据项) 执行主机:192.168.31.249(本机) 类型:C 类变更(改配置)

1. 背景

环境信息(节点 IP、角色、服务账号口令)此前散落各处:拓扑靠临时探测,口令散在 k8s Secret 与各工程 SOP 的取值命令里。需要一个统一入口,让日常运维与新会话都能快速取到,同时不把口令写进任何清单、文档或代码。

前期已确认两条事实:

  • 关键业务文档中没有明文口令——写法都是 kubectl get secret ... | base64 -d,真值在 k8s Secret 中;
  • 本机 ~/.bashrc 第 5~9 行有 非交互守卫(case $- in *i*) ;; *) return;; esac),任何加在守卫之后的加载逻辑对非交互 shell 都无效。

2. 目标

变更完成后应达到:

  1. ~/.secrets/prod.env 存在,权限 600,父目录 ~/.secrets 权限 700;
  2. 其中含 15 个 PROD_* 变量,覆盖 GitLab / MinIO / MariaDB / LDAP / Grafana / Traefik / 智谱(GLM)与 DeepSeek 的账号与口令,以及少量静态环境值;
  3. 交互式终端登录后,这些变量已自动加载并 export;
  4. 非交互场景(Trae 执行命令、脚本)可通过一行显式 source 取到;
  5. 口令明文不出现于任何清单、文档、对话与命令输出中。

3. 前置条件

项 要求 检查命令
kubectl 本机可用,且对 server、monitoring 命名空间有 secret 读权限 kubectl -n server get secret >/dev/null && echo OK
工具 python3 python3 -V
权限 家目录可写,可改 ~/.bashrc test -w "$HOME/.bashrc" && echo OK
备份 改 ~/.bashrc 前必须先备份 见步骤 2

4. 影响范围

  • 主机:仅本机(192.168.31.249),不涉及任何远端主机;
  • 对象:新增 ~/.secrets/;修改 ~/.bashrc(插入 8 行加载逻辑);
  • 停服:否。对 k8s 集群只读(get secret),不写任何资源;
  • 窗口期:无要求,可在任意时间执行;
  • 在跑作业:不涉及,本机无 Slurm/LSF 作业。

5. 分步操作

步骤 1:生成 ~/.secrets/prod.env

从 k8s Secret 抽取真值写入 env 文件。变量与来源映射如下:

变量 命名空间 Secret key
PROD_GITLAB_ROOT_PASSWORD server gitlab-gitlab-initial-root-password password
PROD_GITLAB_SHELL_SECRET server gitlab-gitlab-shell-secret secret
PROD_MINIO_ROOT_USER / _PASSWORD server minio-root-credentials root-user / root-password
PROD_MARIADB_ROOT_PASSWORD server mariadb-root password
PROD_LDAP_ADMIN_PASSWORD server openldap-backup-pw password
PROD_GRAFANA_ADMIN_USER / _PASSWORD monitoring grafana-admin admin-user / admin-password
PROD_TRAEFIK_DASHBOARD_USERS server traefik-dashboard-auth users
PROD_GLM_API_KEY server glm-api-key api-key
PROD_DSK_API_KEY server dsk-api-key api-key

另有 4 个静态值:PROD_K8S_MASTER_IP、PROD_DOMAIN、PROD_GITLAB_ROOT_USER、PROD_LDAP_ADMIN_DN。

增量(2026-10-13):新增 PROD_GLM_API_KEY(命名空间 server / Secret glm-api-key / key api-key),供知识库的智谱嵌入调用取用;同一份 Secret 也可注入知识库服务 Pod 作运行时凭据(单一源)。

增量(2026-10-13,同日第二次):新增 PROD_DSK_API_KEY(命名空间 server / Secret dsk-api-key / key api-key),供知识库网站问答框作生成模型凭据;同样可注入服务 Pod(单一源)。

坑:openldap-bootstrap-secret 里只有口令哈希(*_PASSWORD_HASHED),拿不到明文;明文在 openldap-backup-pw。取值时勿选错 Secret。

mkdir -p "$HOME/.secrets" && chmod 700 "$HOME/.secrets"

# 单条取值模板(输出即明文,勿在有日志的环境执行)
kubectl -n server get secret gitlab-gitlab-initial-root-password \
  -o jsonpath='{.data.password}' | base64 -d

# 完整 15 项按上表逐一取值后,写成 KEY=VALUE 各行,落盘为 0600
install -m 600 /dev/null "$HOME/.secrets/prod.env"

预期:15 个变量全部取到非空值;文件权限 600。 失败判断:某项为空 → 核对 Secret 名与 key 是否与上表一致,勿用哈希字段替代。 实现体:env-inventory/build_secrets_env.py(按 ITEMS 映射逐项取值、shlex.quote 转义、原子替换);实际执行以实现体为准,本命令为等价复现。

步骤 2:配置 ~/.bashrc 自动加载

高危动作:覆盖 ~/.bashrc 前必须备份。

坑:加载块必须插在非交互守卫之前(原文件第 5 行前)。放在守卫之后,非交互 shell 会先 return,变量永远加载不到——这是本变更最容易做错的一点。

cp -p "$HOME/.bashrc" \
  env-inventory/backup/home/rain/.bashrc.bak.$(date +%Y%m%d-%H%M%S)   # 高危:备份

# 待插入内容(插在原第 5 行「# If not running interactively」之前)
cat <<'EOF'
# 凭据自动加载(env-inventory):必须放在下方非交互守卫之前,
# 否则非交互 shell 在守卫处 return,取不到这些变量。
if [ -r "$HOME/.secrets/prod.env" ]; then
    set -a
    . "$HOME/.secrets/prod.env"
    set +a
fi
EOF

预期:插入后 ~/.bashrc 前 12 行为「注释 + if 块 + 原守卫」。 失败判断:bash -n ~/.bashrc 报错 → 立即用步骤 7 回滚。

步骤 3:非交互场景的取用约定

实测本机 Trae 命令 shell 为 bash -c 型(interactive=no),不读 ~/.bashrc,故不会自动加载。约定如下:

set -a; . "$HOME/.secrets/prod.env"; set +a

预期:之后同一命令内可直接用 "$PROD_*"。 失败判断:变量为空 → 确认上一步的 source 未因 set -e 之类提前退出。

6. 验证

# 1) 语法
bash -n "$HOME/.bashrc" && echo "语法 OK"

# 2) 权限
stat -c '%a %n' "$HOME/.secrets" "$HOME/.secrets/prod.env"     # 预期 700 / 600

# 3) 变量数(只计数,不打印值)
awk -F= '/^PROD_/{n++}END{print n}' "$HOME/.secrets/prod.env"  # 预期 15

# 4) 交互式 shell 自动加载(只打印是否已加载)
bash -ic 'printf "%s\n" "${PROD_GRAFANA_ADMIN_USER:+已加载}"'  # 预期 已加载

# 5) 非交互显式 source
set -a; . "$HOME/.secrets/prod.env"; set +a
printf '%s\n' "${PROD_GRAFANA_ADMIN_USER:+已加载}"              # 预期 已加载

# 6) 幂等:重跑实现体,两次变量行 hash 应一致
awk -F= '/^PROD_/' "$HOME/.secrets/prod.env" | md5sum
python3 env-inventory/build_secrets_env.py 2>/dev/null
awk -F= '/^PROD_/' "$HOME/.secrets/prod.env" | md5sum

实测结果(2026-09-29):第 1~6 项全部符合预期;幂等两次 hash 均为 65d4018f290dea255ddb4df46f500682。

实测结果(2026-10-13,新增 GLM 项后):共 14 项,第 1~6 项仍全部符合预期;幂等两次 hash 均为 98079784a536e0dbedf542048bef7586。

实测结果(2026-10-13,新增 DSK 项后):共 15 项,第 1~6 项仍全部符合预期;幂等两次 hash 均为 4fb3eb4822a9e916a7f90caee5246093。

7. 回滚

备份位置:env-inventory/backup/home/rain/.bashrc.bak.20260929-135834 台账:env-inventory/backup/README.md(登记原路径、产生时间、回滚对象、可删时点)

# 1) 恢复 .bashrc
cp -p env-inventory/backup/home/rain/.bashrc.bak.20260929-135834 "$HOME/.bashrc"
bash -n "$HOME/.bashrc" && echo "语法 OK"

# 2) 使凭据失效(可选:仅撤销加载时无需删除文件)
bash -ic 'printf "%s\n" "${PROD_GRAFANA_ADMIN_USER:+仍加载}"'   # 预期 为空

# 3) 彻底撤销:删除凭据文件
rm -i "$HOME/.secrets/prod.env"      # 高危:删除前确认

回滚后验证:bash -ic 'echo ${PROD_GRAFANA_ADMIN_USER:-<未设置>}' 应输出 <未设置>。

触发条件:bash -n 报错、交互终端启动异常、或变量值明显错误,任一达标即回滚,不靠临场判断。

8. 风险说明

风险 缓解
口令集中一处,该文件被读取即全量泄露 ~/.secrets 700 + prod.env 600;确认不在任何 git 仓/dotfile 管理范围内
环境变量对所有子进程可见(含 printenv、报错输出) 命令内只用 "$VAR";禁止 echo/env 打印;不写入日志
修改 ~/.bashrc 语法错误会导致 shell 启动失败 改前备份;改后 bash -n 校验;回滚命令已备
Secret 轮换后快照过期 重跑 env-inventory/build_secrets_env.py 刷新
非交互场景误以为已自动加载 已在第 5 章步骤 3 与本文档明确约定;执行前 source 校验
执行本 SOP 时用手工 kubectl 取值,明文可能进入终端回滚缓冲/日志 优先用实现体(值不落 stdout);手工执行时关闭终端记录

附录 A:交付物清单

文件 说明
env-inventory/SOP.md 本文档
env-inventory/build_secrets_env.py 凭据抽取实现体(15 项映射,值不进 stdout)
env-inventory/scan_credentials.py 文档凭据扫描工具(脱敏侦察,--scan/--strict/--write)
env-inventory/backup/README.md 备份台账
env-inventory/backup/home/rain/.bashrc.bak.20260929-135834 .bashrc 原始备份
~/.secrets/prod.env 运行态凭据文件(600,由实现体生成,不纳入项目)

来源:/home/rain/Documents/k8s_ins/env-inventory/SOP.md | 最后更新:2026-10-13 16:23(由 build/sync.py 同步,请勿在站点侧修改)