Vault
Write a Vault policy using API documentation
Every Vault operation performed through the command-line interface (CLI), API, or web UI requires the client to authenticate and get a token with a policy attached. Vault uses paths, like a filesystem, for secret storage. Every policy in Vault has a corresponding path and capability. Policies give you a declarative way to give the necessary access to each Vault path.
Scenario
In this tutorial, you will learn Vault's policy language and how to translate API documentation to policies.
You need to give read access to the KV-V2 secrets
engine, mounted at the path external-apis with a secret defined at
/external-apis/data/weather/california.
Prerequisites
Set up the lab
- Open a terminal and start a Vault dev server with the literal string - rootas the root token value, and enable TLS.- $ vault server -dev -dev-root-token-id root -dev-tls- The dev server listens on the loopback interface at 127.0.0.1 on TCP port 8200 with TLS enabled. At runtime, the dev server also automatically unseals, and prints the unseal key and initial root token values to the standard output. - Root tokens The dev mode server starts with an initial root token value set. Root token use should be extremely guarded in production environments because it provides full access to the Vault server. You can supply the root token value to start Vault in dev mode for convenience and to keep the steps here focused on the learning goals of this tutorial.
- In a new terminal, export the - VAULT_ADDRand- VAULT_CACERTenvironment variables using the commands suggested in your Vault dev server output.- Copy each command (without the - $) from the server output, and paste it into the new terminal session.- Example: - export VAULT_ADDR='https://127.0.0.1:8200'- Example: - export VAULT_CACERT='/var/folders/qr/zgztx0sj6n1dxy86sl36ntnw0000gn/T/vault-tls3037226588/vault-ca.pem'- Remember to use your dev server's values, not the examples shown here. 
- Export an environment variable for the - vaultCLI to authenticate with the Vault server.- $ export VAULT_TOKEN=root- The Vault server is ready. 
- Enable the KV-V2 secrets engine at the path - external-apis.- $ vault secrets enable -path=external-apis kv-v2- The KV-V2 secrets engine is now mounted at the path - external-apis.
- Create a secret at the path - /external-apis/weather/californiawith the API key for the weather service.- $ vault kv put external-apis/weather/california api_key=1234567890abcdef ============ Secret Path ============ external-apis/data/weather/california ======= Metadata ======= Key Value --- ----- created_time 2025-05-30T15:36:20.422782Z custom_metadata <nil> deletion_time n/a destroyed false version 1- The secret is now stored at the path - /external-apis/data/weather/california. The path returned includes- databecause you are using the KV-V2 secrets engine.
Define a policy
Vault policies use the HashiCorp Configuration Language (HCL) or JSON, and
include zero or more paths. Each path in the policy, expressed with the path keyword followed
by the absolute path, includes the capabilities for that path.
The path /external-apis/data/weather/california references an absolute path to a
secret or configuration within the enabled secrets engine. The read capability
grants access to read the data at the given path.
These paths and capabilities are entirely dependent on the secrets engine or endpoint. Each endpoint describes these details in the Vault API documentation.
Read the Read Secret Version section of the KV-V2 API documentation.

The API documentation focuses on clients programmatic interaction with Vault. To use this resource to define Vault policies requires translation.
The Method defines the HTTP verb GET. These HTTP verbs map closely, but
not perfectly, to policy capabilities. The HTTP verb GET translates to the
read capability.
| HTTP verbs | Path capabilities | 
|---|---|
| POST/PUT | create | 
| GET | read | 
| POST/PUT | update | 
| DELETE | delete | 
| LIST | list | 
The Path defines the path /secret/data/:path?version=:version-number.
The first element of the path secret, represents where you mount the secrets
engine. The documentation uses the default or common mount path for a secrets
engine. The secret element translates to external-apis.
The /data element is static for secrets for this secrets engine.
The :path and :version-number elements represent parameters, or variables,
that you substitute for specific values in a request. Parameters are prefaced
with colon (:). The :path element translates to weather/california.
Write a policy
- Write the policy to a file that grants the capability to read the secret at path - /external-apis/data/weather/california.- $ tee weather-policy.hcl <<EOF # Read the secret at /external-apis/data/weather/california path "/external-apis/data/weather/california" { capabilities = ["read"] } EOF- The recommended practice is to write and store policies in your version control system. You can then update and track changes to the policy. 
- Write the policy to Vault using the - vault policy writecommand.- $ vault policy write weather weather-policy.hcl Success! Uploaded policy: weather
- Read the policy back from Vault. - $ vault policy read weather # Read the secret at /external-apis/data/weather/california path "/external-apis/data/weather/california" { capabilities = ["read"] }
Test the policy
Verify the policy works by getting a token with the weather policy attached, and read a secret.
- Create a token with the - weatherpolicy attached and store the token value in a variable called- WEATHER_TOKEN.- $ WEATHER_TOKEN=$(vault token create -policy=weather --format=json | jq -r '.auth.client_token')
- Lookup the - WEATHER_TOKENand verify the it includes the- weatherpolicy.- $ vault token lookup $WEATHER_TOKEN | grep policies policies [default weather]- The output includes the - Policiesfield with the value- ["default", "weather"]. The- defaultpolicy does not allow access to the- /external-apis/data/weather/californiapath.
- Use the - WEATHER_TOKENto read the secret at- /external-apis/data/weather/california.- $ VAULT_TOKEN=$WEATHER_TOKEN vault kv get external-apis/weather/california ============ Secret Path ============ external-apis/data/weather/california ======= Metadata ======= Key Value --- ----- created_time 2025-05-30T15:36:20.422782Z custom_metadata <nil> deletion_time n/a destroyed false version 1 ===== Data ===== Key Value --- ----- api_key 1234567890abcdef- You created a policy named - weatherthat grants the read capability to the secret at- /external-apis/data/weather/california, and used a token with the policy to read the secret.
Create a secret
You have a new requirement that allows a Vault entity to create and update the weather API value.
Read the Create/Update Secret section of the KV-V2 API documentation.

The API documentation describes the HTTP verb POST for the method, which
translates to the create capability in the policy.
Depending on your security requirements, you can write a new Vault policy; for
example vault policy write weather-create.
You can also group one or more policies in the same policy definition.
For example, you can define a policy that grants the capability to create, update, and read a secret
at the /external-apis/data/weather/california path.
path "/external-apis/data/weather/california" {
  capabilities = ["read"]
}
path "/external-apis/data/weather/california" {
  capabilities = ["create"]
}
This policy expresses two capabilities for the same path. You can also express different capabilities for the same path together.
This example policy grants the capability to create, update, and read
a secret at the /external-apis/data/weather/california path.
path "/external-apis/data/weather/california" {
  capabilities = ["read", "create", "update"]
}
When writing policies, make sure you follow the principle of least privilege and grant just the capabilities required for the task.
- Update the policy to include the - createcapability to create and update a secret at the- /external-apis/data/weather/californiapath.- $ tee weather-policy.hcl <<EOF # Read the secret at /external-apis/data/weather/california path "/external-apis/data/weather/california" { capabilities = ["create", "read", "update"] } EOF- The - createcapability grants the capability to create and update the secret at the given path.
- Write the updated policy to Vault. - $ vault policy write weather weather-policy.hcl Success! Uploaded policy: weather
- Read the policy back from Vault to verify the changes. - $ vault policy read weather # Create, read, and update the secret at /external-apis/data/weather/california path "/external-apis/data/weather/california" { capabilities = ["create", "read", "update"] }- The output includes the updated policy with the - createand- updatecapabilities.
- Create a token with the new - weatherpolicy attached and store the token value in a variable called- WEATHER_TOKEN.- $ WEATHER_TOKEN=$(vault token create -policy=weather --format=json | jq -r '.auth.client_token')
- Update the secret at - /external-apis/data/weather/californiawith a new value.- $ VAULT_TOKEN=$WEATHER_TOKEN vault kv put external-apis/weather/california api_key=abcdef1234567890 ============ Secret Path ============ external-apis/data/weather/california ======= Metadata ======= Key Value --- ----- created_time 2025-05-30T16:40:33.074602Z custom_metadata <nil> deletion_time n/a destroyed false version 2- You updated the secret value, and the output includes the new version number - 2.
Delete and undelete a secret
You have one final requirement to delete and undelete the secret
at the /external-apis/data/weather/california path.
Read the Delete Latest Version of Secret and Undelete Secret Versions section of the KV-V2 API documentation.
Challenge
Use the experience you gained in the Write a policy and Create a secret
sections to define a policy that grants the capability to delete and undelete the secret at the
/external-apis/data/weather/california path.
Expand the Show policy box to see the solution.
Define a policy that grants the capability to delete and undelete secret at the
/external-apis/data/weather/california path.
# Read the secret at /external-apis/data/weather/california
path "/external-apis/data/weather/california" {
  capabilities = ["create", "delete", "read", "update"]
}
path "/external-apis/undelete/weather/california" {
  capabilities = ["update"]
}
The delete capability grants the capability to delete the secret at the given
path. Undelete requires the update capability at the path undelete.
Next steps
Defining policies requires understanding the paths and capabilities of each authentication method and secrets engine. In this tutorial, you translated the API documentation into policies. Learn a different approach in the Write a Policy from Audit Logs tutorial.