OpenBao Features - Declarative Configuration | OpenBao
Skip to main content<br>This is the third part of a multi-part series on OpenBao's features.
In the past few parts, we talked about low-level technical features that<br>OpenBao core maintainers and plugin authors can take advantage of to make<br>secrets management safer and more scalable.
This part focuses on something that applies to operators of OpenBao: better<br>operator experience for initial configuration. We focus on one question:
Question<br>How can we make initial OpenBao deployment easier and more reproducible?
The answer lies in declarative self-initialization<br>and declarative audit device creation.
These features available since OpenBao v2.4.0<br>allow operators to define the state of OpenBao prior to deploying it.
Audit Devices
Sensitive programs like Vault and OpenBao should always have audit logs.<br>Ideally it would be hard to not them set up without audit logs, or at least,<br>make it very hard to do so.
However, the API model of Vault made this difficult originally:
Operators would call sys/init to create seal<br>information and return a root token.
Operators would then have to call sys/audit to<br>create an audit device.
In the meantime, they'd want to be configuring OpenBao: creating auth mounts,<br>policies, secret engines, and the like. Perhaps this was fully automated, like<br>in OpenTofu, and it would be hard to guarantee a strict<br>ordering, due<br>to inherent parallelism.
Motivating us to solve this was one of the few remote code execution<br>vulnerabilities (RCEs)<br>in Vault: audit device configuration frequently interacted with the broader<br>environment, including potentially in ways that lead to RCEs. While HashiCorp<br>opted just to patch one small hole,<br>we opted to reimagine how audit device configuration could be controlled by<br>configuration owners.
Thus declarative audit devices were<br>born.
Here, system operators--those with privileged access to the underlying<br>configuration and broader execution environment--can define audit devices<br>through configuration files, reloading them on SIGHUP. These look like<br>the following:
audit "file" "my-device" {
description = "This audit device writes to stdout which never fails."
options {
file_path = "stdout"
While writing to stdout doesn't matter as much, consider the implications<br>when writing to network devices: operators can<br>disable API-driven creation by setting<br>unsafe_allow_api_audit_creation = false (the default) and ensure that a<br>leaked admin token doesn't result in secrets being exfiltrated to an attacker<br>over the network.
As an added bonus, every single request is now audited after initialization,<br>including any declarative self-initialization requests that we'll see below.
Self-Initialization
Going hand-in-hand with configuration-driven audit devices is declarative<br>self-initialization.
Here, operators define requests that they want executed when OpenBao first starts up:
initialize "authentication" {
request "mount-userpass" {
path = "sys/auth/userpass"
operation = "create"
data = {
type = "userpass"
description = "Administrative access to OpenBao."
request "create-user" {
path = "auth/userpass/users/admin"
operation = "create"
data = {
password = {
eval_source = "env"
eval_type = "string"
// Read the initial administrator password from an
// environment variable.
env_var = "INITIAL_ADMIN_PASSWORD"
require_present = true
token_policies = ["admin"]
request "create-policy" {
operation = "create"
path = "sys/policies/acl/admin"
data = {
policy =
path "*" {
capabilities = ["create", "update", "patch", "read", "delete", "list", "scan", "sudo"]
EOP
This would:
Create a new auth/userpass mount,
Create an administrative user, and
Create a highly privileged policy for that user.
While this may not look that different from an operator running commands<br>manually, consider the implications for OpenBao as a building block of some<br>larger system. This system would need:
A source of identity, to tie OpenBao into;
A KMS or similar auto-unseal device (including static) to automate<br>unseal;
A service orchestration layer (whether systemd unit files or Kubernetes),
A system to manage day one OpenBao operations.
Given those exist, operators can provision the initial state fully<br>declaratively.
OpenBao gives operators several tools for interacting in the form of dynamic<br>data source.<br>These can be environment variables:
password = {
eval_source = "env"
eval_type = "string"
// Read the initial administrator password from an
// environment variable.
env_var = "INITIAL_ADMIN_PASSWORD"
require_present = true
or files:
policy = {
eval_source = "file"
eval_type = "string"
path = "/path/to/admin-policy.hcl"
OpenBao also supports chaining from the value of past<br>requests or<br>responses:
entity_id = {
eval_source = "response"
eval_type = "string"
initialize_name = "identity"
response_name = "entity"
field_selector = ["data", "id"]
and can do CEL or<br>text/template<br>based templating:
path =...