<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://openbao.org/blog/</id>
    <title>OpenBao Blog</title>
    <updated>2026-07-21T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://openbao.org/blog/"/>
    <subtitle>OpenBao Blog</subtitle>
    <icon>https://openbao.org/img/favicon.svg</icon>
    <entry>
        <title type="html"><![CDATA[OpenBao Features - Declarative Configuration]]></title>
        <id>https://openbao.org/blog/features-declarative-configuration/</id>
        <link href="https://openbao.org/blog/features-declarative-configuration/"/>
        <updated>2026-07-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Blog series describing OpenBao's features. This episode focuses on declarative configuration of OpenBao.]]></summary>
        <content type="html"><![CDATA[<p>This is the third part of a <a class="" href="https://openbao.org/blog/tags/features/">multi-part series on OpenBao's features</a>.</p>
<p>In the past few parts, we talked about low-level technical features that
OpenBao core maintainers and plugin authors can take advantage of to make
secrets management safer and more scalable.</p>
<p>This part focuses on something that applies to operators of OpenBao: better
operator experience for initial configuration. We focus on one question:</p>
<div class="theme-admonition theme-admonition-tip admonition_zcLH alert alert--success"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Question</div><div class="admonitionContent_TXrn"><p><strong>How can we make initial OpenBao deployment easier and more reproducible?</strong></p></div></div>
<p>The answer lies in <a class="" href="https://openbao.org/docs/configuration/self-init/">declarative self-initialization</a>
and <a class="" href="https://openbao.org/docs/configuration/audit/">declarative audit device creation</a>.</p>
<p>These features <a class="" href="https://openbao.org/community/release-notes/2-4-0/#features">available since OpenBao v2.4.0</a>
allow operators to define the state of OpenBao prior to deploying it.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="audit-devices">Audit Devices<a href="https://openbao.org/blog/features-declarative-configuration/#audit-devices" class="hash-link" aria-label="Direct link to Audit Devices" title="Direct link to Audit Devices" translate="no">​</a></h2>
<p>Sensitive programs like Vault and OpenBao should always have audit logs.
Ideally it would be hard to not them set up without audit logs, or at least,
make it very hard to do so.</p>
<p>However, the API model of Vault made this difficult originally:</p>
<ol>
<li class="">Operators would call <a class="" href="https://openbao.org/api-docs/system/init/"><code>sys/init</code></a> to create seal
information and return a root token.</li>
<li class="">Operators would then have to call <a class="" href="https://openbao.org/api-docs/system/audit/"><code>sys/audit</code></a> to
create an audit device.</li>
</ol>
<p>In the meantime, they'd want to be configuring OpenBao: creating auth mounts,
policies, secret engines, and the like. Perhaps this was fully automated, like
in OpenTofu, and it would be hard to <a href="https://opentofu.org/docs/internals/graph/#walking-the-graph" target="_blank" rel="noopener noreferrer" class="">guarantee a strict
ordering</a>, due
to inherent parallelism.</p>
<p>Motivating us to solve this was one of the few <a href="https://discuss.hashicorp.com/t/hcsec-2025-14-privileged-vault-operator-may-execute-code-on-the-underlying-host/76033" target="_blank" rel="noopener noreferrer" class="">remote code execution
vulnerabilities (RCEs)</a>
in Vault: audit device configuration frequently interacted with the broader
environment, including potentially in ways that lead to RCEs. While HashiCorp
opted just to <a href="https://developer.hashicorp.com/vault/docs/configuration#allow_audit_log_prefixing" target="_blank" rel="noopener noreferrer" class="">patch one small hole</a>,
we opted to reimagine how audit device configuration could be controlled by
configuration owners.</p>
<p>Thus <a class="" href="https://openbao.org/community/rfcs/config-audit-devices/">declarative audit devices</a> were
born.</p>
<p>Here, system operators--those with privileged access to the underlying
configuration and broader execution environment--can define audit devices
through configuration files, reloading them on <code>SIGHUP</code>. These look like
the following:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">audit </span><span class="token string" style="color:#e3116c">"file"</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"my-device"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">description</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"This audit device writes to stdout which never fails."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">options</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">file_path</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"stdout"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>While writing to <code>stdout</code> doesn't matter as much, consider the implications
when writing to <a class="" href="https://openbao.org/docs/audit/socket/">network devices</a>: operators can
<a class="" href="https://openbao.org/docs/configuration/#parameters">disable API-driven creation</a> by setting
<code>unsafe_allow_api_audit_creation = false</code> (the default) and ensure that a
leaked admin token doesn't result in secrets being exfiltrated to an attacker
over the network.</p>
<p>As an added bonus, every single request is now audited after initialization,
including any declarative self-initialization requests that we'll see below.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="self-initialization">Self-Initialization<a href="https://openbao.org/blog/features-declarative-configuration/#self-initialization" class="hash-link" aria-label="Direct link to Self-Initialization" title="Direct link to Self-Initialization" translate="no">​</a></h2>
<p>Going hand-in-hand with configuration-driven audit devices is <a class="" href="https://openbao.org/docs/configuration/self-init/">declarative
self-initialization</a>.</p>
<p>Here, operators define requests that they want executed when OpenBao first starts up:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">initialize </span><span class="token string" style="color:#e3116c">"authentication"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    request </span><span class="token string" style="color:#e3116c">"mount-userpass"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">path</span><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sys/auth/userpass"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">operation</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">data</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">type</span><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"userpass"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">description</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Administrative access to OpenBao."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    request </span><span class="token string" style="color:#e3116c">"create-user"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">path</span><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"auth/userpass/users/admin"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">operation</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">data</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">password</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token property" style="color:#36acaa">eval_source</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"env"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token property" style="color:#36acaa">eval_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// Read the initial administrator password from an</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// environment variable.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token property" style="color:#36acaa">env_var</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"INITIAL_ADMIN_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token property" style="color:#36acaa">require_present</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">token_policies</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"admin"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    request </span><span class="token string" style="color:#e3116c">"create-policy"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">operation</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"create"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">path</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"sys/policies/acl/admin"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">data</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">policy</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token heredoc string" style="color:#e3116c">&lt;&lt;EOP</span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="display:inline-block;color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="color:#e3116c">path "*" {</span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="color:#e3116c">  capabilities = ["create", "update", "patch", "read", "delete", "list", "scan", "sudo"]</span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="color:#e3116c">}</span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="display:inline-block;color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token heredoc string" style="color:#e3116c">EOP</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This would:</p>
<ol>
<li class="">Create a new <code>auth/userpass</code> mount,</li>
<li class="">Create an administrative user, and</li>
<li class="">Create a highly privileged policy for that user.</li>
</ol>
<p>While this may not look that different from an operator running commands
manually, consider the implications for OpenBao as a building block of some
larger system. This system would need:</p>
<ul>
<li class="">A source of identity, to tie OpenBao into;</li>
<li class="">A KMS or similar auto-unseal device (including <code>static</code>) to automate
unseal;</li>
<li class="">A service orchestration layer (whether systemd unit files or Kubernetes),</li>
<li class="">A system to manage day one OpenBao operations.</li>
</ul>
<p>Given those exist, operators can provision the initial state fully
declaratively.</p>
<p>OpenBao gives operators several tools for interacting in the form of <a class="" href="https://openbao.org/docs/concepts/profiles/#value-types-and-dynamic-data-sources">dynamic
data source</a>.
These can be <a class="" href="https://openbao.org/docs/concepts/profiles/#env-source">environment variables</a>:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">password</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_source</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"env"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// Read the initial administrator password from an</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// environment variable.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">env_var</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"INITIAL_ADMIN_PASSWORD"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">require_present</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>or <a class="" href="https://openbao.org/docs/concepts/profiles/#file-source">files</a>:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">policy</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_source</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"file"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">path</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/path/to/admin-policy.hcl"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>OpenBao also supports chaining from the value of past
<a class="" href="https://openbao.org/docs/concepts/profiles/#request-source">requests</a> or
<a class="" href="https://openbao.org/docs/concepts/profiles/#response-source">responses</a>:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">entity_id</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_source</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"response"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">initialize_name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"identity"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">response_name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"entity"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">field_selector</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"data"</span><span class="token plain">, </span><span class="token string" style="color:#e3116c">"id"</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>and can do <a class="" href="https://openbao.org/docs/concepts/profiles/#cel-source">CEL</a> or
<a class="" href="https://openbao.org/docs/concepts/profiles/#template-source"><code>text/template</code></a>
based templating:</p>
<div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">path</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_source</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"template"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">eval_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"string"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">template</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"auth/userpass/users/{{ .input.username }}"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This allows construction of fairly advanced configurations and interactions
with nearly every subsystem regardless of complexity.</p>
<p>Think of self-initialization like the building block of a fully reproducible
environment: operators define the minimal configuration necessary to stand
up OpenBao and then systems like <a href="https://opentofu.org/" target="_blank" rel="noopener noreferrer" class="">OpenTofu</a> can take
over from there.</p>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p>Self-initialization has three design limitations:</p><ol>
<li class="">It is intentionally only run on first startup. This ensures that an
attacker can't later modify the configuration and grant themselves
privileged access.</li>
<li class="">Only a single node should be started to do self-initialization; parallel
self-initialization is not supported and may fail or lead to split-brained
Raft clusters.</li>
<li class="">Operators need to be running auto-unseal so that initial startup is fully
automatic.</li>
</ol></div></div>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="features" term="features"/>
        <category label="storage" term="storage"/>
        <category label="technical" term="technical"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Features - Transactional Storage]]></title>
        <id>https://openbao.org/blog/features-transactional-storage/</id>
        <link href="https://openbao.org/blog/features-transactional-storage/"/>
        <updated>2026-07-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Blog series describing OpenBao's features. This episode focuses on transactional storage.]]></summary>
        <content type="html"><![CDATA[<p>This is second part of a <a class="" href="https://openbao.org/blog/tags/features/">multi-part series on OpenBao's features</a>.</p>
<p>Today we focus on <a class="" href="https://openbao.org/community/rfcs/transactions/">transactional storage</a>. While
the <a class="" href="https://openbao.org/blog/transactions/">earlier</a> blog <a class="" href="https://openbao.org/blog/raft-transactions/">posts</a>
focused on the what and how of transactions in Raft, this post will focus on
the measurable impact of transactions in OpenBao and their lack in Vault. We
will demo some possible ways of creating snapshots which cannot restore and
are not consistent on Vault and show how we used transactions to achieve
consistency on OpenBao.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="historical-context">Historical context<a href="https://openbao.org/blog/features-transactional-storage/#historical-context" class="hash-link" aria-label="Direct link to Historical context" title="Direct link to Historical context" translate="no">​</a></h2>
<p>Recall from <a class="" href="https://openbao.org/blog/features-paginated-lists/">last week's post</a> that our
starting storage interface was rather limited:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Storage is the way that logical backends are able read/write data.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Storage </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">List</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prefix </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entries </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/sdk/logical/storage.go#L31-L37" target="_blank" rel="noopener noreferrer" class=""><code>fork-point:sdk/logical/storage.go</code></a>).</p>
<p>Also included in the storage model of the fork, though implemented in only
a few backends (Raft, CockroachDB, Consul, FoundationDB, and Spanner) was a
basic batch application mechanism:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// TxnEntry is an operation that takes atomically as part of</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// a transactional update. Only supported by Transactional backends.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> TxnEntry </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Operation Operation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Entry     </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">Entry</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Transactional is an optional interface for backends that</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// support doing transactional updates of multiple keys. This is</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// required for some features such as replication.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Transactional </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// The function to run a transaction</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Transaction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token operator" style="color:#393A34">*</span><span class="token plain">TxnEntry</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/sdk/physical/transactions.go#L13-L30" target="_blank" rel="noopener noreferrer" class=""><code>fork-point:sdk/physical/transactions.go</code></a>).</p>
<p>Notably, from the <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/sdk/physical/transactions.go#L46-L153" target="_blank" rel="noopener noreferrer" class="">implementation of
<code>physical.GenericTransactionHandler</code></a>,
we see that this was not an implementation of check-and-set semantics: <code>LIST</code>
operations are entirely ignored, any <code>GET</code> operations are dispatched ahead of
any writes, and while a rollback log is created and entries read before
issuing any writes, they are not compared against any sent writes. This makes
batch application rather unsafe if used incorrectly: if a (distributed) lock
mechanism or other exclusive ownership semantic does not exist, multiple
in-flight transactions can write to the same storage entries. This may produce
unexpected results.</p>
<p>Luckily, this mechanism was not exposed at the logical level, hiding its use
within Core and all auth and secret plugins, preventing its misuse.</p>
<p>From <a href="https://github.com/openbao/openbao/commit/c1cf97adac5c53301727623a74b828a5f12592cf" target="_blank" rel="noopener noreferrer" class="">commit messages</a>
we can guess this mechanism was an internal implementation detail of the
<a href="https://support.hashicorp.com/hc/en-us/articles/20457140183443-Replication-Overview-and-Merkle-Sync-Loop-Analyses" target="_blank" rel="noopener noreferrer" class="">proprietary Vault Enterprise Performance Replication
mode</a>
and thus not relevant to improving snapshot consistency.</p>
<p>OpenBao instead moved to a much more powerful interactive transaction model:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Transactional is an optional interface for backends that support</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// interactive (mixed code &amp; statement) transactions in a similar</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// style as Go's Database paradigm. This is equivalent to</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// physical.Transactional, not the earlier, one-shot version of the</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// interface.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Transactional </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// This function allows the creation of a new interactive transaction</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// handle, only supporting read operations. Attempts to perform write</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// operations (Put(...) or Delete(...)) will err.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">BeginReadOnlyTx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">txn Transaction</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// This function allows the creation of a new interactive transaction</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// handle, supporting read/write transactions. In some cases, the</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// underlying physical storage backend cannot handle parallel read/write</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// transactions.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">BeginTx</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">txn Transaction</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Transaction is an interactive transactional interface: backend storage</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// operations can be performed, and when finished, Commit or Rollback can</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// be called. When a read-only transaction is created, write calls (Put(...)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// and Delete(...)) will err out.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Transaction </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	Storage</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// Commit a transaction; this is equivalent to Rollback on a read-only</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// transaction. Either Commit or Rollback must be called to release</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// resources.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Commit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// Rollback a transaction, preventing any changes from being persisted.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// Either Commit or Rollback must be called to release resources.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Rollback</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/main/sdk/logical/storage_transactions.go#L10-L43" target="_blank" rel="noopener noreferrer" class=""><code>main:sdk/logical/storage_transactions.go</code></a>).</p>
<p>Callers of this API can perform arbitrary storage operations interleaved with
non-storage calls and have consistency amongst all of them. This is
implemented in both supported storage backends, Raft and PostgreSQL.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="reproducers">Reproducers<a href="https://openbao.org/blog/features-transactional-storage/#reproducers" class="hash-link" aria-label="Direct link to Reproducers" title="Direct link to Reproducers" translate="no">​</a></h2>
<p>Looking at plugin code in our <a href="https://github.com/openbao/openbao/tree/fork-point/builtin" target="_blank" rel="noopener noreferrer" class=""><code>fork-point</code> tag</a>,
any series of multi-write flow could potentially be affected by a snapshot
consistency issue. However, to be affected by snapshot consistency issues,
the server needs to assume that either both writes succeeded or neither did.</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="pki">PKI<a href="https://openbao.org/blog/features-transactional-storage/#pki" class="hash-link" aria-label="Direct link to PKI" title="Direct link to PKI" translate="no">​</a></h3>
<p>One such is in the PKI engine.</p>
<p>When creating a new issuer via <code>&lt;mount&gt;/root/generate/internal</code>, the <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/path_root.go#L256-L320" target="_blank" rel="noopener noreferrer" class="">following
storage operations</a>
are performed:</p>
<ol>
<li class=""><code>config/key/&lt;id&gt;</code>, to <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/storage.go#L437-L440" target="_blank" rel="noopener noreferrer" class="">store the new root CA's key</a></li>
<li class=""><code>config/keys</code>, to <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/storage.go#L509-L511" target="_blank" rel="noopener noreferrer" class="">store the new default issuer config</a></li>
<li class=""><code>config/issuer/&lt;id&gt;</code>, to <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/storage.go#L907-L911" target="_blank" rel="noopener noreferrer" class="">import the new root CA's certificate</a></li>
<li class=""><code>config/issuers</code>, to <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/storage.go#L920-L922" target="_blank" rel="noopener noreferrer" class="">store the new default issuer config</a></li>
<li class=""><code>crls/&lt;id&gt;</code>, to <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/builtin/logical/pki/crl_util.go#L2197-L2203" target="_blank" rel="noopener noreferrer" class="">store the initial empty CRL</a></li>
</ol>
<p>Notably consistency between storage operations 3 and 4 are the crucial:
failure to store the initial issuer's identifier as default will mean that
API compatibility with older Vault versions (and many third-party
applications) which are not aware of multi-issuer features is broken. This
will cause the API to return an error like:</p>
<div class="language-text codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-text codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">err=Error making API request.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">URL: GET http://localhost:8200/v1/058a0c0f-2dc3-a4a3-2e22-b00811700bac/issuer/default</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Code: 500. Errors:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">* 1 error occurred:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        * no default issuer currently configured</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">resp=&lt;nil&gt;</span><br></div></code></pre></div></div>
<p>which will persist on all operations until an operator manually creates an
<a class="" href="https://openbao.org/api-docs/secret/pki/#set-issuers-configuration">association between the generated issuer and the
<code>default</code></a>. Similar issues
could occur whenever an issuer is rotated; the key could be persisted but the
signing certificate could be dropped from the backup.</p>
<p>Notably, PKI's usage here would be a poor fit for check-and-set semantics:
composability of <code>importKey</code> and <code>importIssuer</code> into <code>writeCaBundle</code> would
be difficult to achieve while retaining transactional properties. This is why
the stronger interactive transaction model is better for OpenBao's use case,
even though it limits the theoretical storage backends one could implement
as not every potential storage engine (like S3) implements interactive
transactions.</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="features" term="features"/>
        <category label="storage" term="storage"/>
        <category label="technical" term="technical"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dreaming of a Better User Experience for Shamir's]]></title>
        <id>https://openbao.org/blog/better-shamir-ux/</id>
        <link href="https://openbao.org/blog/better-shamir-ux/"/>
        <updated>2026-07-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A blog outlining what a better user experience for Shamir's might look like and what advantages it might have for OpenBao.]]></summary>
        <content type="html"><![CDATA[<p>At <a class="" href="https://openbao.org/blog/cipherboy-ossna-26-talk/">Open Source Summit North America</a>,
I met <a href="https://engineering.nyu.edu/faculty/justin-cappos" target="_blank" rel="noopener noreferrer" class="">Dr. Justin Cappos</a>,
professor at NYU and major OpenSSF contributor and working group lead, and
several of his students.</p>
<p>Along with broader discussions of how OpenBao and <a href="https://gittuf.dev/" target="_blank" rel="noopener noreferrer" class="">gittuf</a>
might integrate, we talked about Shamir's unsealing and its fundamental
problem: it is a side-effecting process with high-entropy results. You can
wrap it around a common dictionary, hex or base64 encoding, or other means to
make the key shares more consumable by humans, but the results will still be
complex and hard to input and store.</p>
<p>The problems I'm looking for a scheme to solve are two fold:</p>
<ol>
<li class="">Secure storage of Shamir shares are hard. It effectively relies on another,
externally secure system (whether physical or digital) to safely store. In
<a class="" href="https://openbao.org/community/rfcs/emergency-seal/">emergency scenarios</a>, this is fine, but
if Shamir's is in regular use, this can be cumbersome depending on whether
systems are air gapped or similar.</li>
<li class="">We can't easily use <a class="" href="https://openbao.org/docs/configuration/self-init/">declarative self-initialization</a>
as we required a side-effect-less initialization.</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="on-shamirs">On Shamir's<a href="https://openbao.org/blog/better-shamir-ux/#on-shamirs" class="hash-link" aria-label="Direct link to On Shamir's" title="Direct link to On Shamir's" translate="no">​</a></h3>
<p>While I will spare people too much math, some initial context on why this is
non-trivial with Shamir's is important. For a conceptual model, think of
<a href="https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing" target="_blank" rel="noopener noreferrer" class="">Shamir's secret sharing</a>
as using polynomial equations:</p>
<div class="language-text codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-text codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">s + a_1 x_1 + a_2 x_2^2 + a_3 x_3 ^ 3 + ...</span><br></div></code></pre></div></div>
<p>By convention, the secret is embedded as the constant term of this polynomial,
with constants (<code>a_1 ... a_n</code>) being randomly chosen values. To allow for a
threshold of <code>n+1</code> shares required to recover, a <code>n</code> degree polynomial must
be chosen. For two share recovery, a linear equation is used; for three shares
to recover, a quadratic, &amp;c. This is because while <code>n+1</code> <code>(x, y)</code> points
uniquely describe a <code>n</code>-degree polynomial, <code>n</code> shares leaks no information:
nearly any possible constant term could fall out.</p>
<p>This gives Shamir's secret sharing a useful property: <em>information theoretic
security</em>.</p>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p>The above is a simplification: left to the reader are discussions about
encoding secrets and the frequent implementation over finite fields rather
than the real numbers. Make sure to always use cryptographically secure
random number generators and do not roll your own crypto!</p><p>OpenBao has moved <a href="https://pkg.go.dev/github.com/openbao/openbao/sdk/v2/helper/shamir" target="_blank" rel="noopener noreferrer" class="">its Shamir's implementation to
<code>sdk/</code></a>
so that others may consume it.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="requirements">Requirements<a href="https://openbao.org/blog/better-shamir-ux/#requirements" class="hash-link" aria-label="Direct link to Requirements" title="Direct link to Requirements" translate="no">​</a></h3>
<p>Cappos proposed a model for Shamir's that worked by masking password hashes
with the Shamir shares (via an xor); but in our context, we would mask Shamir
shares with password hashes. Supposing such a scheme could exist, we'd care
about the following properties:</p>
<ol>
<li class="">It isn't <em>much</em> more computationally expensive. Shamir's is easy to verify:
combining the pieces and performing a decryption of the root key using the
recovered AES-GCM key is relatively cheap.</li>
<li class="">It doesn't have side effects: we can't require the owner to know which Shamir
share a given password maps to.</li>
<li class="">It retains the core cryptographic properties of Shamir's when used in our
barrier encryption scheme: thresholds, arbitrary share ordering, &amp;c must
all be retained.</li>
<li class="">Storage of shares must be safe in plaintext. Because this is the root of
our cryptography, we don't have any other secure storage mechanism
available yet.</li>
<li class="">Hinted at above, but passwords and shares must be independent. While the
security of the scheme as a whole will be dictated by the combined entropy
of the (threshold-determined) weakest passwords, we can put system limits
on their construction. Passwords shouldn't derive into shares and thus have
unexpected determinism: we'd want strictly independent root keys to allow
for rotation under the same passwords.</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p><em>Aside</em>: Actual security depends on the details of this scheme and what
definition of "isn't much more computationally expensive" is used. Certain
variants provide more security (sum of weakest passwords) whereas others are
faster to verify at the cost of less security (strength of nth weakest
password). Balancing that trade-off will probably depend on use cases; if
you're interested, feel free to <a href="https://github.com/openbao#contact" target="_blank" rel="noopener noreferrer" class="">reach out</a>
to us and mention the blog!</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="results">Results<a href="https://openbao.org/blog/better-shamir-ux/#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h3>
<p>Assuming such a scheme existed, this would give us a great way to extend our
side-effect free <a class="" href="https://openbao.org/docs/configuration/self-init/">declarative self-initialization</a>
to Shamir's seal mechanisms:</p>
<ol>
<li class="">
<p>Operators would establish configuration like they do for auto-unseal
devices and namespace sealing, specifying the number of generated shares
and thresholds. This could perhaps be denoted via a new seal type,
<code>shamir-pass</code> or similar.</p>
</li>
<li class="">
<p>Operators could optionally specify minimum password complexity rules using
our existing <a class="" href="https://openbao.org/docs/concepts/password-policies/">password policies</a>, which
support validating against existing passwords.</p>
</li>
<li class="">
<p>We have two options for how initialization could go:</p>
<ul>
<li class="">
<p>We could either immediately initialize, requiring operators to
authenticate with any provisioned authentication provider and then
subsequently only allow initialization requests (blocking broader
requests to the system) to provide the required passwords until
concluded.</p>
</li>
<li class="">
<p>Or, we could delay self-initialization until sufficient passwords have
been provided, following the existing (unauthenticated) initialization
or rotation patterns.</p>
</li>
</ul>
<p>Notably, neither of these two approaches would yield keys to the API
callers which must be stored.</p>
</li>
</ol>
<p>Within <a class="" href="https://openbao.org/community/rfcs/namespace-sealing/">namespace sealing</a>, we would
already have an authenticated rotation mechanism and be able to reuse that
for initialization.</p>
<p>From an unseal perspective, this also makes it easier for air-gapped operators
wanting to use Shamir's to type and unseal OpenBao.</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="vision" term="vision"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Features - Paginated Lists]]></title>
        <id>https://openbao.org/blog/features-paginated-lists/</id>
        <link href="https://openbao.org/blog/features-paginated-lists/"/>
        <updated>2026-07-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Blog series describing OpenBao's features. This episode focuses on paginated lists.]]></summary>
        <content type="html"><![CDATA[<p>This is the start of a <a class="" href="https://openbao.org/blog/tags/features/">multi-part series on OpenBao's features</a>.</p>
<p>Nearly every single networked interface returning a list of results supports
subsets. SQL supports the <a href="https://www.postgresql.org/docs/current/queries-limit.html" target="_blank" rel="noopener noreferrer" class=""><code>LIMIT</code> and <code>OFFSET</code> keywords</a>,
along with a rich language for filtering returned results. Google Cloud KMS
APIs <a href="https://docs.cloud.google.com/kms/docs/reference/rest/v1/projects.locations.keyRings/list?rep_location=global" target="_blank" rel="noopener noreferrer" class="">supports <code>pageSize</code>, yielding a <code>nextPageToken</code></a>,
for iterating over multiple pages of results.</p>
<p>Many resources in Vault and OpenBao return lists:
<a class="" href="https://openbao.org/api-docs/secret/kv/kv-v2/#list-secrets">KVv2 secrets</a>,
<a class="" href="https://openbao.org/api-docs/secret/pki/#list-certificates">PKI's certificate lists</a>,
<a class="" href="https://openbao.org/api-docs/secret/ssh/#list-roles">SSH's roles</a>, and more.</p>
<p>Paginated lists were shipped <a class="" href="https://openbao.org/community/release-notes/2-0-0/#200">in OpenBao v2.0.0</a>
as our very first feature in our very first release!</p>
<p>So, why doesn't Vault support paginated lists?</p>
<p>The answer lies in its historical great-common-denominator storage interface:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Storage is the way that logical backends are able read/write data.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Storage </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">List</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prefix </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entries </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/8993802145833ab01d49c6070d787a9eccb81546/sdk/logical/storage.go#L31-L37" target="_blank" rel="noopener noreferrer" class=""><code>fork-point:sdk/logical/storage.go</code></a>).</p>
<p>In supporting <a href="https://github.com/openbao/openbao/tree/fork-point/physical" target="_blank" rel="noopener noreferrer" class="">over twenty different storage
backends</a>,
Vault had to support a common core of simple APIs over all potential storage
backends. This meant keeping <code>Storage.List(...)</code> to a simple get-all-results
list operation. If LIST APIs were to limit results, this would mean they'd
still have to fetch them all from storage and only limit them in memory before
sending to the client.</p>
<p>Early in OpenBao's history, the <a class="" href="https://openbao.org/community/policies/plugins/">decision was made</a>
to remove all but the Raft storage backend. This made it possible to iterate
on our storage model. Concretely, <a class="" href="https://openbao.org/community/rfcs/paginated-lists/">paginated lists</a>
and <a class="" href="https://openbao.org/community/rfcs/transactions/">transactional storage</a> (to be discussed
another time!) came out of that. As we <a class="" href="https://openbao.org/community/rfcs/postgresql/">re-introduced</a>
storage backends <a class="" href="https://openbao.org/docs/configuration/storage/postgresql/">like PostgreSQL</a>,
we made sure to include the improvements we've made to the storage API from
the start.</p>
<p>OpenBao's storage interface now looks like:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// Storage is the way that logical backends are able read/write data.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> Storage </span><span class="token keyword" style="color:#00009f">interface</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">List</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prefix </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entries </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">ListPage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prefix </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> after </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> limit </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entries </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> err </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Put</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> entry </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">StorageEntry</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">Delete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> path </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/v2.5.5/sdk/logical/storage.go#L35-L42" target="_blank" rel="noopener noreferrer" class=""><code>v2.5.5:sdk/logical/storage.go</code></a>)</p>
<p>meaning that API handlers can now fetch only a subset of results.</p>
<p>This follows a SQL-like interface:</p>
<div class="language-go codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-go codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">b </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">RaftBackend</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">ListPage</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> prefix </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> after </span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> limit </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token builtin">string</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token builtin">error</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// ... implementation elided ...</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>(from <a href="https://github.com/openbao/openbao/blob/v2.5.5/physical/raft/raft.go#L1716" target="_blank" rel="noopener noreferrer" class=""><code>v2.5.5:physical/raft/raft.go</code></a>)</p>
<p>taking the new parameters <code>after</code> and <code>limit</code>. These are:</p>
<ul>
<li class=""><code>after</code>: an optional entry to begin listing after for pagination; not required to
exist in the list results.</li>
<li class=""><code>limit</code>: an optional number of entries to return; defaults to all entries
when set to a non-positive number.</li>
</ul>
<p>We suggest plugin authors pass these through on all API endpoints to the
underlying storage calls.</p>
<p>For plugin authors who build against OpenBao's SDK but wish to have
compatibility with HashiCorp Vault, we've <a href="https://github.com/openbao/openbao/blob/v2.5.5/sdk/plugin/grpc_storage.go#L92-L115" target="_blank" rel="noopener noreferrer" class="">stubbed the
implementation</a>,
meaning you can safely expose and use a paginated list API and support it
on both server implementations.</p>
<p>In addition, use of paginated lists has lead to improvements like
<a href="https://github.com/openbao/openbao/pull/678" target="_blank" rel="noopener noreferrer" class="">#678</a> by Fatima Patel, to
use pagination during PKI's tidy operations. In the past, tidy operations
could consume a lot of memory if a large number of PKI mounts contained a
large number of stored leaf certificates. We exposed a new <code>page_size</code> option
(defaulting to 1000) to limit the number of certificate serial numbers in
memory during a single PKI tidy operation.</p>
<p>By enforcing this with <a class="" href="https://openbao.org/docs/concepts/policies/#limiting-pagination"><code>pagination_limit</code></a>
in an ACL policy, operators can now ensure that clients use pagination and set
maximum result set sizes going forward.</p>
<p>In short, OpenBao aligns with long-standing industry expectations for
expensive list calls and operators have more control with OpenBao than with
Vault for managing the performance impact of these types of API requests.</p>
<p>Tune in next time for a discussion on <a class="" href="https://openbao.org/blog/transactions/">transactional storage</a>!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="features" term="features"/>
        <category label="storage" term="storage"/>
        <category label="technical" term="technical"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao: Horizontally Scaling Secrets Management - OSSNA 2026]]></title>
        <id>https://openbao.org/blog/cipherboy-ossna-26-talk/</id>
        <link href="https://openbao.org/blog/cipherboy-ossna-26-talk/"/>
        <updated>2026-06-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Blog of Alex's talk at Open Source Summit North America 2026, describing the horizontal scalability features of OpenBao.]]></summary>
        <content type="html"><![CDATA[<p>Slides and content from Alex's Open Source Summit NA 2026 talk, describing the horizontal scalability features of OpenBao.</p>
<p>For a video, see the Linux Foundation's <a href="https://www.youtube.com/watch?v=vNsEAmNPwH0" target="_blank" rel="noopener noreferrer" class="">official YouTube channel</a>.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-01.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Welcome everyone to my talk on OpenBao and how we added horizontal scalability to the project. I'm Alex Scheel, Head of OpenBao Development at ControlPlane, a long time member of the OpenBao TSC, and chair of the OpenBao Development Working Group.</p>
<p>I've been fortunate to have a hand in the development of OpenBao since nearly the beginning of the project, and before that, at HashiCorp's Vault CryptoSec team.</p>
<p>If, like me, you were wishing you could get out for a post-lunch walk, thank you for staying, but we'll have to settle for some photos of Minneapolis I've sprinkled through the presentation. And thank you all for visiting Minnesota, whether from near or far!</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-02.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>First, what is OpenBao?</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-03.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>OpenBao is an open-source secrets manager, featuring everything from static and dynamic secrets to PKI and key management services. We have integrations with everything from External Secrets Operator and Cert Manager to OpenTofu, SOPS, and cosign.</p>
<p>We also have a growing ecosystem; check out our ecosystem page afterwards and if you're an adopter, integrator, or supporter, consider adding your logo!</p>
<p>OpenBao is an OpenSSF Sandbox project and is licensed under the MPLv2.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-04.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>If this sounds familiar, it should be!</p>
<p>OpenBao is the open-source continuation of HashiCorp Vault, started in late 2023 after the relicensing to the non-OSI BUSL license.</p>
<p>We aim to keep API compatibility for client applications, but to improve the operator and developer experience. Towards that goal, we've landed several Vault Enterprise features--such as horizontal scalability, which this talk focuses on--but also many original improvements like declarative self-initialization, storage-level improvements for better performance and snapshot consistency, and landing in our next release, things like an externally pluggable KMS interface, operator-defined workflows built on the existing profile engine, and per-namespace (per-tenant) barrier encryption keys with optional namespace sealing support.</p>
<p>(This photo is taken from the Mill Ruins park, facing the Mill City Museum which is hosting tonight's drone show.)</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-05.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>OpenBao's top-level governance body, its technical steering committee (TSC), is currently made up of the following companies: my employer, ControlPlane, a seat jointly occupied by SAP and Liquid Reply who SAP has contracted with to contribute to our community, Adfinis, Wallix, IOTech, and GitLab.</p>
<p>Our governance is openly documented in the project’s main repository. We have tracks for leadership (in the form of the TSC), for developers (in the form of the Dev Working Group and its many sub-working groups), and maintainership for those interested in contributing to reviews on the project. We’ve also started a marketing working group if talking about OpenBao or its usage is more your style.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-06.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>In my early 2025 talk at FOSDEM (which you can see on the OpenBao blog archive), I mentioned that I had hoped to grow a community around OpenBao of companies that make money supporting it, just like Kubernetes. Not long after that talk, both Adfinis and SAP stepped up and started contributing to the community. This March, I joined ControlPlane to further that mission as well, leading our efforts to commercialize support and maintenance of the project. You can read more about that on ControlPlane's blog.</p>
<p>ControlPlane employs maintainers for FluxCD, is a contributor to several CNCF and OpenSSF efforts, and focuses on a highly regulated customer base like banks and government entities.</p>
<p>I'm happy to report for anyone following along, the OpenBao community is healthy, growing, and my hopes have been answered! Though of course, we always welcome more contributions of any sort!</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-07.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>This now brings us to what we're here to discuss. Horizontal Scalability, and the journey to support it.</p>
<p>I'll focus on three parts mostly:</p>
<ol>
<li class="">
<p>What building blocks did the fork have? What were we starting with?</p>
</li>
<li class="">
<p>How did we support Raft in OpenBao v2.5.0? What challenges did we face along the way?</p>
</li>
<li class="">
<p>How will we support PostgreSQL and more going forward? How will this improve the operator experience?</p>
</li>
</ol>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-08.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>We started by trying to understand what we inherited from HashiCorp Vault.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-09.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Most importantly, we started with a highly available (though, not horizontally scalable!) base. In OpenBao as it stood before this feature, we had data replication already taken care of. We supported two HA storage backends (Integrated Storage aka Raft and PostgreSQL),</p>
<p>OpenBao and HashiCorp Vault have a single active node which can perform write operations; this is a limitation of the Raft protocol and used as a design decision elsewhere.</p>
<p>In Vault Community Edition which we inherited, probably for open-core feature differentiation with Vault Enterprise, HashiCorp only supported cold standbys: these were "unsealed" and ready to take over if the active node went down, but could only forward requests to it and did not do any processing locally.</p>
<p>In OpenBao v2.5.0, we wanted to land horizontal scalability, which meant we needed a way for these cold standby nodes to serve read requests. They still wouldn't handle write requests, but they could help alleviate some of the load from the single active node, depending on the user's workloads.</p>
<p>And, of course, we had a constraint that we wanted to behave similarly to Vault Enterprise's Performance Standby node types.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-10.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>How does Vault Enterprise behave? And what is a read request?</p>
<p>Vault Enterprise roughly defines a read request as something that doesn't cause any storage writes.</p>
<p>Confusingly, this has a very loose association with HTTP verbs. For instance, the Certificate Revocation List (CRL) rotation endpoint in the PKI engine incurs a storage write (the CRL itself), but uses the GET verb. More obviously, login, e.g., via the <code>userpass</code> authentication method, causes several storage writes.</p>
<p>Both of these, if they come into a read-enabled standby, would be forwarded.</p>
<p>For the types of requests that will be handled by a standby node, a KVv1 secret read operation would be handled locally; it is guaranteed to not have any write operations. Most KVv2 operations will not have any writes either. Additionally, some POST operations will be strictly handled locally: if a PKI engine's role is configured not to store leaf certificates, the issuance endpoint could be handled on the read-enabled standby node.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-11.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>From an operational standpoint it is now clear what we want to achieve, though we have a few quirks we need to work out with our storage backends. How do we handle invalidation of caching that occurs naturally?</p>
<p>For integrated storage, each OpenBao node becomes its own storage backend. It uses the Raft consensus protocol to handle replication of data between all nodes. This protocol is based on a leadership election process, which requires an odd number of voting nodes to be consistent. Each write sent by the leader is confirmed by another vote.</p>
<p>This write confirmation forms the basis of the write-ahead-log (WAL) mechanism. This WAL mechanism contains enough information about every storage write, which gives us an easy way to invalidate cached storage entries.</p>
<p>On PostgreSQL however, any number of nodes can be used as they all race to acquire a lock stored in the database. While PostgreSQL handles the data replication for us--giving us a M<!-- -->:N<!-- --> OpenBao service to database node decoupling--it doesn't by default provide enough information for invalidation on standby nodes. But more on that later.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-12.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Looking at the existing code base, there's a few hints we have on how invalidation is supposed to work.</p>
<p>This is a snippet of code from the PKI secrets engine. There are two parts I bolded:</p>
<ol>
<li class="">When we invalidate, we're given a context and the path of the storage entry that changed. We don't get the contents of the entry or if it was updated or deleted.</li>
<li class="">Similarly, we see that we shouldn't block too long: this code path spins off a goroutine to handle the update in the background. Other code paths in this function just flip the value of an atomic boolean for the next API request to adjust.</li>
</ol>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-13.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Putting this together, we learned that cache invalidation must be definite, operating on specific keys which were invalidated; it isn't TTL based. There must be some storage-path-based routing engine that dispatches invalidations from the storage layer, through core, to the plugin.</p>
<p>And, because invalidation must be in some hot path (in the case of Raft, we know it must be part of the WAL application process), we've learned that handling the invalidation synchronously isn't good for performance, so we should execute it asynchronously.</p>
<p>(This photo is features the Third Avenue bridge, looking back on downtown Minneapolis.)</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-14.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Moving right along, it was time to implement this.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-15.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>The design idea roughly looked something like this:</p>
<ol>
<li class="">We started by assuming we could just load all core subsystems and plugins on the standby node.</li>
<li class="">We allowed requests to come in, rather than automatically forwarding them. After this, we built a mechanism to conditionally forward requests when a storage write occurred.</li>
<li class="">And we built a cache invalidation layer based on the earlier analysis of our existing code, and a mechanism for routing storage paths to the owning subsystem.</li>
</ol>
<p>Simple, right?</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-16.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Starting from the existing HA code, it took a lot of work to refactor core to (correctly!) bring up the standby node as a reader. While conceptually simple, we found that we had some partial state (from being non-read-enabled) that we need to make sure we reset. And we found we needed a new post-unseal strategy which did not incur any writes and didn't load any subsystems which only performed writes, such as automatic barrier key rotation or starting the request forwarding server (which standbys connect to).</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-17.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>When processing read requests, we changed the request routing to now only conditionally forward the request (if the node was still a cold standby), and default to processing requests. This necessitated a second forward pass if the request could not be handled locally. Notably, a failed write request would result in no state, as the standby nodes cannot write to their underlying storage.</p>
<p>In creating this, we needed to refactor how requests were processed at the http layer: previously we only read the body once, either to forward it or to process it on the active node. However, as we now consumed the body twice, we built a way of spooling the request body and resetting back to the initial state on forward.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-18.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>The contract between OpenBao's core and its storage engines is conceptually simple: the storage engine just needs to tell us when a write occurs, so we can define a callback approach for this in the base <code>sdk/physical</code> interface.</p>
<p>This was implemented in the Integrated Storage (Raft) backend.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-19.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>However, the actual dispatch of invalidations is more complex.</p>
<p>We take pending callbacks from the storage engine and queue them into an asynchronous fairshare job queue, sharded by expected namespace. This prevents one particularly noisy tenant from starving all other tenants, at the cost of not necessarily guaranteeing relative order of writes across namespaces.</p>
<p>This job then handles the storage-level routing of written path to owning backend. Some backends are privileged, like the core of OpenBao itself, and can take longer to process invalidations. For instance, the mount table explicitly reloads the new entry, potentially spinning off a new external plugin process so that it is ready before the next inbound request. Requests routed to an sandboxed plugin, e.g., PKI, get processed with a short, 2 second context to enforce strict asynchronous behaviors and use of their own background worker contexts.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-20.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>The result of all this is that standby nodes now process read requests. In the chart on the left, before adding read request handling, only a single service process was consuming CPU. Now, on the right, all three service processes share this developer's machine and consume CPU processing requests.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-21.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>When it comes to running in a real, multi-node deployment, the impact becomes more clear. Where there was more contention for certain locks, the OpenBao v2.4.4 cluster's single active node was able to handle far fewer PKI certificate issuance operations. The other two standbys were completely idle.</p>
<p>In OpenBao v2.5.1, all three nodes were able to service requests, decreasing lock contention, giving us higher throughput and lower latency.</p>
<p>You can read more about this in Philipp's entry on the OpenBao blog.</p>
<p>Of course, things don't always go as planned. For some example of bugs we've fixed:</p>
<ol>
<li class="">
<p>When loading current state, we didn't pass through standby vs active node status to all places that needed it. This meant that, when upgrading a legacy non-transactional storage type to a read-enabled standby (say, in a direct migration from OpenBao v2.0.0 to v2.5.0), we'd fail to start up.</p>
</li>
<li class="">
<p>Certain types of specially handled requests (like root token generation) were not correctly forwarded to the active node as they were outside the regular request routing mechanism. This will be fixed in 2.5.4 coming this week.</p>
</li>
<li class="">
<p>But most of our bugs have been in the largest section of new code: invalidation routing. While plugin's invalidation logic was already present in Vault Community Edition, most of the core invalidation logic was presumably hidden in Vault Enterprise and wasn't part of our code base. This is the most difficult to test as it requires understanding and validating each individual subsystem.</p>
</li>
</ol>
<p>Mostly these come from community bug reports -- and some patches have even come from drive-by contributors, which is always appreciated.</p>
<p>The release series containing horizontal read scalability, OpenBao 2.5.x, was shipped at the start of the year, and so may already be running on your systems!</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-22.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Before we move on, I'd like to thank again the contributors to this feature: Fatima was the 2025 OpenBao Mentee sponsored by Adfinis, Philipp, an Adfinis employee, was her mentor and also contributed to the design and implementation, and I helped with implementation, reviews, and debugging.</p>
<p>(This photo was taken by my wife, Katherine Mayo, one winter, looking from the iconic Stone Arch bridge back on the city.)</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-23.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>You might be thinking... wait! ... you mentioned that the invalidation hook was implemented in the Raft backend, but what happened to the PostgreSQL backend?</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-24.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Well, it turns out it is slightly more complicated to implement.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-25.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>We started by thinking that maybe the built-in <code>LISTEN</code>+<code>NOTIFY</code> support in PostgreSQL would allow a sort of storage-level inter-process communication (IPC) which would save us from implementing it at the node-level.</p>
<p>Among other challenges, it turns out that these events may be silently dropped if OpenBao disconnects and reconnects through a proxy such as <code>pgbouncer</code>. This makes it unreliable for our use in invalidations.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-26.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>PostgreSQL has a WAL as well; why can't we use it? For starters, database operators would need to configure PostgreSQL to have a higher WAL verbosity level (<code>wal_level=logical</code>). Additionally, OpenBao cannot subscribe to the WAL on read-replica PostgreSQL nodes; only the PostgreSQL primary sends WAL events. This means having two database connections rather than just one on standby nodes.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-27.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>We thought about adding either a last modification time to the existing OpenBao schema, which loses the ability to easily detect deletes, or adding a new WAL subscription table. The latter puts garbage collection pressure on the database and has some of the same peer longevity problems as the PostgreSQL WAL implementation. We'd need to manually remove processed invalidations and keep track of which invalidations were seen by which live standby nodes.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-28.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>What about moving to a more standard TTL-based expiration? The biggest issues here are that OpenBao relies on invalidating lists--that is, knowing when a new entry was created--and that invalidating certain entries, such as the mount table, is rather expensive as it holds a few global locks that block incoming requests. This means more refactoring would be needed before we could adopt this approach.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-29.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Ultimately, we settled on implementing a GRPC stream-based notification mechanism, using our existing GRPC connection for forwarding requests. The standby will subscribe to the leader for invalidations, wait for the initial index to ensure it is caught up, and then begin processing both read requests and invalidations from the active. The active will send the expected index at which the data was written, which the secondary can then wait for.</p>
<p>Right now, OpenBao will have to manually wait for this event, but PostgreSQL 19 will introduce a <code>WAIT FOR LSN</code> operation.</p>
<p>The benefits of this is that OpenBao will strictly follow PostgreSQL’s lead: operators will promote or demote PostgreSQL nodes to primary, allowing writes to occur, and whichever OpenBao nodes are connected to it will then self-select to become active. No OpenBao specific failover is necessary.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-30.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>The good news is that this approach will hopefully scale to any indexed replicated storage backend, and open up new opportunities in the future.</p>
<p>This is under active development and should be in OpenBao v2.7.0.</p>
<p>(This photo showcases Target Field, where the Minnesota Twins play -- I hear the Linux Foundation has been organizing some visits to watch them play this week.)</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-31.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Briefly before we wrap up, a few more things to mention:</p>
<ol>
<li class="">We're introducing stronger consistency semantics for clients through index headers, aligning with and extending Vault Enterprise's implementation here. This should hopefully help clients to see fewer stale reads.</li>
<li class="">We also have a roadmap towards write scalability through per-namespace storage backends.</li>
</ol>
<p>In Vault Enterprise, this looks like the performance secondary cluster architecture, allowing a very limited form of write scalability: mounts (regardless of namespace) can be mounted as cluster-local, essentially creating a forked/hybrid cluster. Plugin authors can also opt-in to write certain paths to cluster-local storage, such as the PKI plugin’s leaf certificates. This has caused problems for plugins whose clients expect global knowledge: PKI’s CRL functionality needed special cross-cluster synchronization support.</p>
<p>OpenBao is thinking about this in a different way: by using namespaces as the isolating boundary, we know very few storage operations will cross the namespace boundary. This will form the basis for our envisioned multi-writer support: first we’ll add lightweight storage separation (different tables at the BBolt and PostgreSQL levels) using the same storage backend, allowing things like namespace-level storage quotas. Then we’ll introduce out-of-hierarchy namespaces, defined in the configuration file. These won’t inherit policies and access from the root namespace, behaving more like a lightweight, fully-isolated core. Lastly, we’ll move to separate storage backends altogether, adding in the ability for namespaces to designate themselves as active (versus a single global active node). This will allow write scalability across namespaces.</p>
<p>Ultimately, we hope this will lead to a different set of operator tradeoffs: the simplicity of a flat cluster (versus a treed hierarchy) should be easier for operators to understand and we’ll have better write scalability across an entire cluster rather than on a more adhoc basis.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-32.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Lastly, if you're interested in getting involved with the project, check out our community calendar on Proton! You can contribute to a development direction item, join a working group, like our posts on social media, add your logo to the OpenBao Ecosystem page, or just start using OpenBao for your secrets management needs.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-ossna-26/Horizontal-Scalability-Slide-33.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Thank you very much!</p>
<p>If you have any questions later or just want OpenBao stickers, feel free to come and find me at the conference. I may be at the OpenSSF booth, but if not, they--or you--should be able to contact me on their Slack instance. John from ControlPlane and a newly announced OpenSSF Ambassador is also wandering around if I'm busy!</p>
<p>Does anyone have questions now?</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="talks" term="talks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Improved Horizontal Scalability]]></title>
        <id>https://openbao.org/blog/improved-horizontal-scalability/</id>
        <link href="https://openbao.org/blog/improved-horizontal-scalability/"/>
        <updated>2026-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao v2.5.0 enables standby nodes to serve read requests, a first step towards better Horizontal Scalability.]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_i50L" id="summary">Summary<a href="https://openbao.org/blog/improved-horizontal-scalability/#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>In this blog post, I will give you an overview of the new Horizontal Scalability
feature of OpenBao, its (current) limitations and planned future developments.
In the second part, I will show some benchmarks to see in which cases the new
feature helps (spoiler: it works best in read-heavy workloads, but doesn't
improve write-heavy workloads).</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="recap-on-scalability-terminology">Recap on Scalability Terminology<a href="https://openbao.org/blog/improved-horizontal-scalability/#recap-on-scalability-terminology" class="hash-link" aria-label="Direct link to Recap on Scalability Terminology" title="Direct link to Recap on Scalability Terminology" translate="no">​</a></h2>
<p>Let's quickly recap what "horizontal" means in the context of scalability: To
scale a service up (i.e., allow it to handle more load) there are two options:
Give each instance more resources (CPU, memory, network speed, disk capacity,
...) or increase the number of instances. Increasing instance size is referred
to as "vertical" and increasing the number of instances is referred to as
"horizontal" scaling.</p>
<p>Whether this is successful, depends on the problem at hand and the
implementation. There are some problems that scale very well - both horizontally
and vertically - like serving static files. Given that the server is implemented
reasonably well, either doubling the resources per instance or doubling the
number of instances should both double the number of static files you can serve.
Once you start to introduce mutability scalability starts to suffer, especially
if you want to provide strong consistency guarantees.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="recently-released-horizontal-scalability-features">Recently released Horizontal Scalability Features<a href="https://openbao.org/blog/improved-horizontal-scalability/#recently-released-horizontal-scalability-features" class="hash-link" aria-label="Direct link to Recently released Horizontal Scalability Features" title="Direct link to Recently released Horizontal Scalability Features" translate="no">​</a></h2>
<p>With OpenBao v2.5.0, we introduced what we call "read scalability". To ensure
High Availability, OpenBao has supported "standby nodes" since we forked from
Vault. One of these nodes would automatically take over active duty, if the
current leader nodes goes down (planned or unplanned). We extended this feature
to allow the "standby nodes" to become "read-only nodes", meaning they can now
serve read requests on their own, while write requests are still forwarded to
the leader.</p>
<p>This has some limits:</p>
<ul>
<li class="">
<p>The obvious being: If you have mostly write requests with only a few
read-only requests, then read scalability won't help.</p>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p>Keep in mind that a read request on the API level (e.g., HTTP GET) might still
require a write to the storage, e.g. <a class="" href="https://openbao.org/docs/secrets/databases/#usage">reading a dynamic secret from the
database plugin</a> will require a write to storage, because
after its TTL has expired, it needs to be deleted and for this OpenBao has to
do "bookkeeping".</p></div></div>
</li>
<li class="">
<p>Currently, only the Raft storage backend is supported. Support for PostgreSQL
is in the works.</p>
</li>
</ul>
<p>There are also some caveats:</p>
<ul>
<li class="">
<p>It might require changes to your load-balancer setup: If no traffic is routed
to the "read-only nodes", then they won't remove any load from the primary.</p>
</li>
<li class="">
<p>Data read from a standby node might be stale, if it has recently been updated
on the primary. If this is unacceptable to you in general, you can set
<a class="" href="https://openbao.org/docs/configuration/"><code>disable_standby_reads = true</code> in your configuration</a>
to disable reads from standby. Or, if this is acceptable most of the time, you
can ensure to read from the primary in cases where you need the latest data.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="horizontal-scalability-outlook">Horizontal Scalability Outlook<a href="https://openbao.org/blog/improved-horizontal-scalability/#horizontal-scalability-outlook" class="hash-link" aria-label="Direct link to Horizontal Scalability Outlook" title="Direct link to Horizontal Scalability Outlook" translate="no">​</a></h2>
<p>Consistent writing in a distributed fashion is an inherently hard problem. If we
were set out to solve this in a general purpose way, we'd be doomed to fail. We
need to look out for properties of our specific case, that we can exploit:
Currently, there is one leader node per cluster, which will handle all write
request. We are planning to change this and have leader nodes per namespace,
which will handle all write requests for their namespace. As write requests
between sibling namespaces are independent, there is no risk of violating data
integrity (a property we can exploit <!-- -->🎉<!-- -->).</p>
<p>This again has an obvious limitation: if you do not use namespaces or if most of
your traffic is within a single namespace (e.g. you have a test and prod
namespace and prod accounts for 99% of the load) this won't help. But let's take
one step at a time and maybe it is even good enough, because a use cases is
either small enough to avoid scalability problems or big enough to require
namespaces anyway.</p>
<p>Now it is time to look at some benchmarks.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="benchmarks">Benchmarks<a href="https://openbao.org/blog/improved-horizontal-scalability/#benchmarks" class="hash-link" aria-label="Direct link to Benchmarks" title="Direct link to Benchmarks" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="setup">Setup<a href="https://openbao.org/blog/improved-horizontal-scalability/#setup" class="hash-link" aria-label="Direct link to Setup" title="Direct link to Setup" translate="no">​</a></h3>
<p>I have set up two 3-node OpenBao clusters on Azure, one running OpenBao 2.4.4
and one running OpenBao 2.5.1. Each cluster has a dedicated load balancer, but
the load balancer for 2.4.4 is configured to direct traffic only to the primary
node and the load balancer for the 2.5.1 cluster will distribute the traffic
among all nodes.</p>
<p>I ran two benchmarks, one for the KV engine and one for the PKI engine. I ran
both of them for 5 minutes per cluster using the <a href="https://github.com/openbao/benchmark-openbao" target="_blank" rel="noopener noreferrer" class=""><code>benchmark-openbao</code></a> tool.</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="kv-engine-benchmark">KV Engine Benchmark<a href="https://openbao.org/blog/improved-horizontal-scalability/#kv-engine-benchmark" class="hash-link" aria-label="Direct link to KV Engine Benchmark" title="Direct link to KV Engine Benchmark" translate="no">​</a></h3>
<p>The benchmark aims for 500 requests per second, with 90% reads and 10% writes.</p>
<details class="details_xguY alert alert--info details_uWnH" data-collapsed="true"><summary>Full <code>benchmark-openbao</code> Config</summary><div><div class="collapsibleContent_QEc2"><div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_XhbR">benchmark_kv.hcl</div><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">duration</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"5m"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">cleanup</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">workers</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2000</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">rps</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">500</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">disable_keep_alive</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">test </span><span class="token string" style="color:#e3116c">"kvv1_write"</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"writes"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">weight</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">config</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">numkvs</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">kvsize</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">test </span><span class="token string" style="color:#e3116c">"kvv1_read"</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"reads"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">weight</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">90</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">config</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">numkvs</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">kvsize</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div></div></div></details>
<p>If we take a look at the per-node CPU usage, we can clearly see the effects. The
first plot shows the CPU usage of the 2.4.4 cluster over a 15 minute timespan
(average per minute) with the 5 minute benchmark roughly centered. Before and
after the benchmark, we can see the active node hovering around 4% CPU usage,
while the standbys use around 2%. During the benchmark it raises to around 60%
for the primary and 8% for the standbys.</p>
<p><img decoding="async" loading="lazy" alt="CPU usage of 2.4.4 during the benchmark run" src="https://openbao.org/assets/images/benchmark-kv-2-4-4-283dd73f141c9d414f058829149ff735.svg" width="768" height="576" class="img_JF2Q"></p>
<p>The next plot shows the same data for the 2.5.1 cluster. In the first plot
we could clearly see which line is the primary, but here all lines are very
similar. Before and after the benchmark the CPU usage hovers around 4% jumping
up to 30 to 35% for all nodes during the benchmark.</p>
<p><img decoding="async" loading="lazy" alt="CPU usage of 2.5.1 during the benchmark run" src="https://openbao.org/assets/images/benchmark-kv-2-5-1-b7eb57a1ee64bcc592b85a70990f6b8a.svg" width="768" height="576" class="img_JF2Q"></p>
<p>This results in better latencies:</p>
<table><thead><tr><th>operation</th><th style="text-align:right">version</th><th style="text-align:right">mean</th><th style="text-align:right">95th%</th><th style="text-align:right">99th%</th><th style="text-align:right">count</th></tr></thead><tbody><tr><td>reads</td><td style="text-align:right">2.5.1</td><td style="text-align:right">5.75 ms</td><td style="text-align:right">19.55 ms</td><td style="text-align:right">36.94 ms</td><td style="text-align:right">1349402</td></tr><tr><td></td><td style="text-align:right">2.4.4</td><td style="text-align:right">7.92 ms</td><td style="text-align:right">28.69 ms</td><td style="text-align:right">51.64 ms</td><td style="text-align:right">1350523</td></tr><tr><td>writes</td><td style="text-align:right">2.5.1</td><td style="text-align:right">58.08 ms</td><td style="text-align:right">105.90 ms</td><td style="text-align:right">239.21 ms</td><td style="text-align:right">150598</td></tr><tr><td></td><td style="text-align:right">2.4.4</td><td style="text-align:right">87.21 ms</td><td style="text-align:right">201.23 ms</td><td style="text-align:right">355.96 ms</td><td style="text-align:right">149477</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Averaged Results</div><div class="admonitionContent_TXrn"><p>While the Graphs above show a single benchmark run, the tables are the combined
numbers of several benchmark runs.</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="pki-engine-benchmark">PKI Engine Benchmark<a href="https://openbao.org/blog/improved-horizontal-scalability/#pki-engine-benchmark" class="hash-link" aria-label="Direct link to PKI Engine Benchmark" title="Direct link to PKI Engine Benchmark" translate="no">​</a></h3>
<p>The benchmarks aims for only 5 requests per second, generating RSA 2048
certificates with <a class="" href="https://openbao.org/api-docs/secret/pki/#create-update-role"><code>no_store = true</code></a>, which makes this a read-only
operation. Generating a (RSA) private key is quite heavy on the CPU, therefore
the low number of requests.</p>
<details class="details_xguY alert alert--info details_uWnH" data-collapsed="true"><summary>Full <code>benchmark-openbao</code> Config</summary><div><div class="collapsibleContent_QEc2"><div class="language-hcl codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_XhbR">benchmark_pki_rsa2048_no_store.hcl</div><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-hcl codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token property" style="color:#36acaa">duration</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"5m"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">cleanup</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">workers</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">15</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">rps</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token property" style="color:#36acaa">disable_keep_alive</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">test </span><span class="token string" style="color:#e3116c">"pki_issue"</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"pki_issue"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">weight</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">100</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">config</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">setup_delay</span><span class="token punctuation" style="color:#393A34">=</span><span class="token string" style="color:#e3116c">"2s"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">root_ca</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">common_name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"benchmark.test Root Authority"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"rsa"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_bits</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2048"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">intermediate_csr</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">common_name</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"benchmark.test Intermediate Authority"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"rsa"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_bits</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2048"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">role</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">ttl</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"10s"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">no_store</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">generate_lease</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"rsa"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token property" style="color:#36acaa">key_bits</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"2048"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div></div></div></details>
<div class="theme-admonition theme-admonition-tip admonition_zcLH alert alert--success"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Performance Tip</div><div class="admonitionContent_TXrn"><p>If you are using the PKI engine and issue a fair amount of certificates, you
should consider <a class="" href="https://openbao.org/api-docs/secret/pki/#sign-certificate">using Certificate Signing Requests (CSRs)</a> instead of
generating the private key on the OpenBao cluster. Also, using ECDSA or Ed25519
instead of RSA where possible will improve the performance, see "<a class="" href="https://openbao.org/docs/secrets/pki/considerations/#key-types-matter">Key types
matter</a>"</p></div></div>
<p>Here again we have two graphs, first from the 2.4.4 cluster followed by the
2.5.1 cluster. During idle the results are the same as before.</p>
<p>On 2.4.4 cluster the primary spikes to 100% CPU usage, while the standbys don't
see any change (because in contrast to the KV benchmark there are no writes
happening, so they have no raft updates to apply).</p>
<p><img decoding="async" loading="lazy" alt="CPU usage of 2.4.4 during the benchmark run" src="https://openbao.org/assets/images/benchmark-pki-2-4-4-8778a30b94ee3d591bce700b547fff7c.svg" width="768" height="576" class="img_JF2Q"></p>
<p>On the 2.5.1 cluster the load is spread pretty well at roughly 40%.</p>
<p><img decoding="async" loading="lazy" alt="CPU usage of 2.5.1 during the benchmark run" src="https://openbao.org/assets/images/benchmark-pki-2-5-1-703bd8de0d5f7c0ab5881a40a8b18c37.svg" width="768" height="576" class="img_JF2Q"></p>
<p>This time we also see better latencies, but additionally the 2.4.4 cluster
failed to even fulfill the 5 requests per second target and some requests (0.73%)
even failed.</p>
<table><thead><tr><th style="text-align:right">version</th><th style="text-align:right">mean</th><th style="text-align:right">95th%</th><th style="text-align:right">99th%</th><th style="text-align:right">count</th><th style="text-align:right">rate</th><th style="text-align:right">success</th></tr></thead><tbody><tr><td style="text-align:right">2.5.1</td><td style="text-align:right">566.77 ms</td><td style="text-align:right">1976.84 ms</td><td style="text-align:right">3575.30 ms</td><td style="text-align:right">15000</td><td style="text-align:right">5.00</td><td style="text-align:right">100.00 %</td></tr><tr><td style="text-align:right">2.4.4</td><td style="text-align:right">11668.62 ms</td><td style="text-align:right">27152.59 ms</td><td style="text-align:right">38203.77 ms</td><td style="text-align:right">3990</td><td style="text-align:right">1.33</td><td style="text-align:right">99.27 %</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="missing-benchmarks">Missing Benchmarks<a href="https://openbao.org/blog/improved-horizontal-scalability/#missing-benchmarks" class="hash-link" aria-label="Direct link to Missing Benchmarks" title="Direct link to Missing Benchmarks" translate="no">​</a></h3>
<p>I decided against showing a write heavy benchmark, like PKI with <code>no_store = false</code> or KV with 100% write. Not because I want to hide the fact that our read
scalability feature does not help here, but because it would be boring to look
at. The results for both versions would be similar, the only change you could
see is that for 2.5.1 the standby nodes use a little more CPU while the cluster
is idle (as we have seen before).</p>]]></content>
        <author>
            <name>Philipp Stehle</name>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="technical" term="technical"/>
        <category label="performance" term="performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao's Roadmap and Community Direction for 2025-2026]]></title>
        <id>https://openbao.org/blog/roadmap-2.0/</id>
        <link href="https://openbao.org/blog/roadmap-2.0/"/>
        <updated>2025-10-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[An explanation of OpenBao's proposed roadmap and direction for the community for 2025-2026.]]></summary>
        <content type="html"><![CDATA[<p>As the summer of 2025 closed, OpenBao's Dev WG and TSC put together and
approved <a href="https://github.com/openbao/openbao/issues/1974" target="_blank" rel="noopener noreferrer" class="">a new technical direction and roadmap for 2025-2026</a>.
But before we get into the details, I think is important to look back at
and celebrate what all we've accomplished this year:</p>
<ol>
<li class="">
<p>Many technical initiatives have landed, from namespaces to transactional
storage, to CEL support, and many smaller things in between.</p>
</li>
<li class="">
<p>Many continuing working groups and large technical initiates have been
started, from the horizontal scalability WG, focused on read scalability;
the UI WG, focused on a rewrite of our EmberJS Web UI into React; to the
PKCS#11/KMS WG, focused on including external keys into OpenBao. Thank you
to everyone who participates in these!</p>
</li>
<li class="">
<p><a href="https://insights.linuxfoundation.org/project/openbao-2/contributors?timeRange=past365days&amp;start=2024-10-20&amp;end=2025-10-20&amp;auth=success" target="_blank" rel="noopener noreferrer" class="">Many, many contributions from many, many contributors</a>!
We welcomed:</p>
<ul>
<li class="">741 commits to <a href="https://github.com/openbao/openbao/commits/main/?since=2024-09-30&amp;until=2025-10-20" target="_blank" rel="noopener noreferrer" class=""><code>main</code></a>,</li>
<li class="">287 contributors in the past year,</li>
<li class="">10 new committers, and</li>
<li class="">4 new moderators!</li>
</ul>
<p>And like I say nearly every meeting, a special thanks to all net-new
contributors! A fresh set of eyes brings wonders to a storied project,
and often revisiting earlier design choices let us improve the experience.</p>
</li>
</ol>
<p>And yes, not everything on <a href="https://github.com/openbao/openbao/issues/569" target="_blank" rel="noopener noreferrer" class="">the 2024-2025 roadmap</a>
was completed. Don't worry, you can still contribute items from it if you
want! But for a community just starting out, with its first formal direction
proposal, I think the response we got exceeded my wildest expectations.</p>
<hr>
<p>Much like last year, <a href="https://github.com/openbao/openbao/issues/1974" target="_blank" rel="noopener noreferrer" class="">this roadmap</a>
opens with three major categories:</p>
<blockquote>
<ol>
<li class="">"<strong><i>O</i>perator Experience</strong>": to enable easier or safer operation of OpenBao, through changes like profiles, break-glass and backup/restore procedures, and improved monitoring capabilities;</li>
<li class="">"<strong><i>S</i>calability</strong>": to improve optimization and utilization of OpenBao in large, complex environments; and</li>
<li class="">"<strong><i>S</i>ustainability</strong>": to ensure the long-term viability of the code base, react to changing secrets management directives, and stabilize our ability to maintain the project indefinitely.</li>
</ol>
</blockquote>
<p>Together, these spell <em>OSS</em>, reaffirming our commitment to an <a href="https://github.com/openbao/openbao/blob/main/LICENSE" target="_blank" rel="noopener noreferrer" class="">open-source
project</a> lead under
<a href="https://github.com/openbao/openbao/blob/main/CHARTER.md" target="_blank" rel="noopener noreferrer" class="">open governance principals</a>.</p>
<p>Like last time, our roadmap features several items I'd especially like to
highlight:</p>
<ol>
<li class="">Expanding <strong>CEL Support</strong> for non-ACL policies, in the profile system,
and other plugins. This allows greater operator control over authentication
and authorization. <em>Operator Experience</em>.</li>
<li class=""><strong>Lazy loading of mounts, namespaces</strong>, removing them from memory when no
requests have accessed the path in a while. This would allow OpenBao to be
substantially over-committed if workload allows. <em>Scalability</em>.</li>
<li class=""><strong>KMIP Server for Transit</strong> and <strong>PKCS#11 client for Transit</strong>, to allow
consumption and safe usage of Transit-stored keys from other servers via
KMIP and PKCS#11 protocols. <em>Sustainability</em>.</li>
<li class=""><strong>Usage guides</strong> and tutorials for various components. <em>Sustainability</em>.</li>
<li class=""><strong>Versioned documentation</strong> so that pre-release features do not show in
the documentation by default and documentation for particular releases
are maintained accordingly. <em>Sustainability</em>.</li>
</ol>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p>Interested in some of these features? We need your help!</p><p>React (<!-- -->👍<!-- -->) to issues on GitHub to show your support, help contribute use
cases or design documents, or submit code implementing these features! If you
need help getting started, <a href="https://github.com/openbao/#contact" target="_blank" rel="noopener noreferrer" class="">just reach out</a>!</p></div></div>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="direction" term="direction"/>
        <category label="community" term="community"/>
        <category label="collaboration" term="collaboration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The Perfectly Unperfect Mentorship]]></title>
        <id>https://openbao.org/blog/mentorship-program/</id>
        <link href="https://openbao.org/blog/mentorship-program/"/>
        <updated>2025-09-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[No blueprint, no problem. How a 12-week experiment in guided chaos delivered a performance breakthrough.]]></summary>
        <content type="html"><![CDATA[<p>Imagine starting a mentorship program with a big goal and... not a perfect plan. Sound familiar? That was us, three months ago. We had a brilliant mentee, <a href="https://github.com/fatima2003" target="_blank" rel="noopener noreferrer" class=""><strong>Fatima Patel</strong></a>, a crucial feature for OpenBao’s roadmap, and a healthy dose of "let's figure this out as we go."</p>
<p>Spoiler alert: it worked. Spectacularly. But not because we had all the answers on day one. It worked because we treated the mentorship itself like an open-source project: we iterated, adapted, and optimized for success in real-time.</p>
<p>This is the story of how we structured—and restructured—a 12-week program that ended up giving OpenBao a scalability boost and fantastic contributions.</p>
<h4 class="anchor anchorTargetStickyNavbar_i50L" id="the-setup-an-experiment-with-high-stakes"><strong>The Setup: An Experiment with High Stakes</strong><a href="https://openbao.org/blog/mentorship-program/#the-setup-an-experiment-with-high-stakes" class="hash-link" aria-label="Direct link to the-setup-an-experiment-with-high-stakes" title="Direct link to the-setup-an-experiment-with-high-stakes" translate="no">​</a></h4>
<p>The goal was ambitious: transform OpenBao’s <strong>passive standby nodes</strong> into <strong>active cluster participants</strong> that can handle read requests, a key step towards horizontal scalability. <a href="https://www.adfinis.com/" target="_blank" rel="noopener noreferrer" class=""><strong>Adfinis</strong></a> provided the crucial fuel by funding the program, and the initiative was kicked off by <a href="https://github.com/cipherboy" target="_blank" rel="noopener noreferrer" class=""><strong>Alexander Scheel</strong></a>, who created <a href="https://mentorship.lfx.linuxfoundation.org/project/d419da30-b718-435d-8673-6c1260307339" target="_blank" rel="noopener noreferrer" class="">the project on the LFX Mentorship Platform</a>.</p>
<p>My role was to be the primary mentor. This was a shared investment: Adfinis invested funds and my time, while Fatima invested her talent and immense effort.</p>
<p>We started with a hypothesis: intensive, daily collaboration would be the fastest way to onboard her into the complex codebase.</p>
<h4 class="anchor anchorTargetStickyNavbar_i50L" id="the-rhythm-of-mentorship-finding-our-flow"><strong>The Rhythm of Mentorship: Finding Our Flow</strong><a href="https://openbao.org/blog/mentorship-program/#the-rhythm-of-mentorship-finding-our-flow" class="hash-link" aria-label="Direct link to the-rhythm-of-mentorship-finding-our-flow" title="Direct link to the-rhythm-of-mentorship-finding-our-flow" translate="no">​</a></h4>
<p>For the first few weeks, we met <strong>every single day for an hour</strong>. This intensive pace was essential for building context and momentum. But we quickly learned that the magic wasn't just in the meetings—it was in the deep, uninterrupted work happening in between.</p>
<p>So, we adapted. Around the halfway mark, we shifted our rhythm to <strong>three meetings per week</strong>. This wasn't a step back; it was a strategic pivot. The focus moved away from daily "what do we do next?" check-ins to structured sessions where we could define clear tasks for the upcoming week. This gave Fatima the autonomy for deep, focused work and essential self-teaching, while ensuring she always had support to overcome obstacles.</p>
<p>And the support team grew! In the second part of the program, Fatima had the fantastic opportunity to work closely with <a href="https://github.com/phil9909" target="_blank" rel="noopener noreferrer" class=""><strong>Philipp Stehle</strong></a> from Adfinis, who was tackling cache invalidation challenges between nodes. This turned the mentorship into a true team collaboration. Instead of one mentor, she effectively had two, which was an incredible advantage and made the experience much more dynamic.</p>
<h4 class="anchor anchorTargetStickyNavbar_i50L" id="the-mentees-lens-lessons-beyond-the-code"><strong>The Mentee’s Lens: Lessons Beyond the Code</strong><a href="https://openbao.org/blog/mentorship-program/#the-mentees-lens-lessons-beyond-the-code" class="hash-link" aria-label="Direct link to the-mentees-lens-lessons-beyond-the-code" title="Direct link to the-mentees-lens-lessons-beyond-the-code" translate="no">​</a></h4>
<blockquote>
<p>From my side of the screen, this mentorship was more than a 12-week coding sprint — it taught me the importance of confidence, perseverance and how collaboration and adapting strategies as new problems arise are essential parts of working effectively in a team.</p>
<p>When we initially discussed horizontal scalability as the topic for the mentorship, I remember feeling underprepared, having never worked in that space before. My mentor, <a href="https://github.com/driif" target="_blank" rel="noopener noreferrer" class="">Andrii</a>’s uplifting encouragement and guidance helped me dive in, understand the problem space, and start experimenting with solutions. Once <a href="https://github.com/phil9909" target="_blank" rel="noopener noreferrer" class="">Philipp</a> joined the project, the pace picked up and the discussions became even more engaging.</p>
<p>The community also held bi-monthly meetings led by <a href="https://github.com/cipherboy" target="_blank" rel="noopener noreferrer" class="">Alex</a> to review progress on high availability and discuss next steps. These sessions ensured the work stayed aligned with the community’s goals and that our progress moved in the right direction.</p>
<p>Looking back, the experience shaped not just how I write code, but how I approach challenges — with curiosity, collaboration, and confidence!</p>
</blockquote>
<h4 class="anchor anchorTargetStickyNavbar_i50L" id="the-12-week-sprint-a-choice-wed-make-again"><strong>The 12-Week Sprint: A Choice We'd Make Again</strong><a href="https://openbao.org/blog/mentorship-program/#the-12-week-sprint-a-choice-wed-make-again" class="hash-link" aria-label="Direct link to the-12-week-sprint-a-choice-wed-make-again" title="Direct link to the-12-week-sprint-a-choice-wed-make-again" translate="no">​</a></h4>
<p>The LFX platform offers 12-week full-time or 24-week part-time programs. We’re incredibly glad Fatima chose the <strong>12-week option</strong>. It forced a healthy intensity—a focused sprint that kept everyone laser-focused on the goal: delivering a tangible, impactful feature for the community.</p>
<p>And what a feature it was. Under this adapted structure, Fatima’s contributions were profound:</p>
<ul>
<li class="">She enabled <strong>standby nodes to handle read requests</strong>, a fundamental shift from idle replicas to active participants.</li>
<li class="">She implemented the <strong>post-unsealing logic</strong>, ensuring standbys are fully initialized and ready to work.</li>
</ul>
<p>The result? A foundational improvement that makes OpenBao clusters more efficient and performant. Standby nodes are no longer resource-consuming fallback insurance; they are now part of the active workforce.</p>
<h4 class="anchor anchorTargetStickyNavbar_i50L" id="the-real-win-a-model-for-community-led-growth"><strong>The Real Win: A Model for Community-Led Growth</strong><a href="https://openbao.org/blog/mentorship-program/#the-real-win-a-model-for-community-led-growth" class="hash-link" aria-label="Direct link to the-real-win-a-model-for-community-led-growth" title="Direct link to the-real-win-a-model-for-community-led-growth" translate="no">​</a></h4>
<p>This program was a win on every level.</p>
<ul>
<li class=""><strong>For OpenBao:</strong> We gained a critical feature from our roadmap and a valuable contributor.</li>
<li class=""><strong>For Fatima:</strong> She tackled a complex project with direct, high-impact outcomes and the support of a collaborative team.</li>
<li class=""><strong>For <a href="https://www.adfinis.com/" target="_blank" rel="noopener noreferrer" class="">Adfinis</a>:</strong> The investment in funding and our time directly contributed to the health of an open-source project we believe in.</li>
</ul>
<p>The real success wasn't just the code. It was proving that with the right combination of <strong>funding, flexibility, and a team spirit</strong>, you can structure a mentorship to achieve incredible things. It’s about creating a focused environment where a talented developer, like <a href="https://github.com/fatima2003" target="_blank" rel="noopener noreferrer" class=""><strong>Fatima Patel</strong></a>, can deeply integrate with a maintainer's workflow to accelerate complex, high-impact projects that benefit the entire community.</p>
<p>This is how we build a sustainable open-source future: not by waiting for perfect plans, but by creating opportunities, adapting as we go, and investing in people.</p>
<p><strong>Want to learn more about the technical outcomes?</strong> Check out the pull requests and join the conversation on our <a href="https://github.com/openbao/openbao" target="_blank" rel="noopener noreferrer" class="">OpenBao GitHub repository</a>.</p>
<p><strong>Inspired to get involved?</strong> Explore the <a href="https://mentorship.lfx.linuxfoundation.org/project/d419da30-b718-435d-8673-6c1260307339" target="_blank" rel="noopener noreferrer" class="">LFX Mentorship Platform</a> and see how you can contribute.</p>]]></content>
        <author>
            <name>Andrii Fedorchuk</name>
        </author>
        <category label="mentorship" term="mentorship"/>
        <category label="community" term="community"/>
        <category label="opensource" term="opensource"/>
        <category label="collaboration" term="collaboration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[It's a wrap! OpenBao at Open Source Summit Europe 2025]]></title>
        <id>https://openbao.org/blog/wrap-openbao-oss-europe-2025/</id>
        <link href="https://openbao.org/blog/wrap-openbao-oss-europe-2025/"/>
        <updated>2025-08-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao joined the Open Source Summit EU 2025 in Amsterdam and gave roadmap previews, Q&A, and hands-on conversations about open-source secrets management.]]></summary>
        <content type="html"><![CDATA[<p>The OpenBao community had a great time at <strong><a href="https://events.linuxfoundation.org/open-source-summit-europe/" target="_blank" rel="noopener noreferrer" class="">Open Source Summit Europe 2025</a></strong>! The event once again showed how strong the demand for secure and reliable secret management in enterprise environments has become.</p>
<p>One theme was clear: Companies and individuals demand tools to manage secrets across their systems, and solutions like OpenBao are foundational for security and compliance.</p>
<p><img decoding="async" loading="lazy" alt="OpenBao Maintainers" src="https://openbao.org/assets/images/openbao-osseu-2025-9b35bcd2d85ebd8749c0a606ddf457c1.jpg" width="4032" height="3024" class="img_JF2Q"></p>
<p>Together with the Team from RISC-V and DeepComputing we were able to successfully test our riscv64 binaries on a DeepComputing DC-ROMA RISC-V laptop. With our added RISC-V support in <a href="https://github.com/openbao/openbao/pull/168" target="_blank" rel="noopener noreferrer" class="">PR #168</a> this was super easy and just worked out of the box.</p>
<p>Throughout the conference, we shared how OpenBao is able to help organizations to run production workloads securely. We showcased existing features such as strong encryption, fine-grained access controls and namespace isolation. We also gave a glimpse into what’s next: declarative initialization, improvements around namespaces and extended key management capabilities.</p>
<p>Furthermore, the conference was also a wonderful opportunity for OpenBao maintainers to meet in person, exchange ideas, and align on next steps. A big thank you goes to <a href="https://adfinis.com/" target="_blank" rel="noopener noreferrer" class=""><strong>Adfinis</strong></a>, <a href="https://www.paymenttools.com/" target="_blank" rel="noopener noreferrer" class=""><strong>Paymenttools</strong></a> and <a href="https://www.reply.com/" target="_blank" rel="noopener noreferrer" class=""><strong>Reply</strong></a>, who supported the project by sending maintainers to represent OpenBao on-site.</p>
<p>And finally, a heartfelt thanks to everyone who stopped by, joined discussions, or offered feedback. Your energy and curiosity keep the project moving forward. To everyone who was not able to join the conference, feel free to learn more at <a class="" href="https://openbao.org/community/contributing/"><strong>openbao.org</strong></a> or join the conversation on <a href="https://github.com/openbao" target="_blank" rel="noopener noreferrer" class=""><strong>GitHub</strong></a>.</p>]]></content>
        <author>
            <name>Christoph Voigt</name>
            <uri>https://www.christophvoigt.com</uri>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="conferences" term="conferences"/>
        <category label="community" term="community"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Meet OpenBao at Open Source Summit Europe 2025]]></title>
        <id>https://openbao.org/blog/meet-openbao-oss-europe-2025/</id>
        <link href="https://openbao.org/blog/meet-openbao-oss-europe-2025/"/>
        <updated>2025-08-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Join us in Amsterdam 25–27 August for roadmap previews, deep-dive Q&A, and hands-on conversations about open-source secrets management.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Meet OpenBao at OSS Europe 2025" src="https://openbao.org/assets/images/ossummit_meet_bao-de70bcb4879d02ce2bd6c1aefb8fce00.png" width="1260" height="226" class="img_JF2Q"></p>
<p>Open source builders, security engineers, and platform teams are converging on Amsterdam and OpenBao will be in the middle of it, thanks to the generosity of the Linux Foundation.</p>
<p>We’re excited to announce our first official booth at <strong><a href="https://events.linuxfoundation.org/open-source-summit-europe/" target="_blank" rel="noopener noreferrer" class="">Open Source Summit Europe 2025</a></strong>. If you care about secure automation, multi‑tenant architectures, or meeting the stewards of your critical infrastructure tooling, come talk with us!</p>
<p>Official event site: <a href="https://events.linuxfoundation.org/open-source-summit-europe/" target="_blank" rel="noopener noreferrer" class="">Open Source Summit Europe</a></p>
<p><strong>Find Us</strong><br>
<!-- -->Event: Open Source Summit Europe 2025<br>
<!-- -->Dates: 25–27 August 2025<br>
<!-- -->Location: RAI Amsterdam, Netherlands<br>
<!-- -->Booth: <code>G/S7</code><br>
<!-- -->Hashtag: <code>#OSSummit</code> <code>#OpenBao</code></p>
<p>This isn’t just a swag stop (expect some stickers); it’s a place to trade real-world stories, get practical guidance, and influence the <a href="https://github.com/openbao/openbao/issues/569" target="_blank" rel="noopener noreferrer" class="">OpenBao roadmap</a>, now ready for its second iteration!</p>
<figure><img src="https://openbao.org/img/ossummit_bao_booth.png" alt="OpenBao booth preview at OSS Europe"><figcaption><em>Can you spot Bao in the booth mock? Try to find Bao on the picture!</em></figcaption></figure>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="what-youll-get-at-the-booth">What You’ll Get at the Booth<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#what-youll-get-at-the-booth" class="hash-link" aria-label="Direct link to What You’ll Get at the Booth" title="Direct link to What You’ll Get at the Booth" translate="no">​</a></h2>
<p><strong>Guided Walkthroughs</strong> – We’ll walk you through the latest capabilities: Namespaces, advanced policy handling, paginated lists, and more... Ask deep architectural questions (scaling, HSM integrations, and migration strategies) and get answers from the people writing the code.</p>
<p><strong>Deployment &amp; Design Q&amp;A</strong> – Are you architecting resilient deployments, tightening policy boundaries, or integrating with existing PKI or signing workflows? Bring real problems, leave with practical next steps.</p>
<p><strong>Roadmap Preview</strong> – Near‑term energy: safer ops (policy and audit hygiene), resilience (parallel and namespace unseal), practical scalability (standby node read request handling). Bigger ecosystem/registry ideas come later. Tell us what you need most!</p>
<p><strong>Community Meetups</strong> – Connect with maintainers, contributors, downstream integrators, and fellow operators. Hallway conversations around pain points often become features.</p>
<p><strong>Contribution Guidance</strong> – Want to help? We’ll highlight good first issues, active design discussions, and how to start, whether you're an experienced developer new to Open Source, someone looking to get into technical writing, or anything in between!</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="why-it-matters">Why It Matters<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#why-it-matters" class="hash-link" aria-label="Direct link to Why It Matters" title="Direct link to Why It Matters" translate="no">​</a></h2>
<p>OpenBao represents a community‑first, transparently governed evolution in secrets management. No lock‑in. No unclear licensing pivots. Just open, auditable, extensible security primitives stewarded in the open. Our presence at OSS Europe marks a milestone in maturity—and a recommitment to collaborative innovation.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="who-should-stop-by">Who Should Stop By?<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#who-should-stop-by" class="hash-link" aria-label="Direct link to Who Should Stop By?" title="Direct link to Who Should Stop By?" translate="no">​</a></h2>
<ul>
<li class="">OSPS leadership looking to understand viable alternatives to their company's vendor lock-in problems</li>
<li class="">Platform &amp; DevSecOps teams standardizing secret workflows</li>
<li class="">Security engineers evaluating trust, provenance, and lifecycle controls</li>
<li class="">Architects designing regulated or multi‑tenant environments</li>
<li class="">Contributors (or future ones) curious where to jump in</li>
<li class="">Anyone comparing OpenBao with legacy or closed models</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="key-themes-well-be-talking-about">Key Themes We’ll Be Talking About<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#key-themes-well-be-talking-about" class="hash-link" aria-label="Direct link to Key Themes We’ll Be Talking About" title="Direct link to Key Themes We’ll Be Talking About" translate="no">​</a></h2>
<ul>
<li class="">Secure multi‑tenancy with Namespaces</li>
<li class="">Operational trust: auditing, rotation, lifecycle management</li>
<li class="">Plugin &amp; ecosystem growth</li>
<li class="">Secrets management at scale</li>
<li class="">Community governance &amp; sustainability</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="engage-before--during--after">Engage Before / During / After<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#engage-before--during--after" class="hash-link" aria-label="Direct link to Engage Before / During / After" title="Direct link to Engage Before / During / After" translate="no">​</a></h2>
<ul>
<li class="">Plan Your Visit: Add our booth to your event schedule (check the published schedule once live).</li>
<li class="">Register: Early reg &amp; travel info via the event site’s <a href="https://events.linuxfoundation.org/open-source-summit-europe/register/" target="_blank" rel="noopener noreferrer" class="">registration page</a>.</li>
<li class="">Follow Along: <a href="https://openbao.org/" target="_blank" rel="noopener noreferrer" class="">openbao.org</a> &amp; our LinkedIn page (<a href="https://www.linkedin.com/company/openbao" target="_blank" rel="noopener noreferrer" class="">OpenBao on LinkedIn</a>) for micro‑updates and drop‑in session times.</li>
<li class="">Ask Early: Have a thorny problem? Post it in advance in community channels so we can prep a live walkthrough.</li>
<li class="">Remote? We’ll share recaps, photos, and key takeaways using <code>#OSSummit</code> and <code>#OpenBao</code>.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="call-to-action">Call to Action<a href="https://openbao.org/blog/meet-openbao-oss-europe-2025/#call-to-action" class="hash-link" aria-label="Direct link to Call to Action" title="Direct link to Call to Action" translate="no">​</a></h2>
<p>Show up. Challenge us. Tell us what you need from the next generation of open‑source secrets management, and help build and shape it. OpenBao moves fastest when the community is loud.</p>
<p>See you in Amsterdam!<br>
<!-- -->— The OpenBao Team</p>]]></content>
        <author>
            <name>Andrii Fedorchuk</name>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="conferences" term="conferences"/>
        <category label="community" term="community"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Joins the OpenSSF to Advance Secure Secrets Management in Open Source]]></title>
        <id>https://openbao.org/blog/openbao-joins-the-openssf/</id>
        <link href="https://openbao.org/blog/openbao-joins-the-openssf/"/>
        <updated>2025-06-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao has moved into the OpenSSF, building stronger partnerships for the future.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" src="https://openssf.org/wp-content/uploads/2025/06/OpenSSF-Blog-Graphics-53-1.png" alt="OpenBao Joins the OpenSSF to Advance Secure Secrets Management in Open Source" class="img_JF2Q"></p>
<p>We’re excited to welcome <a href="https://openssf.org/projects/openbao/" target="_blank" rel="noopener noreferrer" class="">OpenBao</a> to the <a href="https://openssf.org/" target="_blank" rel="noopener noreferrer" class="">Open Source Security Foundation (OpenSSF)</a> as a newly accepted <a href="https://openssf.org/projects/openbao/" target="_blank" rel="noopener noreferrer" class="">sandbox project</a>!</p>
<p>OpenBao is an open source identity-based secrets and encryption management system that helps organizations securely store, manage, and audit access to sensitive data like API keys, passwords, and certificates. Originally developed under LF Edge and forked from HashiCorp Vault, OpenBao has now found its new home in the OpenSSF, where it aligns more directly with the needs of security professionals and open source maintainers.</p>
<p>“Joining OpenSSF has been a dream come true,” said <strong>Alex Scheel</strong>, Chair of the OpenBao Technical Steering Committee. “This wouldn’t be possible without the support of OpenSSF’s Technical Advisory Council—many thanks for their help and consideration!”</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="why-openbao">Why OpenBao?<a href="https://openbao.org/blog/openbao-joins-the-openssf/#why-openbao" class="hash-link" aria-label="Direct link to Why OpenBao?" title="Direct link to Why OpenBao?" translate="no">​</a></h2>
<p>Modern systems rely on a growing number of secrets to operate securely—from database credentials to cloud service API tokens. Managing and auditing access to these secrets is complex, and building custom solutions can introduce more risk than reward. OpenBao solves this problem by providing robust encryption services that are tightly gated by authentication and authorization controls. It integrates with the tools and ecosystems open source developers and security teams already use, including Sigstore and SLSA.</p>
<p>Through its CLI, UI, and HTTP API, OpenBao makes it easier to:</p>
<ul>
<li class="">Securely manage and distribute secrets across teams and environments</li>
<li class="">Apply fine-grained access controls</li>
<li class="">Rotate keys and credentials automatically</li>
<li class="">Maintain detailed audit trails for compliance and incident response</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="moving-to-the-openssf">Moving to the OpenSSF<a href="https://openbao.org/blog/openbao-joins-the-openssf/#moving-to-the-openssf" class="hash-link" aria-label="Direct link to Moving to the OpenSSF" title="Direct link to Moving to the OpenSSF" translate="no">​</a></h2>
<p>The move from LF Edge to OpenSSF reflects a strategic decision by OpenBao’s Technical Steering Committee to better align with its contributor base and project mission. While the project is deeply grateful for the support from LF Edge during its early development, the OpenSSF offers a broader and more targeted platform to grow its community and expand adoption.</p>
<p>“We’re looking forward to collaborating with various working groups and SIGs within OpenSSF—especially to help strengthen secrets management best practices in open source policy and guidance,” said Scheel. “We also remain committed to maintaining partnerships with LF Edge and other Linux Foundation projects as our ecosystems evolve.”</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="whats-next">What’s Next<a href="https://openbao.org/blog/openbao-joins-the-openssf/#whats-next" class="hash-link" aria-label="Direct link to What’s Next" title="Direct link to What’s Next" translate="no">​</a></h2>
<p>Now in the sandbox stage of OpenSSF’s project lifecycle, OpenBao is focused on increasing transparency, improving governance, and deepening integration with other OpenSSF initiatives. Its ongoing work will support supply chain security, secrets hygiene, and broader security-by-design efforts across open source projects.</p>
<p>We’re thrilled to support the OpenBao community and look forward to seeing its impact grow across the open source security landscape.</p>
<p>🔐 Get Involved: <a href="https://github.com/openbao/openbao" target="_blank" rel="noopener noreferrer" class="">Visit the OpenBao GitHub repository</a> and join the conversation on the <a href="https://linuxfoundation.slack.com/archives/C02H1G4TH" target="_blank" rel="noopener noreferrer" class="">OpenSSF Slack</a> and <a href="https://linuxfoundation.zulipchat.com/#narrow/channel/529890-openssf-openbao-discussion" target="_blank" rel="noopener noreferrer" class="">Zulip</a>.</p>
<hr>
<p>This post was originally authored by the OpenSSF marketing team and posted on <a href="https://openssf.org/blog/2025/06/17/openbao-joins-the-openssf-to-advance-secure-secrets-management-in-open-source/" target="_blank" rel="noopener noreferrer" class="">the OpenSSF blog</a>.</p>]]></content>
        <author>
            <name>OpenSSF</name>
            <uri>https://openssf.org</uri>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="community" term="community"/>
        <category label="collaboration" term="collaboration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Announcing OpenBao Namespaces]]></title>
        <id>https://openbao.org/blog/namespaces-announcement/</id>
        <link href="https://openbao.org/blog/namespaces-announcement/"/>
        <updated>2025-05-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Enabling Multi-Tenancy within OpenBao]]></summary>
        <content type="html"><![CDATA[<p>We are excited to introduce <strong>Namespaces</strong> to the OpenBao Secret Manager – a powerful feature designed to bring robust multi-tenancy and fine-grained isolation to your secrets management workflows.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="what-are-namespaces">What Are Namespaces?<a href="https://openbao.org/blog/namespaces-announcement/#what-are-namespaces" class="hash-link" aria-label="Direct link to What Are Namespaces?" title="Direct link to What Are Namespaces?" translate="no">​</a></h2>
<p>Namespaces in OpenBao are logical partitions within a single OpenBao instance, functioning as isolated environments where teams, organizations, or applications can operate independently.</p>
<p>Each namespace acts like a mini-OpenBao, with its own policies, authentication methods, secret engines, tokens, and identity groups. This architecture enables organizations to implement a true <em>OpenBao-as-a-Service</em> model, empowering internal customers to self-manage their environments securely and efficiently.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="why-namespaces">Why Namespaces?<a href="https://openbao.org/blog/namespaces-announcement/#why-namespaces" class="hash-link" aria-label="Direct link to Why Namespaces?" title="Direct link to Why Namespaces?" translate="no">​</a></h2>
<p>Strong isolation between teams, business units, or tenants becomes critical as organizations scale, especially when handling sensitive data.</p>
<p>Namespaces enable secure multi-tenancy. Each tenant (e.g., team, organisation, or application) operates within its namespace, isolated from others. Permissions are strictly scoped, preventing users from accessing or interfering with resources outside their assigned namespace.</p>
<p>Furthermore, namespaces enable the delegation of administration and promote self-service. Namespace admins can manage their own policies, secret engines, auth modes, or even quotas, without impacting other tenants, reducing the burden on cluster-level operators.</p>
<p>Finally, namespaces are one of a few planned stepping stones towards OpenBao's <a class="" href="https://openbao.org/blog/vision-for-namespaces/">horizontal scalability</a> journey. OpenBao aims to allow support for large deployments with many infrequently accessed mounts, without overloading cluster nodes, while keeping a simpler cluster topology.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="how-to-use-namespaces">How to use Namespaces<a href="https://openbao.org/blog/namespaces-announcement/#how-to-use-namespaces" class="hash-link" aria-label="Direct link to How to use Namespaces" title="Direct link to How to use Namespaces" translate="no">​</a></h2>
<p>Namespaces will enable plenty of use cases and multi-tenancy scenarios. Let's consider a possible namespace setup for a SaaS Company. The platform team retains a top-level namespace for shared infrastructure. On the other hand, each tenant receives a fully isolated namespace to, e.g., model a staging system.</p>
<figure><figcaption>An example namespace structure to separate tenants and the platform team.</figcaption></figure>
<p>To use this new feature, no extra setup or configuration is required. The OpenBao CLI now features a special <code>namespace</code> sub-command, which can be used to administrate Namespaces.</p>
<p>To recreate the structure of the given example, we would do the following workflow:</p>
<ol>
<li class=""><strong>Create Namespaces:</strong></li>
</ol>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain"># creates a namespace "tenant" on root-level</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$ bao namespace create tenants</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># creates a child-namespace within tenants</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$ bao namespace create -ns tenants tenant-c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># creates a child-namespace within tenants/tenants-c</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$ bao namespace create -ns tenants/tenant-c prod</span><br></div></code></pre></div></div>
<p>Note how we use the <code>-ns</code> (short form for <code>-namespace</code>) flag to create a child-namespace <code>tenant-c</code> within the namespace <code>tenant</code>. To view status and metadata, we can utilize the <code>lookup</code> command:</p>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">$ bao namespace lookup -ns tenants/tenant-c prod</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Key                Value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---                -----</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">custom_metadata    map[]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">id                 8QujqL</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">path               tenants/tenant-c/prod/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tainted            false</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">uuid               f06d10c7-1300-6c4d-8616-c203b5fdf705</span><br></div></code></pre></div></div>
<p>Furthermore, we can easily enumerate our hierarchy of namespaces by using the <code>scan</code> subcommand.</p>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">$ bao namespace scan</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Keys</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">----</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tenants/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tenants/tenant-c/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">tenants/tenant-c/prod/</span><br></div></code></pre></div></div>
<ol start="2">
<li class=""><strong>Create Resources within Namespaces</strong></li>
</ol>
<p>Since the introduction of Namespaces, many OpenBao commands have become namespace-aware. Similar to our example before, we can add <code>-namespace</code> or in short <code>-ns</code> to the command.</p>
<p>For demonstration purposes, let's create a KV secrets engine and populate it with a secret.</p>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">$ bao secrets enable -ns=tenants/tenant-c/prod -description="Production Secrets" kv</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Success! Enabled the kv secrets engine at: kv/</span><br></div></code></pre></div></div>
<p>Now that we have created a new kv secrets engine, it will be listed among our default engines:</p>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain">$ bao secrets list -ns tenants/tenant-c/prod</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Path&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Type&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Accessor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Description</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">----&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ----&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --------&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -----------</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cubbyhole/&nbsp; &nbsp; ns_cubbyhole&nbsp; &nbsp; cubbyhole_9a4e44d3&nbsp; &nbsp; per-token private secret storage</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">identity/ &nbsp; &nbsp; ns_identity &nbsp; &nbsp; identity_61c42408 &nbsp; &nbsp; identity store</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">kv/ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kv&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kv_b993bbec &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Production Secrets</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sys/&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ns_system &nbsp; &nbsp; &nbsp; system_ba514ba2 &nbsp; &nbsp; &nbsp; system endpoints used for control, policy and debugging</span><br></div></code></pre></div></div>
<p>Let's read and write a secret...</p>
<div class="language-bash codeBlockContainer_fzKF theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_Yymh"><pre tabindex="0" class="prism-code language-bash codeBlock_hK5r thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_fsFi"><div class="token-line" style="color:#393A34"><span class="token plain"># Create the secret within namespace</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$ bao kv put -namespace=tenants/tenant-c/prod -mount=kv auth-token foo=bar</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Success! Data written to: kv/auth-token</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># Read it</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">$ bao kv get -namespace=tenants/tenant-c/prod -mount=kv auth-token</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">=== Data ===</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Key&nbsp; &nbsp; Value</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">---&nbsp; &nbsp; -----</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">foo&nbsp; &nbsp; bar</span><br></div></code></pre></div></div>
<ol start="3">
<li class=""><strong>Lifecycle Operations</strong></li>
</ol>
<p>Over time, tenants will inevitably require various changes and customizations to their namespaces. Moving the administration away from the OpenBao operators means that the tenant operator can perform those changes on demand and individually. Consequently, we implemented the associated (and probably expected) lifecycle features such as:</p>
<ul>
<li class="">Namespace-aware policies and quotas</li>
<li class="">Moving or renaming secret or auth engines across namespaces</li>
<li class="">Locking and unlocking of namespaces</li>
</ul>
<p>While we have many plans on extending namespace capabilities in the future to make them even more helpful, we still maintain API compatibility with Vault Enterprise to enable a smooth migration path.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="looking-ahead-horizontal-scalability">Looking Ahead: Horizontal Scalability<a href="https://openbao.org/blog/namespaces-announcement/#looking-ahead-horizontal-scalability" class="hash-link" aria-label="Direct link to Looking Ahead: Horizontal Scalability" title="Direct link to Looking Ahead: Horizontal Scalability" translate="no">​</a></h2>
<p>Namespaces will give organisations the possibility to better structure and isolate secret information. However, the introduction of namespaces is just the first step. Our vision includes supporting <em>lazy loading</em> of namespaces and mounts, allowing OpenBao clusters to efficiently serve workloads with many infrequently accessed resources. This will enable even greater scalability and resilience, as nodes will no longer need to load the entire system state at once.</p>
<p><a class="" href="https://openbao.org/blog/vision-for-namespaces/">Here</a> is another article that you can read more about OpenBaos' scalability efforts. Sounds interesting? Reach out to the project via <a href="https://github.com/orgs/openbao/discussions" target="_blank" rel="noopener noreferrer" class="">Github</a>, <a href="https://github.com/openbao#contact" target="_blank" rel="noopener noreferrer" class="">Zulip</a>, or <a href="https://lists.openssf.org/g/openbao" target="_blank" rel="noopener noreferrer" class="">Mailinglist</a> if you want to support our work in the areas of namespaces or scalability.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="get-started">Get Started<a href="https://openbao.org/blog/namespaces-announcement/#get-started" class="hash-link" aria-label="Direct link to Get Started" title="Direct link to Get Started" translate="no">​</a></h2>
<p>We just carved a beta release of <a href="https://github.com/openbao/openbao/releases/tag/v2.3.0-beta20250528" target="_blank" rel="noopener noreferrer" class="">OpenBao 2.3</a>. We encourage you to explore the new features and share your feedback as we continue to improve OpenBao as a secure, scalable, and self-service secrets management solution.</p>
<p>Looking ahead, the namespaces working group is actively exploring improvements such as namespace sealing, non-hierarchical namespaces, per-namespace storage backends, and plugin isolation. These efforts aim to make namespace usage more flexible, efficient, and secure in future releases.</p>
<p>We welcome contributions from individuals and organizations, whether helping to improve documentation, clarifying existing content, or contributing to upcoming features. Your input plays a vital role in shaping the future of OpenBao.</p>]]></content>
        <author>
            <name>Christoph Voigt</name>
            <uri>https://www.christophvoigt.com</uri>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="community" term="community"/>
        <category label="collaboration" term="collaboration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Adopted as the Secret Store for EdgeX Foundry]]></title>
        <id>https://openbao.org/blog/edgex-selects-openbao/</id>
        <link href="https://openbao.org/blog/edgex-selects-openbao/"/>
        <updated>2025-03-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why EdgeX chose OpenBao for its critical secret storage]]></summary>
        <content type="html"><![CDATA[<p>Great news for the OpenBao community! In a major step towards enhancing its own security and openness, EdgeX Foundry has officially adopted OpenBao as its default secret store for the EdgeX 4.0 release.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="what-is-edgex-foundry">What is EdgeX Foundry?<a href="https://openbao.org/blog/edgex-selects-openbao/#what-is-edgex-foundry" class="hash-link" aria-label="Direct link to What is EdgeX Foundry?" title="Direct link to What is EdgeX Foundry?" translate="no">​</a></h2>
<p>For those unfamiliar, <a href="https://www.edgexfoundry.org/" target="_blank" rel="noopener noreferrer" class="">EdgeX Foundry</a> is an open-source, IoT/edge computing framework hosted by the Linux Foundation. It’s designed to enable seamless communication between devices, applications and services using a flexible, microservices-based architecture. Whether you’re working in automation, energy, or building management, EdgeX helps bring everything together in a standardized way.</p>
<p><img decoding="async" loading="lazy" src="https://www.edgexfoundry.org/cmsfiles/image/company-logo-lg.png" alt="edgex-logo" class="img_JF2Q"></p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="the-need-for-secret-storage">The Need for Secret Storage<a href="https://openbao.org/blog/edgex-selects-openbao/#the-need-for-secret-storage" class="hash-link" aria-label="Direct link to The Need for Secret Storage" title="Direct link to The Need for Secret Storage" translate="no">​</a></h2>
<p>Security is a top priority in EdgeX, and managing secrets—like API keys, passwords, and certificates—is crucial. Instead of reinventing the wheel, EdgeX has always integrated third-party open-source solutions for secret management. Until now, it relied on HashiCorp Vault for securely storing sensitive information.</p>
<p>However, with Vault moving to a Business Source License (BSL), the EdgeX community wanted to consider an alternative going forward. That’s where OpenBao comes in.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="the-role-of-openbao">The Role of OpenBao<a href="https://openbao.org/blog/edgex-selects-openbao/#the-role-of-openbao" class="hash-link" aria-label="Direct link to The Role of OpenBao" title="Direct link to The Role of OpenBao" translate="no">​</a></h2>
<p>OpenBao is a community-driven, open-source project under the Linux Foundation. It provides an identity-based secrets and encryption management system, ensuring sensitive data stays protected. Since it shares a strong foundation with Vault, OpenBao makes for a natural transition.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="why-openbao">Why OpenBao?<a href="https://openbao.org/blog/edgex-selects-openbao/#why-openbao" class="hash-link" aria-label="Direct link to Why OpenBao?" title="Direct link to Why OpenBao?" translate="no">​</a></h2>
<p>Adopting OpenBao brings several advantages to EdgeX Foundry, including:</p>
<p>✅ Seamless Migration – OpenBao is designed to be API compatible with its upstream, making the switch smooth and hassle-free.</p>
<p>✅ Open &amp; Vendor-Neutral Licensing – open-source freedom and long-term community collaboration.</p>
<p>✅ Security-First Approach – Strong encryption and identity-based access controls keep secrets safe.</p>
<p>✅ Active Community Support – A dedicated team ensures ongoing improvements, security updates and feature enhancements.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="what-this-means-for-edgex-users">What this means for EdgeX Users<a href="https://openbao.org/blog/edgex-selects-openbao/#what-this-means-for-edgex-users" class="hash-link" aria-label="Direct link to What this means for EdgeX Users" title="Direct link to What this means for EdgeX Users" translate="no">​</a></h2>
<p>If you’re already using EdgeX, this change should be practically seamless. The Core Services have been updated to work with OpenBao while keeping the same APIs as before, meaning minimal disruption. You’ll still manage secrets securely, with the added benefit of an actively maintained and community-driven solution.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="looking-ahead">Looking Ahead<a href="https://openbao.org/blog/edgex-selects-openbao/#looking-ahead" class="hash-link" aria-label="Direct link to Looking Ahead" title="Direct link to Looking Ahead" translate="no">​</a></h2>
<p>The move to OpenBao reflects EdgeX Foundry’s ongoing dedication to security, transparency, and open-source collaboration. With EdgeX 4.0 (codenamed Odesa) now released, it is the perfect time to explore OpenBao, share feedback, and get involved in shaping its future.</p>
<p>Stay tuned for more updates on OpenBao and <a href="https://github.com/orgs/edgexfoundry/discussions" target="_blank" rel="noopener noreferrer" class="">keep in touch with EdgeX</a> and related commercial products, as they enjoy the benefits of security and openness with OpenBao going forward!</p>]]></content>
        <author>
            <name>James Butcher</name>
            <uri>https://www.linkedin.com/in/james-butcher-15698115</uri>
        </author>
        <category label="announcement" term="announcement"/>
        <category label="community" term="community"/>
        <category label="collaboration" term="collaboration"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Vision for Namespaces, Horizontal Scalability]]></title>
        <id>https://openbao.org/blog/vision-for-namespaces/</id>
        <link href="https://openbao.org/blog/vision-for-namespaces/"/>
        <updated>2025-02-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Description of Alex's vision for how Namespaces and Horizontal Scalability can improve OpenBao]]></summary>
        <content type="html"><![CDATA[<p>As the OpenBao community <a href="https://github.com/openbao/openbao/issues/787" target="_blank" rel="noopener noreferrer" class="">starts development on Namespaces</a>
and the Horizontal Scalability Working Group has its kickoff, I wanted to take
the opportunity to put forward a blog post describing how these two groups'
work can compliment each other and provide an alternative path forward other
than Vault Enterprise's Performance Secondary and Disaster Recovery clustering
modes.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="scaling-read-operations">Scaling Read Operations<a href="https://openbao.org/blog/vision-for-namespaces/#scaling-read-operations" class="hash-link" aria-label="Direct link to Scaling Read Operations" title="Direct link to Scaling Read Operations" translate="no">​</a></h2>
<p>Most obviously, the first step for the Horizontal Scalability working group
will be to <a href="https://github.com/openbao/openbao/issues/569" target="_blank" rel="noopener noreferrer" class="">allow standby nodes to service requests</a>
as described in our project direction &amp; roadmap:</p>
<blockquote>
<ol start="4">
<li class="">Allow HA standby nodes to service read-only (from a storage modification PoV) requests. (scalability)<!-- -->
<ul>
<li class="">Currently HA mode standby nodes forward all requests up to the active node, preventing horizontal scalability of OpenBao. Due to limitations in Raft (only the active node can perform storage writes), we can't immediately scale writes. Thus, start by bringing these nodes "online" (loading the mount table, plugins, &amp;c) and allowing them to service read-only requests, returning <code>ErrReadOnly</code> on storage write operations to trigger automatic request forwarding.</li>
</ul>
</li>
</ol>
</blockquote>
<p>The shortcoming of this is that writes are not scalable: there is still only
a single active writer node. Note that a read operation in this context refers
to any API request (of any operation type) that results only in <code>get</code> or <code>list</code>
("read") storage operations. Any operations involving a storage write (<code>put</code>
or <code>delete</code>) would be forwarded to the active node for processing.</p>
<p>This behaves similarly to Performance Secondary Standby nodes.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="scaling-write-operations">Scaling Write Operations<a href="https://openbao.org/blog/vision-for-namespaces/#scaling-write-operations" class="hash-link" aria-label="Direct link to Scaling Write Operations" title="Direct link to Scaling Write Operations" translate="no">​</a></h2>
<p>In our RFC for namespaces, there is the following future work item:</p>
<blockquote>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="per-namespace-storage-segments">Per-Namespace Storage Segments<a href="https://openbao.org/blog/vision-for-namespaces/#per-namespace-storage-segments" class="hash-link" aria-label="Direct link to Per-Namespace Storage Segments" title="Direct link to Per-Namespace Storage Segments" translate="no">​</a></h3>
<p>At the physical storage level, a namespace could be implemented as a new database schema in PostgreSQL (with each plugin being a new database table) or a new disk directory in Raft/BoltDB. This can likely build on top of storage views, using the existing JSON namespace data to translate source path to destination. This would help with scaling OpenBao: each tenant would have its own data storage location and so could impact other tenants less. Theoretically this could even lead to per-segment unique storage backend depending on workload characteristics assuming no cross-segment consistency is required.</p>
<p>However, this work is strictly disjoint from implementing namespaces as a feature and so will be done later.</p>
</blockquote>
<p>In conjunction with additional changes to horizontal scalability, this change
could allow each namespace to have a different active node dictated by its
storage backend, distributing writes across the cluster. Notably, very few
operations are truly cross-namespace; this is mostly limited to the creation
and deletion of namespaces and mount move operations, which affects the
namespace store in the parent context in addition to the actual target
namespace.</p>
<p>The benefit of this approach is that it doesn't affect plugins, token stores,
ACL stores, or any other namespace-specific functionality. This is because
our namespace design opted to place all namespace-specific data within the
namespace's path (<code>/namespaces/&lt;uuid&gt;</code>) rather than mixing it within the
root of storage (<code>/core</code> or <code>/sys</code>) across all namespaces.</p>
<p>Additionally, this gives a natural place for segmenting storage, allowing
smaller databases when used with PostgreSQL or Raft. This allows greater
scalability as many have scalability problems when lots of data is written
to a single backend instance. By supporting different storage types (e.g.,
mixing and matching PostgreSQL and Raft), namespaces with different SLAs
or workload write/read ratios can be supported.</p>
<p>One shortcoming with this approach is it doesn't allow scaling all types of
workloads. For instance, a single PKI mount which stores certificates will
not be horizontally scalable as writes will not be able to be distributed.
However, the majority of large, diverse workloads will be able to be
distributed because of this change.</p>
<p>Another shortcoming is the complexity this entails for an operator. Some
of this may be mitigated by allowing namespace-native configuration, without
requiring full configuration file changes.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="disaster-recovery">Disaster Recovery<a href="https://openbao.org/blog/vision-for-namespaces/#disaster-recovery" class="hash-link" aria-label="Direct link to Disaster Recovery" title="Direct link to Disaster Recovery" translate="no">​</a></h2>
<p>OpenBao recently added support for <a href="https://github.com/openbao/openbao/issues/578" target="_blank" rel="noopener noreferrer" class="">Raft non-voter nodes</a>.
This can likely form the basis of <a href="https://github.com/openbao/openbao/issues/38" target="_blank" rel="noopener noreferrer" class="">disaster recovery</a>,
especially if enablement for other storage backends (like PostgreSQL) is
added.</p>
<p>Notably in Raft, non-voter status means that these nodes do not contribute to
quorum requirements, allowing writes to commit faster but still allowing the
use of Raft to distribute updates. This means that adding non-voter nodes
results in additional traffic from the leader but doesn't otherwise impact
write speeds. By putting these non-voters in secondary data centers, with
<a href="https://github.com/openbao/openbao/pull/996" target="_blank" rel="noopener noreferrer" class="">the ability to promote non-voter nodes</a>,
we can subsequently initiate a failover operation in the event the primary
cluster goes down, with minimal data loss.</p>
<p>PostgreSQL can similarly be extended to support a non-voter setup, wherein
certain nodes will not attempt to become leaders unless updated later. This
will behave similarly to Raft, allowing more read scalability via the use of
read-only PostgreSQL replicas in other secondary data centers.</p>
<p>By broadening <a href="https://github.com/openbao/openbao/issues/607" target="_blank" rel="noopener noreferrer" class="">the use of transactions</a>,
we can further guarantee that these other nodes are consistent, independent
of what storage backend is used.</p>
<p>Additionally, we could allow standby or non-voter nodes to serve read requests
without an active leader. This could potentially be extended to support
generating offline authentication tokens using JWTs or similar signature-based
schemes for use with non-lease paths. This would allow for greater high
availability in the event of a leadership outage.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="offline-recovery-mode">Offline Recovery Mode<a href="https://openbao.org/blog/vision-for-namespaces/#offline-recovery-mode" class="hash-link" aria-label="Direct link to Offline Recovery Mode" title="Direct link to Offline Recovery Mode" translate="no">​</a></h2>
<p>Sometimes a hybrid replication mode would be preferred; Vault Enterprise
supports this via a <a href="https://developer.hashicorp.com/vault/api-docs/system/replication/replication-performance#create-paths-filter" target="_blank" rel="noopener noreferrer" class="">path filtering operation</a>.</p>
<p>When we combine the <a href="https://openbao.org/blog/vision-for-namespaces/#scaling-write-operations" class="">earlier work for per-namespace storage backends</a>
with an additional Namespaces future work item:</p>
<blockquote>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="per-namespace-seal-mechanisms">Per-Namespace Seal Mechanisms<a href="https://openbao.org/blog/vision-for-namespaces/#per-namespace-seal-mechanisms" class="hash-link" aria-label="Direct link to Per-Namespace Seal Mechanisms" title="Direct link to Per-Namespace Seal Mechanisms" translate="no">​</a></h3>
<p>The existing Vault Enterprise Namespace feature supports locking and unlocking namespaces by an operator with access to the parent namespace. While potentially useful to limit requests to a namespace without impacting other users, we could add a similar mechanism using the Barrier + Keyring functionality to also give us per-tenant encryption. This also lets the tenant control their own encryption keys. With lazy loading of namespaces (preventing inbound requests unless the namespace is unsealed), this behaves similarly to locking and unlocking the namespace though doesn’t conflict with it.</p>
<p>However, this work is strictly disjoint from implementing namespaces as a feature and so will be done later.</p>
</blockquote>
<p>If we implement non-hierarchical namespaces, which do not chaining to <code>root</code>
as a parent for tokens, ACL policies, or layered sealing, this allows us to
have cluster-independent namespaces. We would additionally need the Shamir
fallback <a href="https://github.com/openbao/openbao/issues/1021" target="_blank" rel="noopener noreferrer" class="">from the parallel unseal RFCs</a>.</p>
<p>This gives two nice properties:</p>
<ol>
<li class="">We can have a stronger path filtering, allowing replication of namespaces
in disjoint cluster topologies. For instance, a secondary site may have only
a subset of namespaces, which it may be non-voter on until promoted to
leader during an outage.</li>
<li class="">A namespace could potentially be shared by two different organizations as
a form of secret sharing with some peer establishment protocol.</li>
</ol>
<p>Notably, the parallel unseal allows either Shamir's based initial
establishment or the use of public keys explicitly provisioned for local-only
seal material usable by the remote cluster. This allows local disaster nodes
to survive the outage of the primary seal mechanism.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="lazy-loading">Lazy Loading<a href="https://openbao.org/blog/vision-for-namespaces/#lazy-loading" class="hash-link" aria-label="Direct link to Lazy Loading" title="Direct link to Lazy Loading" translate="no">​</a></h2>
<p>By making Namespaces have their own seal mechanism, we'll be forcing OpenBao
to handle the scenario when a namespace cannot be loaded. We have two options:</p>
<ol>
<li class="">To hard fail, requiring operators to rectify the problem immediately. With
things like parallel unseal, this should be doable unless a storage engine
itself is down.</li>
<li class="">To soft fail, refusing to load the namespace (and any children) but
continuing regular operation on all other namespaces.</li>
</ol>
<p>This sits on different sides of a security/availability problem: we could be
available, but not processing key revocations because a single namespace is
offline, or we could be in a similar place, not processing all revocations
because a single offline namespace resulted in all namespaces being
unavailable.</p>
<p>I'd like to see namespaces, and eventually mounts, be lazily loadable. This
will likely require new interfaces for backends to indicate when they'd next
like their Rollback function to be issued, if that occurs too infrequently.
And mounts will need to be audited for lease expiry, with some window for
mount reuse without unmounting refreshed on last request.</p>
<p>But, this will allow us to scale OpenBao to workloads with lots of
infrequently-accessed mounts without requiring all nodes in a cluster have
the capability of loading the entire system at once.</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="vision" term="vision"/>
        <category label="community" term="community"/>
        <category label="technical" term="technical"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao @ GitLab - FOSDEM '25]]></title>
        <id>https://openbao.org/blog/cipherboy-fosdem-25-talk/</id>
        <link href="https://openbao.org/blog/cipherboy-fosdem-25-talk/"/>
        <updated>2025-02-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Blog of Alex's talk at FOSDEM '25, describing the usage of OpenBao at GitLab]]></summary>
        <content type="html"><![CDATA[<p>Slides and content from Alex's <a class="" href="https://openbao.org/blog/fosdem-25/">FOSDEM '25 talk</a> about OpenBao's usage at GitLab.</p>
<p>For a video, see our <a href="https://youtu.be/V50hdX2d8IA" target="_blank" rel="noopener noreferrer" class="">official YouTube channel</a> or <a href="https://video.fosdem.org/2025/ua2118/fosdem-2025-5145-openbao-at-gitlab-building-native-secrets-for-gitlab-ci-cd-pipelines.av1.webm" target="_blank" rel="noopener noreferrer" class="">on the FOSDEM video mirror</a>.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-01.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Hello everyone! I'm Alex Scheel, a Staff Backend Engineer at GitLab and Chair of the OpenBao Technical Steering Committee. I'm here to talk about OpenBao and its usage at GitLab.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-02.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>To get started, the most important question is, "What is OpenBao"?</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-03.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>OpenBao is a fork of HashiCorp Vault, remaining under the original Mozilla Public License, with open governance under the Linux Foundation's LF Edge subproject.</p>
<p>It is an advanced secrets manager supporting four categories of features:</p>
<ol>
<li class=""><em>Static secrets</em>, provisioned by users directly and securely stored.</li>
<li class=""><em>Dynamic secrets</em>, automatically generated on-demand to integrate with things like databases or cloud provider identities.</li>
<li class=""><em>Encryption services</em>, supporting PKI or SSH certificate creation and KMS-like encryption-as-a-service functionality.</li>
<li class="">And lastly, <em>Sync, Visibility, and Management</em> of these secrets: integrations with Kubernetes External Secret Operator, Cert-Manager, and a custom templating agent to handle last-mile delivery of secrets. All of this comes with detailed audit logs tracking access to the system.</li>
</ol>
<p>A secrets manager is, to organizations and developers writing applications, what a password manager is for humans.</p>
<p>OpenBao is API-driven and highly flexible. It supports many different authentication engines, from OIDC and Kubernetes to LDAP and Kerberos, and creating or storing many types of identities, letting it function as an <em>identity broker</em>.</p>
<p>The goal is to trade-off a little bit of <em>operational risk</em> -- one more, admittedly complex, service to run -- to greatly lessen the <em>security risk</em> of compromise: you can enforce a healthy secrets posture to ensure that rotation and revocation of sensitive credentials are possible, limiting your organization's exposure window in the event of compromise.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-04.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>While a complete timeline of OpenBao would take a while, there's a few important events I want to highlight:</p>
<ul>
<li class="">HashiCorp first released Vault in April of 2015, so there has been nearly a decade of work on it.</li>
<li class="">In August of 2023, HashiCorp announced that they'd be relicensing their products under the non-OSI Business Source License (violating freedom zero); this triggered the early fork of Terraform into OpenTofu, our sister project also under the Linux Foundation.</li>
<li class="">The fork of Vault by IBM Software came much later, in November of that year, and kept with the naming convention. Unlike OpenTofu, which was made up of many member companies which sponsored full-time development, OpenBao has been more of a grass-roots, community effort.</li>
<li class="">We've done 8 releases -- two major and six bug fixes, shipped several core improvements, and put together our Technical Steering Committee and governing documents.</li>
<li class="">My employer, GitLab, joined the project officially in July and achieved voting status in October of last year. To the best of my knowledge, I'm incredibly fortunate to be one of the few people employed to work on OpenBao full time.</li>
</ul>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-05.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>One of the things you might be asking is, OK, it is another fork of a HashiCorp product. What's different about this one?</p>
<p>While OpenBao remains in the spirit of the original project, we've made a few changes to make it easier to maintain and contribute:</p>
<ol>
<li class="">We started with a reduced base, removing many components that an open-source group with no formal funding could not support. That meant making hard choices around storage backends -- Raft and now PostgreSQL are the only supported two -- but also the removal of proprietary cloud integrations for authentication and dynamic secrets for the time being. We hope to revive especially the cloud auth and secret plugins as we get more funding and interest.</li>
<li class="">Using that space, we've made core technological improvements to the storage subsystem--paginated lists and transactions--which in turn allowed us to improve scalability. These improvements were directly made possible by removing every single storage backend but Raft. We hope these types of improvements will continue after we add APIs for additional external, community-provided storage plugins, so that we can make long-term improvements to upcoming features like namespaces and horizontal scalability.</li>
<li class="">Lastly, we've set up an open organization with clear contribution and project leadership processes. Our RFC process is open to anyone to draft designs and propose major or minor changes to the architecture or project. We've started a community mentorship program, helping two individuals with different familiarity with OpenBao to contribute. But throughout this, we continued under the original MPL license.</li>
</ol>
<p>In short, my personal vision for where I hope OpenBao can go is to build an ecosystem similar to Kubernetes: companies large and small, and individuals experienced or just starting out, can contribute to the project and find market segments to provide derivative offerings while contributing to a common code base.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-06.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>Next, you might be asking "why GitLab"?</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-07.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>For a while, GitLab has been focused on building a more complete DevSecOps platform.</p>
<p>A common problem our customers face is managing secrets in their CI/CD Pipelines. Today, they have one of two options:</p>
<ol>
<li class="">They can use masked variables. These have very few controls over the scope of access and customers can't easily differentiate in the dashboard between secrets and inconsequential data, though all are stored encrypted at rest. A few customers have many thousands of variables and the difference in ideal behavior differs substantially between the two use cases for them. No one solution will really work for both.</li>
<li class="">Instead, many customers turn to our external integrations with various other secret management providers. However, the user experience isn't quite there: one typically has to work across several teams to enable OIDC ID Token authentication so pipelines can access secrets and the customer must organize the logistics of secret storage and rotation. Because GitLab plays a very minor role, mostly by providing identity to the pipelines, it lacks visibility into the actual secrets and the hierarchy administrators have set up.</li>
</ol>
<p>In short, there is no easy-to-use, per-project dashboard for secrets and neither approach can provide this easily. And many times, a developer has to find many individuals in their organization with permissions to do one of these steps in order to onboard their new project.</p>
<p>In late 2023, GitLab started working on this problem, building their own design from the ground up. In May, my colleague, Jocelyn, published this in a blog post, considering the use of OpenBao to solve this problem.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-08.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>OpenBao is a great choice for GitLab because we already support a HashiCorp Vault integration. For Premium and Ultimate tier customers, the Pipeline runner features native integration for fetching secrets from Vault: while all GitLab versions support issuing the OIDC ID Tokens, these paid plans offer support for a simplified pipeline syntax, improving the developer experience over manual CLI calls to Vault.</p>
<p>Being a mature secrets management solution already, OpenBao brings several useful properties to GitLab:</p>
<ol>
<li class="">It has already been deployed at scale by various entities.</li>
<li class="">It has historically undergone audits and certifications useful for enterprise customers.</li>
<li class="">It is a self-contained service, which we can isolate from the rest of our environment and treat as trusted.</li>
</ol>
<p>What we'd like to do is provide a single dashboard which lets us aggregate information into a project-specific view of secrets. Whereas previously audit logs might be separate between GitLab and a backend Vault instance, we can correlate them natively within the GitLab UI. Or, where access controls required understanding two separate permissions models--that of GitLab and that of Vault's ACL policies--GitLab will translate its own roles into OpenBao policies on behalf of the user.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-09.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>At its core, our architecture is just like it was before, but with OpenBao replacing HashiCorp Vault and moving it from the customer's deployment to our management scope. It remains a separate service that pipeline workers talk to and customers will eventually be able to bring their own KMS to secure key material as well.</p>
<p>What is new is the interactions, typically driven by a user, between Rails and OpenBao for management purposes. When a user initiates any secrets management
request, they do so via GitLab's Rail's API, which enforces initial authentication and holds privileged tokens for ACL management. In the future, we seek to add a User JWT issuer, allowing direct secret write operations by users without invoking Rails.</p>
<p>We thus get a clean trust separation, between three different entities:</p>
<ol>
<li class="">GitLab Rails, which will perform various administrative actions on behalf of users,</li>
<li class="">Pipelines, which will execute jobs and fetch secrets, and</li>
<li class="">OpenBao, which is the source of truth for authorization and secret storage.</li>
</ol>
<p>With official PostgreSQL support, OpenBao will be able to use the same database as Rails for smaller self-managed GitLab instances, avoiding the complexities of managing Raft which come with running Vault. Data will be encrypted before storing it in PostgreSQL and requires keys from a seal mechanism to decrypt.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-10.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>The key to integrating OpenBao is to be opinionated about its data storage layout. Philosophically, OpenBao aligns with key/value databases: its API path structure usually mirrors the underlying data storage. ACL policies are groups of grants to specific capabilities–like read, write, delete–on specific API paths, with a default deny rule. After authentication, perhaps via a third-party engine, OpenBao issues a token, mapping an identity to a set of ACL policies. Thus, there is no concept of a long-term identity which has ownership of a secret.</p>
<p>The core of our design to integrate with OpenBao is a data layout which provides multi-tenancy and isolation of secrets. This architecture is familiar to many of our customers who have successfully integrated with their HashiCorp Vault clusters.</p>
<p>Each top-level tenant, usually the owner of a repository, has a separate path area in OpenBao. Within this space, they have an authentication mount for authorizing pipeline's access to secrets, with roles corresponding to each project. Each project has its own KVv2 secrets engine for storing that project's secrets, which contains custom metadata indicating the scope and contextual information like description.</p>
<p>GitLab Rails can read this metadata and provision ACL policies and JWT roles for all scopes when changes are necessary.</p>
<p>When support for Namespaces lands upstream, we'll seek to provision each tenants into their own namespaces and, long-term, we wish to use unique encryption keys with separate seal mechanisms to provide greater data isolation on GitLab.Com via per-tenant encryption keyrings.</p>
<p>Within the core management space is another authentication mount for authorizing Rail's own requests into OpenBao. The core of these requests are for provisioning new tenants and their mounts but also being the trusted entity that maintains the ACL policies. These ACL policies reflect the permissions and scopes of access designated by users for accessing these secrets: each environment or branch for a project is a separate policy, which contains read access to secrets within that scope.</p>
<p>Authentication occurs via a properties based model. OIDC ID Tokens issued by GitLab to pipeline jobs have claims reflecting contextual metadata, such as the repository, branch, initiating user, and environment. Each tenant's JWT mount matches these claims to a per-project role, with dynamic generation of ACL policies based on the properties present on the token.</p>
<p>Uniquely, this model lets us use OpenBao as the single source of truth for all operations: permissions are reflected via ACL roles, scopes and context are present in contextual metadata, and Rails is only present as a management engine and a trusted token issuer and pipeline provisioner and does not store data of its own.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-11.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>So from a developer's perspective, all this work leads to the following two actions to use secrets in their pipelines:</p>
<ol>
<li class="">Create a new secret via the native GitLab UI, specifying the scope of access and its value.</li>
<li class="">Access the secret from a pipeline's <code>.gitlab-ci.yml</code> definition file, using the secret name as the reference key.</li>
</ol>
<p>And GitLab Rails and OpenBao will handle the rest.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-12.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>At GitLab, we've been really excited about using OpenBao. If you are too, we welcome contributors of any sort! You can check out our roadmap, join our weekly community calls, or talk about OpenBao on social media or at conferences.</p>
<p>If you're a customer interested in the work GitLab is doing to build our native pipeline secrets solution, ask your account team about joining our beta program.</p>
<hr>
<object type="image/svg+xml" data="/img/talks/cipherboy-fosdem-25/OpenBao-at-GitLab-Slide-13.svg"><p>SVG rendering is not supported on your browser.</p></object>
<p>I'm happy to take questions now, but if you have any additional questions or want stickers or a picture with our cute mascot, BaoBao, find me afterwards in person or online!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="talks" term="talks"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Travels Back Home]]></title>
        <id>https://openbao.org/blog/bao-back-home/</id>
        <link href="https://openbao.org/blog/bao-back-home/"/>
        <updated>2025-02-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao's travels back home]]></summary>
        <content type="html"><![CDATA[<p>OpenBao returns from FOSDEM '25 and OpenUK's State of Open Con this week,
reflecting on the travels and activities of the events.</p>
<p>Many thanks to Fatima for running the <a class="" href="https://openbao.org/community/contributing/">community calls</a>
in our absence!</p>
<p><img decoding="async" loading="lazy" alt="Alex-Presenting-FOSDEM" src="https://openbao.org/assets/images/alex-fosdem-25-speaking-dfd5c014101703549fcbd94778caeb43.jpg" width="1152" height="2048" class="img_JF2Q"></p>
<p><em>photo credit: nicolas; pictured: alex</em></p>
<p>FOSDEM '25 was Alex's first time speaking at a conference and we are happy to
report it was a success! The details of the talk were saved and will be
published in a follow-up blog along with the recording when it is made
available from the conference. It was great to meet so many people interested
in identity and access management and OpenBao's role in solving secrets
management problems, at GitLab and beyond.</p>
<p><img decoding="async" loading="lazy" alt="OpenBao-as-SOOCon-Sponsor" src="https://openbao.org/assets/images/openbao-sooc-sponsor-62a150ba9a0c46113e17b8ad7cd0d3ed.jpg" width="2048" height="1105" class="img_JF2Q"></p>
<p>After arriving in London, BaoBao was happy to find the conference venue was
very well organized and everything was ready. And look, our logo is situated
nicely on the list of table holders! BaoBao thanks OpenUK for generously
sponsoring OpenBao's attendance this year and hopes to participate in the
future.</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-after-setup" src="https://openbao.org/assets/images/openbao-sooc-table-9689dae8e7443f344bf0e22b8b52a91f.jpg" width="2048" height="1513" class="img_JF2Q"></p>
<p>During setup, BaoBao took a place on the table to get ready for the next two
days of meeting people. When <a href="https://opentofu.org/" target="_blank" rel="noopener noreferrer" class="">OpenTofu</a> couldn't make
it, Alex volunteered to represent them as well, which served as a great
conversation starter. BaoBao knows that they'd do the same, after all, we're
both OpenHashiForks!</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Percona-Hijinx-Hat" src="https://openbao.org/assets/images/openbao-sooc-percona-39b6dd4c0f30d1bc0048d7f325d8461a.jpg" width="2048" height="1550" class="img_JF2Q"></p>
<p>After meeting the kind folks from <a href="https://www.percona.com/" target="_blank" rel="noopener noreferrer" class="">Percona</a> at
FOSDEM, we encountered them again at State of Open, where they played hijinks
with BaoBao! When Alex wandered off, they bestowed upon BaoBao a
<a href="https://valkey.io/" target="_blank" rel="noopener noreferrer" class="">Valkey</a> hat -- <a href="https://github.com/openbao/openbao/issues/965" target="_blank" rel="noopener noreferrer" class="">a good reminder to revive and rename our
secrets engine</a>! BaoBao
appreciated the effort to avoid feeling chilly in the big conference center.</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Percona-Hijinx-Hat" src="https://openbao.org/assets/images/openbao-sooc-osacon-db5e4e80bc7dcb5b31ecc2bac13b89be.jpg" width="2048" height="1435" class="img_JF2Q"></p>
<p>Later, <a href="https://osacon.io/" target="_blank" rel="noopener noreferrer" class="">OSA Con</a> joined in the fun, placing a warning
sticker that this booth talked too much about open source... BaoBao thought
this disclaimer was much needed!</p>
<p><img decoding="async" loading="lazy" alt="OpenBao-Dotan" src="https://openbao.org/assets/images/openbao-sooc-dotan-5a85ef83be5de9d4ddfa20f64b99e72f.jpg" width="2048" height="1536" class="img_JF2Q"></p>
<p><em>photo credit: nigel; pictured: alex and dotan</em></p>
<p>Finally, BaoBao and Alex got to meet <a href="https://www.linkedin.com/posts/horovits_stateofopencon-openbao-soocon25-activity-7292823212332085248-U4Bh?utm_source=share&amp;utm_medium=member_desktop" target="_blank" rel="noopener noreferrer" class="">Dotan Horovits</a>,
the CNCF Ambassador who made the necessary connections to get OpenBao
invited to State of Open Con!</p>
<p>Both Alex and BaoBao had lots of fun networking and making friends
with fans of OpenBao. Thank you to everyone who organized these events and
helped them run so smoothly! A special thanks to all who offered to support
OpenBao or consider it for use in their company!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="stickers" term="stickers"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao Travels to FOSDEM]]></title>
        <id>https://openbao.org/blog/bao-at-fosdem-25/</id>
        <link href="https://openbao.org/blog/bao-at-fosdem-25/"/>
        <updated>2025-01-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao's travels to FOSDEM '25]]></summary>
        <content type="html"><![CDATA[<p>Follow along with OpenBao's travels this week as we attend FOSDEM '25 and
State of Open Con!</p>
<div class="theme-admonition theme-admonition-info admonition_zcLH alert alert--info"><div class="admonitionHeading_EuVW"><span class="admonitionIcon_pqj5"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_TXrn"><p>Check out <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5145-openbao-at-gitlab-building-native-secrets-for-gitlab-ci-cd-pipelines/" target="_blank" rel="noopener noreferrer" class="">Alex's talk at FOSDEM</a>,
on Sunday, February 2nd, at 2:05 PM GMT+1 in room UA2.118 (Henriot) as part
of the Identity and Access Management track.</p><p>If you can't attend in person, it will also be <a href="https://live.fosdem.org/watch/ua2118" target="_blank" rel="noopener noreferrer" class="">live streamed</a>.</p></div></div>
<p><img decoding="async" loading="lazy" alt="BaoBao-Departs-via-Airplane" src="https://openbao.org/assets/images/baobao-fosdem-25-airplane-3e7dbc2c503cf2124bc535b453172ca4.jpg" width="1500" height="1500" class="img_JF2Q"></p>
<p>From snowy Minnesota, <a class="" href="https://openbao.org/blog/fosdem-25/">BaoBao</a> took its
first ride to London Heathrow to begin its voyage to FOSDEM '25. With a brief
layover, it explored King's Cross and the Coal Drops Yard. Rich with history,
this area has long been used as a rail hub for the UK and now is connected to
Europe via the Channel Tunnel.</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Departs-for-France" src="https://openbao.org/assets/images/baobao-fosdem-25-train-paris-50d4922095f13cffea174ed02f605fec.jpg" width="1129" height="1500" class="img_JF2Q"></p>
<p>From there, BaoBao boarded a train to Paris, France for some sightseeing and
meetings with community members. BaoBao wishes that secrets management was as
easy as traveling via European trains, but, with the help of the community,
knows it will improve!</p>
<p>First up, the Eiffel Tower!</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Eiffel-Tower" src="https://openbao.org/assets/images/baobao-fosdem-25-eiffel-2066606bd824368a824205f959448bef.jpg" width="1129" height="1500" class="img_JF2Q"></p>
<p>While it was rainy and dark, seeing the structure all lit up in person was
very impressive! BaoBao thought the structure loomed larger than life, just
like attackers in the shadows, targeting deployments using insecure secrets
management practices...</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Louvre" src="https://openbao.org/assets/images/baobao-fosdem-25-louvre-2270067a20e6fc1eb6311134da6deb35.jpg" width="1500" height="1570" class="img_JF2Q"></p>
<p>The next day, BaoBao explored Paris a bit more, visiting the Notre Dame, the
Pantheon, and finally, the Louvre! One of the largest museums in the world,
filled with all types of art, from paintings to sculptures to fashion, this
museum would take several visits to fully appreciate. BaoBao thinks there's
art to open source too, and wishes it would be in its own museum some day!</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Colleagues" src="https://openbao.org/assets/images/baobao-fosdem-25-colleagues-832ca16260b1aeba217c784f55682502.jpg" width="1500" height="1129" class="img_JF2Q"></p>
<p>BaoBao went out for dinner with its colleagues, Julien Cassignol (right),
OpenBao TSC representative and CTPO of Wallix, and Dan Ghita (left),
OpenBao Maintainer and backup Viaccess-Orca representative. BaoBao thinks
its favorite part of open source is the friends you make along the way.</p>
<p><img decoding="async" loading="lazy" alt="BaoBao-Brussels" src="https://openbao.org/assets/images/baobao-fosdem-25-brussels-cc4cdf7642dfa2ccd44a70da30a0ead3.jpg" width="1500" height="1456" class="img_JF2Q"></p>
<p>On Friday, BaoBao took the train from Paris to Brussels to join the fun that
is FOSDEM. At dinner with friends old and new, BaoBao met Jan Martens, OpenBao
Maintainer.</p>
<p>And now, BaoBao rests for the conference ahead -- and hopes to see you there!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="stickers" term="stickers"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OpenBao at FOSDEM, State of Open Con!]]></title>
        <id>https://openbao.org/blog/fosdem-25/</id>
        <link href="https://openbao.org/blog/fosdem-25/"/>
        <updated>2025-01-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OpenBao will be at FOSDEM '25 and SOOC '25 next month]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="openbao-mascot" src="https://openbao.org/assets/images/bao-mascot-b78a73a1544ab81831d5fb0be25f850e.jpg" width="6048" height="2927" class="img_JF2Q"></p>
<p>I'm happy to share that OpenBao will be present at two conferences in February: FOSDEM '25 in Brussels and State of Open Con 2025 in London!</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="fosdem">FOSDEM<a href="https://openbao.org/blog/fosdem-25/#fosdem" class="hash-link" aria-label="Direct link to FOSDEM" title="Direct link to FOSDEM" translate="no">​</a></h3>
<p>I will be <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-5145-openbao-at-gitlab-building-native-secrets-for-gitlab-ci-cd-pipelines/" target="_blank" rel="noopener noreferrer" class="">giving a talk</a> on Sunday, February 2nd, at 2:05 PM GMT+1 in <a href="https://fosdem.org/2025/schedule/room/ua2118/" target="_blank" rel="noopener noreferrer" class="">room UA2.118 (Henriot)</a> as part of the <a href="https://fosdem.org/2025/schedule/track/iam/" target="_blank" rel="noopener noreferrer" class="">Identity and Access Management</a> track. I'll give a brief history of the project, share how GitLab is using OpenBao, and ways you can become involved. Several OpenBao maintainers will be there, including Jan Martens, and stickers will be available!</p>
<p>This talk will also be <a href="https://live.fosdem.org/watch/ua2118" target="_blank" rel="noopener noreferrer" class="">live-streamed</a> for anyone unable to make it.</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="state-of-open-con">State of Open Con<a href="https://openbao.org/blog/fosdem-25/#state-of-open-con" class="hash-link" aria-label="Direct link to State of Open Con" title="Direct link to State of Open Con" translate="no">​</a></h3>
<p>Thanks to the generous help of <a href="https://openuk.uk/profiles/amanda-brock/" target="_blank" rel="noopener noreferrer" class="">Amanda Brock</a> and <a href="https://github.com/horovits/" target="_blank" rel="noopener noreferrer" class="">Dotan Horovits</a>, OpenBao has been provided a free non-profit table at <a href="https://stateofopencon.com/" target="_blank" rel="noopener noreferrer" class="">State of Open Con</a> from Tuesday, February 4th to Wednesday, February 5th. If you're curious about OpenBao and want to try some hands-on demos, stop by the booth--plenty of stickers will be available and we'll be contributing an OpenBao mascot (like pictured above) to the prize drawing on Tuesday!</p>
<p>If any community members are interested in helping to staff the booth, let us know as we have one free registration remaining.</p>
<p><img decoding="async" loading="lazy" alt="openbao-mascot" src="https://openbao.org/assets/images/SOOC-OpenBao-New-Year-ee9c3863b3d17de1b5dddc63b0f50cdd.png" width="1080" height="1080" class="img_JF2Q"></p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="meetings">Meetings<a href="https://openbao.org/blog/fosdem-25/#meetings" class="hash-link" aria-label="Direct link to Meetings" title="Direct link to Meetings" translate="no">​</a></h3>
<p>If anyone is interested in meeting with me in either Brussels or London, please reach out <a href="mailto:alexander.m.scheel@gmail.com" target="_blank" rel="noopener noreferrer" class="">via email</a>.</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="conferences" term="conferences"/>
        <category label="stickers" term="stickers"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[December OpenBao RFC Update]]></title>
        <id>https://openbao.org/blog/rfcs-dec-2024/</id>
        <link href="https://openbao.org/blog/rfcs-dec-2024/"/>
        <updated>2024-12-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Overview of in-progress OpenBao RFCs and their status]]></summary>
        <content type="html"><![CDATA[<p>The second half of 2024 saw several fabulous RFCs from different contributors to OpenBao. Here's a few worth highlighting and how you can get involved!</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="in-progress">In-Progress<a href="https://openbao.org/blog/rfcs-dec-2024/#in-progress" class="hash-link" aria-label="Direct link to In-Progress" title="Direct link to In-Progress" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao697--vault17189---ssh-ca-multi-issuer"><a href="https://github.com/openbao/openbao/issues/679" target="_blank" rel="noopener noreferrer" class="">openbao#697 / vault#17189 - SSH CA Multi-Issuer</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao697--vault17189---ssh-ca-multi-issuer" class="hash-link" aria-label="Direct link to openbao697--vault17189---ssh-ca-multi-issuer" title="Direct link to openbao697--vault17189---ssh-ca-multi-issuer" translate="no">​</a></h3>
<p><strong>Description</strong>: Vault and OpenBao have <a href="https://github.com/hashicorp/vault/issues/17189" target="_blank" rel="noopener noreferrer" class="">long had issues</a> supporting proper rotation of CAs in both the SSH and PKI engines. Previously, an operator would either have to remount an entirely new engine, manually copying configuration and policy, or they'd have to destructively remove the existing CA and create a new one, creating a downtime window. While PKI got updates to add multi-issuer support <a href="https://developer.hashicorp.com/vault/docs/release-notes/1.11.0#improved-ca-rotation" target="_blank" rel="noopener noreferrer" class="">in Vault v1.11</a>, neither Vault nor OpenBao saw improvements to SSH CA rotation. This RFC by one our OpenBao Mentees, <a href="https://github.com/Gabrielopesantos" target="_blank" rel="noopener noreferrer" class="">Gabriel</a>, brings parity by adding multi-issuer support to the SSH engine for zero-downtime CA rotation.</p>
<p><strong>How you can help</strong>: Gabriel is working hard on the implementation for this feature, but we'd appreciate feedback on the design from any users of the SSH CA!</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao753---cel-for-pki-policy"><a href="https://github.com/openbao/openbao/issues/753" target="_blank" rel="noopener noreferrer" class="">openbao#753 - CEL for PKI Policy</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao753---cel-for-pki-policy" class="hash-link" aria-label="Direct link to openbao753---cel-for-pki-policy" title="Direct link to openbao753---cel-for-pki-policy" translate="no">​</a></h3>
<p><strong>Description</strong>: The PKI Engine's role-based certificate validation method is inflexible: every possible certificate field and extension, complete with desired validation mechanism must be implemented in the engine itself, requiring a release for users to adopt. For instance, <code>allowed_domains</code> on a role today doesn't support setting default domains or rejecting requests with only a partial list of allowed domains. While functionally equivalent (in that, a user could request multiple certificates each with a subset of approved domains), it is hard for a PKI operator to ensure that all approved domains have been issued for in a single certificate. Fatima, another OpenBao Mentee, proposes to use Google's Common Expression Language (CEL), widely used in GCP and Kubernetes for validation and templating, to enforce issuance policy and template the final certificate from request parameters.</p>
<p><strong>How you can help</strong>: Have experience using CEL or doing complex, company-specific PKI integrations? We'd love to hear from you about the proposed design!</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao787---add-namespace-support"><a href="https://github.com/openbao/openbao/issues/787" target="_blank" rel="noopener noreferrer" class="">openbao#787 - Add Namespace Support</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao787---add-namespace-support" class="hash-link" aria-label="Direct link to openbao787---add-namespace-support" title="Direct link to openbao787---add-namespace-support" translate="no">​</a></h3>
<p><strong>Description</strong>: Vault Enterpise supports Namespaces, a way of creating multi-tenancy and delegating permissions without running multiple clusters. <a href="https://lists.openssf.org/g/OpenBao-TSC/topic/openbao_dev_wg_proposal_to/108266694" target="_blank" rel="noopener noreferrer" class="">Users</a> <a href="https://github.com/openbao/openbao/issues/486" target="_blank" rel="noopener noreferrer" class="">have</a> <a href="https://github.com/orgs/openbao/discussions/293" target="_blank" rel="noopener noreferrer" class="">requested</a> similar abilities with OpenBao, so a temporary working group was formed to create the design and initial implementation. This RFC, published by <a href="https://github.com/genelet/" target="_blank" rel="noopener noreferrer" class="">Peter</a>, proposes API compatibility for consuming applications but suggests many future improvements to scalability and tenant isolation.</p>
<p><strong>How you can help</strong>: While the initial implementation will be done by the Namespace WG, we welcome feedback on the design, testing of the feature, and designs and implementations for future enhancements.</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao549--vault5275---recursively-list-keys"><a href="https://github.com/openbao/openbao/issues/549" target="_blank" rel="noopener noreferrer" class="">openbao#549 / vault#5275 - Recursively List Keys</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao549--vault5275---recursively-list-keys" class="hash-link" aria-label="Direct link to openbao549--vault5275---recursively-list-keys" title="Direct link to openbao549--vault5275---recursively-list-keys" translate="no">​</a></h3>
<p><strong>Description</strong>: The <a href="https://github.com/hashicorp/vault/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc" target="_blank" rel="noopener noreferrer" class="">most widely requested Vault feature</a> with no solution <a href="https://github.com/hashicorp/vault/issues/5275" target="_blank" rel="noopener noreferrer" class="">is adding the ability to recursively list keys</a>. Prior to <a class="" href="https://openbao.org/community/rfcs/transactions/">transactions</a> (for consistency) and <a class="" href="https://openbao.org/community/rfcs/paginated-lists/">pagination</a> (for resource constraining expensive calls), this was hard to do safely. This RFC proposes introducing a new operation, with HTTP verb <code>SCAN</code> or via <code>GET</code> with <code>?scan=true</code>, and ACL capability (<code>scan</code>) to allow plugin authors to introduce recursive list endpoints and operators to secure access to them.</p>
<p><strong>How you can help</strong>: After the initial implementation is merged, it would be great to have feedback or PRs on additional endpoints to use this new operation.</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="acl-improvements---openbao769--vault5362---filter-list-results-and-openbao791---enforce-list-pagination">ACL Improvements - <a href="https://github.com/openbao/openbao/issues/769" target="_blank" rel="noopener noreferrer" class="">openbao#769 / vault#5362 - Filter LIST Results</a> and <a href="https://github.com/openbao/openbao/issues/791" target="_blank" rel="noopener noreferrer" class="">openbao#791 - Enforce List Pagination</a><a href="https://openbao.org/blog/rfcs-dec-2024/#acl-improvements---openbao769--vault5362---filter-list-results-and-openbao791---enforce-list-pagination" class="hash-link" aria-label="Direct link to acl-improvements---openbao769--vault5362---filter-list-results-and-openbao791---enforce-list-pagination" title="Direct link to acl-improvements---openbao769--vault5362---filter-list-results-and-openbao791---enforce-list-pagination" translate="no">​</a></h3>
<p><strong>Description</strong>: The <a href="https://github.com/hashicorp/vault/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc" target="_blank" rel="noopener noreferrer" class="">fourth-most widely requested Vault feature</a> with no solution <a href="https://github.com/openbao/openbao/issues/769" target="_blank" rel="noopener noreferrer" class="">is filtering LIST results</a> to only show accessible paths. <a href="https://github.com/openbao/openbao/issues/769" target="_blank" rel="noopener noreferrer" class="">This RFC</a> proposes a new ACL policy parameter, <code>list_scan_response_keys_filter_path</code>, which contains a path to template with each list response item (from <code>.keys</code>) to check against the ACL system for visibility under the same token policy. While this is an expensive operation, a <a href="https://github.com/openbao/openbao/issues/791" target="_blank" rel="noopener noreferrer" class="">follow-up RFC</a> proposes another parameter, <code>pagination_limit</code>, to allow policy authors to require usage of paginated lists (thereby reducing the load on path filtering).</p>
<p><strong>How you can help</strong>: It would be great to have feedback on the templating design and how support for multiple paths could potentially behave (with an <code>AND</code> or <code>OR</code> conjunctions).</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="completed">Completed<a href="https://openbao.org/blog/rfcs-dec-2024/#completed" class="hash-link" aria-label="Direct link to Completed" title="Direct link to Completed" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao296---transactional-storage"><a href="https://github.com/openbao/openbao/issues/432" target="_blank" rel="noopener noreferrer" class="">openbao#296 - Transactional Storage</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao296---transactional-storage" class="hash-link" aria-label="Direct link to openbao296---transactional-storage" title="Direct link to openbao296---transactional-storage" translate="no">​</a></h3>
<p><strong>Description</strong>: Recently merged and released in <a class="" href="https://openbao.org/community/release-notes/2-1-0/">v2.1.0</a> was support for transactional storage across the entire OpenBao stack (from underlying physical storage backend to plugins). This allowed us to <a href="https://github.com/openbao/openbao/issues/432" target="_blank" rel="noopener noreferrer" class="">improve the scalability</a> and fault-tolerance of OpenBao above and beyond what HashiCorp Vault had.</p>
<p><strong>How you can help</strong>: A follow-up <a href="https://github.com/openbao/openbao/issues/607" target="_blank" rel="noopener noreferrer" class="">tracking issue</a> invites contributions of places where transactions should be used. As always, we welcome testing of this feature.</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="upcoming">Upcoming<a href="https://openbao.org/blog/rfcs-dec-2024/#upcoming" class="hash-link" aria-label="Direct link to Upcoming" title="Direct link to Upcoming" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao235---add-xchacha20-poly1305-barrier-encryption-support"><a href="https://github.com/openbao/openbao/issues/235" target="_blank" rel="noopener noreferrer" class="">openbao#235 - Add XChaCha20-Poly1305 Barrier Encryption Support</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao235---add-xchacha20-poly1305-barrier-encryption-support" class="hash-link" aria-label="Direct link to openbao235---add-xchacha20-poly1305-barrier-encryption-support" title="Direct link to openbao235---add-xchacha20-poly1305-barrier-encryption-support" translate="no">​</a></h3>
<p><strong>Description</strong>: OpenBao uses AES256-GCM96 as its barrier encryption algorithm. While suitably secure and FIPS compliant, this requires frequent key rotation to compensate for the 96-bit nonce (which is not collision resistant). Switching to XChaCha20-Poly1305 would allow us to maintain a smaller barrier keyring (as key rotation would not need to be done automatically) and avoid concerns over nonce collisions.</p>
<p><strong>How you can help</strong>: While a proof of concept was proposed, we're looking for a volunteer to take over polishing the feature!</p>
<h3 class="anchor anchorTargetStickyNavbar_i50L" id="openbao17---add-acme-support-to-the-tls-listener"><a href="https://github.com/openbao/openbao/issues/17" target="_blank" rel="noopener noreferrer" class="">openbao#17 - Add ACME Support to the TLS Listener</a><a href="https://openbao.org/blog/rfcs-dec-2024/#openbao17---add-acme-support-to-the-tls-listener" class="hash-link" aria-label="Direct link to openbao17---add-acme-support-to-the-tls-listener" title="Direct link to openbao17---add-acme-support-to-the-tls-listener" translate="no">​</a></h3>
<p><strong>Description</strong>: While OpenBao supports PKI capabilities, due to a chicken-and-egg problem, it is hard to issue the TLS listener's own certificate via a CA stored in OpenBao. With auto-unseal and ACME support, however, it would be possible to do and greatly improve operator's experience when using other CAs as well.</p>
<p><strong>How you can help</strong>: While a proof of concept was proposed, much polish was needed to complete this feature and we're looking for a volunteer to take over development!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="community" term="community"/>
        <category label="mentee" term="mentee"/>
        <category label="rfcs" term="rfcs"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Announcing OpenBao v2.1.0!]]></title>
        <id>https://openbao.org/blog/release-v2-1-0/</id>
        <link href="https://openbao.org/blog/release-v2-1-0/"/>
        <updated>2024-11-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[We are thrilled to announce the availability of OpenBao v2.1.0, focused on safety and scalability improvements!]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" src="https://raw.githubusercontent.com/openbao/artwork/refs/heads/main/color/openbao-text-color.svg" alt="openbao-logo" class="img_JF2Q"></p>
<p>We are thrilled to announce <a class="" href="https://openbao.org/downloads/?version=v2.1.0">the availability</a> of <a class="" href="https://openbao.org/community/release-notes/2-1-0/">OpenBao v2.1.0</a>, focused on safety and scalability improvements!</p>
<p>This release spent some time laying the groundwork for safety and scalability improvements for releases to come. With the help of the community, OpenBao will now take advantage of transactional storage semantics from its underlying data store, giving operators and plugin developers confidence in the consistency of storage writes. This storage safety allows us to focus on alternative storage layouts for improving scalability, for instance, increasing the maximum number of mount table entries past the single-entry limit.</p>
<p>This release also features contributions from many new and repeat contributors; thank you all!</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="key-highlights-of-the-release">Key highlights of the release<a href="https://openbao.org/blog/release-v2-1-0/#key-highlights-of-the-release" class="hash-link" aria-label="Direct link to Key highlights of the release" title="Direct link to Key highlights of the release" translate="no">​</a></h2>
<p>Major features:</p>
<ul>
<li class=""><strong>Remove Mount Table Limits</strong>: Using transactional storage, we've split the auth and secret mount tables into separate storage entries, removing the requirement that the entire table fit into a single storage entry limited by max_entry_size. This allows potentially hundreds of thousands of mounts on a single scaled-up server.</li>
<li class=""><strong>Transactional Storage</strong>: Plugin developers can now take advantage of safe storage modification APIs when the underlying physical storage supports them. The physical.TransactionalBackend and logical.TransactionalStorage types allow developers to begin read-only and writable transactions, committing or rolling back the desired changes.</li>
<li class=""><strong>Transit</strong>: Support PKI CSR and certificate storage alongside key material. This allows callers to securely create keys and submit requests for certificates without the key material leaving Transit. Storage of the certificate on the key avoids the need for an additional K/V mount. Rotation of this certificate and its chain is also supported.</li>
<li class=""><code>physical/postgres</code>: Reintroduce Postgres database for OpenBao storage, implementing paginated list support. This feature is currently in <strong>preview</strong> and breaking changes may occur.</li>
</ul>
<p>Plugin improvements:</p>
<ul>
<li class=""><code>auth/jwt</code>: Allow templating ACL policies from data in claims on JWT or OIDC ID tokens.</li>
<li class=""><code>auth/oidc</code>: Add a new oauth2_metadata configuration option to enable sending any of the tokens from the token issuer to the client.</li>
<li class=""><code>auth/oidc</code>: Add a new callback_mode role option value <strong>device</strong> to use the oidc device flow instead of a callback, add a new poll_interval role option to control how often to poll for a response, and add a new callbackmode=device option to the oidc login method in the cli.</li>
<li class=""><code>auth/oidc</code>: Add new <strong>callback_mode=direct</strong> role option to cause the oidc callback to be direct to the server instead of the client, and add a callbackmode=direct option to the oidc login method in the cli.</li>
<li class=""><code>docker</code>: add /bin/vault symlink to docker images.</li>
<li class=""><code>rpm</code>: Fix packaging to properly annotate configs entries for noreplace.</li>
<li class=""><code>secrets/kv</code>: Implement transactions to prevent canceled operations from corrupting storage.</li>
<li class=""><code>secrets/pki</code>: Use transactions for root generation, issuer import.</li>
<li class=""><code>secrets/pki</code>: add not_before parameter to precisely define a certificate's "not before" field.</li>
<li class=""><code>secrets/pki</code>: Add revoked_safety_buffer to control retention on revoked certificates separately from expired certificates.</li>
<li class=""><code>secrets/pki</code>: Delete invalid certificates during tidy via tidy_invalid_certs=true if they cannot be parsed due to Go's x509 handling.</li>
<li class=""><code>secrets/pki</code>: Support revoking expired certificates with the allow_expired_cert_revocation CRL configuration.</li>
<li class=""><code>storage/postgresql</code>: Allow table creation to improve first-start UX.</li>
</ul>
<p>Stay tuned for more great features to come!</p>
<h2 class="anchor anchorTargetStickyNavbar_i50L" id="looking-ahead">Looking ahead<a href="https://openbao.org/blog/release-v2-1-0/#looking-ahead" class="hash-link" aria-label="Direct link to Looking ahead" title="Direct link to Looking ahead" translate="no">​</a></h2>
<p>Several feature-related working groups have spun up, including one around Namespaces which will bring welcomed multi-tenancy improvements in the future. OpenBao's mentees have also been making great improvements! Stay tuned for progress on <a href="https://github.com/openbao/openbao/issues/679" target="_blank" rel="noopener noreferrer" class="">multi-issuer SSH CA support</a> and <a href="https://github.com/openbao/openbao/issues/753" target="_blank" rel="noopener noreferrer" class="">Common Expression Language (CEL)-based PKI issuance policy</a>.</p>
<p>Changes are well underway for the next release, including usability enhancements to the PKI engine, improvements to the K/V engine based on paginated lists and transactional storage, additions to the ACL system to handle recursive listing, and an RFC for restricting the results of <a href="https://github.com/openbao/openbao/issues/769" target="_blank" rel="noopener noreferrer" class="">list operations to only visible entries</a>.</p>
<p>If anyone has private forks of HashiCorp Vault, we are happy to collaborate around timely security fixes or syncing modifications to the core or plugins.</p>
<p>As always, we appreciate any and all contributions!</p>]]></content>
        <author>
            <name>Alex Scheel</name>
            <uri>https://cipherboy.com</uri>
        </author>
        <category label="release" term="release"/>
        <category label="announcement" term="announcement"/>
        <category label="release" term="release"/>
    </entry>
</feed>