Ansible Vault: Decrypt และ Edit Encrypted Files

เมื่อเก็บข้อมูล sensitive ด้วย Ansible Vault แล้ว การ decrypt, แก้ไข และ rotate passwords เป็นงานที่ต้องทำเป็นประจำ — Vault มีคำสั่งครบถ้วนสำหรับ lifecycle management ของ encrypted files ทั้ง view, edit, decrypt, rekey และการจัดการ vault ใน CI/CD pipeline

บทความนี้ครอบคลุม ansible-vault view และ edit สำหรับดูและแก้ไข, decrypt สำหรับแปลงกลับเป็น plain text, rekey สำหรับเปลี่ยน password, การใช้ Vault ใน CI/CD, การ migrate จาก plain text ไป Vault และ best practices สำหรับ vault management ใน team

ansible-vault view — ดูเนื้อหาโดยไม่สร้าง Plain Text

ansible-vault view decrypt ไฟล์ชั่วคราวเพื่อแสดงใน terminal แล้วลบออกทันที — ไม่มีไฟล์ plain text ค้างบน disk ทำให้ปลอดภัยกว่า decrypt

# ดูเนื้อหา vault file (prompt ขอ password)
ansible-vault view group_vars/all/vault.yml

# ดูโดยใช้ password file
ansible-vault view --vault-password-file .vault_pass group_vars/all/vault.yml

# ดูหลาย files ต่อเนื่อง
ansible-vault view group_vars/all/vault.yml
ansible-vault view group_vars/production/vault.yml
ansible-vault view host_vars/db01/vault.yml

# ดูด้วย vault ID
ansible-vault view --vault-id [email protected]_pass_prod group_vars/production/vault.yml

# ตรวจสอบว่าไฟล์เป็น vault หรือไม่ก่อน view
head -1 group_vars/all/vault.yml
# ถ้าขึ้นต้น $ANSIBLE_VAULT → เป็น encrypted file

ansible-vault edit — แก้ไข Encrypted File โดยตรง

ansible-vault edit decrypt ชั่วคราว เปิด editor แล้ว re-encrypt อัตโนมัติเมื่อบันทึก — ไม่ต้อง decrypt → แก้ไข → encrypt เอง เป็น workflow ที่ปลอดภัยที่สุดสำหรับแก้ไข vault

# เปิดแก้ไข (จะเปิด $EDITOR หรือ vi เป็น default)
ansible-vault edit group_vars/all/vault.yml

# กำหนด editor เฉพาะ
EDITOR=nano ansible-vault edit group_vars/all/vault.yml
EDITOR=code ansible-vault edit group_vars/all/vault.yml

# แก้ไขด้วย password file
ansible-vault edit --vault-password-file .vault_pass group_vars/all/vault.yml

# workflow ที่แนะนำ:
# 1. ใช้ ansible-vault edit เสมอ — ไม่มี plain text ค้างบน disk
# 2. ถ้าต้องการ diff — ใช้ ansible-vault view ก่อน แล้ว edit
# 3. ระวัง: ถ้า editor crash ระหว่าง edit อาจมี tmp file ค้าง
#    ตรวจสอบด้วย: ls /tmp/.ansible_vault_*

ansible-vault decrypt — แปลงกลับเป็น Plain Text

ansible-vault decrypt แปลง encrypted file กลับเป็น plain text ถาวร — ใช้เฉพาะเมื่อจำเป็นจริง ๆ เช่น migration หรือ debugging และต้อง re-encrypt ทันทีหลังเสร็จ

# Decrypt ไฟล์ (แปลงกลับเป็น plain text ถาวร)
ansible-vault decrypt group_vars/all/vault.yml

# Decrypt ด้วย password file
ansible-vault decrypt --vault-password-file .vault_pass group_vars/all/vault.yml

# Decrypt ไปยัง output file ต่างหาก (ไม่แก้ไขต้นฉบับ)
ansible-vault decrypt group_vars/all/vault.yml --output /tmp/vault_decrypted.yml

# Decrypt หลายไฟล์พร้อมกัน
ansible-vault decrypt \
  group_vars/all/vault.yml \
  group_vars/production/vault.yml

# !!! สำคัญมาก: Re-encrypt ทันทีหลังเสร็จ !!!
# ห้ามปล่อย plain text ค้างใน repo
ansible-vault encrypt group_vars/all/vault.yml

# ตรวจสอบว่า encrypt แล้วจริงก่อน commit
head -1 group_vars/all/vault.yml
# ต้องขึ้นต้น: $ANSIBLE_VAULT;1.1;AES256

ansible-vault rekey — เปลี่ยน Vault Password

ansible-vault rekey เปลี่ยน encryption password โดยไม่ต้อง decrypt → encrypt ใหม่เอง — ใช้เมื่อต้องการ rotate password เป็นประจำหรือเมื่อสงสัยว่า password ถูกรู้โดยผู้ที่ไม่ควรรู้

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

# เปลี่ยนด้วย password files (สำหรับ automation)
ansible-vault rekey \
  --vault-password-file .old_vault_pass \
  --new-vault-password-file .new_vault_pass \
  group_vars/all/vault.yml

# เปลี่ยน password หลายไฟล์พร้อมกัน
ansible-vault rekey \
  --vault-password-file .old_vault_pass \
  --new-vault-password-file .new_vault_pass \
  group_vars/all/vault.yml \
  group_vars/production/vault.yml \
  host_vars/db01/vault.yml

# Rekey workflow ที่แนะนำ:
# 1. สร้าง new password file
echo "NewVaultPassword2024" > .new_vault_pass
chmod 600 .new_vault_pass
# 2. Rekey ทุกไฟล์
find . -name "vault.yml" -exec ansible-vault rekey \
  --vault-password-file .old_vault_pass \
  --new-vault-password-file .new_vault_pass {} \;
# 3. ทดสอบว่า decrypt ได้ด้วย new password
ansible-vault view --vault-password-file .new_vault_pass group_vars/all/vault.yml
# 4. แทนที่ .vault_pass ด้วย new password
mv .new_vault_pass .vault_pass
rm .old_vault_pass

Vault ใน CI/CD Pipeline

ใน CI/CD เช่น GitHub Actions หรือ GitLab CI ไม่มี interactive prompt — ต้องใช้ vault password ผ่าน environment variable หรือ secrets manager เพื่อให้ pipeline decrypt vault ได้อัตโนมัติ

# วิธีที่ 1: ใช้ environment variable กับ script
# get_vault_pass.sh:
#!/bin/bash
echo "$ANSIBLE_VAULT_PASSWORD"

# ใน GitHub Actions:
# env:
#   ANSIBLE_VAULT_PASSWORD: ${{ secrets.VAULT_PASSWORD }}

# ansible.cfg:
[defaults]
vault_password_file = ./get_vault_pass.sh

# วิธีที่ 2: เขียน password จาก env ลงไฟล์ชั่วคราว
# .github/workflows/deploy.yml:
# - name: Setup vault password
#   run: echo "${{ secrets.VAULT_PASSWORD }}" > .vault_pass
# - name: Run playbook
#   run: ansible-playbook site.yml
# - name: Cleanup
#   run: rm -f .vault_pass
#   if: always()

# วิธีที่ 3: ใช้ --vault-password-file กับ /dev/stdin
echo "$ANSIBLE_VAULT_PASSWORD" | ansible-playbook site.yml \
  --vault-password-file /dev/stdin

Migrate Plain Text ไป Vault

การ migrate project ที่มี credentials เป็น plain text อยู่แล้วให้เป็น vault — ทำทีละขั้นตอนเพื่อไม่ให้ playbook หยุดทำงาน

# ขั้นตอน migrate plain text → vault

# 1. ระบุ variables ที่เป็น sensitive
# ค้นหา patterns ที่น่าสงสัยใน group_vars/
grep -r "password\|secret\|key\|token" group_vars/ --include="*.yml"

# 2. สร้าง vault.yml ใหม่จาก variables ที่พบ
ansible-vault create group_vars/all/vault.yml
# เขียน vault variables ใน editor:
# vault_db_password: "รหัสที่เคยอยู่ใน main.yml"
# vault_api_key: "key ที่เคยอยู่ใน main.yml"

# 3. แก้ไข main.yml ให้ reference vault variables แทน
# เปลี่ยนจาก:
# db_password: "PlainTextPass"
# เป็น:
# db_password: "{{ vault_db_password }}"

# 4. ลบ plain text values จาก main.yml

# 5. ทดสอบ playbook ด้วย vault
ansible-playbook site.yml --vault-password-file .vault_pass --check

# 6. Commit vault.yml (encrypted) และ main.yml ที่แก้ไขแล้ว
# ห้าม commit .vault_pass !!!
git add group_vars/all/vault.yml group_vars/all/main.yml
git commit -m "Migrate sensitive vars to Ansible Vault"

ตรวจสอบ Git History หลัง Migrate

หลัง migrate ต้องตรวจสอบว่า plain text credentials ไม่ถูก commit ไว้ใน git history ก่อนหน้า — ถ้ามีต้องล้างออกและ rotate passwords ทันที

# ตรวจสอบว่า git history มี plain text passwords หรือไม่
git log --all --full-history -- group_vars/all/main.yml | head -20

# ค้นหา sensitive strings ใน git history
git grep "password:" $(git log --all --pretty=format:"%H")

# ถ้าพบ plain text ใน history → ต้อง rewrite history
# (ใช้ git-filter-repo หรือ BFG Repo-Cleaner)
# แต่วิธีที่ง่ายและปลอดภัยกว่าคือ rotate passwords ทันที

# Rotate passwords หลังพบว่า exposed:
# 1. เปลี่ยน password จริงบน server ก่อน
# 2. แก้ไข vault.yml ด้วย ansible-vault edit
# 3. Run playbook เพื่อ apply new password
ansible-playbook site.yml --tags "update_credentials"

# ตรวจสอบว่า vault files ใน current commit ถูก encrypt แล้ว
git show HEAD:group_vars/all/vault.yml | head -1
# ต้องเป็น: $ANSIBLE_VAULT;1.1;AES256

Best Practices สำหรับ Vault Management ใน Team

การจัดการ vault ใน team ต้องพิจารณาเรื่อง password sharing, rotation schedule และ access control เพื่อให้ทั้ง security และ usability ไปด้วยกันได้

# Best practices สำหรับ team vault management

# 1. ใช้ vault password manager แทนไฟล์ plain text
# เช่น 1Password, HashiCorp Vault, AWS Secrets Manager
# script ดึง password จาก 1Password CLI:
#!/bin/bash
op item get "Ansible Vault Password" --field password

# 2. กำหนด rotation schedule
# - Rotate vault password: ทุก 90 วัน
# - Rotate application secrets: ทุก 30 วัน
# - Rotate ทันทีเมื่อ: ลบ team member ออก, สงสัยถูก expose

# 3. แยก vault passwords ตาม environment
# .vault_pass_dev    (ทุกคนในทีมเข้าถึงได้)
# .vault_pass_staging (เฉพาะ senior devs)
# .vault_pass_prod   (เฉพาะ ops team)

# 4. ใช้ pre-commit hook ป้องกัน commit plain text
# .git/hooks/pre-commit:
#!/bin/bash
# ตรวจว่าไม่มี vault files ที่ยัง plain text
for f in $(git diff --cached --name-only | grep vault.yml); do
  if ! head -1 "$f" | grep -q "ANSIBLE_VAULT"; then
    echo "ERROR: $f is not encrypted! Run: ansible-vault encrypt $f"
    exit 1
  fi
done

# 5. Document vault structure ใน README.md
# ระบุ: ไฟล์ vault ไหนมีอะไรบ้าง, ใครเป็นคน rotate, เก็บ password ที่ไหน

สรุป

Ansible Vault lifecycle มีคำสั่งครบสำหรับทุก operation — view สำหรับดูโดยปลอดภัย, edit สำหรับแก้ไขโดยตรง, decrypt สำหรับแปลงเป็น plain text เมื่อจำเป็น, rekey สำหรับ rotate password และ script-based password สำหรับ CI/CD automation

Pattern ที่ควรจำ: ใช้ edit แทน decrypt เสมอเพื่อหลีกเลี่ยง plain text ค้างบน disk, ถ้าต้อง decrypt ให้ encrypt กลับทันที, ใช้ pre-commit hook ป้องกัน commit vault files ที่ยัง plain text, rotate vault password ทุก 90 วันและทันทีเมื่อลบ team member ออก และใช้ secrets manager แทน plain text password file ใน production