Ansible Vault 加密变量文件应直接加密整个 YAML 文件,而非单个变量;使用 ansible-vault create 或 encrypt 创建/加密,执行时通过 --ask-vault-pass 或 --vault-password-file 提供密码,静态加载推荐 vars_files,多环境用 --vault-id 区分密码,CI/CD 中须严控密码注入与销毁。

Ansible Vault 加密变量文件的正确姿势
直接加密 vars_files 引入的 YAML 文件最稳妥,别试图加密单个变量值或硬编码进 playbook。Vault 不是字符串加解密工具,它只作用于整个文件(或内联的 !vault 块,但后者难维护)。
常见错误现象:ERROR! Attempting to decrypt an unknown format string——通常因为手动改过加密后的内容、用了非 Vault 生成的 base64 块,或把加密内容粘贴进未声明 !vault 标签的变量定义里。
- 用
ansible-vault create group_vars/prod/secrets.yml新建加密文件,交互输入密码;已有明文文件则用ansible-vault encrypt - 确保该文件只含变量定义,不要混入 playbook 逻辑或注释(YAML 注释在加密后可能破坏结构)
- 执行时必须显式提供密码方式:命令行输
--ask-vault-pass,或通过--vault-password-file指定脚本/文件(注意权限:仅当前用户可读)
playbook 中安全引用加密变量的三种场景
加密文件本身不运行,只是被 vars_files 或 include_vars 加载。关键在“怎么加载”和“何时解密”。
- 静态加载(推荐):
vars_files: [ "group_vars/{{ inventory_hostname }}/secrets.yml" ]—— Ansible 在解析阶段自动解密,变量可直接用于when、loop等上下文 - 动态加载:
include_vars: file=secrets.yml—— 解密发生在 task 运行时,变量只在当前 play 内有效;不能用于hosts:或vars:顶层定义 - 绝对避免:
vars: { db_password: !vault | ... }写在 playbook 里——可读性差、无法复用、diff 时暴露加密块结构
多环境共用 Vault 密码时的兼容性陷阱
Ansible 默认只支持一个 Vault 密码。如果 dev/test/prod 要用不同密码(比如合规要求),就不能靠 --vault-password-file 简单指定一个文件。
- 方案一:用
ansible-vault encrypt --vault-id dev@prompt --vault-id prod@prompt多次加密同一文件,每个vault-id对应独立密码;执行时用--vault-id prod@file指定对应密码源 - 方案二:为不同环境建独立加密文件(
dev-secrets.yml、prod-secrets.yml),配合 inventory 变量控制加载路径,再统一用一个密码管理 - 坑点:Vault ID 名称(如
prod)必须和vars_files中的路径或条件严格匹配,大小写敏感,且不能含下划线以外的特殊字符
CI/CD 流水线中 Vault 密码传递的最小权限实践
把明文密码塞进环境变量或配置文件,等于白加密。真正要守住的是密码的“使用边界”。
- GitLab CI:用
VAULT_PASSWORD_FILE指向/vault/.pass,该文件由 CI runner 启动时从 secret 注入,权限设为0400;playbook 执行命令加--vault-password-file {{ VAULT_PASSWORD_FILE }} - GitHub Actions:用
env:传入密码内容,配合echo "${{ secrets.VAULT_PASS }}" > .vault_pass临时写入,执行完立即rm .vault_pass - 致命错误:在 playbook 里用
lookup('file', '.vault_pass')读取密码——Ansible 会把它当普通变量打印到日志,密码瞬间泄露
Vault 加密本身很轻量,真正的复杂度永远在密码生命周期管理上:谁生成、谁保管、谁有权解密、失效后如何轮换。别让一个 ansible-vault encrypt 命令,掩盖了这些环节的松动。

















