Architecture
Big picture
The CLI assembles two things and binds them together: a key-value (KV) store that holds the unseal keys and root token, and a HashiCorp Vault Application Programming Interface (API) client that points at one Vault server. The --mode flag picks which KV backend to build, the Vault SDK builds the client, and internalVault.New ties them into one vault value that every subcommand operates through (cmd/bank-vaults/unseal.go:86). The Vault interface is the only surface the commands touch (internal/vault/operator_client.go:44).
Components
CLI commands
The cmd/bank-vaults/ package holds the cobra subcommands. main.go defines the root command, every flag, and the --mode constants (cmd/bank-vaults/main.go:39). init.go, unseal.go, and configure.go are the three core jobs; metrics.go adds a Prometheus exporter, and common.go holds the shared KV store builder. main() parses flags and calls execute() to run the cobra root (cmd/bank-vaults/main.go:300, cmd/bank-vaults/main.go:140).
Vault operations (internal/vault)
internal/vault/operator_client.go is the operation core. It declares the Vault interface (internal/vault/operator_client.go:44) and the vault struct that implements it (internal/vault/operator_client.go:120). Sibling files implement the pieces of configure: auth_methods.go, secrets_engines.go, policies.go, audits.go, plugins.go, identity_groups.go, and startup_secrets.go.
KV backends (pkg/kv)
pkg/kv/kv.go declares the Service interface that every backend implements, with just Set and Get (pkg/kv/kv.go:53). Each subdirectory is one backend: awskms, gckms, azurekv, alibabakms/alibabaoss, ocikms/oci, s3, gcs, vault, k8s, hsm, file, dev, and multi.
Vault SDK (external)
The CLI does not carry its own Vault client. It imports github.com/bank-vaults/vault-sdk/vault and calls vault.NewRawClient() to get a HashiCorp Vault API client (cmd/bank-vaults/unseal.go:24, cmd/bank-vaults/unseal.go:80).
How a request flows
Tracing bank-vaults unseal --mode aws-kms-s3:
- The command's
Runreads flags into anunsealCfg(cmd/bank-vaults/unseal.go:60,cmd/bank-vaults/unseal.go:65). kvStoreForConfigbuilds the KV store for the chosen mode (cmd/bank-vaults/unseal.go:74). Foraws-kms-s3it creates an S3 backend withs3.New, wraps it withawskms.New, and returnsmulti.New(services)so several regions can be combined (cmd/bank-vaults/common.go:162,cmd/bank-vaults/common.go:175,cmd/bank-vaults/common.go:185).vault.NewRawClient()builds the Vault API client (cmd/bank-vaults/unseal.go:80).internalVault.Newbinds the store and client into avaultvalue (cmd/bank-vaults/unseal.go:86).- The command enters a loop that calls
unseal(ctx, unsealConfig, v)and sleeps forunsealPeriodbetween attempts (cmd/bank-vaults/unseal.go:137). unsealchecksv.Sealed()and returns early if Vault is already unsealed, otherwise callsv.Unseal(ctx)(cmd/bank-vaults/unseal.go:154,cmd/bank-vaults/unseal.go:162,cmd/bank-vaults/unseal.go:170).(*vault).Unsealloops over key IDs, pulls each from the KV store, and sends it to Vault (internal/vault/operator_client.go:197). With the awskms backend theGetreads ciphertext from S3 and decrypts it through KMS before the key reaches Vault (pkg/kv/awskms/awskms.go:86).
Key design decisions
The KV store is layered for envelope encryption. A KMS backend implements kv.Service but holds another kv.Service inside it: awsKMS carries a store kv.Service field (pkg/kv/awskms/awskms.go:38). Set encrypts then writes to the inner store, and Get reads from the inner store then decrypts (pkg/kv/awskms/awskms.go:109, pkg/kv/awskms/awskms.go:86). The unseal key is always ciphertext at rest in the object store.
The multi store multiplexes one logical store over several backends, so the AWS path can write the same key to S3 buckets in several regions (cmd/bank-vaults/common.go:185).
The configuration decoder fails on unknown keys. Configure sets ErrorUnused: true on its mapstructure decoder so a typo in the YAML becomes an error rather than a silent no-op (internal/vault/operator_client.go:574). This matters because purge mode deletes Vault state not present in the YAML.
Extension points
- KV backends implement the two-method
kv.Serviceinterface (pkg/kv/kv.go:53); a new key store is a new package underpkg/kvplus a case inkvStoreForConfig(cmd/bank-vaults/common.go:81). - The
--modeconstants enumerate the supported backends, includinghsmandhsm-k8sfor PKCS#11 devices (cmd/bank-vaults/main.go:39,cmd/bank-vaults/common.go:303). - The wider umbrella extends Vault through the Operator's CRD and the Secrets Webhook, in separate repositories.