Ansible Vault: เข้ารหัส Sensitive Data (Passwords, Keys)

Ansible Vault เป็นฟีเจอร์ในตัวของ Ansible สำหรับเข้ารหัส sensitive data เช่น passwords, API keys, private keys และ database credentials — แทนที่จะเก็บข้อมูลเหล่านี้เป็น plain text ใน playbook หรือ inventory, Vault เข้ารหัสด้วย AES-256 ทำให้ commit ไว้ใน git ได้อย่างปลอดภัย

บทความนี้ครอบคลุมการสร้างและเข้ารหัสไฟล์ด้วย ansible-vault create และ encrypt, การเข้ารหัส string เดี่ยวด้วย encrypt_string, การใช้ vault password file และ password prompt, การ decrypt เพื่อดูข้อมูล และ pattern สำหรับ vault ใน production project

Ansible Vault คืออะไรและทำงานอย่างไร

Vault ใช้ AES-256-CBC encryption พร้อม PBKDF2 key derivation — ไฟล์ที่เข้ารหัสแล้วขึ้นต้นด้วย $ANSIBLE_VAULT; บอก Ansible ว่าต้อง decrypt ก่อนใช้งาน

# ตัวอย่างไฟล์ที่เข้ารหัสด้วย Vault
$ANSIBLE_VAULT;1.1;AES256
66386439653236336462626566653131623064656263353735303136
33626262396430383933353831346631623831656437656463643339
...

# Vault ทำงานได้กับ:
# - ไฟล์ทั้งไฟล์ (เช่น group_vars/all/vault.yml)
# - ตัวแปรเดี่ยวในไฟล์ YAML (inline encrypted string)
# - ไฟล์ทุกประเภท (binary, certs, keys)

# การทำงานเมื่อ run playbook:
# ansible-playbook site.yml --ask-vault-pass
# ansible-playbook site.yml --vault-password-file .vault_pass

สร้างและเข้ารหัสไฟล์ด้วย ansible-vault create

ansible-vault create เปิด text editor เพื่อให้เขียนเนื้อหา แล้วบันทึกเป็น encrypted file ทันที — เหมาะสำหรับสร้างไฟล์ vault ใหม่ที่เก็บ credentials หลายตัว

# สร้างไฟล์ vault ใหม่ (เปิด $EDITOR)
ansible-vault create group_vars/all/vault.yml

# เนื้อหาที่เขียนใน editor (plain text ก่อน encrypt):
---
vault_db_password: "MySecretPass123!"
vault_api_key: "sk-abc123xyz789"
vault_redis_password: "RedisSecret456"
vault_smtp_password: "MailSecret789"
vault_ssl_cert_key: |
  -----BEGIN RSA PRIVATE KEY-----
  MIIEowIBAAKCAQEA...
  -----END RSA PRIVATE KEY-----

# ผลลัพธ์: group_vars/all/vault.yml จะเป็น encrypted text
# เมื่อ save และออกจาก editor

# ดู structure ที่แนะนำ:
group_vars/
  all/
    main.yml      # plain variables (references vault vars)
    vault.yml     # encrypted secrets

เข้ารหัสไฟล์ที่มีอยู่แล้ว

ansible-vault encrypt เข้ารหัสไฟล์ที่มีอยู่แล้ว — ใช้เมื่อมีไฟล์ plain text อยู่แล้วและต้องการ encrypt ก่อน commit ใน git

# เข้ารหัสไฟล์ที่มีอยู่
ansible-vault encrypt group_vars/production/secrets.yml

# เข้ารหัสหลายไฟล์พร้อมกัน
ansible-vault encrypt \
  group_vars/production/secrets.yml \
  host_vars/db01/credentials.yml \
  files/ssl/private.key

# เข้ารหัสด้วย vault ID (สำหรับ multiple vault passwords)
ansible-vault encrypt --vault-id prod@prompt secrets.yml

# ตรวจสอบว่าไฟล์ถูกเข้ารหัสแล้ว
head -1 group_vars/production/secrets.yml
# Output: $ANSIBLE_VAULT;1.1;AES256

# ดูเนื้อหาที่เข้ารหัสโดยไม่ decrypt
cat group_vars/production/secrets.yml

เข้ารหัส String เดี่ยวด้วย encrypt_string

ansible-vault encrypt_string เข้ารหัสเฉพาะ string เดียวและได้ output ที่ใส่ inline ใน YAML file ได้ทันที — เหมาะสำหรับเมื่อต้องการเข้ารหัสแค่ค่าเดียวในไฟล์ที่เหลือเป็น plain text

# เข้ารหัส string เดี่ยว (จะ prompt ขอ vault password)
ansible-vault encrypt_string 'MySecretPass123!' --name 'db_password'

# Output ที่ได้:
db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653236336462626566653131623064656263
          35353032366162363138653234386334396536316239
          ...

# นำ output ไปใส่ใน variables file โดยตรง
# group_vars/all/main.yml:
---
app_name: myapp
app_port: 8080
db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653236336462626566...

# เข้ารหัสหลาย strings ต่อเนื่อง
ansible-vault encrypt_string 'secret1' --name 'var1'
ansible-vault encrypt_string 'secret2' --name 'var2'

# Pipe ค่าเข้า (ไม่ต้อง type บน command line)
echo -n 'MySecretPass' | ansible-vault encrypt_string --stdin-name db_password

Vault Password: Prompt vs Password File

Ansible Vault รองรับ 2 วิธีหลักในการระบุ password — --ask-vault-pass สำหรับ interactive use, และ --vault-password-file สำหรับ automation และ CI/CD

# วิธีที่ 1: Prompt ขอ password ทุกครั้ง
ansible-playbook site.yml --ask-vault-pass

# วิธีที่ 2: อ่านจากไฟล์ (สำหรับ automation)
ansible-playbook site.yml --vault-password-file .vault_pass

# สร้าง vault password file
echo "MyVaultPassword" > .vault_pass
chmod 600 .vault_pass

# !!!สำคัญ: เพิ่ม .vault_pass ใน .gitignore เสมอ!!!
echo ".vault_pass" >> .gitignore

# กำหนด default ใน ansible.cfg เพื่อไม่ต้องระบุทุกครั้ง
# ansible.cfg:
[defaults]
vault_password_file = .vault_pass

# วิธีที่ 3: Script ที่ return password (สำหรับ secrets manager)
ansible-playbook site.yml --vault-password-file /opt/scripts/get_vault_pass.sh

# ตัวอย่าง script ดึงจาก environment variable:
#!/bin/bash
echo "$VAULT_PASSWORD"

Multiple Vault Passwords ด้วย Vault ID

Vault ID ช่วยแยก passwords สำหรับ environment ต่าง ๆ — เช่น production ใช้ password ต่างจาก staging โดย label ไว้ในตัว encrypted string เลย

# สร้างไฟล์ vault ด้วย vault ID
ansible-vault create --vault-id prod@prompt group_vars/production/vault.yml
ansible-vault create --vault-id staging@prompt group_vars/staging/vault.yml

# เข้ารหัส string ด้วย vault ID
ansible-vault encrypt_string --vault-id prod@prompt \
  'ProdPassword!' --name db_password

# Output จะมี vault ID label:
db_password: !vault |
          $ANSIBLE_VAULT;1.2;AES256;prod
          ...

# รัน playbook ที่มีหลาย vault IDs
ansible-playbook site.yml \
  --vault-id [email protected]_pass_prod \
  --vault-id [email protected]_pass_staging

# ใช้ prompt สำหรับบาง ID, file สำหรับบาง ID
ansible-playbook site.yml \
  --vault-id prod@prompt \
  --vault-id [email protected]_pass_dev

ดูและแก้ไขไฟล์ที่เข้ารหัส

ใช้ ansible-vault view ดูเนื้อหาโดยไม่บันทึกเป็น plain text, และ ansible-vault edit เปิด editor เพื่อแก้ไขโดยตรง — ทั้งสองคำสั่งไม่ decrypt ไฟล์ค้างไว้

# ดูเนื้อหาโดยไม่บันทึก plaintext
ansible-vault view group_vars/all/vault.yml

# แก้ไขโดยตรงใน editor
ansible-vault edit group_vars/all/vault.yml

# Decrypt ไฟล์ (สร้าง plaintext file) — ระวัง: ไม่ควรทำบน production
ansible-vault decrypt group_vars/all/vault.yml

# Re-encrypt หลังแก้ไข (ถ้า decrypt ไปแล้ว)
ansible-vault encrypt group_vars/all/vault.yml

# เปลี่ยน vault password (rekey)
ansible-vault rekey group_vars/all/vault.yml
# จะ prompt ขอ old password และ new password

# เปลี่ยน password โดยระบุทั้งสองใน command
ansible-vault rekey \
  --vault-password-file .old_vault_pass \
  --new-vault-password-file .new_vault_pass \
  group_vars/all/vault.yml

Pattern: Vault ใน Production Project

โครงสร้างที่แนะนำสำหรับ production project — แยกไฟล์ vault ออกจาก plain variables, ใช้ naming convention ชัดเจน และอ้างอิง vault variables ใน main.yml แทนที่จะใช้ตรงจาก vault

# โครงสร้าง project พร้อม vault
myproject/
├── .gitignore           # ต้องมี .vault_pass และ *.vault_pass*
├── .vault_pass          # ห้าม commit! — เพิ่มใน .gitignore
├── ansible.cfg          # vault_password_file = .vault_pass
├── site.yml
├── group_vars/
│   ├── all/
│   │   ├── main.yml     # plain vars ที่ reference vault vars
│   │   └── vault.yml    # encrypted secrets
│   └── production/
│       ├── main.yml
│       └── vault.yml    # production-specific secrets
└── host_vars/
    └── db01/
        ├── main.yml
        └── vault.yml    # host-specific credentials
# group_vars/all/vault.yml (encrypted — เนื้อหาก่อน encrypt)
---
vault_db_password: "ProdDBPass123!"
vault_app_secret_key: "long-random-secret-key-here"
vault_smtp_password: "SMTPpass456"
vault_api_token: "Bearer abc123xyz"

# group_vars/all/main.yml (plain text — reference vault vars)
---
app_name: myapp
app_port: 8080

# ตั้งชื่อโดยไม่มี vault_ prefix เพื่อ simplicity ใน tasks
db_password:      "{{ vault_db_password }}"
app_secret_key:   "{{ vault_app_secret_key }}"
smtp_password:    "{{ vault_smtp_password }}"
api_token:        "{{ vault_api_token }}"
# ใช้ตัวแปรใน task โดยตรง (ผ่าน main.yml reference)
---
- name: Configure application database
  template:
    src: database.conf.j2
    dest: /etc/myapp/database.conf
    mode: '0640'
  # template ใช้ {{ db_password }} ซึ่งมาจาก main.yml → vault.yml

# ตัวอย่างใน template:
# templates/database.conf.j2:
# [database]
# host = {{ db_host }}
# password = {{ db_password }}   ← ค่ามาจาก vault โดยอัตโนมัติ

# รัน playbook พร้อม vault
ansible-playbook site.yml --vault-password-file .vault_pass
# หรือถ้า set ansible.cfg แล้ว:
ansible-playbook site.yml

สรุป

Ansible Vault ให้วิธีเก็บ sensitive data ใน git อย่างปลอดภัยโดยใช้ AES-256 encryption — สร้างไฟล์ vault ด้วย create, เข้ารหัสไฟล์เดิมด้วย encrypt, เข้ารหัส string เดี่ยวด้วย encrypt_string และดูหรือแก้ไขด้วย view/edit

Pattern ที่ควรจำ: เพิ่ม .vault_pass ใน .gitignore เสมอ, ตั้งชื่อ vault variables ด้วย prefix vault_ และ reference ผ่าน group_vars/all/main.yml แทนการใช้ตรงจาก vault, ใช้ vault_password_file ใน ansible.cfg เพื่อไม่ต้อง type password ทุกครั้ง และใช้ encrypt_string เมื่อต้องการ encrypt แค่ค่าเดียวในไฟล์ที่เหลือเป็น plain text