OpenBao Features – Declarative Configuration

cipherboy1 pts0 comments

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 =...

openbao audit create configuration operators declarative

Related Articles