把密钥加密后放进仓库
目标
把 secret 存放在仓库中但不保留明文,并熟练掌握只在执行时解密使用的流程。
为什么重要
secret 管理的衡量标准不是“是否加密”,而是**“有多少条泄露路径,以及吊销和轮换需要多少分钟”**。当 secret 与代码位于同一仓库时,可以统计数量并经过 review,从而回答这两个问题。相反,如果它们散落在 .env 文件、聊天记录和 wiki 中,就几乎无法彻底吊销。本实验尤其需要注意两点:密码文件应放在仓库外或加入 .gitignore,并把权限设为 600;同时,处理 secret 的 task 必须添加 no_log。如果费力加密后又把明文打印到执行日志中,加密就毫无意义。
步骤
- 创建不少于 8 字节的
/root/ans/vault/.vault_pass,并将权限设为600。在/root/ans/vault/.gitignore中加入.vault_pass。 - 将
/opt/lab/fixtures/ansible/vault-secrets.plain.yml复制到/root/ans/vault/vars/secrets.yml后加密。第一行必须是 vault header,且不得看到明文密码。 - 创建
/root/ans/vault/vars/inline.yml,只加密registry_token键的值。该值可以是任意以ghp_开头的字符串,文件本身必须保持明文。 - 在
/root/ans/vault/site.yml中读取加密变量并创建/root/ans/vault/artifacts/app.env。内容要包含DB_PASSWORD=labhub-Pr0d-2026,权限为600。 - 给处理 secret 的 task 添加
no_log,并把执行日志保存到/root/ans/vault/out/run.txt。日志中不得留下密码。 - 创建
/root/ans/vault/.vault_pass_new,并对secrets.yml执行 rekey。新密码可以打开文件,旧密码则不能。 - 创建
/root/ans/vault/.vault_pass_prod,并加密/root/ans/vault/vars/prod.yml,所用 vault-id 的标签为prod。header 必须是$ANSIBLE_VAULT;1.2;AES256;prod。 - 创建
/root/ans/vault/out/audit.json,其中包含三个键:encrypted_files(至少 3 个加密文件路径)、plaintext_leaks(0 个)和verdict("clean")。
参考
- 每个实验都会启动全新的实验 Pod。如果
/root/ans/inventory/hosts.ini不存在,请先重新创建与第一个实验相同的 inventory(web1·web2·db1,ansible_host=127.0.0.1、ansible_port=2222、ansible_user=root,并在[prod:children]中加入 web·db)。结构可以参考/opt/lab/fixtures/ansible/inventory.sample.ini。 - 执行时添加
--vault-password-file /root/ans/vault/.vault_pass。 - 使用
ansible-vault view 파일可以只查看解密结果,文件本身不会改变。 - 常见错误 1:密码文件末尾的换行导致无法打开。文件中只保留一行密码。
- 常见错误 2:没有添加
no_log,使 secret 原样出现在debug输出或模块结果中。
创建并保护密码文件
创建不少于 8 字节的 /root/ans/vault/.vault_pass,并将权限设为 600。在 /root/ans/vault/.gitignore 中加入 .vault_pass。
至少使用 8 个字符,并将权限设为 600。该文件绝对不能被提交。
加密整个变量文件
将 /opt/lab/fixtures/ansible/vault-secrets.plain.yml 复制到 /root/ans/vault/vars/secrets.yml 后加密。第一行必须是 vault header,且不得看到明文密码。
复制 fixture 中的明文文件后执行 encrypt。第一行应变为 vault header。
只对单个值进行内联加密
创建 /root/ans/vault/vars/inline.yml,只加密 registry_token 键的值。该值可以是任意以 ghp_ 开头的字符串,文件本身必须保持明文。
把 encrypt_string 的输出粘贴到 YAML 文件中。文件本身是明文,只有值是密文。
在 playbook 中使用解密后的值
在 /root/ans/vault/site.yml 中读取加密变量并创建 /root/ans/vault/artifacts/app.env。内容要包含 DB_PASSWORD=labhub-Pr0d-2026,权限为 600。
通过 vars_files 读取加密文件,并使用 --vault-password-file 运行。结果文件的权限为 600。
防止 secret 留在日志中
给处理 secret 的 task 添加 no_log,并把执行日志保存到 /root/ans/vault/out/run.txt。日志中不得留下密码。
给处理 secret 的 task 添加 no_log,并亲自确认执行日志中没有该值。
轮换密码
创建 /root/ans/vault/.vault_pass_new,并对 secrets.yml 执行 rekey。新密码可以打开文件,旧密码则不能。
rekey 后,旧密码必须无法再打开文件。请另行创建新密码文件。
使用 vault-id 标签区分密钥
创建 /root/ans/vault/.vault_pass_prod,并加密 /root/ans/vault/vars/prod.yml,所用 vault-id 的标签为 prod。header 必须是 $ANSIBLE_VAULT;1.2;AES256;prod。
格式为 --vault-id 라벨@파일。使用标签后,header 版本会变为 1.2,并写入该标签。
生成仓库 secret 审计报告
创建 /root/ans/vault/out/audit.json,其中包含三个键:encrypted_files(至少 3 个加密文件路径)、plaintext_leaks(0 个)和 verdict("clean")。
将加密文件列表和明文泄露列表整理为 JSON。泄露数量必须为 0。