Operations

Vault Policies

In Vault, we use policies to govern the behavior of clients and instrument Role-Based Access Control (RBAC) by specifying access privileges (authorization).

When you first initialize Vault, the root policy gets created by default. The root policy is a special policy that gives superuser access to everything in Vault. This allows the superuser to set up the initial policies, auth methods, etc.

In addition, another built-in policy, default, is created. The default policy is attached to all tokens and provides common permissions.

Everything in Vault is path based, and admins write policies to grant or forbid access to certain paths and operations in Vault. Vault operates on a secure by default standard, and as such, an empty policy grants no permissions in the system.

HashiCorp Configuration Language (HCL)

Policies written in HCL format are often referred as ACL Policies. (NOTE: HCL is JSON compatible; therefore JSON can be used as completely valid input.) Sentinel is another framework for policy which is available in Vault Enterprise. Since Sentinel is an enterprise-only feature, this guide focuses on writing ACL policies as a foundation.

Personas

The scenario described in this guide introduces the following personas:

  • root sets up initial policies for admin
  • admin is empowered with managing a Vault infrastructure for a team or organizations
  • provisioner configures secrets engines and creates policies for client apps

Challenge

Since Vault centrally secures, stores, and controls access to secrets across distributed infrastructure and applications, it is critical to control permissions before any user or machine can gain access.

Solution

Restrict the use of root policy, and write fine-grained policies to practice least privileged. For example, if an app gets AWS credentials from Vault, write policy grants to read from AWS secrets engine but not to delete, etc.

Policies are attached to tokens and roles to enforce client permissions on Vault.

Prerequisites

To perform the tasks described in this guide, you need to have a Vault environment. Refer to the Getting Started guide to install Vault. Make sure that your Vault server has been initialized and unsealed.

NOTE: An interactive tutorial is also available if you do not have a Vault environment to perform the steps described in this guide. Click the Show Tutorial button to launch the tutorial.

Policy requirements

Since this guide demonstrates the creation of an admin policy, log in with root token if possible. Otherwise, make sure that you have the following permissions:

# Manage auth methods broadly across Vault
path "auth/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Create, update, and delete auth methods
path "sys/auth/*"
{
  capabilities = ["create", "update", "delete", "sudo"]
}

# List auth methods
path "sys/auth"
{
  capabilities = ["read"]
}

# Create and manage ACL policies
path "sys/policies/acl/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# To list policies - Step 3
path "sys/policies/acl"
{
  capabilities = ["list"]
}

# List, create, update, and delete key/value secrets
path "secret/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Create and manage secrets engines broadly across Vault.
path "sys/mounts/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Read health checks
path "sys/health"
{
  capabilities = ["read", "sudo"]
}

# To perform Step 4
path "sys/capabilities"
{
  capabilities = ["create", "update"]
}

# To perform Step 4
path "sys/capabilities-self"
{
  capabilities = ["create", "update"]
}

Step 1: Write ACL policies in HCL format

Remember, an empty policy grants no permission in the system. Therefore ACL policies are defined for each path.

path "<PATH>" {
  capabilities = [ "<LIST_OF_CAPABILITIES>" ]
}

Define one or more capabilities on each path to control operations that are permitted.

CapabilityAssociated HTTP verbs
createPOST/PUT
readGET
updatePOST/PUT
deleteDELETE
listLIST

In addition, there are sudo and deny which don't map to HTTP verbs.

  • sudo allows access to paths that are root-protected (Refer to the Root protected endpoints section)
  • deny disallows access

Policy requirements

The first step in creating policies is to gather policy requirements.

Example:

admin is a type of user empowered with managing a Vault infrastructure for a team or organizations. Empowered with sudo, the Administrator is focused on configuring and maintaining the health of Vault cluster(s) as well as providing bespoke support to Vault users.

admin must be able to:

  • Enable and manage auth methods broadly across Vault
  • Enable and manage the key/value secrets engine at secret/ path
  • Create and manage ACL policies broadly across Vault
  • Read system health check

provisioner is a type of user or service that will be used by an automated tool (e.g. Terraform) to provision and configure a namespace within a Vault secrets engine for a new Vault user to access and write secrets.

provisioner must be able to:

  • Enable and manage auth methods
  • Enable and manage the key/value secrets engine at secret/ path
  • Create and manage ACL policies

Now, you are ready to author policies to fulfill these requirements.

Example policy for admin

admin-policy.hcl

# Manage auth methods broadly across Vault
path "auth/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Create, update, and delete auth methods
path "sys/auth/*"
{
  capabilities = ["create", "update", "delete", "sudo"]
}

# List auth methods
path "sys/auth"
{
  capabilities = ["read"]
}

# List existing policies
path "sys/policies/acl"
{
  capabilities = ["list"]
}

# Create and manage ACL policies
path "sys/policies/acl/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# List, create, update, and delete key/value secrets
path "secret/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Manage secrets engines
path "sys/mounts/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# List existing secrets engines.
path "sys/mounts"
{
  capabilities = ["read"]
}

# Read health checks
path "sys/health"
{
  capabilities = ["read", "sudo"]
}

Example policy for provisioner

provisioner-policy.hcl

# Manage auth methods broadly across Vault
path "auth/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# Create, update, and delete auth methods
path "sys/auth/*"
{
  capabilities = ["create", "update", "delete", "sudo"]
}

# List auth methods
path "sys/auth"
{
  capabilities = ["read"]
}

# List existing policies
path "sys/policies/acl"
{
  capabilities = ["list"]
}

# Create and manage ACL policies via API & UI
path "sys/policies/acl/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

# List, create, update, and delete key/value secrets
path "secret/*"
{
  capabilities = ["create", "read", "update", "delete", "list"]
}

Step 2: Create policies

Now, create admin and provisioner policies in Vault.

CLI command / API call using cURL / Web UI

CLI command

To create policies:

$ vault policy write <POLICY_NAME> <POLICY_FILE>

Example:

# Create admin policy
$ vault policy write admin admin-policy.hcl

# Create provisioner policy
$ vault policy write provisioner provisioner-policy.hcl

API call using cURL

To create a policy, use the /sys/policies/acl endpoint:

$ curl --header "X-Vault-Token: <TOKEN>" \
       --request PUT \
       --data <PAYLOAD> \
       <VAULT_ADDRESS>/v1/sys/policies/acl/<POLICY_NAME>

Where <TOKEN> is your valid token, and <PAYLOAD> includes the policy name and stringified policy.

Example:

Now, create admin and provisioner policies:

# Create the API request payload. Use stringified policy expression.
$ tee admin-payload.json <<EOF
{
  "policy": "# Manage auth methods broadly across Vault\npath \"auth/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# Create, update, and delete auth methods\npath \"sys/auth/*\"\n{\n  capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n}\n\n# List auth methods\npath \"sys/auth\"\n{\n  capabilities = [\"read\"]\n}\n\n# List existing policies\npath \"sys/policies/acl\"\n{\n  capabilities = [\"list\"]\n}\n\n# Create and manage ACL policies \npath \"sys/policies/acl/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# List, create, update, and delete key/value secrets\npath \"secret/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# Manage secrets engines\npath \"sys/mounts/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# List existing secrets engines.\npath \"sys/mounts\"\n{\n  capabilities = [\"read\"]\n}\n\n# Read health checks\npath \"sys/health\"\n{\n  capabilities = [\"read\", \"sudo\"]\n}"
}
EOF

# Create admin policy
$ curl --header "X-Vault-Token: ..." \
       --request PUT \
       --data @admin-payload.json \
       http://127.0.0.1:8200/v1/sys/policies/acl/admin

# Create the API request payload for creating provisioner policy
$ tee provisioner-payload.json <<EOF
{
  "policy": "# Manage auth methods broadly across Vault\npath \"auth/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# Create, update, and delete auth methods\npath \"sys/auth/*\"\n{\n  capabilities = [\"create\", \"update\", \"delete\", \"sudo\"]\n}\n\n# List auth methods\npath \"sys/auth\"\n{\n  capabilities = [\"read\"]\n}\n\n# List existing policies\npath \"sys/policies/acl\"\n{\n  capabilities = [\"list\"]\n}\n\n# Create and manage ACL policies via API & UI\npath \"sys/policies/acl/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\", \"sudo\"]\n}\n\n# List, create, update, and delete key/value secrets\npath \"secret/*\"\n{\n  capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\"]\n}"
}
EOF

# Create provisioner policy
$ curl --header "X-Vault-Token: ..." \
       --request PUT \
       --data @provisioner-payload.json \
       http://127.0.0.1:8200/v1/sys/policies/acl/provisioner

Web UI

  1. Open a web browser and launch the Vault UI (e.g. http://127.0.0.1:8200/ui) and then login.

  2. Click the Policies tab, and then select Create ACL policy.

  3. Toggle the Upload file sliding switch, and click Choose a file to select your admin-policy.hcl file you authored. Set the Name to admin.

  4. Click Create Policy to complete.

  5. Click Policies > Create ACL policy again, and then toggle the Upload file sliding switch.

  6. Click Choose a file to select your provisioner-policy.hcl file you authored. Set the Name to provisioner.

  7. Click Create Policy to complete.

Step 3: View existing policies

Make sure that you see the policies you created in Step 2.

CLI command / API call using cURL / Web UI

CLI command

The following command lists existing policies:

$ vault policy list

To view a specific policy:

$ vault policy read <POLICY_NAME>

Example:

# Read admin policy
$ vault policy read admin

# Mount and manage auth methods broadly across Vault
path "auth/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}

path "sys/auth/*"
{
  capabilities = ["create", "read", "update", "delete", "sudo"]
}

# Create and manage ACL policies broadly across Vault
path "sys/policies/acl/*"
{
  capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
...

API call using cURL

To list existing ACL policies, use the /sys/policies/acl endpoint.

$ curl --request LIST --header "X-Vault-Token: ..." http://127.0.0.1:8200/v1/sys/policies/acl | jq

To read a specific policy, the endpoint path should be /sys/policies/acl/<POLICY_NAME>.

Example:

# Read the admin policy
$ curl --header "X-Vault-Token: ..." http://127.0.0.1:8200/v1/sys/policies/acl/admin | jq
{
  "request_id": "3f826e5c-70a0-2998-8082-fe34c67c59d1",
  "lease_id": "",
  "renewable": false,
  "lease_duration": 0,
  "data": {
    "name": "admin",
    "policy": "# Manage auth methods broadly across Vault\npath \"auth/*\"\n{\n  capabilities = [\"create\", \"read\" ...
  },
  "wrap_info": null,
  "warnings": null,
  "auth": null
}

Web UI

  1. Select the Policies tab.

  2. Select ACL Policies to view the list of exiting policies. Policies

  3. Select an individual policy name to view its content.

Step 4: Check capabilities of a token

This step shows how to print out the permitted capabilities of a token on a path. This can help verifying what operations are granted based on the policies attached to the token.

CLI command / API call using cURL / Web UI

CLI command

The command is:

$ vault token capabilities <TOKEN> <PATH>

Example:

First, create a token attached to admin policy:

$ vault token create -policy="admin"
Key                  Value
---                  -----
token                2sHGlAHNj36LpqQ2Zevl2Owi
token_accessor       4G4UIsQOMwifg7vMLqf6QIc3
token_duration       768h
token_renewable      true
token_policies       ["admin" "default"]
identity_policies    []
policies             ["admin" "default"]

Now, fetch the capabilities of this token on the sys/auth/approle path.

$ vault token capabilities 2sHGlAHNj36LpqQ2Zevl2Owi sys/auth/approle
create, delete, read, sudo, update

The result should match the policy rule you wrote on the sys/auth/* path. You can repeat the steps to generate a token for provisioner and check its capabilities on paths.

In the absence of a token, it returns the capabilities of the current token invoking this command.

$ vault token capabilities sys/auth/approle
root

API call using cURL

Use the sys/capabilities endpoint.

Example:

First, create a token attached to the admin policy:

$ curl --request POST --header "X-Vault-Token: ..." --data '{ "policies":"admin" }' \
       http://127.0.0.1:8200/v1/auth/token/create
{
   "request_id": "bd9b3216-f7e6-610c-4861-38b9112a1821",
   "lease_id": "",
   "renewable": false,
   "lease_duration": 0,
   "data": null,
   "wrap_info": null,
   "warnings": null,
   "auth": {
     "client_token": "3xlduc1vGMD7vKeGLyONAxdS",
     "accessor": "FOoNv0YJSCqtPVCpW03qVeKd",
     "policies": [
       "admin",
       "default"
     ],
     "token_policies": [
       "admin",
       "default"
     ],
     "metadata": null,
     "lease_duration": 2764800,
     "renewable": true,
     "entity_id": ""
   }
}

Now, fetch the capabilities of this token on the sys/auth/approle path.

# Request payload
$ tee payload.json <<EOF
{
  "token": "3xlduc1vGMD7vKeGLyONAxdS",
  "path": "sys/auth/approle"
}
EOF

$ curl --request POST --header "X-Vault-Token: ..." \
       --data @payload.json \
       http://127.0.0.1:8200/v1/sys/capabilities | jq
{
  "sys/auth/approle": [
    "create",
    "delete",
    "read",
    "sudo",
    "update"
  ],
  "capabilities": [
    "create",
    "delete",
    "read",
    "sudo",
    "update"
  ],
  ...
}

The result should match the policy rule you wrote on the sys/auth/* path. You can repeat the steps to generate a token for provisioner and check its capabilities on paths.

To check the current token's capabilities permitted on a path, use the sys/capabilities-self endpoint.

$ curl --request POST --header "X-Vault-Token: ..." \
       --data '{"path":"sys/auth/approle"}' \
       http://127.0.0.1:8200/v1/sys/capabilities-self

Web UI

  1. Click the Vault CLI shell icon (>_) to open a command shell. Run the following command to create a new token: vault write auth/token/create policies=admin Create Policy

  2. Run the following command to fetch the capabilities of this generated token on the sys/auth/approle path: vault write sys/capabilities token=<token> path=sys/auth/approle Create Policy

  3. Click the icon (>_) again to hide the shell.

Root protected API endpoints

The following paths requires a root token or sudo capability in the policy:

PathHTTP verbDescription
auth/token/accessorsLISTList token accessor
auth/token/create-orphanPOSTCreate an orphan token (the same as no_parent option)
auth/tokenPOSTCreate a periodic or an orphan token (period or no_parent) option
pki/rootDELETEDelete the current CA key (pki secrets engine)
pki/root/sign-self-issuedPOSTUse the configured CA certificate to sign a self-issued certificate (pki secrets engine)
ssh/roles/:name with admin_userPOSTCreate an admin user role at remote host (SSH secrets engine)
sys/auditGETList enabled audit devices
sys/audit/:pathPUT, DELETEEnable or remove an audit device
sys/auth/:pathGET, POST, DELETEManage the auth methods (enable, read, delete, and tune)
sys/config/auditing/request-headersGETList the request headers that are configured to be audited
sys/config/auditing/request-headers:nameGET, PUT, DELETEManage the auditing headers (create, update, read and delete)
sys/config/corsGET, PUT, DELETEConfigure CORS setting
sys/config-uiGETConfigure the UI settings
sys/leases/lookup/:prefixLISTList lease IDs
sys/leases/revoke-force/:prefixPUTRevoke all secrets or tokens ignoring backend errors
sys/leases/revoke-prefix/:prefixPUTRevoke all secrets generated under a given prefix
sys/plugins/catalog/:type/:nameGET, PUT, DELETERegister a new plugin, or read/remove an existing plugin
sys/rawLIST, GETReturns a list of keys for a given path prefix
sys/replication/reindexPOSTReindex the local data storage
sys/replication/performance/primary/secondary-tokenPOSTGenerate a performance secondary activation token
sys/replication/dr/primary/secondary-tokenPOSTGenerate a DR secondary activation token
sys/rotatePUTTrigger a rotation of the backend encryption key
sys/sealPUTSeals the Vault
sys/step-downPUTForces the node to give up active status

Help and Reference