linux shell 的 readonly 是内置命令,仅限当前进程内防止变量误改,无法跨进程限制子脚本;真正防护需靠不导出敏感变量、显式传参、临时文件权限控制、运行时密钥注入及篡改校验等分层机制。

Linux Shell 本身没有 readonly 指令用于保护变量不被子脚本篡改——这是常见误解。Shell 的 readonly 是**内置命令(builtin)**,作用是将当前 Shell 进程内的变量设为只读,但它**无法跨进程生效**。子脚本(如 ./deploy-step2.sh)作为独立进程启动,默认继承父 Shell 的环境变量副本,但对父进程的 readonly 变量无感知,更不会受其约束。
为什么 readonly 在发布流程中“看似失效”
假设主发布脚本中写:
export TOKEN="abc123"readonly TOKEN
./subscript.sh # 子脚本里仍可直接修改 TOKEN(它操作的是自己的副本)
关键点:
- 子进程无法修改父进程的内存,所以父进程的
readonly对它毫无影响 -
export TOKEN让变量进入环境,但环境变量在子进程里默认是可写的(除非子脚本自己再设 readonly) - Shell 的
readonly不提供进程间防护,仅限单个 shell 实例内防误操作
真正有效的 Token 保护方案
要防止子脚本篡改或泄露核心 Token,需从**作用域隔离**和**执行边界控制**入手:
-
不导出敏感变量:主脚本中避免
export TOKEN。改用显式传参或文件注入:./subscript.sh --token "$(cat /run/secrets/deploy_token)" -
用临时文件 + 严格权限:将 Token 写入
/tmp/.token.XXXXXX,设置chmod 600,子脚本只读不写,执行后立即rm -f -
利用 systemd 或容器运行时隔离:在 CI/CD 中通过 secret mount(如 Docker
--secret、GitHub Actionssecrets)注入,子脚本只能读取,无法修改宿主环境 -
子脚本启动时自我锁定:在
subscript.sh开头主动声明:TOKEN=$(get_token_from_secure_source); readonly TOKEN—— 这样它自己内部就不会意外覆盖
辅助加固:让篡改行为“立刻暴露”
即使不能完全阻止,也要让非法修改可被快速发现:
- 主脚本在调用子脚本前后校验 Token 完整性:
before=$(sha256sum → 执行子脚本 → <code>after=$(sha256sum → 报警不一致 - 子脚本开头加入守卫逻辑:
if [[ "$TOKEN" != "^[a-zA-Z0-9_\-]{20,}$" ]]; then echo "FATAL: TOKEN tampered!" >&2; exit 1; fi - 日志审计:所有含
TOKEN的命令行参数记录到专用日志(避免写入ps或历史),配合auditd监控敏感文件访问
Shell 的 readonly 是好习惯,但不是安全锁。生产级发布流程中的 Token 防护,靠的是分层设计:不暴露、不继承、不信任子进程、有校验、可追溯。











