Documentation
¶
Overview ¶
Package openbao is a pure-Go (CGO-free) reimplementation of the deterministic core of Ruby's `vault` gem — the official OpenBao / HashiCorp Vault client (Vault::Client / OpenBao::Client). It reproduces the client configuration, the Logical/KV/Transit/Sys/Auth endpoint groups, the Secret response model, and the HTTP-status→error mapping the gem performs around a transport — without any Ruby runtime.
It is the OpenBao/Vault client for [go-embedded-ruby](https://github.com/go-embedded-ruby/ruby), but a standalone, reusable module — a sibling of go-ruby-faraday/faraday and go-ruby-net-http/net-http.
What it is — and isn't ¶
Everything the vault gem does around the wire is deterministic and needs no interpreter, so it lives here as pure Go: resolving the address/token/ namespace from config or the environment, building the /v1/ request path, JSON-encoding request bodies, decoding the Secret response (data/lease_id/renewable/warnings/auth), and mapping a non-2xx status onto the error tree. The HTTP round-trip itself is a host seam: the terminal Doer performs the transport. The default production Doer is backed by net/http; tests inject a DoerFunc stub (or drive the default Doer against an in-process httptest server), and the core opens no socket of its own. This mirrors the gem, whose Persistent HTTP connection is the only piece that touches the network.
Flow ¶
client := openbao.NewClient(openbao.Config{
Address: "https://127.0.0.1:8200",
Token: "s.sometoken",
})
// arbitrary logical path
secret, err := client.Logical().Read("secret/data/foo")
// KV v2 helper (rewrites secret/foo -> secret/data/foo)
secret, err = client.KVv2("secret").Read("foo")
// transit encrypt
enc, err := client.Transit("transit").Encrypt("mykey", []byte("hello"))
// approle login, then adopt the returned client token
login, err := client.Auth().AppRole("approle").Login(roleID, secretID)
client.AdoptToken(login)
Value model ¶
A Secret carries the decoded response fields (Data, LeaseID, LeaseDuration, Renewable, Warnings, Auth). Errors are a single VaultError type whose Kind places it in the gem's error tree (VaultError → HTTPError → HTTPClientError/HTTPServerError, plus HTTPConnectionError), matched with errors.Is against the Err* sentinels so a superclass matches its subclasses. A host (go-embedded-ruby / rbgo) maps its Ruby Vault::Client / Secret / VaultError objects to and from these shapes.
Index ¶
- Constants
- Variables
- func IsHTTPClientError(err error) bool
- func IsHTTPError(err error) bool
- func IsHTTPServerError(err error) bool
- func IsNotFound(err error) bool
- type AppRoleAuth
- type Auth
- type Client
- func (c *Client) Address() string
- func (c *Client) AdoptToken(s *Secret) *Client
- func (c *Client) Auth() *Auth
- func (c *Client) KVv1(mount string) *KVv1
- func (c *Client) KVv2(mount string) *KVv2
- func (c *Client) Logical() *Logical
- func (c *Client) Namespace() string
- func (c *Client) SetNamespace(ns string) *Client
- func (c *Client) SetToken(token string) *Client
- func (c *Client) Sys() *Sys
- func (c *Client) Token() string
- func (c *Client) Transit(mount string) *Transit
- type Config
- type Doer
- type DoerFunc
- type ErrorKind
- type KVv1
- type KVv2
- func (k *KVv2) Delete(path string) (*Secret, error)
- func (k *KVv2) DeleteMetadata(path string) (*Secret, error)
- func (k *KVv2) DeleteVersions(path string, versions ...int) (*Secret, error)
- func (k *KVv2) Destroy(path string, versions ...int) (*Secret, error)
- func (k *KVv2) List(path string) (*Secret, error)
- func (k *KVv2) Read(path string) (*Secret, error)
- func (k *KVv2) ReadMetadata(path string) (*Secret, error)
- func (k *KVv2) ReadVersion(path string, version int) (*Secret, error)
- func (k *KVv2) Undelete(path string, versions ...int) (*Secret, error)
- func (k *KVv2) Write(path string, data map[string]any) (*Secret, error)
- func (k *KVv2) WriteMetadata(path string, meta map[string]any) (*Secret, error)
- type Logical
- type Request
- type Response
- type Secret
- type SecretAuth
- type Sys
- func (s *Sys) DeletePolicy(name string) error
- func (s *Sys) DisableMount(path string) error
- func (s *Sys) EnableMount(path, engineType string, opts map[string]any) error
- func (s *Sys) Health() (map[string]any, error)
- func (s *Sys) LookupLease(leaseID string) (*Secret, error)
- func (s *Sys) Mounts() (map[string]any, error)
- func (s *Sys) Policies() (*Secret, error)
- func (s *Sys) Policy(name string) (*Secret, error)
- func (s *Sys) PutPolicy(name, policy string) error
- func (s *Sys) RenewLease(leaseID string, increment int) (*Secret, error)
- func (s *Sys) RevokeLease(leaseID string) error
- func (s *Sys) SealStatus() (map[string]any, error)
- type TokenAuth
- type Transit
- func (t *Transit) Decrypt(key, ciphertext string, context ...[]byte) (*Secret, error)
- func (t *Transit) Encrypt(key string, plaintext []byte, context ...[]byte) (*Secret, error)
- func (t *Transit) GenerateDataKey(key, keyType string) (*Secret, error)
- func (t *Transit) Rewrap(key, ciphertext string, context ...[]byte) (*Secret, error)
- func (t *Transit) Sign(key string, input []byte) (*Secret, error)
- func (t *Transit) Verify(key string, input []byte, signature string) (*Secret, error)
- type UserpassAuth
- type VaultError
Constants ¶
const DefaultAddress = "https://127.0.0.1:8200"
DefaultAddress is the address used when neither the config nor the environment supplies one, matching the vault gem's default.
Variables ¶
var ( ErrVaultError = &VaultError{Kind: KindVaultError, Message: string(KindVaultError)} ErrHTTPError = &VaultError{Kind: KindHTTPError, Message: string(KindHTTPError)} ErrHTTPConnectionError = &VaultError{Kind: KindHTTPConnectionError, Message: string(KindHTTPConnectionError)} ErrHTTPClientError = &VaultError{Kind: KindHTTPClientError, Message: string(KindHTTPClientError)} ErrHTTPServerError = &VaultError{Kind: KindHTTPServerError, Message: string(KindHTTPServerError)} ErrMissingRequired = &VaultError{Kind: KindMissingRequired, Message: string(KindMissingRequired)} )
Sentinel errors for errors.Is matching. Each names an error kind; a concrete VaultError with that Kind (or a subtree of it) matches via VaultError.Is.
Functions ¶
func IsHTTPClientError ¶
IsHTTPClientError reports whether err is a gem 4xx HTTPClientError.
func IsHTTPError ¶
IsHTTPError reports whether err is any gem HTTPError (client/server/connection).
func IsHTTPServerError ¶
IsHTTPServerError reports whether err is a gem 5xx HTTPServerError.
func IsNotFound ¶
IsNotFound reports whether err is an HTTPError with a 404 status.
Types ¶
type AppRoleAuth ¶
type AppRoleAuth struct {
// contains filtered or unexported fields
}
AppRoleAuth is the AppRole login helper rooted at a mount (default "approle").
type Auth ¶
type Auth struct {
// contains filtered or unexported fields
}
Auth is the auth-method endpoint group (Vault::Client#auth): token self-management and the AppRole / Userpass login flows, each of which yields a Secret whose Auth.ClientToken the client can adopt with Client.AdoptToken.
func (*Auth) AppRole ¶
func (a *Auth) AppRole(mount string) *AppRoleAuth
AppRole returns the AppRole login helper rooted at mount (default "approle").
func (*Auth) Userpass ¶
func (a *Auth) Userpass(mount string) *UserpassAuth
Userpass returns the Userpass login helper rooted at mount (default "userpass").
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a configured OpenBao/Vault API client (Vault::Client / OpenBao::Client). It carries the resolved address, token and namespace, and the transport Doer; the endpoint groups are reached through Client.Logical, Client.KVv1, Client.KVv2, Client.Transit, Client.Sys and Client.Auth.
func NewClient ¶
NewClient builds a Client from cfg, resolving unset fields from the environment and the defaults.
func (*Client) AdoptToken ¶
AdoptToken adopts the client_token from a login/auth Secret as the client's token (Vault::Client#token=), returning the client for chaining. A nil secret or one without an auth client token leaves the token unchanged.
func (*Client) Logical ¶
Logical returns the logical-backend endpoint group (Vault::Client#logical).
func (*Client) SetNamespace ¶
SetNamespace sets the Vault namespace and returns the client for chaining.
type Config ¶
type Config struct {
// Address is the OpenBao/Vault server address (scheme+host+port).
Address string
// Token is the Vault token sent as X-Vault-Token.
Token string
// Namespace is the Vault namespace sent as X-Vault-Namespace (Enterprise /
// OpenBao namespaces).
Namespace string
// Timeout is the per-request timeout of the default net/http transport; 0
// means no timeout. Ignored when Doer is set.
Timeout time.Duration
// Doer overrides the transport seam. When nil, a net/http-backed Doer is
// used. Tests and hosts inject their own.
Doer Doer
}
Config configures a Client. Any zero field is resolved from the environment (Address from VAULT_ADDR/BAO_ADDR, Token from VAULT_TOKEN/BAO_TOKEN, Namespace from VAULT_NAMESPACE/BAO_NAMESPACE) and finally from the built-in defaults.
type Doer ¶
Doer is the transport host seam: given a prepared Request it performs the HTTP round-trip and returns the Response, or a transport error. The default production Doer ([defaultDoer]) is backed by net/http; the core opens no socket of its own, so tests inject a DoerFunc stub (or drive the default Doer against an in-process httptest server). A future rbgo binding wires this to Ruby's Net::HTTP.
type DoerFunc ¶
DoerFunc adapts a function to the Doer interface — the convenient way to inject a stub transport in tests or a custom transport in a host.
type ErrorKind ¶
type ErrorKind string
ErrorKind identifies a vault-gem error subclass.
const ( KindVaultError ErrorKind = "Vault::VaultError" KindHTTPError ErrorKind = "Vault::HTTPError" KindHTTPConnectionError ErrorKind = "Vault::HTTPConnectionError" KindHTTPClientError ErrorKind = "Vault::HTTPClientError" KindHTTPServerError ErrorKind = "Vault::HTTPServerError" KindMissingRequired ErrorKind = "Vault::MissingRequiredStateError" )
The vault-gem error subclasses, named as in the gem.
type KVv1 ¶
type KVv1 struct {
// contains filtered or unexported fields
}
KVv1 is a KV version-1 secrets-engine helper rooted at a mount (default "secret"). Paths are joined under the mount; the payload is stored flat, so the verbs delegate straight to Logical.
type KVv2 ¶
type KVv2 struct {
// contains filtered or unexported fields
}
KVv2 is a KV version-2 secrets-engine helper rooted at a mount (default "secret"). It performs the version-2 path rewriting (data/, metadata/, delete/, undelete/, destroy/) and the versioned request bodies the engine expects.
func (*KVv2) Delete ¶
Delete soft-deletes the latest version of the KV v2 secret at path (DELETE <mount>/data/<path>).
func (*KVv2) DeleteMetadata ¶
DeleteMetadata deletes the KV v2 metadata (and every version) for path (DELETE <mount>/metadata/<path>).
func (*KVv2) DeleteVersions ¶
DeleteVersions soft-deletes specific versions of the KV v2 secret at path (POST <mount>/delete/<path>).
func (*KVv2) Destroy ¶
Destroy permanently destroys specific versions of the KV v2 secret at path (POST <mount>/destroy/<path>).
func (*KVv2) Read ¶
Read reads the latest version of the KV v2 secret at path (GET <mount>/data/<path>).
func (*KVv2) ReadMetadata ¶
ReadMetadata reads the KV v2 metadata for path (GET <mount>/metadata/<path>).
func (*KVv2) ReadVersion ¶
ReadVersion reads a specific version of the KV v2 secret at path (GET <mount>/data/<path>?version=N).
func (*KVv2) Undelete ¶
Undelete restores previously soft-deleted versions of the KV v2 secret at path (POST <mount>/undelete/<path>).
type Logical ¶
type Logical struct {
// contains filtered or unexported fields
}
Logical is the logical-backend endpoint group (Vault::Client#logical): the generic read/write/list/delete verbs over an arbitrary API path, the primitive every higher-level helper (KV, transit, sys, auth) builds on.
func (*Logical) Delete ¶
Delete deletes the secret at path (DELETE /v1/<path>, Vault::Logical#delete).
func (*Logical) List ¶
List lists the keys at path (LIST /v1/<path>, Vault::Logical#list): a 404 yields a nil secret and nil error.
type Request ¶
type Request struct {
// Method is the upper-case HTTP method ("GET", "PUT", "POST", "DELETE",
// "LIST").
Method string
// URL is the fully-built request URL.
URL string
// Headers are the outgoing headers.
Headers map[string]string
// Body is the JSON-encoded request body, or nil.
Body []byte
}
Request is the prepared HTTP request the client hands to a Doer: the fully built URL (Address + "/v1/" + path), the method, the header set (including X-Vault-Token / X-Vault-Namespace when configured) and the JSON-encoded body (nil for a bodyless request). It is a transport-agnostic value so a host can wire it to any HTTP stack.
type Response ¶
type Response struct {
// StatusCode is the HTTP status code.
StatusCode int
// Body is the raw response body.
Body []byte
// Header carries the response headers.
Header map[string][]string
}
Response is the transport result a Doer returns: the HTTP status code, the raw response body, and the response headers. The client decodes the body into a Secret (2xx) or maps the status onto a VaultError (non-2xx).
type Secret ¶
type Secret struct {
// RequestID is the server-assigned request identifier.
RequestID string `json:"request_id"`
// LeaseID is the lease identifier for a leased secret ("" when not leased).
LeaseID string `json:"lease_id"`
// LeaseDuration is the lease TTL in seconds.
LeaseDuration int `json:"lease_duration"`
// Renewable reports whether the lease can be renewed.
Renewable bool `json:"renewable"`
// Data is the secret payload (Vault::Secret#data).
Data map[string]any `json:"data"`
// Warnings carries any server-side warnings (Vault::Secret#warnings).
Warnings []string `json:"warnings"`
// Auth carries the authentication response for a login/token call
// (Vault::Secret#auth); nil otherwise.
Auth *SecretAuth `json:"auth"`
// WrapInfo carries response-wrapping metadata when the call was wrapped; nil
// otherwise (Vault::Secret#wrap_info).
WrapInfo map[string]any `json:"wrap_info"`
}
Secret is the decoded OpenBao/Vault response envelope (Vault::Secret). Reads and writes that return data populate Data; leased secrets populate LeaseID/LeaseDuration/Renewable; login and token responses populate Auth. Any server-side warnings are surfaced in Warnings.
type SecretAuth ¶
type SecretAuth struct {
// ClientToken is the issued Vault token (auth.client_token).
ClientToken string `json:"client_token"`
// Accessor is the token accessor.
Accessor string `json:"accessor"`
// Policies are the token's policies.
Policies []string `json:"policies"`
// TokenPolicies are the token's token-scoped policies.
TokenPolicies []string `json:"token_policies"`
// Metadata is the token metadata map.
Metadata map[string]any `json:"metadata"`
// LeaseDuration is the token TTL in seconds.
LeaseDuration int `json:"lease_duration"`
// Renewable reports whether the token can be renewed.
Renewable bool `json:"renewable"`
}
SecretAuth is the authentication half of a Secret (Vault::Secret#auth), populated by login and token endpoints.
type Sys ¶
type Sys struct {
// contains filtered or unexported fields
}
Sys is the system-backend endpoint group (Vault::Client#sys): server health and seal status, secrets-engine mount management, ACL policy management and lease management.
func (*Sys) DeletePolicy ¶
DeletePolicy deletes the named ACL policy (DELETE sys/policies/acl/<name>).
func (*Sys) DisableMount ¶
DisableMount unmounts the secrets engine at path (DELETE sys/mounts/<path>).
func (*Sys) EnableMount ¶
EnableMount mounts a secrets engine of the given type at path (POST sys/mounts/<path>). Extra options (description, config, options) are merged into the request body.
func (*Sys) Health ¶
Health returns the server health (GET sys/health). Its payload is a flat object (initialized/sealed/standby/version/…), so it is returned as a raw map rather than a Secret envelope.
func (*Sys) LookupLease ¶
LookupLease looks up a lease by id (PUT sys/leases/lookup).
func (*Sys) Mounts ¶
Mounts lists the mounted secrets engines (GET sys/mounts) as a raw map keyed by mount path.
func (*Sys) Policies ¶
Policies lists the ACL policy names (GET sys/policies/acl). The names are in the returned secret's Data under "keys"/"policies".
func (*Sys) PutPolicy ¶
PutPolicy writes the named ACL policy from an HCL/JSON rules string (PUT sys/policies/acl/<name>).
func (*Sys) RenewLease ¶
RenewLease renews a lease by id, requesting increment seconds of additional TTL (PUT sys/leases/renew).
func (*Sys) RevokeLease ¶
RevokeLease revokes a lease by id (PUT sys/leases/revoke).
type TokenAuth ¶
type TokenAuth struct {
// contains filtered or unexported fields
}
TokenAuth is the token self-management helper (auth/token).
func (*TokenAuth) LookupSelf ¶
LookupSelf looks up the current token (GET auth/token/lookup-self).
func (*TokenAuth) RenewSelf ¶
RenewSelf renews the current token, requesting increment seconds of additional TTL (POST auth/token/renew-self).
func (*TokenAuth) RevokeSelf ¶
RevokeSelf revokes the current token (POST auth/token/revoke-self).
type Transit ¶
type Transit struct {
// contains filtered or unexported fields
}
Transit is a transit secrets-engine helper rooted at a mount (default "transit"): encryption, decryption, rewrapping, signing, verification and data-key generation as cryptographic operations performed by the server without exposing the key.
func (*Transit) Decrypt ¶
Decrypt decrypts ciphertext with the named key (POST <mount>/decrypt/<key>). The returned secret's Data carries "plaintext" (base64-encoded by the engine).
func (*Transit) Encrypt ¶
Encrypt encrypts plaintext with the named key (POST <mount>/encrypt/<key>). The plaintext is base64-encoded as the engine requires; an optional context (for a keyed/derived key) is base64-encoded too. The returned secret's Data carries "ciphertext".
func (*Transit) GenerateDataKey ¶
GenerateDataKey generates a new high-entropy data key wrapped (and optionally returned in plaintext) by the named key (POST <mount>/datakey/<keyType>/<key>). keyType is "plaintext" or "wrapped".
func (*Transit) Rewrap ¶
Rewrap rewraps ciphertext to the key's latest version (POST <mount>/rewrap/<key>).
type UserpassAuth ¶
type UserpassAuth struct {
// contains filtered or unexported fields
}
UserpassAuth is the Userpass login helper rooted at a mount (default "userpass").
type VaultError ¶
type VaultError struct {
// Kind names the specific gem error subclass (see the Err* sentinels).
Kind ErrorKind
// Message is the error text (VaultError#message).
Message string
// StatusCode is the HTTP status for an HTTPError (0 for a connection error).
StatusCode int
// Errors is the API "errors" array returned in the response body, if any.
Errors []string
// Cause is the underlying transport error for an HTTPConnectionError.
Cause error
}
VaultError is the root of the vault gem's error tree (Vault::VaultError). Every error carries a human message; errors raised from an HTTP response also carry the response StatusCode and the API "errors" array so callers can inspect what the server reported. Transport failures carry the underlying error as VaultError.Cause.
The concrete kinds are distinguished by VaultError.Kind; the predicate helpers (IsHTTPError, IsHTTPClientError, …) and the sentinel values (ErrHTTPError, …) let callers match with errors.Is, mirroring Ruby's rescue of a Vault::HTTPError subclass.
func (*VaultError) Error ¶
func (e *VaultError) Error() string
Error implements the error interface (VaultError#message).
func (*VaultError) Is ¶
func (e *VaultError) Is(target error) bool
Is reports whether e matches target: true when target is a *VaultError whose Kind is e's Kind or an ancestor of it, so errors.Is(err, ErrHTTPError) matches any client/server/connection error and errors.Is(err, ErrVaultError) matches every gem error — mirroring Ruby's rescue of a superclass.
func (*VaultError) Unwrap ¶
func (e *VaultError) Unwrap() error
Unwrap exposes the underlying transport error for errors.Is/As on the cause.
