第十二章:Vault 加密与安全

学习使用 Ansible Vault 加密敏感数据,确保安全。

最后更新: 2024-01-26
页面目录

Ansible Vault 加密与安全

Ansible Vault 是用于加密敏感数据的功能,确保密码、密钥等敏感信息的安全。

Vault 概述

┌─────────────────────────────────────────────────────────────────┐
│                      Ansible Vault                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   明文文件 ─────► ansible-vault ─────► 加密文件                  │
│     encrypt                          decrypt                   │
│                                                                  │
│   ┌─────────────┐                                               │
│   │ Sensitive  │                                               │
│   │   Data     │  ───►  AES-256 加密  ───►  Vault File         │
│   │ Passwords  │                                               │
│   │   Keys     │                                               │
│   │   Tokens   │                                               │
│   └─────────────┘                                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

创建加密文件

基本命令

# 创建加密文件
ansible-vault create secrets.yml

# 编辑加密文件
ansible-vault edit secrets.yml

# 查看加密文件
ansible-vault view secrets.yml

创建流程

# 创建文件,会提示输入密码
$ ansible-vault create vault.yml
New Vault password: ****
Confirm New Vault password: ****

# 文件内容
---
db_password: "supersecret"
api_token: "abc123xyz"

加密现有文件

# 加密文件
ansible-vault encrypt secrets.yml

# 加密多个文件
ansible-vault encrypt secrets.yml prod_secrets.yml

# 加密整个目录
ansible-vault encrypt_string

解密和使用

解密文件

# 解密文件(会提示密码)
ansible-vault decrypt secrets.yml

# 解密到指定文件
ansible-vault decrypt secrets.yml --output=secrets_decrypted.yml

在 Playbook 中使用

# 运行时输入密码
ansible-playbook site.yml --ask-vault-pass

# 使用密码文件
ansible-playbook site.yml --vault-password-file ~/.vault_pass

# 同时使用多个密码
ansible-playbook site.yml \
  --vault-id prod@prompt \
  --vault-id dev@.vault_pass

Vault ID 和多密码

使用 Vault ID

# 创建带 ID 的加密文件
ansible-vault create --vault-id prod@prompt prod_vault.yml
ansible-vault create --vault-id dev@prompt dev_vault.yml

多密码策略

# 生产环境
ansible-vault create --vault-id production@prompt prod_vault.yml

# 开发环境
ansible-vault create --vault-id development@prompt dev_vault.yml

密码文件配置

# 创建密码文件
echo "my_production_password" > ~/.vault_pass_prod
chmod 600 ~/.vault_pass_prod

# 使用密码文件
ansible-playbook site.yml --vault-id prod@~/.vault_pass_prod

ansible.cfg 配置

[defaults]
# 密码文件路径
vault_password_file = ~/.vault_pass

# 或使用脚本
vault_password_file = ~/.vault_pass.sh

# 如果有多个 vault
[privilege_escalation]
# ...

Vault 密码脚本

#!/bin/bash
# ~/.vault_pass.sh

# 根据环境返回不同密码
if [ "$1" = "prod" ]; then
    echo "prod_password"
elif [ "$1" = "dev" ]; then
    echo "dev_password"
else
    echo "default_password"
fi

chmod +x ~/.vault_pass.sh

实践:敏感数据管理

项目结构

project/
├── ansible.cfg
├── site.yml
├── group_vars/
   └── all/
       └── vault.yml          # 加密的通用变量
├── host_vars/
   ├── web1/
      └── vault.yml          # 加密的主机变量
   └── db1/
       └── vault.yml
├── roles/
   └── webserver/
       └── defaults/
           └── main.yml
└── vars/
    └── prod_vault.yml         # 生产环境加密文件

vault.yml 示例

# group_vars/all/vault.yml
---
vault_db_password: "MySecureDBPassword123!"
vault_api_key: "sk_prod_abcdef123456"
vault_aws_access_key: "AKIAIOSFODNN7EXAMPLE"
vault_aws_secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
vault_jwt_secret: "your-super-secret-jwt-signing-key"
vault_smtp_password: "smtp_password_123"

引用加密变量

# 在 Playbook 或任务中使用
---
- name: Configure database
  hosts: dbservers
  vars_files:
    - group_vars/all/vault.yml
  
  tasks:
    - name: Set MySQL root password
      mysql_user:
        name: root
        host: localhost
        password: "{{ vault_db_password }}"
        login_unix_socket: /var/run/mysqld/mysqld.sock

分层 Vault

# group_vars/all/vault.yml
---
vault_shared_secret: "shared_across_all"

# group_vars/production/vault.yml
---
vault_db_password: "prod_db_password"
vault_api_key: "prod_api_key"

# group_vars/staging/vault.yml
---
vault_db_password: "staging_db_password"
vault_api_key: "staging_api_key"

Vault 命令参考

创建和编辑

# 创建加密文件
ansible-vault create file.yml

# 编辑加密文件
ansible-vault edit file.yml

# 查看加密文件
ansible-vault view file.yml

加密和解密

# 加密文件
ansible-vault encrypt file.yml

# 解密文件
ansible-vault decrypt file.yml

# 加密多个文件
ansible-vault encrypt file1.yml file2.yml

# 加密字符串
ansible-vault encrypt_string 'my_secret' --name 'password'

密码管理

# 更改密码
ansible-vault rekey file.yml

# 批量更改密码
ansible-vault rekey file1.yml file2.yml

# 创建密码文件
echo "password" > vault_pass
chmod 600 vault_pass

信息查看

# 查看加密文件信息
ansible-vault view --vault-id prod@prompt file.yml

Playbook 集成

完整示例

# site.yml
---
- name: Deploy application with secrets
  hosts: webservers
  become: yes
  vars_files:
    - group_vars/all/vault.yml
    - group_vars/all/non_secret.yml
  
  tasks:
    - name: Create secrets directory
      file:
        path: /etc/myapp/secrets
        state: directory
        mode: '0700'
    
    - name: Write secret to file
      copy:
        content: |
          DB_PASSWORD={{ vault_db_password }}
          API_KEY={{ vault_api_key }}
        dest: /etc/myapp/secrets/.env
        mode: '0600'
      no_log: true
    
    - name: Configure application
      template:
        src: config.j2
        dest: /etc/myapp/config.yml

运行时指定 Vault

# 交互式输入密码
ansible-playbook site.yml --ask-vault-pass

# 使用密码文件
ansible-playbook site.yml --vault-password-file ~/.vault_pass

# 使用 Vault ID
ansible-playbook site.yml --vault-id dev@prompt

# 生产环境需要两个 vault
ansible-playbook site.yml \
  --vault-id prod@prompt \
  --vault-id prod_secrets@~/.vault_pass_prod

最佳实践

1. 使用强密码

# 生成强随机密码
python3 -c "import secrets; print(secrets.token_urlsafe(32))"

# 使用密码管理器生成
# 1Password, LastPass, Bitwarden 等

2. 分离敏感数据

# 好的实践
# group_vars/all/vault.yml - 加密所有敏感数据
# group_vars/all/public.yml - 非敏感配置

# 不推荐的实践
# 直接在 vars 中写密码
vars:
  db_password: "secret"  # 不安全!

3. 使用 Vault ID 分离环境

# 生产
ansible-vault create --vault-id production@prompt prod_vault.yml

# 测试
ansible-vault create --vault-id test@prompt test_vault.yml

# 开发
ansible-vault create --vault-id dev@prompt dev_vault.yml

4. 保护密码文件

# 设置正确权限
chmod 600 ~/.vault_pass
chmod 700 ~/.vault_pass.sh

# 不提交到 Git
echo ".vault_pass*" >> .gitignore

5. CI/CD 集成

# GitLab CI 示例
# .gitlab-ci.yml
variables:
  ANSIBLE_VAULT_PASSWORD: ${CI_VAULT_PASSWORD}

run_ansible:
  script:
    - echo $ANSIBLE_VAULT_PASSWORD > vault_pass
    - ansible-playbook site.yml --vault-password-file vault_pass

常见问题

忘记 Vault 密码

无法恢复,必须使用备份密码或重新设置。

多个 Vault 文件冲突

# 确保变量名唯一
# 使用前缀区分
vault_prod_db_password
vault_stg_db_password

Vault 文件过大

# 使用外部密钥管理
# AWS KMS, HashiCorp Vault, CyberArk 等

- name: Fetch secret from AWS
  shell: |
    aws secretsmanager get-secret-value \
      --secret-id prod/db-password \
      --query SecretString \
      --output text
  register: db_password
  no_log: true

下一步

现在你已经掌握了 Vault 加密的使用。接下来让我们学习 Ansible Galaxy。

👉 Ansible Galaxy