跳到主要内容

Vault 与密钥

本章目标:用 Ansible Vault 管理敏感变量,做到 Git 可追踪、磁盘上非明文、运行时受控解密,并理清 Vault 与 SSH 私钥、CI 密钥注入的边界。

Vault 不是权限系统:能拿到 Vault 密码的人就能看到明文。它解决的是「仓库/备份里不出现明文秘密」。


1. 哪些该进 Vault

应该不应该
数据库密码、API Token非敏感的端口、包名、开关
云 AK/SK(若必须给 Ansible 用)逻辑主机名、分组结构
TLS 私钥内容、密钥口令公钥(通常可明文)
应用 SECRET_KEY文档、注释、示例占位符

原则:最小秘密集。秘密越少,轮换与审计越简单。


2. 加密整个文件(推荐起步)

2.1 目录拆分

group_vars/web/
vars.yml # 明文:端口、副本数…
vault.yml # 密文:密码、Token

group_vars/web/vars.yml

---
nginx_listen_port: 80
db_host: 10.0.1.21
db_user: app
# 密码在 vault.yml
db_password: "{{ vault_db_password }}"

2.2 创建并编辑

cd ~/ansible-for-ops
mkdir -p group_vars/web

ansible-vault create group_vars/web/vault.yml

写入:

---
vault_db_password: "change-me-strong"
vault_app_secret: "change-me-strong"

命名习惯:Vault 内用 vault_ 前缀,明文 vars 再映射一次,避免「到底哪个文件是真源」混淆。

2.3 已有明文改加密

ansible-vault encrypt group_vars/web/vault.yml
ansible-vault view group_vars/web/vault.yml
ansible-vault edit group_vars/web/vault.yml
ansible-vault decrypt group_vars/web/vault.yml # 一般不需要,紧急才用
ansible-vault rekey group_vars/web/vault.yml # 人员变动时换密码

加密后文件头类似:

$ANSIBLE_VAULT;1.1;AES256
6638...

可安全提交 Git(仍需保护 Vault 密码)。


3. 加密单个字符串

适合「大部分明文、只有一两个字段敏感」:

ansible-vault encrypt_string 'S3cr3t!' --name 'vault_db_password'

把终端输出粘贴进 group_vars/web/vars.yml

vault_db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
6638...
db_password: "{{ vault_db_password }}"
可读性

字段一多,整文件加密的 vault.yml 更好维护;encrypt_string 适合少量嵌入。


4. 运行时如何提供密码

交互

ansible-playbook playbooks/web.yml --ask-vault-pass

密码文件(本地/CI)

umask 077
echo 'your-vault-pass' > ~/.ansible/vault_pass_web
chmod 600 ~/.ansible/vault_pass_web

ansible-playbook playbooks/web.yml \
--vault-password-file ~/.ansible/vault_pass_web

ansible.cfg

[defaults]
vault_password_file = ~/.ansible/vault_pass_web
禁止

vault_pass 提交进业务仓库;或在多用户共用的 NFS home 里乱放明文密码文件。

环境变量(注意进程列表与调试日志)

# 自定义脚本包装更常见:从密钥管理器取密码写临时文件
export ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault_pass_web

5. 多密码与 vault-id(多环境)

ansible-vault encrypt group_vars/web/vault.yml --vault-id prod@prompt
ansible-playbook playbooks/site.yml --vault-id prod@~/.ansible/vault_prod

场景:

  • staging / prod 使用不同 Vault 密码
  • 不同团队角色接触不同秘密集

ansible.cfg 示例:

[defaults]
vault_identity_list = staging@~/.ansible/vault_staging, prod@~/.ansible/vault_prod

6. Playbook 中使用秘密

- name: 写应用环境文件
ansible.builtin.template:
src: app.env.j2
dest: /data/app/.env
owner: app
group: app
mode: "0600"

templates/app.env.j2

DB_HOST={{ db_host }}
DB_USER={{ db_user }}
DB_PASSWORD={{ db_password }}
APP_SECRET={{ vault_app_secret }}

要点:

  • 落盘权限 0600,属主最小化
  • 不要 debug: var=db_password
  • 失败日志也可能回显参数;敏感 task 注意模块是否支持 no_log: true
- name: 可能回显敏感参数的任务
ansible.builtin.command: /usr/local/bin/set-secret
no_log: true

no_log: true 会隐藏该任务输出,排障变难,只加在真正敏感处。


7. 与 SSH 私钥、机器身份的关系

秘密类型建议存放
控制节点 SSH 私钥控制节点文件系统 + 权限 600,或 ssh-agent / 硬件钥;一般不进 Git Vault
应用 TLS keyVault 加密变量或从密钥系统下发
云 API KeyCI 密钥注入 / Vault / 云侧 IAM 角色(更优)

把「登录机器的钥匙」和「应用用的钥匙」分开管理,轮换策略也不同。


8. CI 集成要点

以 GitLab CI / Jenkins 为例,模式相同:

  1. CI 变量保存 Vault 密码(masked + protected)
  2. Job 写入临时文件 chmod 600
  3. ansible-playbook --vault-password-file ...
  4. Job 结束删除临时文件

注意:

  • MR 流水线不要用生产 Vault 密码(protected branch only)
  • 日志中关闭冗余 -vvv,避免模块参数泄露
  • 变更人与解密权限可审计(谁触发了 prod job)

伪示例:

echo "$ANSIBLE_VAULT_PASSWORD" > "$CI_PROJECT_DIR/.vault_pass"
chmod 600 "$CI_PROJECT_DIR/.vault_pass"
ansible-playbook -i inventory/prod.ini playbooks/site.yml \
--vault-password-file "$CI_PROJECT_DIR/.vault_pass"
rm -f "$CI_PROJECT_DIR/.vault_pass"

9. 轮换与应急

事件动作
人员离职ansible-vault rekey,并轮换被解密过的业务密码
密码泄露rekey + 轮换全部 vault 内秘密 + 审查 Git 历史访问
紧急明文排障decrypt 到安全介质,结束后删明文并 re-encrypt

Git 历史中若曾提交过明文,加密后历史仍在;需要改写历史或视为已泄露并轮换。


10. 练习与验收

练习 A
创建 group_vars/web/vault.yml,映射 db_password,在 template 中引用;确认未解密时 playbook 失败,解密后成功。

练习 B
encrypt_string 嵌一个变量,ansible-vault view 相关文件确认格式。

练习 C
给写 .env 的 task 加 mode: "0600" 与必要的 no_log

验收清单

  • 仓库中无明文业务密码
  • vars / vault 拆分清晰
  • 本地与 CI 均通过 password-file 解密
  • 知道 rekey 与「历史明文」风险

下一章:生产规范与 Web 节点实战 —— 把 Role、护栏、Vault 收成一套可交付工程。