Site logo
Tác giả
  • avatar Nguyễn Đức Xinh
    Name
    Nguyễn Đức Xinh
    Twitter
Ngày xuất bản
Ngày xuất bản

Ansible Vault: Hướng dẫn bảo mật Secrets và quản lý mật khẩu trong Automation - Part 1

Giới Thiệu

Khi làm việc với Ansible, bạn thường xuyên phải lưu trữ thông tin nhạy cảm như:

  • Database passwords
  • API keys và tokens
  • SSH private keys
  • SSL certificates
  • Cloud credentials (AWS, Azure, GCP)

Ansible Vault giúp bạn mã hóa các thông tin này một cách an toàn ngay trong Git repository.

Trong bài học này, bạn sẽ học:

  • Cách encrypt/decrypt files và variables
  • Quản lý vault passwords
  • Best practices cho production
  • Integration với CI/CD

Tại Sao Cần Ansible Vault?

❌ Vấn Đề: Plain Text Secrets

# vars/database.yml - NGUY HIỂM!
db_host: prod-mysql.example.com
db_user: admin
db_password: SuperSecret123!  # ← Ai cũng thấy được
api_key: sk-1234567890abcdef    # ← Lộ trên Git

Hậu quả:

  • Ai có access Git repository đều thấy passwords
  • Secrets bị lộ trong Git history
  • Vi phạm security compliance
  • Rủi ro bị tấn công

✅ Giải Pháp: Ansible Vault

# vars/database.yml - ĐÃ MÃ HÓA
$ANSIBLE_VAULT;1.1;AES256
66386439653231363937303466326534643938316334363761623566633038366235373334613934
6231373537346435643538386264613961633738356265380a666437343932383264633831326437
37373435326634323564346365633866643837653565393037313239333464613736343636343965
3736346338353264300a356531356634383735343031363937653565363261386665303666333632
6234

Chỉ người có vault password mới decrypt được!


Các Lệnh Cơ Bản

1. Encrypt File

# Mã hóa toàn bộ file
ansible-vault encrypt vars/secrets.yml

# Sẽ hỏi password 2 lần
New Vault password: 
Confirm New Vault password:
Encryption successful

2. View Encrypted File

# Xem nội dung file đã mã hóa
ansible-vault view vars/secrets.yml

# Nhập password để xem
Vault password:
db_password: SuperSecret123!
api_key: sk-1234567890abcdef

3. Edit Encrypted File

# Sửa file đã mã hóa (mở editor)
ansible-vault edit vars/secrets.yml

# File sẽ được decrypt tạm thời, sau khi save sẽ encrypt lại

4. Decrypt File

# Giải mã file về plain text
ansible-vault decrypt vars/secrets.yml

# CHÚ Ý: Cẩn thận khi commit sau khi decrypt!

5. Rekey - Đổi Password

# Thay đổi vault password
ansible-vault rekey vars/secrets.yml

Vault password: [old password]
New Vault password: [new password]
Confirm New Vault password: [new password]
Rekey successful

Encrypt String - Inline Encryption

Thay vì mã hóa cả file, bạn có thể mã hóa từng biến:

# Mã hóa một string
ansible-vault encrypt_string 'SuperSecret123!' --name 'db_password'

Output:

db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653231363937303466326534643938316334363761623566633038366235373334613934
          6231373537346435643538386264613961633738356265380a666437343932383264633831326437
          37373435326634323564346365633866643837653565393037313239333464613736343636343965
          3736346338353264300a356531356634383735343031363937653565363261386665303666333632
          6234

Ví Dụ Thực Tế

# Encrypt database password
ansible-vault encrypt_string 'MyDBPass456' --name 'db_password' >> vars/database.yml

# Encrypt API key
ansible-vault encrypt_string 'sk-abc123xyz' --name 'api_key' >> vars/api.yml

File vars/database.yml:

# Các biến bình thường
db_host: mysql.example.com
db_port: 3306
db_name: production

# Biến đã mã hóa
db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653231363937303466326534643938316334363761623566633038366235373334613934
          6231373537346435643538386264613961633738356265380a666437343932383264633831326437
          37373435326634323564346365633866643837653565393037313239333464613736343636343965
          3736346338353264300a356531356634383735343031363937653565363261386665303666333632
          6234

Lợi ích: Chỉ secret được mã hóa, các biến khác vẫn readable!


Chạy Playbook Với Vault

Cách 1: Nhập Password Mỗi Lần

ansible-playbook deploy.yml --ask-vault-pass

Sẽ hỏi password mỗi khi chạy:

Vault password: 

Cách 2: Password File

Tạo file chứa password:

# Tạo password file
echo 'MyVaultPassword123' > ~/.vault_pass.txt

# Phân quyền bảo mật
chmod 600 ~/.vault_pass.txt

Chạy playbook:

ansible-playbook deploy.yml --vault-password-file ~/.vault_pass.txt

Cách 3: Cấu Hình ansible.cfg

# ansible.cfg
[defaults]
vault_password_file = ~/.vault_pass.txt

Bây giờ chạy bình thường:

ansible-playbook deploy.yml
# Không cần --vault-password-file

Cách 4: Environment Variable

export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt
ansible-playbook deploy.yml

Multiple Vault IDs - Nhiều Vault Passwords

Trong thực tế, bạn có thể cần nhiều passwords cho các môi trường khác nhau.

Scenario

  • dev environment: dev vault password
  • staging environment: staging vault password
  • production environment: production vault password

Tạo Encrypted Files Với Vault ID

# Encrypt file cho dev
ansible-vault encrypt vars/dev_secrets.yml --encrypt-vault-id dev

# Encrypt file cho prod
ansible-vault encrypt vars/prod_secrets.yml --encrypt-vault-id prod

Tạo Vault Password Files

# ~/.vault_passwords/dev.txt
DevVaultPass123

# ~/.vault_passwords/prod.txt
ProdVaultPass789

Chạy Playbook Với Multiple Vault IDs

ansible-playbook deploy.yml \
  --vault-id dev@~/.vault_passwords/dev.txt \
  --vault-id prod@~/.vault_passwords/prod.txt

Cấu Hình ansible.cfg

[defaults]
vault_identity_list = dev@~/.vault_passwords/dev.txt, prod@~/.vault_passwords/prod.txt

Vault Password Scripts

Thay vì lưu password trong file, bạn có thể dùng script để lấy password từ secret manager.

Script Lấy Password Từ AWS Secrets Manager

#!/bin/bash
# ~/.vault_scripts/aws_secrets.sh

aws secretsmanager get-secret-value \
  --secret-id ansible-vault-password \
  --query SecretString \
  --output text

Phân quyền:

chmod +x ~/.vault_scripts/aws_secrets.sh

Sử dụng:

ansible-playbook deploy.yml --vault-password-file ~/.vault_scripts/aws_secrets.sh

Script Lấy Password Từ HashiCorp Vault

#!/bin/bash
# ~/.vault_scripts/hashicorp_vault.sh

vault kv get -field=password secret/ansible/vault

Thực Hành: Deploy WordPress Với Vault

Bước 1: Tạo Project Structure

wordpress-deploy/
├── ansible.cfg
├── inventory.yml
├── deploy.yml
├── vars/
│   ├── common.yml
│   └── secrets.yml (encrypted)
└── roles/
    ├── mysql/
    └── wordpress/

Bước 2: Tạo Secrets File

# Tạo file secrets
cat > vars/secrets.yml << EOF
---
# Database credentials
mysql_root_password: RootPass123!
mysql_wordpress_password: WPPass456!

# WordPress admin
wp_admin_user: admin
wp_admin_password: AdminPass789!
wp_admin_email: admin@example.com

# API Keys
sendgrid_api_key: SG.1234567890abcdef
cloudflare_api_key: cf_1234567890xyz
EOF

# Mã hóa file
ansible-vault encrypt vars/secrets.yml

Bước 3: Common Variables

# vars/common.yml (không mã hóa)
---
mysql_host: localhost
mysql_port: 3306
mysql_database: wordpress

wp_version: "6.4"
wp_site_url: "https://example.com"
wp_site_title: "My WordPress Site"

Bước 4: Playbook

# deploy.yml
---
- name: Deploy WordPress với MySQL
  hosts: webservers
  become: yes
  
  vars_files:
    - vars/common.yml
    - vars/secrets.yml  # File đã encrypt
  
  tasks:
    - name: Install MySQL Server
      apt:
        name: mysql-server
        state: present
    
    - name: Create WordPress database
      mysql_db:
        name: "{{ mysql_database }}"
        state: present
        login_unix_socket: /var/run/mysqld/mysqld.sock
    
    - name: Create WordPress user
      mysql_user:
        name: wordpress
        password: "{{ mysql_wordpress_password }}"  # Từ vault
        priv: "{{ mysql_database }}.*:ALL"
        state: present
        login_unix_socket: /var/run/mysqld/mysqld.sock
    
    - name: Download WordPress
      get_url:
        url: "https://wordpress.org/wordpress-{{ wp_version }}.tar.gz"
        dest: /tmp/wordpress.tar.gz
    
    - name: Extract WordPress
      unarchive:
        src: /tmp/wordpress.tar.gz
        dest: /var/www/html
        remote_src: yes
    
    - name: Configure wp-config.php
      template:
        src: templates/wp-config.php.j2
        dest: /var/www/html/wordpress/wp-config.php
        mode: '0640'

Bước 5: Template File

<!-- templates/wp-config.php.j2 -->
<?php
define('DB_NAME', '{{ mysql_database }}');
define('DB_USER', 'wordpress');
define('DB_PASSWORD', '{{ mysql_wordpress_password }}');
define('DB_HOST', '{{ mysql_host }}');

// Security keys - từ vault
define('AUTH_KEY',         '{{ wp_auth_key | default("put your unique phrase here") }}');
define('SECURE_AUTH_KEY',  '{{ wp_secure_auth_key | default("put your unique phrase here") }}');
?>

Bước 6: Chạy Deployment

# Chạy với vault password
ansible-playbook deploy.yml --ask-vault-pass

# Hoặc với password file
ansible-playbook deploy.yml --vault-password-file ~/.vault_pass.txt

Best Practices

1. Tách Secrets Ra File Riêng

TỐT:

vars/
├── common.yml          # Public variables
└── secrets.yml         # Encrypted secrets

KHÔNG TỐT:

vars/
└── all.yml             # Mixed public + secrets

2. Git Ignore Plain Text Passwords

# .gitignore
*.vault_pass.txt
.vault_pass
vault-password.txt
*_decrypted.yml

3. Đặt Tên Biến Rõ Ràng

TỐT:

db_password: !vault |...
api_key_production: !vault |...
ssl_certificate_password: !vault |...

KHÔNG TỐT:

pass: !vault |...
key: !vault |...
secret: !vault |...

4. Encrypt Inline Thay Vì Whole File

TỐT (dễ review changes):

# vars/database.yml
db_host: mysql.example.com  # Plain text
db_port: 3306              # Plain text
db_password: !vault |      # Chỉ secret mới encrypt
          $ANSIBLE_VAULT;1.1;AES256
          ...

KHÔNG TỐT (khó review):

# Toàn bộ file encrypted - không biết gì thay đổi

5. Rotate Passwords Định Kỳ

# Đổi vault password mỗi quý
ansible-vault rekey vars/secrets.yml

# Backup trước khi rekey
cp vars/secrets.yml vars/secrets.yml.backup

Tiếp tục phần sau...