Skip to content

Share one client across components

You want configuration from Vault and signing or encryption through Vault's transit engine, over one client rather than three.

Build one source, inject the client

import (
    configvault "gitlab.com/phpboyscout/go/config-vault"
    "gitlab.com/phpboyscout/go/vaultclient"
)

src := vaultclient.Ambient(
    vaultclient.WithAddress("https://vault.example.com:8200"),
)

client, err := src.VaultClient(ctx)
if err != nil {
    return err
}

backend := configvault.FromClient(client, "secret", "app/config")

config-vault takes the client directly — Vault is the provider where the client is the prerequisite, so no further seam is needed.

When you already assembled a config

cfg := vaultapi.DefaultConfig()
cfg.HttpClient = myInstrumentedClient

src, err := vaultclient.FromConfig(cfg)

That rung checks cfg.Error for you — the field DefaultConfig populates instead of returning an error — so a broken config fails here rather than at the first request.

When you already have a client

src, err := vaultclient.FromClient(client)

Useful when something else in your process owns the Vault connection and you want the same one used everywhere.

Namespaces

src := vaultclient.Ambient(vaultclient.WithNamespace("team-a"))

Or VAULT_NAMESPACE, which DefaultConfig reads. Vault Enterprise only.

Renewing the token

The client you get holds the token that was set when it was built, and nothing renews it. If your process outlives the token's TTL, keep a vaultapi.LifetimeWatcher running against the client and rebuild the source when renewal finally fails:

client, err := src.VaultClient(ctx)
if err != nil {
    return err
}

watcher, err := client.NewLifetimeWatcher(&vaultapi.LifetimeWatcherInput{
    Secret: authSecret,
})
if err != nil {
    return err
}

go watcher.Start()
defer watcher.Stop()

This is the caller's job rather than the module's, and why is worth reading before you decide it is not your problem.

Bounding and scoping

src := vaultclient.Ambient(
    vaultclient.WithBuildTimeout(5*time.Second),
    vaultclient.WithLifetimeContext(appCtx),
)

Per attempt, not a total budget. vaultapi.NewClient does no network I/O, so the bound matters less here than for a provider whose resolution reaches a metadata service — but it costs nothing to set.