Ansible Vault

Ansible Vault #

Setiap project Ansible yang serius menyimpan data sensitif: password database, API key, private key SSL, token autentikasi, dan kredensial layanan pihak ketiga. Menyimpan nilai-nilai ini dalam plaintext di repository Git adalah risiko keamanan yang tidak bisa diterima — cukup satu commit yang ceroboh, satu clone ke laptop yang hilang, atau satu kontributor yang kurang hati-hati, dan seluruh infrastruktur bisa terbuka ke publik. Ansible Vault adalah solusi bawaan Ansible untuk masalah ini: ia mengenkripsi file atau string individual menggunakan algoritma AES-256, sehingga data sensitif bisa disimpan aman di Git tanpa risiko bocor ke orang yang tidak berkepentingan. Artikel ini membahas cara kerja Vault di balik layar, dua mode enkripsi yang tersedia, strategi mengelola vault password, integrasi dengan role dan CI/CD, serta pola yang harus kita hindari agar implementasi Vault benar-benar memberikan perlindungan yang diharapkan.

Mengapa Vault Itu Penting #

Sebelum membahas sintaks dan perintah, penting untuk memahami ancaman apa yang sebenarnya di mitigasi oleh Vault. Ada tiga skenario umum yang menyebabkan secret bocor dari repository Ansible, dan setiap skenario membutuhkan perlindungan yang berbeda.

Skenario pertama: clone ke developer yang tidak berkepentingan. Repository Ansible di-clone oleh banyak orang — bukan hanya engineer yang menangani deployment production, tapi juga data analyst yang butuh akses ke log, manajer proyek yang ingin membaca dokumentasi, atau kontributor baru yang sedang onboarding. Tanpa enkripsi, semua orang yang punya akses baca ke repository akan melihat semua secret.

Skenario kedua: backup otomatis yang bocor. Banyak tim mencadangkan repository Git ke layanan cloud seperti GitHub, GitLab, Bitbucket, atau mirror internal. Backup ini sering kali memiliki kontrol akses yang lebih longgar dari repository utama — siapa yang punya akses ke organisasi GitHub bisa melihat semua branch, termasuk branch yang berisi secret yang belum dirotasi.

Skenario ketiga: history yang tidak bisa dihapus. Git menyimpan seluruh history perubahan. Jika sebuah file secrets.yml pernah ter-commit dalam bentuk plaintext, menghapusnya di commit berikutnya tidak menghapus record dari history. Siapapun yang punya akses ke repository sebelum commit perbaikan bisa me-recover file tersebut dengan git log -p.

Vault menjawab ketiga skenario ini dengan satu pendekatan: file atau string sensitif tidak pernah ada dalam bentuk plaintext di Git. File yang dienkripsi oleh Vault hanya berisi ciphertext yang tidak bisa dibaca tanpa vault password. Siapapun yangclone repository tanpa vault password akan melihat ciphertext yang tidak berguna.

Vault bukan pengganti secret manager — ia adalah pelengkap. Vault mengenkripsi data at rest di repository, tapi ia tidak mencegah vault password bocor, tidak mencatat audit trail yang detail, dan tidak mendukung rotasi otomatis. Untuk secret yang sangat sensitif seperti database root password atau private key produksi, pertimbangkan untuk menggunakan Vault untuk caching lokal dan external secret manager (HashiCorp Vault, AWS Secrets Manager) sebagai sumber utama. Artikel encryption membahas pola integrasi ini secara mendalam.

Arsitektur: Bagaimana Vault Bekerja di Balik Layar #

Memahami alur kerja Vault membantu kita membuat keputusan yang tepat saat melakukan troubleshoot masalah atau merancang workflow baru. Diagram berikut menunjukkan alur lengkap dari plaintext menjadi ciphertext dan sebaliknya.

flowchart TD
    A["Plaintext file<br/>secrets.yml"] --> B{"ansible-vault<br/>encrypt"}
    B --> C["Vault password<br/>dari prompt / file / env"]
    C --> D["Key derivation<br/>PBKDF2 + salt"]
    D --> E["AES-256-CTR<br/>encryption"]
    E --> F["Ciphertext file<br/>$ANSIBLE_VAULT;1.1;AES256"]
    F --> G["Commit ke Git<br/>aman karena ciphertext"]

    H["Playbook run"] --> I["Ansible baca file vault"]
    I --> J["Vault password<br/>disuplai ke ansible-playbook"]
    J --> K["Decrypt on-the-fly<br/>di memory"]
    K --> L["Variabel tersedia<br/>di runtime"]
    L --> M["Task berjalan<br/>dengan secret asli"]

    G -. commit .-> H

    style B stroke:#ff9800,stroke-width:2px
    style E stroke:#ff9800,stroke-width:2px
    style F stroke:#2196f3,stroke-width:2px
    style K stroke:#2196f3,stroke-width:2px

Tiga hal penting dari diagram ini:

1. Salt dan key derivation. Ansible Vault tidak menggunakan vault password secara langsung sebagai kunci AES. Ia melewati vault password melalui fungsi derivasi kunci berbasis PBKDF2 dengan salt acak. Ini berarti dua file yang dienkripsi dengan password yang sama akan menghasilkan ciphertext yang berbeda, dan serangan rainbow table menjadi tidak efektif.

2. Header $ANSIBLE_VAULT;1.1;AES256. Setiap file yang dienkripsi Vault dimulai dengan header ini. Header memberitahu Ansible versi format Vault yang digunakan dan algoritma yang dipakai. Saat ini Ansible mendukung format 1.1 (standar) dan 1.2 (format baru dengan fitur tambahan). Versi 1.1 sudah cukup untuk kebanyakan kasus.

3. Decrypt on-the-fly. File vault tidak pernah di-decrypt ke disk saat playbook berjalan. Ansible mendekripsi di memory, menggunakan nilai plaintext hanya untuk task yang sedang berjalan, lalu melepaskannya saat playbook selesai. Ini meminimalkan window di mana secret berada dalam bentuk yang bisa diekstrak.

Format Vault 1.2 (diperkenalkan di Ansible 2.12) membawa beberapa peningkatan: dukungan key wrapping yang lebih baik, format binary yang lebih ringkas, dan kemampuan untuk mengenkripsi dengan multiple vault ID dalam satu file. Untuk project baru, gunakan format 1.2 kecuali ada kompatibilitas dengan Ansible versi lama. Set format default dengan ANSIBLE_VAULT_FORMAT=1.2 di environment.

Dua Mode: Enkripsi File vs Enkripsi String #

Vault mendukung dua granularitas enkripsi yang berbeda. Masing-masing punya tempat yang tepat dalam strategi keamanan Ansible.

Mode 1: Enkripsi file penuh #

Seluruh isi file dienkripsi menjadi ciphertext. Mode ini cocok untuk file yang isinya seluruhnya sensitif — misalnya vault.yml yang berisi semua secret production.

# Enkripsi file yang sudah ada (file plaintext di-overwrite dengan ciphertext)
ansible-vault encrypt group_vars/production/vault.yml

# Buat file terenkripsi baru langsung dari editor
ansible-vault create group_vars/production/vault.yml

# Edit file terenkripsi — Ansible decrypt, buka editor, encrypt lagi saat simpan
ansible-vault edit group_vars/production/vault.yml

# Lihat isi tanpa membuka editor
ansible-vault view group_vars/production/vault.yml

# Decrypt permanen ke disk (hati-hati — akan menulis plaintext!)
ansible-vault decrypt group_vars/production/vault.yml

Kapan pakai mode ini: ketika sebuah file hanya berisi data sensitif dan tidak ada nilai biasa yang perlu di-review di Git. File vault.yml di group_vars/production/ adalah contoh klasik — isinya 100% password dan token.

Mode 2: Enkripsi string individual #

Hanya nilai tertentu yang dienkripsi, sedangkan struktur file YAML tetap dalam plaintext. Mode ini cocok untuk file yang sebagian besar isinya biasa tapi ada satu atau dua nilai yang sensitif.

# Enkripsi sebuah string dan tampilkan di stdout
ansible-vault encrypt_string 'SuperSecret123' --name 'db_password'

Output yang dihasilkan:

db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  66386439653236336462626566653339316533393634313636353535623135623
  3365663636343365623062323438353563373832663430640a633138623430383
  ...

String terenkripsi ini bisa langsung ditempel ke file YAML mana pun, bercampur dengan variabel plaintext biasa. Saat Ansible menjalankan playbook, ia mengenali tag !vault dan mendekripsi nilai tersebut secara otomatis.

Kapan pakai mode ini: ketika sebuah file berisi campuran variabel biasa (yang perlu di-review di Git, misalnya hostname, port, nama environment) dan nilai sensitif (yang tidak boleh terlihat). Contoh: file group_vars/all/vars.yml yang berisi konfigurasi umum untuk semua server.

Tabel Perbandingan Kedua Mode #

Aspek Enkripsi File Penuh Enkripsi String Individual
Granularitas Seluruh file ciphertext Hanya nilai tertentu yang ciphertext
File bisa di-review di Git Tidak (semua ciphertext) Ya (struktur plaintext, hanya nilai yang sensitif)
Perintah utama ansible-vault encrypt ansible-vault encrypt_string
Kasus penggunaan vault.yml dedicated File vars campuran
Overhead edit Harus decrypt → edit → encrypt tiap kali Edit biasa, hanya nilai !vault yang di-decode
Cocok untuk tim besar Kurang (sulit code review) Lebih (struktur tetap visible)
Performa runtime Sama Sama

Decision Tree Memilih Mode #

flowchart TD
    A["File berisi data sensitif?"] -- "Tidak" --> B["Tidak perlu Vault"]
    A -- "Ya" --> C{"File isinya 100%<br/>data sensitif?"}
    C -- "Ya" --> D["Mode: Enkripsi File Penuh<br/>ansible-vault encrypt"]
    C -- "Tidak" --> E{"Ada nilai biasa<br/>yang perlu di-review?"}
    E -- "Ya" --> F["Mode: Enkripsi String<br/>ansible-vault encrypt_string"]
    E -- "Tidak" --> G["Pisah jadi 2 file:<br/>vars.yml + vault.yml"]
    G --> D

    style D stroke:#2196f3,stroke-width:2px
    style F stroke:#2196f3,stroke-width:2px
    style G stroke:#2196f3,stroke-width:2px

Tabel Lengkap Operasi Vault #

Setiap sub-perintah ansible-vault punya tujuan spesifik. Tabel ini merangkum semuanya dengan contoh penggunaan dan catatan penting.

Perintah Tujuan Contoh Catatan Penting
encrypt Enkripsi file yang sudah ada ansible-vault encrypt vars.yml File asli di-overwrite dengan ciphertext
create Buat file baru dan langsung enkripsi ansible-vault create vault.yml Membuka editor, lalu encrypt saat simpan
decrypt Decrypt permanen ke disk ansible-vault decrypt vault.yml Hati-hati — file jadi plaintext
view Lihat isi tanpa ubah file ansible-vault view vault.yml Read-only, keluar tanpa simpan
edit Decrypt → buka editor → encrypt lagi ansible-vault edit vault.yml Editor dari EDITOR env var
rekey Ganti vault password tanpa decrypt ansible-vault rekey vault.yml Butuh password lama dan baru
encrypt_string Enkripsi sebuah string ansible-vault encrypt_string 'secret' Output ke stdout, copy-paste manual
encrypt_string --stdin-name Enkripsi string dari stdin echo "secret" | ansible-vault encrypt_string --stdin-name Berguna untuk script

Poin penting dari tabel ini:

  • decrypt jarang dipakai dalam workflow normal — ia menghapus perlindungan. Jika kita perlu “melihat” isi file, gunakan view. Kalau perlu “mengedit”, gunakan edit (file akan ter-encrypt lagi saat simpan).
  • rekey adalah cara resmi untuk mengganti vault password tanpa risiko plaintext terekspos di disk. Operasi rekey hanya menerima input/output ciphertext; tidak ada tahap intermediate di mana file berada dalam plaintext.
  • encrypt_string tidak menulis file — kita harus menyalin output dan menempelkannya secara manual ke file target. Ini adalah fitur keamanan (tidak ada plaintext yang ditulis ke disk), tapi juga sumber kesalahan umum (lupa menyalin output).

Vault Password Management: Sumber dan Strategi #

Vault password adalah kunci enkripsi yang paling kritis — siapa yang memiliki password ini bisa mendekripsi semua file yang dienkripsi dengan password tersebut. Ada beberapa cara menyediakannya ke Ansible, dan pilihan yang tepat bergantung pada konteks eksekusi: dijalankan secara manual oleh engineer, dijalankan oleh CI/CD, atau dijalankan oleh orchestrator seperti AWX.

Sumber Vault Password #

# Cara 1: Prompt interaktif — Ansible bertanya saat playbook mulai
ansible-playbook site.yml --ask-vault-pass

# Cara 2: File password — Ansible membaca dari file
ansible-playbook site.yml --vault-password-file ~/.vault_pass

# Cara 3: Skrip pembangk password — output stdout menjadi password
ansible-playbook site.yml --vault-password-file ~/bin/get-vault-pass.sh

# Cara 4: Environment variable
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
ansible-playbook site.yml
# ansible.cfg — set default agar tidak perlu flag tiap kali
[defaults]
vault_password_file = ~/.vault_pass

File vault password tidak boleh di-commit ke Git. Tambahkan ke .gitignore segera setelah membuatnya. File ini berisi kunci enkripsi semua secret — bocornya satu file berarti bocornya semua vault yang menggunakan password tersebut.

# .gitignore
.vault_pass
*.vault_pass
vault_pass.txt
ansible_vault_password

ANTI-PATTERN: vault password di repository #

# ANTI-PATTERN: password di dalam playbook atau vars file
# File: group_vars/all/vault.yml
vault_db_password: "MyVaultPassword123!"   # ← JANGAN! Ini bukan cara kerja Vault
# BENAR: password di file terpisah, di luar repository
# File: ~/.vault_pass (chmod 600)
MyVaultPassword123!

# ansible.cfg referensikan file ini
[defaults]
vault_password_file = ~/.vault_pass
# BENAR (alternatif): password dari secret manager saat runtime
# File: ~/bin/get-vault-pass.sh
#!/bin/bash
aws secretsmanager get-secret-value \
    --secret-id ansible/vault-password \
    --query SecretString --output text

Sequence Diagram Resolusi Vault Password #

sequenceDiagram
    participant Dev as "Developer / CI"
    participant ANS as "ansible-playbook"
    participant CFG as "ansible.cfg"
    participant SRC as "Password Source"
    participant VLT as "Vault File"
    participant TSK as "Task"

    Dev->>ANS: "ansible-playbook site.yml"
    ANS->>CFG: "baca default config"
    CFG-->>ANS: "vault_password_file = ~/bin/get-vault-pass.sh"

    alt "--ask-vault-pass di-pass"
        ANS->>Dev: "prompt Vault password:"
        Dev-->>ANS: "ketik password (hidden)"
    else "--vault-password-file di-pass"
        ANS->>SRC: "baca file / jalankan script"
        SRC-->>ANS: "password dari file / script stdout"
    else "ANSIBLE_VAULT_PASSWORD_FILE env"
        ANS->>SRC: "baca path dari env var"
        SRC-->>ANS: "password"
    end

    ANS->>VLT: "decrypt group_vars/production/vault.yml"
    VLT-->>ANS: "plaintext di memory"
    ANS->>TSK: "jalankan task dengan secret"
    TSK-->>ANS: "hasil eksekusi"
    ANS-->>Dev: "output playbook (dengan no_log di tempat yang sesuai)"

Penting dari sequence diagram: password hanya ada di memory selama playbook berjalan, dan Ansible tidak menulisnya ke log. Tapi kalau ada task yang echo password tanpa no_log: true, password bisa muncul di output — selalu kombinasikan Vault dengan no_log di task yang sensitif.


Vault IDs: Isolasi per Environment #

Untuk proyek dengan beberapa environment (development, staging, production), menggunakan vault password yang sama untuk semua environment adalah risiko yang tidak perlu. Jika vault password staging bocor, attacker bisa mendekripsi file vault production. Vault IDs memecahkan masalah ini.

Vault ID adalah label yang mengidentifikasi vault tertentu. File yang dienkripsi dengan vault ID tertentu hanya bisa di-decrypt dengan vault password yang sesuai dengan ID tersebut.

# Enkripsi string dengan vault ID 'production'
ansible-vault encrypt_string 'ProdSecret' \
    --name 'db_password' \
    --vault-id production@~/.vault_pass_prod

# Enkripsi string dengan vault ID 'staging'
ansible-vault encrypt_string 'StagingSecret' \
    --name 'db_password' \
    --vault-id staging@~/.vault_pass_staging

Output untuk production:

db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  production    # ← vault ID terlihat di header
  66386439653236336462626566653339...

Saat menjalankan playbook dengan multiple vault ID:

ansible-playbook site.yml \
    --vault-id production@~/.vault_pass_prod \
    --vault-id staging@~/.vault_pass_staging

Tabel Pola Penggunaan Vault ID #

Pola Cocok untuk Kelebihan Kekurangan
Satu vault ID global Project kecil, satu environment Sederhana, satu password Bocor = seluruh secret bocor
Per environment (prod, staging, dev) Project multi-environment Isolasi per environment Perlu manage beberapa password
Per tim (backend, frontend, data) Organisasi besar dengan tim khusus Isolasi per tim Bisa eksplosif jadi banyak password
Per jenis data (db, api, ssl) Compliance requirement tinggi Granular, rotasi independen Butuh katalog vault yang baik
Hybrid: per environment + per jenis Enterprise Isolasi maksimal Kompleksitas tinggi

Rekomendasi: mulai dengan per environment (prod/staging/dev). Tambahkan granularitas hanya kalau ada kebutuhan compliance atau security yang jelas.

Jangan gunakan vault ID ‘default’. Vault ID default adalah alias untuk vault tanpa label. Menggunakan default membuat mudah untuk tidak sengaja mendekripsi file dengan password yang salah. Selalu gunakan label yang eksplisit seperti production@path atau staging@path.

Struktur File Vault yang Direkomendasikan #

Pola terbaik dalam mengelola Vault adalah memisahkan variabel biasa dari variabel sensitif ke file berbeda. Pola ini memudahkan code review (reviewer bisa membaca variabel biasa di Git tanpa perlu vault password) dan mengurangi risiko tidak sengaja commit secret.

Struktur Direktori #

inventory/
  production/
    hosts.ini
    group_vars/
      all/
        vars.yml          # Variabel biasa — plaintext, aman di Git
        vault.yml         # Variabel sensitif — DIENKRIPSI
      dbservers/
        vars.yml          # Konfigurasi spesifik DB — plaintext
        vault.yml         # Password DB — DIENKRIPSI
      webservers/
        vars.yml
        vault.yml
  staging/
    hosts.ini
    group_vars/
      all/
        vars.yml
        vault.yml
      ...

Contoh Konten #

# inventory/production/group_vars/dbservers/vars.yml — plaintext
db_host: prod-db.internal
db_port: 5432
db_name: app_production
db_user: app_user
db_pool_size: 20
db_password: "{{ vault_db_password }}"   # Referensikan variabel dari vault
# inventory/production/group_vars/dbservers/vault.yml — TERENKRIPSI
# ansible-vault encrypt_string 'SuperSecret123' --name 'vault_db_password'
vault_db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  66386439653236336462626566653339...

vault_db_admin_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  66386439653236336462626566653340...

Dengan pola ini:

  • vars.yml bisa di-review di pull request tanpa vault password — reviewer bisa baca konfigurasi dan menilai apakah sesuai.
  • vault.yml hanya berisi secret dan seluruhnya terenkripsi.
  • Playbook menggunakan db_password (dari vars.yml) yang nilainya di-resolve dari vault_db_password (dari vault.yml).
  • Saat deploy ke environment berbeda (staging), cukup swap seluruh direktori group_vars/ — variabel reference tetap sama, hanya nilai yang berbeda.

ANTI-PATTERN: Satu vault untuk semua environment #

# ANTI-PATTERN: satu vault.yml untuk semua environment
inventory/
  group_vars/
    all/
      vault.yml    # ← berisi secret production DAN staging
# Isi vault.yml — semua secret dalam satu file
vault_prod_db_password: SuperSecret123
vault_staging_db_password: LessSecret456
# Masalah: bocor satu file = bocor SEMUA environment
# Masalah: rotasi password production mengharuskan edit file yang sama dengan staging
# BENAR: vault per environment
inventory/
  production/
    group_vars/all/vault.yml    # hanya secret production
  staging/
    group_vars/all/vault.yml    # hanya secret staging
  development/
    group_vars/all/vault.yml    # hanya secret development
# BENAR (lebih granular): vault per environment per group
inventory/
  production/
    group_vars/
      dbservers/vault.yml       # secret khusus DB production
      webservers/vault.yml      # secret khusus web production

Vault dalam Pipeline CI/CD #

Menggunakan Vault di CI/CD membutuhkan perhatian khusus karena runner CI bukan engineer yang bisa memasukkan password saat prompt. Ada beberapa pola untuk menyediakan vault password di pipeline.

Pola 1: Secret di platform CI #

# .github/workflows/deploy.yml
name: Deploy ke Production
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production    # Memerlukan approval manual
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Ansible
        run: pip install ansible

      - name: Buat file vault password
        run: |
          echo "${{ secrets.VAULT_PASSWORD }}" > /tmp/.vault_pass
          chmod 600 /tmp/.vault_pass          

      - name: Jalankan playbook
        run: |
          ansible-playbook -i inventory/production/ site.yml \
            --vault-password-file /tmp/.vault_pass          

      - name: Bersihkan vault password
        if: always()
        run: rm -f /tmp/.vault_pass

Poin kritis:

  • chmod 600 — file password harus readable hanya oleh owner.
  • if: always() — cleanup harus jalan bahkan kalau playbook gagal, supaya password tidak tertinggal di runner.
  • environment: production — GitHub Actions menyediakan approval gate sebelum job jalan ke environment yang dilindungi.

Pola 2: Vault password dari cloud secret manager #

# .github/workflows/deploy.yml
- name: Ambil vault password dari AWS Secrets Manager
  run: |
    aws secretsmanager get-secret-value \
      --secret-id ansible/vault-password \
      --query SecretString \
      --output text > /tmp/.vault_pass
    chmod 600 /tmp/.vault_pass    
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Pola ini lebih aman karena vault password sendiri di-rotasi oleh AWS, dan CI tidak perlu tahu nilai plaintext — hanya akses ke Secrets Manager.

Pola 3: AWX / Ansible Tower sebagai secret store #

Untuk tim yang sudah menggunakan AWX atau Ansible Tower, Vault Credential di AWX adalah pendekatan terbaik. AWX menyimpan vault password di database internal yang dienkripsi dengan Fernet, dan credential ini hanya bisa diakses oleh Job Template yang punya hak.

# ansible.cfg di runner CI — tidak perlu vault_password_file
[defaults]
# AWX yang handle vault password, bukan runner

Runner CI memicu AWX Job Template via API atau webhook; AWX yang handle vault decryption menggunakan credential yang tersimpan aman.

AWX Vault Credential vs Vault Password File — AWX Vault Credential adalah pendekatan yang lebih aman untuk organisasi. Vault password disimpan terenkripsi di database AWX, audit log mencatat siapa yang menggunakan credential, dan rotasi cukup dilakukan sekali di AWX. Runner CI tidak pernah melihat vault password. Untuk tim kecil yang belum pakai AWX, secret di platform CI sudah cukup.

ANTI-PATTERN: vault password di pipeline log #

# ANTI-PATTERN: echo password di step yang gagal di-debug
- name: Debug vault issue
  run: |
    cat /tmp/.vault_pass    # ← JANGAN! Password akan muncul di log GitHub Actions    
# BENAR: gunakan mask dan hapus file sebelum debug
- name: Debug vault issue
  run: |
    if [ ! -s /tmp/.vault_pass ]; then
      echo "Vault file kosong atau tidak ada"
    fi
    # JANGAN cat /tmp/.vault_pass di log
    # Gunakan 'echo "::add-mask::$(cat /tmp/.vault_pass)"' untuk mask di log    

GitHub Actions secara otomatis mendeteksi string yang terlihat seperti secret dan mem-mask-nya di log. Tapi jangan mengandalkan auto-mask — selalu hindari echo nilai secret di command yang terlihat di log.


Rekey: Rotasi Vault Password #

Vault password harus di-rotasi secara berkala — sama seperti password akun lainnya. Jika ada kemungkinan password bocor (laptop hilang, kontributor keluar dari tim, repository mirror terekspos), ganti password segera. ansible-vault rekey memungkinkan rotasi tanpa harus decrypt dan re-encrypt file secara manual.

# Rekey file tunggal
ansible-vault rekey group_vars/production/vault.yml
# Prompt: Vault password (lama)
# Prompt: New Vault password (baru)
# Prompt: Confirm New Vault password

# Rekey semua file vault dalam satu direktori
find group_vars/ -name 'vault.yml' -exec ansible-vault rekey {} \;

# Rekey dengan vault ID spesifik
ansible-vault rekey group_vars/production/vault.yml --vault-id production@prompt

Rekey menerima password lama dan password baru dalam satu operasi, dan hanya menghasilkan ciphertext baru — tidak pernah ada tahap di mana file plaintext ditulis ke disk. Setelah rekey, commit file yang sudah di-rekey ke Git.

Kapan Harus Rekey #

Situasi Tindakan Prioritas
Developer yang tahu vault password meninggalkan tim Rekey semua vault yang diketahuinya Mendesak
Laptop/perangkat yang berisi vault password hilang Rekey semua vault di perangkat tersebut Mendesak
Audit security menemukan password di file log/backup Rekey vault yang terkait Mendesak
Rotasi berkala (misal setiap 90 hari) Rekey semua vault Rutin
Tidak ada insiden, hanya best practice Tidak perlu rekey
Rekey hanya mengganti password, tidak mengganti ciphertext salt. Salt dihasilkan sekali per file dan tetap sama setelah rekey. Untuk keamanan maksimum, decrypt semua file, hapus dari Git history, lalu encrypt ulang dengan password baru. Tapi untuk kebanyakan kasus, rekey sudah cukup.

Integrasi Vault dengan Role dan Playbook #

Vault tidak berdiri sendiri — ia bekerja sama dengan role dan playbook untuk menyediakan secret ke task yang membutuhkan. Pemahaman yang baik tentang integrasi ini mencegah kesalahan umum seperti variabel yang tidak ter-resolve atau secret yang bocor ke log.

Pola 1: Variabel Vault Dirujuk di vars.yml #

# roles/webserver/defaults/main.yml
db_host: localhost
db_port: 5432

# roles/webserver/vars/main.yml
# (vars/main.yml punya priority lebih tinggi dari defaults)

# inventory/production/group_vars/webservers/vars.yml
db_host: prod-db.internal
db_password: "{{ vault_db_password }}"   # Referensikan variabel dari vault.yml

# inventory/production/group_vars/webservers/vault.yml (TERENKRIPSI)
vault_db_password: !vault |
  $ANSIBLE_VAULT;1.1;AES256
  ...
# playbook site.yml
- hosts: webservers
  roles:
    - role: webserver

Saat playbook berjalan, Ansible memuat variabel dalam urutan: defaultsinventory varsplay varsrole varshost_varsgroup_vars. Variabel vault_db_password dari vault.yml di-resolve dulu, lalu db_password di vars.yml mengambil nilainya. Role webserver menerima db_password yang sudah ter-resolve saat task berjalan.

Artikel role membahas precedence variabel secara lebih detail. Untuk konteks tentang bagaimana role di-compose ke dalam playbook yang lebih besar, lihat automation.

Pola 2: no_log di Task yang Sensitif #

Variabel yang di-resolve dari vault bisa muncul di output Ansible jika task yang menggunakan variabel tersebut di-log. Tambahkan no_log: true untuk mencegah:

# BENAR: sembunyikan output task yang menggunakan secret
- name: Set database password untuk user aplikasi
  postgresql_user:
    name: app_user
    password: "{{ db_password }}"
    state: present
  no_log: true    # Ansible tidak akan menampilkan command atau output task ini

no_log: true menyembunyikan seluruh output task — termasuk error message. Ini trade-off antara keamanan dan kemudahan debug. Untuk development, kita bisa menonaktifkan no_log; untuk production, aktifkan selalu.

Kapan TIDAK pakai no_log: saat kita butuh men-debug task yang gagal dan output task tersebut tidak sensitif. Tapi ingat, kalau task menggunakan variabel dari vault, outputnya kemungkinan besar sensitif. Default yang aman: no_log: true di semua task yang menggunakan variabel dari vault.

Pola 3: Task yang Menulis Secret ke File di Managed Node #

Kadang secret perlu ditulis ke file di server tujuan (misalnya konfigurasi database yang dipakai aplikasi). Pola ini butuh perhatian khusus:

- name: Deploy konfigurasi database
  template:
    src: db_config.j2
    dest: /etc/myapp/db.conf
    owner: myapp
    group: myapp
    mode: '0600'    # Hanya owner yang bisa baca
  no_log: true

# db_config.j2
host={{ db_host }}
port={{ db_port }}
user={{ db_user }}
password={{ db_password }}

Perhatikan mode: '0600' — file konfigurasi yang berisi password harus readable hanya oleh user yang menjalankan aplikasi. 0600 artinya hanya owner yang punya akses baca dan tulis.


Kapan Tidak Pakai Vault / Alternatif #

Vault adalah solusi yang sangat baik untuk kebanyakan kasus, tapi bukan satu-satunya. Ada situasi di mana pendekatan lain lebih sesuai.

Tetap Gunakan Vault #

TETAP gunakan Ansible Vault jika:
  ✓ Secret disimpan di repository Git (file config, inventory, role defaults)
  ✓ Tim kecil-menengah tanpa dedicated secret manager
  ✓ Project open source atau repository publik (Vault memungkinkan sharing
    secret terenkripsi tanpa mengekspos nilai)
  ✓ Compliance tidak mewajibkan audit trail granular per akses secret
  ✓ Rotasi secret dilakukan manual per rilis (tidak butuh real-time rotation)

Pertimbangkan External Secret Manager #

PERTIMBANGKAN HashiCorp Vault / AWS Secrets Manager jika:
  ✗ Secret berubah secara real-time (rotasi otomatis setiap jam/menit)
  ✗ Compliance mengharuskan audit trail detail per akses
  ✗ Tim besar dengan banyak aplikasi yang butuh secret berbeda
  ✗ Secret dishare antara banyak sistem (Ansible + Kubernetes + aplikasi)
  ✗ Ada kebutuhan dynamic secret (misal database credential yang berubah tiap koneksi)

Tabel Perbandingan Vault dengan Alternatif #

Aspek Ansible Vault HashiCorp Vault AWS Secrets Manager
Kompleksitas setup Rendah (built-in) Tinggi (perlu server) Sedang (perlu akun AWS)
Audit trail Git history Log detail per akses CloudTrail + log akses
Rotasi otomatis Tidak (manual rekey) Ya (dynamic secret) Ya (Lambda rotation)
Biaya Gratis (bagian dari Ansible) Gratis (open source) + infra Per secret per bulan
Cocok untuk Secret statis di repo Secret dinamis, high-security Project di AWS ecosystem
Offline support Ya (file terenkripsi lokal) Tidak (perlu server running) Tidak (perlu koneksi AWS)

Kita juga bisa mengombinasikan Vault dengan secret manager: gunakan Vault untuk file konfigurasi yang disimpan di repo, dan secret manager untuk secret yang sangat sensitif (seperti database root password). Ansible mengambil secret dari kedua sumber saat runtime, dan secret manager menjadi sumber otoritatif untuk secret yang paling kritis.

Artikel encryption membahas layer-layer enkripsi dan integrasi dengan external secret manager secara lebih detail. Untuk pola workflow dan approval gate yang mengombinasikan Vault dengan kontrol akses, lihat workflow.


Ringkasan #

  • Ansible Vault mengenkripsi data sensitif menggunakan AES-256 dengan key derivation PBKDF2 — file terenkripsi aman disimpan di Git tanpa risiko bocor ke orang yang tidak berkepentingan.
  • Dua mode tersedia: enkripsi file penuh (ansible-vault encrypt) untuk file yang seluruhnya sensitif, dan enkripsi string (ansible-vault encrypt_string) untuk nilai individual dalam file YAML yang sebagian besar isinya biasa.
  • Pisahkan variabel biasa dari vaultvars.yml (plaintext, aman di review) mereferensikan vault.yml (terenkripsi) — pola ini membuat code review lebih mudah dan mengurangi risiko commit tidak sengaja.
  • Vault password tidak boleh di-commit ke Git — simpan di file lokal dengan chmod 600 di .gitignore, atau sebagai secret di platform CI/CD, atau di AWX Vault Credential untuk organisasi yang lebih besar.
  • Gunakan vault ID berbeda per environment (production@path, staging@path) — bocornya vault password staging tidak mengkompromikan vault production, dan rotasi per environment bisa dilakukan independen.
  • Rotasi password dengan ansible-vault rekey — tidak pernah ada tahap di mana file plaintext ditulis ke disk, jadi rekey aman dilakukan rutin tanpa risiko.
  • Integrasikan dengan no_log: true di task yang menggunakan variabel dari vault — tanpa no_log, secret bisa muncul di output Ansible saat task gagal dan dijalankan dalam mode verbose.
  • Vault bukan satu-satunya solusi — untuk secret yang sangat sensitif atau butuh rotasi real-time, pertimbangkan external secret manager (HashiCorp Vault, AWS Secrets Manager) dan ambil secret saat runtime menggunakan lookup plugin.

← Sebelumnya: Drift Handling   Berikutnya: Encryption →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact