Learn Secret Management - Access Control Policies (HCL)
Episode 7 of 21

Learn Secret Management - Access Control Policies (HCL)

Writing HCL-format access rules that determine who may access which path in OpenBao, distinguishing exact paths from prefix wildcards, understanding all capabilities, and testing privilege enforcement via policy write and token create.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

Episode 6 brought you to the PKI Secrets Engine, where OpenBao issues TLS certificates automatically. But who is allowed to request those certificates? The answer is governed by policies. Episode 7 discusses Access Control Policies — the HCL language that determines which paths can be accessed and which actions are allowed. Without the right policies, a leaked token could roam through all of OpenBao. With the right policies, the impact of a leak can be narrowed as much as possible.

What is an Access Control Policy

A policy is a declarative rule that connects paths with capabilities. Its structure is simple: a path block contains a list of allowed operations on that path. The deny-by-default principle applies — if a path is not mentioned at all in any policy owned by a token, access is denied.

Policies are written in HCL (HashiCorp Configuration Language), a plain text file with the .hcl extension:

policy.hcl
# Minimal policy for an application
path "secret/data/app" {
  capabilities = ["read"]
}
 
path "secret/data/app/*" {
  capabilities = ["create", "read", "update", "delete"]
}

The two blocks above show two different matching patterns — exact path and prefix wildcard. Both are often written side by side because they are complementary in nature.

Exact Path vs Prefix Wildcard

The path pattern in a policy determines how broadly the rule applies:

PatternMatchesExample operation
secret/data/appExactly one pathRead the app secret
secret/data/app/*All sub-paths beneath itManage any key under app
secret/data/app/Sub-paths with a trailing slashAll descendants without touching app itself

This difference is crucial: secret/data/app only covers that exact path, while secret/data/app/* covers its descendants — for example secret/data/app/backend and secret/data/app/frontend. To cover both at once, you write two lines like in the example above.

There is also the + operator, which matches exactly one segment — useful when you want to restrict to a single level without an overly broad wildcard, for example secret/data/+/db.

The decision rule: OpenBao uses the longest prefix match. If multiple rules collide, the most specific rule wins. And if one of the capabilities is deny, deny always overrides any permission.

Available Capabilities

Capabilities are the operations allowed on a path. Here is the complete list:

CapabilityMeaning
createCreate new data at the path
readRead existing data
updateUpdate existing data
deleteDelete data
listList the contents of a path
sudoPrivileged access that requires a sudo-capable token (e.g. writing policies)
denyDeny all access, overrides other capabilities

Note sudo — the capability that allows sensitive operations such as sys/policy or auth/token. This capability should only be granted to highly trusted users. Meanwhile, deny serves as a last-resort safety: placing it on a path guarantees a token will never touch that path, regardless of any other policy it holds.

Writing and Applying Policies

Applying a policy is as simple as writing a file and uploading it to OpenBao:

Write and inspect a policy
bao policy write my-policy policy.hcl
bao policy read my-policy
bao policy list

bao policy write my-policy policy.hcl takes the contents of policy.hcl and stores it as a policy named my-policy. An installed policy can be read back for auditing, and deleted with bao policy delete when no longer needed.

Testing Privilege Enforcement

A policy only takes effect when a token bound to it is created. A token is created by attaching a policy:

Create a policy-bound token
bao token create -policy=my-policy -format=json

The resulting token only inherits the capabilities from my-policy (plus built-in policies). Test it with that token:

Test a token's access rights
export VAULT_TOKEN="s.xxxxxxxxxxxx"
bao kv get secret/data/app
bao kv get secret/data/lain

bao kv get secret/data/app succeeds because that path is covered by the policy. Conversely, bao kv get secret/data/lain is denied with permission denied because none of the token's policies cover that path. This is privilege enforcement in action: access follows the policy, not desire.

Warning

Always start from the smallest policy and add only what is needed. The least privilege principle applies strictly here — a token circulating in application code should not carry sudo capabilities or full access to secret/data/*.

Policy Writing Best Practices

A few patterns that make policies safer and easier to maintain:

  • One policy per role — name it after its function, such as app-backend, app-frontend, or admin-audit, instead of piling all access into one giant policy.
  • Start narrow — only grant the capabilities actually used. A read-only token does not need create and update.
  • Separate user policies from machine policies — humans can be managed via SSO and groups, machines via AppRole; don't combine both in one file.
  • Review regularly — run bao policy list then bao policy read on each policy, and make sure no outdated rules are left behind.

A policy is not write-once-and-forget. It evolves with your architecture, and like code, it deserves regular review.

Conclusion

In this episode 7 you wrote HCL-format Access Control Policies, distinguished exact paths from prefix wildcards, learned all capabilities from create to deny, applied policies via bao policy write, and tested privilege enforcement with a policy-bound token.

Key takeaways:

  • Deny by default — paths not mentioned cannot be accessed.
  • Longest prefix match — the most specific rule wins, and deny always wins.
  • A token is only as strong as its policies — control the impact of leaks with narrow policies.
  • Use + and * deliberately — an overly broad wildcard is a risk.

In the next episode, episode 8, we discuss who carries those policies: Authentication Methods — how users and machines identify themselves via tokens, userpass, AppRole, and SSO such as OIDC, GitHub, Okta, and Azure AD.

Learn Secret Management - Access Control Policies (HCL) | Learn Secret Management with OpenBao