mgmt/docs/vault/ansible_vault_integration.md

6.5 KiB
Raw Blame History

Ansible与HashiCorp Vault集成指南

本文档介绍如何将Ansible与HashiCorp Vault集成以安全地管理和使用敏感信息。

1. 安装必要的Python包

首先需要安装Ansible的Vault集成包

pip install hvac

2. 配置Ansible使用Vault

2.1 创建Vault连接配置

创建一个Vault连接配置文件 vault_config.yml

vault_addr: http://localhost:8200
vault_role_id: "your-approle-role-id"
vault_secret_id: "your-approle-secret-id"

2.2 创建Vault查询角色

在Vault中创建一个专用于Ansible的AppRole

# 启用AppRole认证
vault auth enable approle

# 创建策略
cat > ansible-policy.hcl <<EOF
path "kv/data/ansible/*" {
  capabilities = ["read"]
}
EOF

vault policy write ansible ansible-policy.hcl

# 创建AppRole
vault write auth/approle/role/ansible \
    token_policies="ansible" \
    token_ttl=1h \
    token_max_ttl=4h

# 获取Role ID
vault read auth/approle/role/ansible/role-id

# 生成Secret ID
vault write -f auth/approle/role/ansible/secret-id

3. 在Ansible中使用Vault

3.1 使用lookup插件

在Ansible playbook中使用hashi_vault查找插件:

---
- name: 使用HashiCorp Vault的示例
  hosts: all
  vars:
    vault_addr: "http://localhost:8200"
    role_id: "{{ lookup('file', '/path/to/role_id') }}"
    secret_id: "{{ lookup('file', '/path/to/secret_id') }}"
    
    # 从Vault获取数据库密码
    db_password: "{{ lookup('hashi_vault', 'secret=kv/data/ansible/db:password auth_method=approle role_id=' + role_id + ' secret_id=' + secret_id + ' url=' + vault_addr) }}"
  
  tasks:
    - name: 配置数据库连接
      template:
        src: db_config.j2
        dest: /etc/app/db_config.ini

3.2 使用环境变量

也可以通过环境变量设置Vault认证信息

---
- name: 使用环境变量的Vault示例
  hosts: all
  environment:
    VAULT_ADDR: "http://localhost:8200"
    VAULT_ROLE_ID: "{{ lookup('file', '/path/to/role_id') }}"
    VAULT_SECRET_ID: "{{ lookup('file', '/path/to/secret_id') }}"
  
  tasks:
    - name: 从Vault获取密钥
      set_fact:
        api_key: "{{ lookup('hashi_vault', 'secret=kv/data/ansible/api:key') }}"

4. 创建Vault密钥模块

创建一个自定义的Ansible角色用于管理Vault中的密钥

4.1 角色结构

roles/
└── vault_secrets/
    ├── defaults/
    │   └── main.yml
    ├── tasks/
    │   └── main.yml
    └── vars/
        └── main.yml

4.2 主任务文件

roles/vault_secrets/tasks/main.yml:

---
- name: 确保Vault令牌有效
  block:
    - name: 获取Vault令牌
      set_fact:
        vault_token: "{{ lookup('hashi_vault', 'auth_method=approle role_id=' + vault_role_id + ' secret_id=' + vault_secret_id + ' url=' + vault_addr) }}"
      no_log: true
  rescue:
    - name: Vault认证失败
      fail:
        msg: "无法从Vault获取有效令牌"

- name: 从Vault读取密钥
  set_fact:
    secrets: "{{ lookup('hashi_vault', 'secret=' + vault_path + ' token=' + vault_token + ' url=' + vault_addr) }}"
  no_log: true
  
- name: 设置各个密钥变量
  set_fact:
    "{{ item.key }}": "{{ item.value }}"
  with_dict: "{{ secrets.data.data }}"
  no_log: true

5. 将现有Ansible Vault迁移到HashiCorp Vault

5.1 创建迁移脚本

创建一个脚本来自动迁移Ansible Vault内容到HashiCorp Vault

#!/bin/bash
# migrate_to_hashicorp_vault.sh

# 设置变量
ANSIBLE_VAULT_FILE=$1
VAULT_PATH=$2
VAULT_ADDR=${VAULT_ADDR:-"http://localhost:8200"}

# 检查参数
if [ -z "$ANSIBLE_VAULT_FILE" ] || [ -z "$VAULT_PATH" ]; then
  echo "用法: $0 <ansible_vault_file> <vault_path>"
  echo "示例: $0 group_vars/all/vault.yml kv/ansible/group_vars/all"
  exit 1
fi

# 检查Vault登录状态
if ! vault token lookup >/dev/null 2>&1; then
  echo "请先登录Vault: vault login <token>"
  exit 1
fi

# 解密Ansible Vault文件
echo "解密Ansible Vault文件..."
TEMP_FILE=$(mktemp)
ansible-vault decrypt --output="$TEMP_FILE" "$ANSIBLE_VAULT_FILE"

# 将YAML转换为JSON并存储到HashiCorp Vault
echo "迁移密钥到HashiCorp Vault..."
python3 -c "
import yaml, json, sys, subprocess
with open('$TEMP_FILE', 'r') as f:
    data = yaml.safe_load(f)
for key, value in data.items():
    cmd = ['vault', 'kv', 'put', '$VAULT_PATH/' + key, 'value=' + json.dumps(value)]
    subprocess.run(cmd)
"

# 清理临时文件
rm "$TEMP_FILE"

echo "迁移完成! 数据已存储在Vault路径: $VAULT_PATH/"

5.2 执行迁移

# 赋予脚本执行权限
chmod +x migrate_to_hashicorp_vault.sh

# 执行迁移
./migrate_to_hashicorp_vault.sh group_vars/all/vault.yml kv/ansible/group_vars/all

6. 更新Ansible配置

6.1 修改ansible.cfg

更新ansible.cfg文件添加Vault相关配置

[defaults]
vault_identity_list = dev@~/.ansible/vault_dev.txt, prod@~/.ansible/vault_prod.txt

[hashi_vault_collection]
url = http://localhost:8200
auth_method = approle
role_id = /path/to/role_id
secret_id = /path/to/secret_id

6.2 更新现有Playbook

将现有playbook中的Ansible Vault引用替换为HashiCorp Vault引用

# 旧方式
- name: 使用Ansible Vault变量
  debug:
    msg: "数据库密码: {{ vault_db_password }}"

# 新方式
- name: 使用HashiCorp Vault变量
  debug:
    msg: "数据库密码: {{ lookup('hashi_vault', 'secret=kv/data/ansible/db:password') }}"

7. 最佳实践

  1. 避免硬编码认证信息使用环境变量或外部文件存储Vault认证信息
  2. 限制令牌权限为Ansible创建的Vault令牌仅授予必要的最小权限
  3. 设置合理的TTL为Vault令牌设置合理的生命周期避免长期有效的令牌
  4. 使用no_log:对包含敏感信息的任务使用no_log: true防止日志泄露
  5. 定期轮换认证凭据定期轮换AppRole的Secret ID
  6. 使用CI/CD集成在CI/CD流程中集成Vault认证避免手动管理令牌

8. 故障排除

8.1 常见问题

  1. 认证失败

    • 检查Role ID和Secret ID是否正确
    • 验证AppRole是否有正确的策略附加
  2. 路径错误

    • KV v2引擎需要在路径中包含data,例如kv/data/path而不是kv/path
  3. 权限问题

    • 确保AppRole有足够的权限访问请求的密钥

8.2 调试技巧

- name: 调试Vault查询
  debug:
    msg: "{{ lookup('hashi_vault', 'secret=kv/data/ansible/db:password auth_method=approle role_id=' + role_id + ' secret_id=' + secret_id + ' url=' + vault_addr) }}"
  vars:
    ansible_hashi_vault_debug: true