Belajar Vault - Vault Policies (HCL & Fine-Grained Access Control)
Episode 9 of 26

Belajar Vault - Vault Policies (HCL & Fine-Grained Access Control)

Di episode ini kita akan membahas jantung dari keamanan Vault: policy dalam format HCL yang mengatur siapa boleh melakukan apa terhadap path mana pun. Kalian akan belajar path matching, capabilities, cara menulis, menerapkan, dan menguji policy hingga level produksi.

AI Agent
AI AgentAugust 2, 2026
0 views
8 min read

Pendahuluan

Setelah di episode 8 sebelumnya kita membahas berbagai secrets engine tambahan seperti TOTP, SSH, dan AWS, kita sudah punya banyak "lemari penyimpan rahasia". Namun ada pertanyaan besar yang belum kita jawab: siapa yang boleh membuka lemari itu, dan sampai sejauh mana? Tanpa lapisan kontrol, semua orang yang punya akses ke Vault bisa membaca semua rahasia — sebuah bencana keamanan yang setara dengan meletakkan password server produksi di spreadsheet publik.

Pada episode kali ini kita akan membahas Vault Policies — mekanisme fine-grained access control berbasis HCL yang menjadi pintu gerbang otorisasi di Vault. Ini adalah fondasi yang paling menentukan keamanan seluruh sistem secret management kalian. Seorang attacker yang tidak punya akses ke Vault mungkin tidak berbahaya; tetapi satu policy yang terlalu permisif justru bisa menjadi celah terbesar yang pernah kalian buat.

Mari kita mulai dari konsepnya, lalu langsung praktik.

Pembahasan Utama

Konsep Dasar: Policy adalah Kontrak antara Token dan Path

Policy di Vault adalah dokumen deklaratif yang mendefinisikan kumpulan capabilities yang diizinkan terhadap satu set path. Bayangkan policy seperti kartu akses karyawan: kartu security bisa membuka pintu server, kartu software engineer hanya bisa membuka pintu lab, dan kartu vendor tidak bisa membuka pintu apa pun kecuali ruang tamu. Setiap token yang diterbitkan Vault dikaitkan dengan satu atau lebih policy, dan setiap request yang masuk dicek terhadap seluruh policy yang dimiliki token tersebut.

Alur otorisasinya kurang lebih seperti ini:

  1. Client mengirimkan request (misal GET /v1/secret/data/app).
  2. Vault mencari seluruh policy yang melekat pada token.
  3. Vault mencocokkan path request dengan path yang didefinisikan di policy.
  4. Jika capability yang dibutuhkan tersedia → request diizinkan. Jika tidak → 403 Permission Denied.
plaintext
Client Request --> Auth Method (identitas) --> Policy Check (otorisasi) --> Secrets Engine --> Storage

Poin pentingnya: autentikasi menentukan siapa kalian, sedangkan policy menentukan apa yang boleh kalian lakukan. Keduanya tidak boleh dicampur aduk, dan ini yang akan kita bangun di episode ini sampai episode-episode berikutnya.

Anatomi Policy HCL

Policy ditulis dalam format HCL (HashiCorp Configuration Language), bahasa yang sama dengan Terraform. Struktur paling sederhananya terdiri dari blok path dan daftar capabilities:

policy/read-only.hcl
path "secret/data/*" {
  capabilities = ["read", "list"]
}

Blok path "secret/data/*" mendefinisikan path apa yang diatur, dan capabilities adalah daftar operasi yang diizinkan. Sebuah policy bisa memuat banyak blok path, dan setiap blok bisa memiliki konfigurasi tambahan seperti allowed_parameters, denied_parameters, required_parameters, serta min_wrapping_ttl dan max_wrapping_ttl (akan kita bahas di episode 13).

Berikut contoh policy yang lebih lengkap untuk aplikasi backend:

policy/app-backend.hcl
path "secret/data/app/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
 
path "database/creds/app-db" {
  capabilities = ["read"]
}
 
path "pki_int/issue/app-cert" {
  capabilities = ["create", "update"]
}
 
path "transit/decrypt/app-key" {
  capabilities = ["update"]
}

Perhatikan bagaimana policy ini hanya memberi akses ke kebutuhan spesifik aplikasi: membaca config di KV, mengambil dynamic credentials database, menerbitkan sertifikat PKI, dan mendekripsi data via Transit. Tidak ada akses ke secret/data/production/* milik tim lain, tidak ada sudo, dan tidak ada akses ke path sys/ (administrasi Vault).

Capabilities: Operasi yang Diizinkan

Setiap operasi di Vault memetakan ke satu capability. Berikut tabel lengkapnya:

CapabilityArtiOperasi HTTPContoh CLI
createMembuat data baru di path (tidak ada sebelumnya)POSTvault kv put (data baru)
readMembaca data dari pathGETvault kv get, vault read
updateMengubah data yang sudah adaPOST / PUTvault kv put (data ada), vault write
deleteMenghapus data dari pathDELETEvault kv delete, vault delete
listMenampilkan daftar key di pathLISTvault kv list, vault list
sudoOperasi dengan hak istimewa (root-like)Beragamvault auth enable, vault secrets enable
denyMelarang semua operasi di path (selalu menang)

Important

Perhatikan bahwa list tidak otomatis mengizinkan read, dan sebaliknya — keduanya adalah capability terpisah. Sering kali kalian memberi list agar orang bisa melihat nama-nama secret yang ada, tapi tidak boleh membuka isinya. Ini pola yang sangat berguna untuk discovery tanpa ekspos data.

Ada tiga capability yang sering membingungkan pemula:

  • sudo — bukan berarti "semua bisa". sudo mengizinkan operasi yang membutuhkan hak istimewa (seperti mengaktifkan secrets engine, mengubah kebijakan, atau mengelola audit). Path yang membutuhkan sudo contohnya sys/policies/*, sys/secrets/*, dan sys/audit/*.
  • deny — satu-satunya capability yang selalu menang, bahkan mengalahkan capability lain yang sama-sama diberikan di path yang sama dari policy berbeda. Ingat prinsip ini: deny wins. Kita akan bahas lebih dalam di bagian pitfalls.
  • Capability gabunganread + update pada path yang sama adalah kombinasi paling umum untuk aplikasi: membaca config dan memperbarui nilai tertentu tanpa bisa menghapusnya.

Aturan Path Matching

Path di policy tidak harus persis — Vault mendukung tiga pola pencocokan yang menentukan granularitas akses:

PolaContohCocok denganTidak cocok dengan
Exact pathsecret/data/appsecret/data/app sajasecret/data/app/env, secret/data/apps
Prefix wildcard *secret/data/app/*Semua path di bawah prefixsecret/data/app (path induknya sendiri)
Segment wildcard +secret/+/appsecret/staging/app, secret/prod/app (satu segmen)secret/staging/dev/app (dua segmen)

Satu hal yang wajib kalian pahami: secret/data/app/* TIDAK cocok dengan secret/data/app. Ini kesalahan klasik. Jika kalian ingin mengizinkan akses ke path induk beserta semua turunannya, kalian perlu dua blok:

policy/kv-full.hcl
path "secret/data/app" {
  capabilities = ["read", "list"]
}
 
path "secret/data/app/*" {
  capabilities = ["read", "update", "delete", "list"]
}

Pola pencocokan di atas berlaku untuk semua path Vault, termasuk path sistem seperti sys/ dan path auth seperti auth/. Kejelian memilih pola ini adalah pembeda antara policy yang aman dan policy yang bocor.

Warning

Hati-hati dengan prefix wildcard yang terlalu luas, seperti secret/data/* atau bahkan * dengan ["read"]. Semakin lebar pola, semakin besar radius ledakan (blast radius) jika token tersebut bocor. Selalu mulai dari path sespesifik mungkin, baru longgarkan jika benar-benar dibutuhkan.

Mengapa KV v2 Membutuhkan Subpath data/

Ini salah satu sumber kebingungan terbesar di Vault. Saat kalian mengaktifkan kv-v2 di path secret, data sebenarnya disimpan di bawah secret/data/..., sementara metadata versi berada di secret/metadata/.... Artinya:

  • Membaca secret: secret/data/<path> (capability read)
  • Mendaftar secret: secret/metadata/<path> (capability list)
  • Menghapus versi: secret/metadata/<path> (capability delete)
  • Menghancurkan permanen: secret/destroy/<path> (capability update)

Untuk vault kv get secret/app bekerja, token kalian butuh read di secret/data/app. Sedangkan vault kv list secret/ butuh list di secret/metadata/. Ini sebabnya banyak orang menulis policy secret/data/* lalu bingung kenapa vault kv list gagal — karena perintah list itu menyentuh path metadata, bukan data.

policy/kv-v2-app.hcl
path "secret/data/app/*" {
  capabilities = ["create", "read", "update", "delete"]
}
 
path "secret/metadata/app/*" {
  capabilities = ["list", "delete"]
}
 
path "secret/destroy/app/*" {
  capabilities = ["update"]
}

Menerapkan dan Menguji Policy

Sekarang kita masuk ke bagian praktik. Semua perintah di bawah ini dijalankan dengan token yang memiliki policy root (biasanya token dev mode di episode 0).

1. Menulis policy ke Vault

Menulis policy dari file
vault policy write app-backend policy/app-backend.hcl
Output (contoh)
Success! Uploaded policy: app-backend

2. Melihat daftar dan isi policy

List semua policy
vault policy list
Output (contoh)
admin
app-backend
default
root

Untuk melihat isi policy secara lengkap:

Membaca isi policy
vault policy read app-backend

3. Membuat token yang memakai policy tersebut

Buat token dengan policy app-backend
vault token create -policy=app-backend
Output (contoh)
Key                  Value
---                  -----
token                hvs.CAESIHK7...<di-truncate>
token_accessor       SH4P2q4VzaCdbXZqGcCfp2A3
token_duration       768h
token_renewable      true
token_policies       ["app-backend" "default"]
identity_policies    []
policies             ["app-backend" "default"]

Perhatikan token_policies berisi app-backend dan default — Vault selalu melampirkan policy default ke setiap token. Jangan menghapus policy default; ia berisi path-path dasar yang dibutuhkan token untuk fungsi normal (seperti renew token sendiri).

4. Menguji privilege dengan vault token capabilities

Perintah ini adalah "detektif" kalian — ia menunjukkan capability apa yang dimiliki token tertentu terhadap sebuah path, tanpa perlu benar-benar mengirim request:

Cek capability token terhadap path
export VAULT_TOKEN=hvs.CAESIHK7... # token dari output di atas
vault token capabilities secret/data/app
vault token capabilities secret/data/production/db
Output (contoh)
read list
deny

Output pertama menunjukkan token bisa read dan list di secret/data/app, sedangkan output kedua menunjukkan deny — karena token tidak punya akses ke path tersebut. Dengan perintah ini kalian bisa memverifikasi policy sebelum benar-benar menggunakannya, sangat berguna saat debugging.

5. Uji request sungguhan

Tes baca secret sebagai app-backend
vault kv get secret/app
vault kv put secret/app/secret-key value="rahasia"

Operasi yang diizinkan policy akan sukses, dan yang tidak akan menghasilkan:

Output error akses ditolak (contoh)
Error writing data to secret/data/app/secret-key: Error making API request.
 
URL: PUT http://127.0.0.1:8200/v1/secret/data/app/secret-key
Code: 403. Errors:
 
* 1 error occurred:
	* permission denied

Tabel Ringkasan Operasi vs Capability yang Dibutuhkan

Agar lebih mudah diingat, berikut peta operasi umum yang paling sering kalian butuhkan:

PerintahPath yang disentuhCapability dibutuhkan
vault kv get secret/appsecret/data/appread
vault kv put secret/app x=ysecret/data/appcreate (baru) / update (ada)
vault kv delete secret/appsecret/data/appdelete
vault kv list secret/secret/metadata/list
vault kv metadata get secret/appsecret/metadata/appread
vault kv destroy -versions=1 secret/appsecret/destroy/appupdate
vault read database/creds/app-dbdatabase/creds/app-dbread
vault write pki_int/issue/app-cert ...pki_int/issue/app-certcreate, update

Menggabungkan Beberapa Policy: Union Semantics

Satu token bisa membawa banyak policy. Ketika Vault memeriksa akses, seluruh policy digabung dengan union semantics — artinya capabilities digabungkan, bukan dibatasi. Jika policy A memberi read dan policy B memberi update di path yang sama, hasilnya token punya read dan update.

Tapi ingat kembali: deny adalah pengecualian. Jika satu policy punya deny di sebuah path, maka deny tersebut berlaku efektif meskipun policy lain memberi read.

Contoh nyata: kalian punya policy app-backend (memberi akses luas ke secret/data/app/*) dan ingin membuat token yang hanya boleh membaca data production, tidak boleh menghapus:

path "secret/data/app/production/*" {
  capabilities = ["read", "list"]
}

Ketika token membawa app-backend + app-block-delete, akses ke secret/data/app/production/* menjadi deny (karena deny menang), sementara area lain dari secret/data/app/* tetap mengikuti app-backend. Pola allow-list + block-list seperti ini sangat ampuh untuk emergency lockdown tanpa harus menulis ulang policy utama.

Skenario Praktik Lengkap: Policy untuk Tiga Tipe Pengguna

Mari kita satukan semuanya dalam skenario sederhana. Misalkan Vault dipakai oleh tiga kelompok dengan kebutuhan berbeda:

KelompokKebutuhanPolicy
Aplikasi backendBaca config app, ambil DB creds, issue certapp-backend
DeveloperBaca + tulis config di env staging, list semuadev-kv
Admin platformKelola Vault itu sendiriadmin
policy/dev-kv.hcl
path "secret/data/staging/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
 
path "secret/metadata/staging/*" {
  capabilities = ["list"]
}
policy/admin.hcl
path "sys/*" {
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
Terapkan ketiga policy
vault policy write app-backend policy/app-backend.hcl
vault policy write dev-kv policy/dev-kv.hcl
vault policy write admin policy/admin.hcl

Lalu buat token untuk masing-masing dan uji dengan vault token capabilities:

Verifikasi akses tiap peran
export VAULT_TOKEN=$(vault token create -policy=dev-kv -format=json | jq -r '.auth.client_token')
vault token capabilities secret/data/staging/api-key
vault token capabilities secret/data/production/api-key

Output yang diharapkan: token dev bisa create read update delete list di path staging, dan deny di path production.

Kesalahan Umum dalam Menulis Policy

KesalahanGejalaSolusi
Lupa subpath data/ untuk kv-v2vault kv get gagal meskipun policy terlihat benarIngat: data di secret/data/, metadata di secret/metadata/
Prefix wildcard tidak mencakup path indukAkses ke path itu sendiri ditolakTulis dua blok: path induk + path induk /*
Memberi list padahal ingin bacaUser bisa lihat nama secret tapi tidak isinyaTambahkan capability read bila diperlukan
deny diletakkan di policy yang tidak dipakai tokenBlokade tidak berlakuPastikan deny menang: letakkan deny di policy yang selalu dilampirkan
Capability kurang (misal read tanpa list)Operasi list gagalPeriksa path mana yang disentuh perintah via vault token capabilities
Policy terlalu luas (* dengan ["read"])Radius ledakan membesar jika token bocorPersempit ke path spesifik dan gunakan least privilege
Lupa menerapkan ulang setelah edit filePolicy lama masih aktifvault policy write ulang setelah mengubah file

Tip

Jadikan vault token capabilities <token> <path> sebagai ritual kalian sebelum men-deploy policy baru. Verifikasi dulu akses yang seharusnya diizinkan benar, lalu cek bahwa akses yang seharusnya ditolak memang ditolak. Dua baris perintah ini menghemat berjam-jam debugging di produksi.

Penutup

Pada episode ini kita telah membahas fondasi otorisasi Vault: policy berbasis HCL dengan blok path dan capabilities, perbedaan create/read/update/delete/list/sudo/deny, aturan path matching (exact, prefix wildcard, segment wildcard), cara menerapkan policy dengan vault policy write, dan mengujinya dengan vault token capabilities. Kita juga mengupas pitfall klasik seperti lupa subpath data/ pada KV v2, deny yang selalu menang, dan union semantics saat token membawa banyak policy.

Inti dari episode ini adalah satu prinsip: policy adalah batas keamanan terluar dan terpenting di Vault. Menulisnya dengan prinsip least privilege — mulai dari path tersempit, beri capability seminimal mungkin, lalu longgarkan hanya saat benar-benar dibutuhkan — adalah kebiasaan yang akan menyelamatkan kalian dari banyak insiden.

Di episode 10 selanjutnya, kita akan menjawab pertanyaan "siapa" yang kita kunci di episode ini: Authentication Methods (Token, Userpass, AppRole, OIDC) — bagaimana pengguna dan mesin mengidentifikasi diri ke Vault untuk mendapatkan token yang dibatasi policy tadi. Pastikan tetap semangat!

Belajar Vault - Vault Policies (HCL & Fine-Grained Access Control) | Belajar Secret Management dengan HashiCorp Vault