Vault API
Overview
Vault exposes a RESTful JSON API on port 8200. All requests include X-Vault-Token header for authenticated endpoints. Unauthenticated endpoints (health, init) need no token.
Base URL: http://vault.vault:8200 (in-cluster) or https://vault.kubexa.tech (external via Gateway).
API Endpoints
System
| Method | Endpoint | Description | Auth |
|--------|----------|-------------|------|
| GET | /v1/sys/health | Cluster health (see status codes below) | No |
| GET | /v1/sys/seal-status | Seal status | No |
| PUT | /v1/sys/init | Initialize cluster | No |
| PUT | /v1/sys/unseal | Unseal (submit key share) | No |
| GET | /v1/sys/leader | Current leader info | No |
Health status codes:
| Code | Meaning |
|------|---------|
| 200 | Active, unsealed |
| 429 | Standby, unsealed |
| 472 | Disaster Recovery secondary (enterprise) |
| 473 | Performance standby (enterprise) |
| 501 | Not initialized |
| 503 | Sealed |
Auth (Kubernetes)
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /v1/auth/kubernetes/login | Login with service account JWT |
# Login with K8s SA token
SA_JWT=$(kubectl create token my-sa -n my-ns)
curl -s http://vault.vault:8200/v1/auth/kubernetes/login \
-d "{\"role\":\"my-role\",\"jwt\":\"$SA_JWT\"}"
# Returns: {"auth":{"client_token":"hvs...","policies":["my-policy"]}}
KV Secrets (v2)
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/{mount}/data/{path} | Read secret |
| PUT | /v1/{mount}/data/{path} | Create/update secret |
| DELETE | /v1/{mount}/data/{path} | Delete latest version |
| GET | /v1/{mount}/metadata/{path} | Read metadata (versions, timestamps) |
| POST | /v1/{mount}/delete/{path} | Delete all versions |
| POST | /v1/{mount}/undelete/{path} | Undelete |
# Write a secret
curl -s http://vault.vault:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN" \
-d '{"data":{"password":"s3cret!"}}'
# Read a secret
curl -s http://vault.vault:8200/v1/secret/data/myapp \
-H "X-Vault-Token: $VAULT_TOKEN"
# Returns: {"data":{"data":{"password":"s3cret!"},"metadata":{...}}}
# List secrets at a path
curl -s http://vault.vault:8200/v1/secret/metadata/myapp \
-H "X-Vault-Token: $VAULT_TOKEN" \
| jq '.data.keys'
KV Secrets (v1)
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/{mount}/{path} | Read secret |
| PUT | /v1/{mount}/{path} | Create/update secret |
| DELETE | /v1/{mount}/{path} | Delete secret |
Policies
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/sys/policies/acl | List ACL policies |
| GET | /v1/sys/policies/acl/{name} | Read policy |
| PUT | /v1/sys/policies/acl/{name} | Create/update policy |
| DELETE | /v1/sys/policies/acl/{name} | Delete policy |
# Create read-only policy for myapp
curl -s http://vault.vault:8200/v1/sys/policies/acl/myapp \
-X PUT \
-H "X-Vault-Token: $VAULT_TOKEN" \
-d '{"policy":"path \"secret/data/myapp/*\" {capabilities=[\"read\",\"list\"]}"}'
Token
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /v1/auth/token/create | Create token |
| POST | /v1/auth/token/create-orphan | Create orphan token |
| GET | /v1/auth/token/lookup-self | Validate/lookup own token |
| POST | /v1/auth/token/renew-self | Renew own token |
| POST | /v1/auth/token/revoke-self | Revoke own token |
Auth Methods
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/sys/auth | List enabled auth methods |
| POST | /v1/sys/auth/{type} | Enable auth method |
| DELETE | /v1/sys/auth/{path} | Disable auth method |
Secrets Engines
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | /v1/sys/mounts | List enabled secret engines |
| POST | /v1/sys/mounts/{path} | Enable secret engine (type: kv-v2, kv, transit, etc.) |
| DELETE | /v1/sys/mounts/{path} | Disable/delete secret engine |
Raft
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /v1/sys/storage/raft/join | Join Raft cluster |
| GET | /v1/sys/storage/raft/configuration | List Raft peers |
| POST | /v1/sys/storage/raft/snapshot | Take Raft snapshot |
# Join Raft cluster
curl -s http://127.0.0.1:8200/v1/sys/storage/raft/join \
-X POST \
-d '{"leader_api_addr":"http://vault-0.vault-internal:8200"}'
# Take snapshot
curl -s http://vault.vault:8200/v1/sys/storage/raft/snapshot \
-H "X-Vault-Token: $VAULT_TOKEN" \
-o vault-snapshot.snap
Auth Methods Summary
| Method | Endpoint Mount | Use Case |
|--------|---------------|----------|
| Kubernetes | /v1/auth/kubernetes/login | In-cluster pods via SA JWT |
| Token | /v1/auth/token/create | Root token, periodic tokens |
| AppRole | /v1/auth/approle/login | Machine-to-machine (w/ secretId) |
| Userpass | /v1/auth/userpass/login | Human users |
| LDAP | /v1/auth/ldap/login | Enterprise directory integration |
| JWT/OIDC | /v1/auth/jwt/login | External OIDC providers |
| Cert | /v1/auth/cert/login | mTLS client certificates |
Health Check Examples
# Quick health
curl -s http://vault.vault:8200/v1/sys/health | jq .initialized
# Detailed status
curl -s http://vault.vault:8200/v1/sys/seal-status | jq '.sealed, .t, .n, .progress'
Common Mistakes
- KV v2 path includes
data/prefix. For KV v2 engine mounted atsecret, the read path is/v1/secret/data/myapp, not/v1/secret/myapp. The latter returns a 404. - Health endpoint returns non-200 for sealed/standby. A 503 (sealed) is NOT an error — it's expected after restart. Check
initializedandsealedfields in the response body, not the HTTP status alone. - Token in URL is stripped by proxies. Use
X-Vault-Tokenheader, not?token=query param. Proxies and load balancers may log or strip query params. - Kubernetes auth needs SA token with right audience. The
vaultaudience must be configured in the SA or the default token may not be accepted. Usekubectl create tokenwith--audience=vaultfor explicit audience. listcapabilities for metadata listing. Reading/v1/secret/metadata/(to list keys) requireslistcapability at that path, notread. Without it, the response is empty.- Raft join after unseal. A sealed node cannot join the Raft cluster. Always unseal before
raft join. The joining node will sync data from the leader. - Snapshot restore requires same cluster size. Raft snapshots can only be restored to a cluster with the same number of peers. Adding/removing nodes after restore may fail.