Yesterday I wrote about moving autonomous-agent secrets out of a flat .env file. That work gave the agent a separate Vaultwarden identity, access to a restricted collection, and an audit trail that reaches Graylog and Wazuh.
It was a useful improvement. It was not the end of the secrets-management work.

Vaultwarden is good at storing credentials that people create, own, recover, and sometimes share with automation. It is not a workload identity system, a certificate authority, or a dynamic credential broker. Treating it as one would overstate what I built and eventually force the wrong product into the wrong job.
Today I added HashiCorp Vault to the lab. I did not replace Vaultwarden. I separated the credential classes and gave each system a job that fits how it was designed.
That decision also brought me back to Chapter 9 of my book, Cybersecurity Architect's Handbook, Second Edition. One of the Chapter 9 labs walks through installing and configuring HashiCorp Vault. The lab teaches the mechanics, but the architectural lesson is broader: deploying a secrets platform is not the same as building a secrets architecture. The design still has to address trust, identity, policy, recovery, audit, failure, and operational ownership.
This time I applied that lesson to my own environment.
Vaultwarden and Vault solve different problems
My recommendation is not to replace Vaultwarden with HashiCorp Vault. I use them for different credential classes.
| Capability | Vaultwarden | HashiCorp Vault |
|---|---|---|
| Human passwords and logins | Strong fit | Poor fit |
| Browser and mobile autofill | Strong fit | Not designed for it |
| Shared human and automation records | Strong fit | Possible, but API and CLI oriented |
| Workload authentication | Limited | Strong fit |
| Short-lived credentials | Limited | Core capability |
| Dynamic database credentials | No | Yes |
| Internal PKI and short-lived certificates | No | Yes |
| SSH certificate authority | No | Yes |
| Cryptography as a service | No | Transit secrets engine |
| Fine-grained machine policy | Collection-oriented | Path and capability policies |
| Secret leases and revocation | No | Yes |
| Server-side request audit trail | Limited, client-reported events | Strong audit-device model |
| Operational complexity | Low | Substantial |
| Failure impact | Humans and current automation cannot retrieve secrets | Workloads may fail to start, authenticate, or renew leases |
Vaultwarden remains the better location for:
- Human website and infrastructure logins
- Recovery codes and break-glass credentials
- Credentials I use interactively
- Vendor credentials that lack machine-oriented integration
- Shared records where operator ownership and browser or mobile access matter
- Recovery metadata for the secrets infrastructure itself
HashiCorp Vault fits the machine side through purpose-built secrets engines.
- Machine-only API credentials that still exist in protected local configuration
- Short-lived workload tokens
- Dynamic database credentials where the database supports them
- Internal PKI for services and service-to-service mutual TLS
- SSH certificates instead of distributing more long-lived private keys
- Encryption, signing, HMAC, and key rotation through the Transit secrets engine
- Central policy and server-side audit for autonomous-agent access
The split also protects recovery. Vault must not be the only place that stores the information needed to recover Vault. Vaultwarden remains an independent human-facing recovery and break-glass system.
Vaultwarden
Human logins
Recovery credentials
MFA recovery
Break-glass access
Manually used vendor credentials
Vault recovery records and documentation
HashiCorp Vault
Machine-only KV secrets
Dynamic credentials
Internal PKI
SSH certificate authority
Transit cryptography
Short-lived workload tokens
Server-side access audit
Graylog and Wazuh
Vault audit telemetry
Authentication and policy failures
Lease and token anomalies
Administrative changes
Seal, leadership, and availability events
The systems overlap at a few points, but they do not compete for the same primary role.
Installing Vault was the easy part
Chapter 9 of Cybersecurity Architect's Handbook, Second Edition includes a hands-on lab for installing and configuring HashiCorp Vault. That foundation matters. An architect should understand what the platform does at the command line and API level before deciding where it belongs in an enterprise design.
The install itself, however, is only one part of the control plane. A working service can still have weak bootstrap trust, an overpowered operator, untested backups, exposed recovery material, or audit logs that create a second secret store inside the SIEM.
I deployed Vault 2.0.4 on a dedicated Debian 13 virtual machine. The service uses TLS and Integrated Storage with Raft.[10] I installed it from HashiCorp's official repository after validating the package-signing key. The listener permits TLS 1.2 and TLS 1.3.
I also accounted for the license. Vault 1.15 and later use the Business Source License 1.1 with HashiCorp's additional use grant. My self-hosted internal use falls within that grant, but BSL 1.1 is not an OSI-approved open-source license. That distinction matters when selecting the platform for a product, managed service, or redistributable solution.
Before sending a password or installing a key, I verified the server's SSH host identity against an out-of-band fingerprint. The permanent connection uses strict host-key checking and a dedicated known-hosts file. Password authentication was only a bootstrap mechanism. After the dedicated automation key worked, I locked the account password and removed the account from the broad sudo group.
The automation account can now run only two fixed operational actions: report Vault status and retrieve sanitized audit events. It cannot use a general-purpose root shell through sudo.
This is the kind of detail that disappears when a deployment record says only "Vault installed successfully."
Initialization is a custody decision
I initialized Vault with three Shamir key shares and a threshold of two. Recovery records went into Vaultwarden only after a Vaultwarden backup. None of those values went into Git, chat, Wiki.js, shell output, or the deployment documentation.
The initial root token was treated as bootstrap material. I used it to establish the first operational controls, then revoked it and verified that it no longer authenticated. Routine administration now uses a non-root operator identity with policy-bound access. Workloads use narrower authentication and do not inherit the operator's capabilities.
That separation is deliberate:
Initial root token
-> bootstrap only
-> establish authentication, policy, audit, and recovery
-> revoke and verify revocation
Operator identity
-> approved administrative paths
-> no routine root-token use
Workload identity
-> only the secret or issuance path required by the workload
-> short Vault token lifetime
-> revocable without changing the human operator account
The recovery design still has limitations. The current recovery records are held in the existing CIPHER-accessible Vaultwarden collection. I did not move them, add another custodian, or create a new offline recovery arrangement during this change. Those are custody decisions, not cleanup tasks an autonomous agent should make on its own.
A vault does not make a static vendor key dynamic
This distinction matters enough to say plainly: moving a static API key into Vault does not make the underlying credential dynamic.

The UniFi Protect key, Graylog token, Wazuh credentials, Wiki.js token, and similar credentials remain long-lived unless the target platform supports automated issuance or rotation. Vault can control which workload retrieves a key. It can issue a short-lived Vault token that authorizes retrieval. It can audit the request, deliver the value through Vault Agent, and coordinate a rotation workflow.
Vault cannot revoke or regenerate a vendor key by itself. I still need an authorized integration with the target platform to create the replacement, test it, update every consumer, and revoke the old value.
That means KV migration improves access control and auditability, but it does not magically fix the lifecycle of the credential stored in KV. I am keeping that line visible as the remaining .env consumers move one at a time. I will not delete a secret from the old source until the replacement retrieval path works, the consumer has been tested, and rollback is understood.
The dynamic database secrets engine is different. Where the database supports it, Vault can create a credential on demand, attach a lease, and revoke it when the lease ends.[4][8] The same distinction applies to certificates. Vault's PKI secrets engine can issue a short-lived certificate from a constrained role.[5] It is not just retrieving a certificate that somebody generated months ago.
This is the practical progression from the previous Vaultwarden work. Vaultwarden reduced broad file access and gave the agent a separate human-style vault identity. HashiCorp Vault gives workloads a machine-oriented control plane with policies, leases, revocation, and mandatory server-side request handling.
Internal PKI belongs in the architecture
I configured Vault as the online internal issuing certificate authority. I did not make Vault the root CA.

The hierarchy uses a separately controlled P-384 root and a Vault-managed P-384 intermediate. The root has a path-length constraint of one. The intermediate has a path-length constraint of zero, and its private key was generated inside Vault. The key is non-exportable.
secdoc Internal Root CA
P-384, separately controlled, path length 1
-> secdoc Internal Issuing CA 01
P-384, key held by Vault, path length 0
-> internal server certificates, maximum 30 days
-> internal client certificates, maximum 7 days
-> constrained UniFi TLS certificates, maximum 30 days
-> constrained UniFi RadSec clients, maximum 7 days
This limits the effect of a Vault compromise. An attacker with issuance rights could misuse the online intermediate until I revoke it, but could not create another intermediate trusted by the estate without the root. The tradeoff is operational. Root ceremonies are slower, and losing the root would prevent an orderly intermediate replacement. That is why root recovery material and its ownership cannot depend only on Vault.
I issued a one-hour validation certificate, verified the chain and private-key match, revoked it, and confirmed the revocation through Vault. The public root and issuing chain are versioned. Private keys, passphrases, tokens, unseal material, and Raft snapshots are not.
The Vault listener still uses an independent bootstrap CA. I left it that way on purpose. Moving the listener to the new hierarchy before trust distribution and renewal are proven would create unnecessary recovery coupling. The PKI service should not become the only path to restoring the TLS endpoint used to operate the PKI service.
Vault can issue UniFi certificates, but that is only half the integration
Vault can issue certificates that a UniFi component might use. It cannot force an unsupported UniFi product to consume them safely.

The current design includes constrained roles for UniFi TLS servers and RadSec clients. No production UniFi certificate or trust store was changed today.
RadSec is a strong candidate because supported UniFi Network versions accept a PEM client certificate, private key, and CA bundle. External RADIUS and EAP-TLS are also reasonable PKI uses, but certificate issuance does not solve endpoint enrollment. Supplicants still need MDM, SCEP, EST, or another controlled delivery and renewal mechanism.
UniFi application HTTPS and captive portals are conditional. I need to verify the exact product, firmware, import format, chain behavior, renewal interface, upgrade persistence, and rollback path before replacing a working certificate. If the product does not expose a stable certificate-management interface, a supported reverse proxy may be safer than modifying vendor-managed files.
I will not replace device adoption certificates, firmware-managed certificates, or private device-to-controller trust through unsupported filesystem changes. I also will not use the general Vault intermediate for TLS inspection. Deep inspection needs its own subordinate CA, a limited client trust scope, a privacy review, and a fast rollback procedure.
Issuing a certificate is easy. Keeping the correct clients trusting it, renewing it before expiration, and recovering when the import fails is the actual integration work.
Audit data can become secret data
Vault audit devices provide server-side request visibility, but raw Vault audit records are not ordinary application logs.[9] Depending on configuration and request type, they can contain sensitive request, response, identity, token-related, or error material. Copying raw records into multiple logging platforms would enlarge the secret-handling boundary.

I enabled a file audit device and built a fixed, root-owned exporter that emits only an allowlisted metadata projection. It removes request and response bodies, client tokens, token accessors, entity identifiers, authentication metadata, secret values, headers, cookies, wrapped tokens, and raw errors.
Every five minutes, a collector sends the sanitized records independently to Graylog and Wazuh. Graylog keeps the searchable operational history. Wazuh evaluates the same normalized events for authentication failures, policy changes, audit-device changes, destructive operations, seal activity, and other administrative behavior.
The collector tracks delivery state separately for each destination. If Wazuh is unavailable after Graylog accepts an event, the Wazuh copy remains pending without producing another Graylog copy.
I tested the path with real Vault activity. The final acceptance search found 280 Vault audit records in Graylog with no failed shards and no prohibited fields. Wazuh had 42 indexed Vault alerts over the tested 24-hour window with no failed shards. An immediate collector rerun produced zero duplicate deliveries.
The numbers are less important than the boundary. The SIEM can tell me what class of operation occurred, whether it succeeded, and which policy-sensitive path was involved. It cannot reconstruct the secret-bearing request.
A snapshot is not a recovery test
Integrated Storage uses Raft, which gives Vault a built-in snapshot mechanism and supports a future highly available topology. The current deployment is still one node. Raft storage does not make one node highly available.

I created protected snapshots during the build, but I did not accept the backup because a file existed. I restored the final post-PKI snapshot into an isolated Vault 2.0.4 instance and tested the result.
The restore proved:
- The two-of-three Shamir threshold still worked
- The initial root token remained revoked
- Operator authentication and policies survived
- The audit device returned
- KV data returned
- The PKI mount, issuer hierarchy, and constrained roles returned
- The restored intermediate could issue a chain-valid certificate
- The restored certificate could be revoked
That test found the kind of problem a snapshot inspection alone cannot find. The restored audit device expected its production absolute path, so the isolated environment needed a safe user-space path mapping before Vault could load the recovered state. The snapshot was valid. The recovery environment was incomplete. I fixed the environment and reran the test rather than writing "restore successful" based on the snapshot header.
The single-node design remains a pilot limitation. Existing certificates continue to validate during a Vault outage, but workloads cannot obtain new secrets, renew leases, or request certificates. I documented that failure mode rather than describing the service as highly available.
The architecture behind the lab
The Chapter 9 Vault lab in Cybersecurity Architect's Handbook, Second Edition gives readers a way to work with the technology rather than only reading about it. Today's deployment applied the same concepts beyond the basic install.

I authenticated the infrastructure before trusting it. I separated human, operator, bootstrap, recovery, and workload identities. I restricted the automation account instead of granting broad root access. I kept recovery outside the system being recovered. I designed certificate issuance around an offline root and constrained online intermediate. I sanitized audit data before expanding its trust boundary. I restored the backup and exercised the recovered PKI rather than treating a snapshot as evidence by itself.
Those are familiar architecture principles:
- Establish trust before sending credentials
- Give each identity only the access required for its role
- Separate operational administration from workload access
- Keep recovery independent from the protected service
- Design credential issuance, rotation, revocation, and expiration as one lifecycle
- Treat audit data according to its sensitivity
- Test failure and recovery paths while the system is healthy
- Record accepted limitations without relabeling them as future features
The technology is HashiCorp Vault. The work is security architecture.
What remains
I now have the control plane needed to move machine-only secrets out of the remaining general-purpose .env file. That migration is not complete. Each consumer still needs a scoped workload identity, a policy, a retrieval or issuance method, a rotation plan, and an acceptance test.

Dynamic database credentials are useful only after I integrate each database and prove application behavior during lease renewal. SSH certificates are useful only after I design host trust, principal restrictions, TTLs, renewal, and emergency access. Transit is useful only when an application is designed around ciphertext and key-version lifecycle instead of treating Vault as a remote command-line encryption tool.
The internal root still needs controlled trust distribution. UniFi integration needs product-by-product validation. The one-node Raft pilot still has an availability limitation. Recovery custody remains concentrated because I deliberately did not change custodianship during this deployment.
That is an honest status. Vault is running, hardened, audited, backed up, restored, and issuing certificates through a constrained intermediate. It has not made every credential dynamic, removed every bootstrap dependency, or made the secrets service highly available.
Vaultwarden work changed how the agent retrieves shared credentials. Today's Vault deployment adds the machine side: workload identity, path-based policy, leases, revocation, PKI, server-side audit, and tested recovery.
I need both systems. Vaultwarden answers who owns and recovers the human credential. HashiCorp Vault answers which workload may obtain or create a machine credential, for how long, under which policy, and with what server-side record.
That division is much stronger than trying to make one vault solve every problem.