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
root
as 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_ADDR
andVAULT_CACERT
environment 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
vault
CLI 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/california
with 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 includesdata
because 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 write
command.$ 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
weather
policy attached and store the token value in a variable calledWEATHER_TOKEN
.$ WEATHER_TOKEN=$(vault token create -policy=weather --format=json | jq -r '.auth.client_token')
Lookup the
WEATHER_TOKEN
and verify the it includes theweather
policy.$ vault token lookup $WEATHER_TOKEN | grep policies policies [default weather]
The output includes the
Policies
field with the value["default", "weather"]
. Thedefault
policy does not allow access to the/external-apis/data/weather/california
path.Use the
WEATHER_TOKEN
to 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
weather
that 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
create
capability to create and update a secret at the/external-apis/data/weather/california
path.$ 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
create
capability 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
create
andupdate
capabilities.Create a token with the new
weather
policy attached and store the token value in a variable calledWEATHER_TOKEN
.$ WEATHER_TOKEN=$(vault token create -policy=weather --format=json | jq -r '.auth.client_token')
Update the secret at
/external-apis/data/weather/california
with 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.