FreeBSD.software
Home/Guides/HashiCorp Vault on FreeBSD: Secrets Management Review
review·2026-04-09·10 min read

HashiCorp Vault on FreeBSD: Secrets Management Review

In-depth review of HashiCorp Vault on FreeBSD: installation, dev and production modes, secrets engines, authentication methods, PKI certificate management, and policy configuration.

HashiCorp Vault on FreeBSD: Secrets Management Review

HashiCorp Vault is a secrets management tool that centralizes the storage, access, and distribution of sensitive data -- API keys, database credentials, TLS certificates, encryption keys, and any other secret your infrastructure needs. Instead of scattering secrets across configuration files, environment variables, and ad-hoc password managers, Vault provides a single API-driven system with fine-grained access control, audit logging, and automatic secret rotation. On FreeBSD, Vault runs as a native binary with no runtime dependencies, integrates with the rc.d service framework, and works well in jail-based architectures. This review covers installation, development and production deployment modes, secrets engines, authentication methods, PKI certificate management, policy configuration, and operational considerations.

What Vault Solves

The problem Vault addresses is secret sprawl. In a typical infrastructure:

  • Database passwords are stored in application configuration files, sometimes in plaintext.
  • API keys are committed to version control or passed through environment variables.
  • TLS certificates are manually generated and distributed, with no central tracking of expiration.
  • SSH keys are distributed to servers with no revocation mechanism.
  • Different teams manage secrets in different ways with no audit trail.

Vault centralizes all of this. Applications request secrets from Vault at runtime via an HTTP API. Vault authenticates the requester, checks access policies, logs the access, and returns the secret. Secrets can be static (stored values) or dynamic (generated on demand with automatic expiration).

Installation on FreeBSD

Binary Package

sh
pkg install vault

This installs the Vault binary at /usr/local/bin/vault and the rc.d script at /usr/local/etc/rc.d/vault.

Manual Binary Installation

For the latest version not yet in the ports tree:

sh
fetch https://releases.hashicorp.com/vault/1.17.0/vault_1.17.0_freebsd_amd64.zip unzip vault_1.17.0_freebsd_amd64.zip -d /usr/local/bin/ chmod +x /usr/local/bin/vault

Verify Installation

sh
vault version vault -autocomplete-install

The autocomplete install adds shell completions for vault commands -- useful for interactive use.

Development Mode

Dev mode runs Vault entirely in memory with no configuration file. It is designed for local development and testing, not production.

Start Vault in dev mode:

sh
vault server -dev

Dev mode outputs a root token and sets up an in-memory storage backend. In a second terminal:

sh
export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='root-token-from-output' vault status vault secrets list

Dev mode characteristics:

  • All data is in memory -- nothing survives a restart.
  • TLS is disabled -- communication is over plain HTTP.
  • The root token is printed to stdout.
  • The KV secrets engine is mounted at secret/ by default.
  • Auto-unsealing is enabled -- no unseal keys needed.

Use dev mode for learning, testing policies, and developing integrations. Never use dev mode for production.

Production Deployment

A production Vault deployment requires persistent storage, TLS, and proper initialization.

Configuration File

Create /usr/local/etc/vault/vault.hcl:

sh
storage "file" { path = "/var/db/vault/data" } listener "tcp" { address = "127.0.0.1:8200" tls_cert_file = "/usr/local/etc/vault/tls/vault.crt" tls_key_file = "/usr/local/etc/vault/tls/vault.key" } api_addr = "https://127.0.0.1:8200" cluster_addr = "https://127.0.0.1:8201" ui = true disable_mlock = false log_level = "info"

Create required directories:

sh
mkdir -p /var/db/vault/data mkdir -p /usr/local/etc/vault/tls chown -R vault:vault /var/db/vault chown -R vault:vault /usr/local/etc/vault

TLS Certificates

Generate a self-signed certificate for initial setup (replace with a proper certificate for production):

sh
openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes \ -keyout /usr/local/etc/vault/tls/vault.key \ -out /usr/local/etc/vault/tls/vault.crt \ -subj "/CN=vault.example.com" \ -addext "subjectAltName=DNS:vault.example.com,IP:127.0.0.1" chmod 600 /usr/local/etc/vault/tls/vault.key chown vault:vault /usr/local/etc/vault/tls/*

Storage Backends

The file storage backend works for single-node deployments. For high availability:

  • Raft (integrated storage) -- Vault's built-in consensus storage. No external dependencies. Recommended for most deployments.
  • Consul -- HashiCorp's service mesh and KV store. Adds complexity but provides service discovery integration.
  • PostgreSQL -- database-backed storage. Works well on FreeBSD where PostgreSQL is a first-class citizen.

Raft storage configuration:

sh
storage "raft" { path = "/var/db/vault/raft" node_id = "vault-1" }

Start and Initialize

Enable and start Vault:

sh
sysrc vault_enable="YES" service vault start

Initialize Vault:

sh
export VAULT_ADDR='https://127.0.0.1:8200' export VAULT_CACERT='/usr/local/etc/vault/tls/vault.crt' vault operator init -key-shares=5 -key-threshold=3

This produces 5 unseal keys and a root token. Store the unseal keys securely -- losing them means losing access to Vault permanently. The -key-threshold=3 means any 3 of the 5 keys are needed to unseal Vault.

Unseal Vault (repeat with 3 different keys):

sh
vault operator unseal <key-1> vault operator unseal <key-2> vault operator unseal <key-3>

Verify status:

sh
vault status

The output should show Sealed: false after successful unsealing.

Secrets Engines

Secrets engines are plugins that store, generate, or encrypt data. Each engine is mounted at a path and provides a set of API endpoints.

KV (Key-Value) Secrets

The simplest secrets engine -- stores and retrieves static secrets.

Enable KV v2 (versioned):

sh
vault secrets enable -path=kv kv-v2

Store a secret:

sh
vault kv put kv/database/production username="dbadmin" password="s3cret-p@ss"

Retrieve a secret:

sh
vault kv get kv/database/production vault kv get -field=password kv/database/production

KV v2 maintains version history:

sh
vault kv get -version=1 kv/database/production vault kv metadata get kv/database/production

Database Secrets Engine

Generates dynamic database credentials that expire automatically. Applications request credentials from Vault, use them, and Vault revokes them after the TTL expires.

Enable the database engine:

sh
vault secrets enable database

Configure a PostgreSQL connection:

sh
vault write database/config/production \ plugin_name=postgresql-database-plugin \ connection_url="postgresql://{{username}}:{{password}}@localhost:5432/myapp?sslmode=disable" \ allowed_roles="readonly,readwrite" \ username="vault_admin" \ password="vault_admin_password"

Create a role that defines what credentials are generated:

sh
vault write database/roles/readonly \ db_name=production \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h"

Generate credentials:

sh
vault read database/creds/readonly

This returns a temporary username and password that expire after 1 hour. The application uses these credentials, and Vault automatically drops the database role when the TTL expires.

Transit Secrets Engine

Encryption as a service -- applications send plaintext to Vault, which returns ciphertext. The encryption keys never leave Vault.

Enable the transit engine:

sh
vault secrets enable transit vault write -f transit/keys/myapp-encryption

Encrypt data:

sh
vault write transit/encrypt/myapp-encryption plaintext=$(echo -n "sensitive data" | base64)

Decrypt data:

sh
vault write transit/decrypt/myapp-encryption ciphertext="vault:v1:..."

This is useful for applications that need to encrypt data at rest without managing encryption keys themselves.

PKI Secrets Engine

Vault can act as a certificate authority, issuing TLS certificates on demand. This eliminates manual certificate management and integrates certificate issuance into your automated infrastructure.

Set Up a Root CA

sh
vault secrets enable pki vault secrets tune -max-lease-ttl=87600h pki vault write -field=certificate pki/root/generate/internal \ common_name="Example Root CA" \ issuer_name="root-ca" \ ttl=87600h > /tmp/root_ca.crt vault write pki/config/urls \ issuing_certificates="https://vault.example.com:8200/v1/pki/ca" \ crl_distribution_points="https://vault.example.com:8200/v1/pki/crl"

Set Up an Intermediate CA

sh
vault secrets enable -path=pki_int pki vault secrets tune -max-lease-ttl=43800h pki_int vault write -format=json pki_int/intermediate/generate/internal \ common_name="Example Intermediate CA" \ issuer_name="intermediate-ca" \ | jq -r '.data.csr' > /tmp/intermediate.csr vault write -format=json pki/root/sign-intermediate \ csr=@/tmp/intermediate.csr \ format=pem_bundle \ ttl=43800h \ | jq -r '.data.certificate' > /tmp/intermediate.crt vault write pki_int/intermediate/set-signed certificate=@/tmp/intermediate.crt

Create a Role and Issue Certificates

sh
vault write pki_int/roles/example-dot-com \ allowed_domains="example.com" \ allow_subdomains=true \ max_ttl="720h" vault write pki_int/issue/example-dot-com \ common_name="app.example.com" \ ttl="72h"

This issues a TLS certificate valid for 72 hours. Applications can request certificates programmatically, and Vault handles issuance, renewal tracking, and revocation.

Authentication Methods

Vault supports multiple authentication methods for different client types.

Token Authentication

The default method. Tokens are created by authenticated users or by Vault itself:

sh
vault token create -policy="readonly" -ttl="1h"

AppRole

Designed for machine-to-machine authentication. An application receives a role ID (public) and a secret ID (private) to authenticate:

sh
vault auth enable approle vault write auth/approle/role/myapp \ token_policies="myapp-policy" \ token_ttl=1h \ secret_id_ttl=720h vault read auth/approle/role/myapp/role-id vault write -f auth/approle/role/myapp/secret-id

Applications authenticate by providing both IDs:

sh
vault write auth/approle/login \ role_id="role-id-value" \ secret_id="secret-id-value"

LDAP

For user authentication against an LDAP directory:

sh
vault auth enable ldap vault write auth/ldap/config \ url="ldaps://ldap.example.com" \ binddn="cn=vault,dc=example,dc=com" \ bindpass="bind-password" \ userdn="ou=users,dc=example,dc=com" \ userattr="uid" \ groupdn="ou=groups,dc=example,dc=com" \ groupattr="cn"

Policies

Policies define what secrets a token can access. They use HCL (HashiCorp Configuration Language) syntax.

Create a policy file /usr/local/etc/vault/policies/myapp.hcl:

sh
# Read database credentials path "database/creds/readonly" { capabilities = ["read"] } # Read KV secrets for myapp path "kv/data/myapp/*" { capabilities = ["read", "list"] } # Issue TLS certificates path "pki_int/issue/example-dot-com" { capabilities = ["create", "update"] } # Deny access to everything else (implicit)

Apply the policy:

sh
vault policy write myapp /usr/local/etc/vault/policies/myapp.hcl

List and read policies:

sh
vault policy list vault policy read myapp

Audit Logging

Enable audit logging to track all Vault access:

sh
vault audit enable file file_path=/var/log/vault/audit.log

Every request and response is logged in JSON format, with sensitive values hashed (HMAC-SHA256). The audit log tells you who accessed what secret, when, and from which IP address.

Create the log directory:

sh
mkdir -p /var/log/vault chown vault:vault /var/log/vault

FreeBSD-Specific Considerations

Memory Locking

Vault uses mlock to prevent secrets from being swapped to disk. On FreeBSD, the vault user needs appropriate permissions:

sh
# In /etc/sysctl.conf security.bsd.unprivileged_mlock=1

Or run Vault as root with disable_mlock = false in the configuration (less ideal but functional).

Jail Deployment

Vault runs well in a FreeBSD jail. Key considerations:

  • Ensure the jail has network access to port 8200 (and 8201 for cluster communication).
  • The vault data directory must be persistent across jail restarts.
  • Memory locking must be allowed in the jail.

Backup

Back up the Vault data directory:

sh
# For file storage backend zfs snapshot tank/vault@backup-$(date +%Y%m%d) # For Raft storage vault operator raft snapshot save /var/backups/vault/snapshot-$(date +%Y%m%d).snap

The Raft snapshot command creates a consistent point-in-time backup that can be restored to a new Vault cluster.

Verdict

HashiCorp Vault is the most capable secrets management tool available for FreeBSD infrastructure. It replaces ad-hoc secret distribution with a centralized, audited, policy-controlled system. The dynamic secrets capability -- generating database credentials, TLS certificates, and cloud access tokens on demand with automatic expiration -- fundamentally changes how applications handle sensitive data.

On FreeBSD, Vault runs cleanly as a single binary with no runtime dependencies. The file and Raft storage backends require no external services. The PKI secrets engine alone justifies deployment for organizations that manage more than a handful of TLS certificates.

The learning curve is real. Vault's concepts (sealing, policies, secrets engines, auth methods) require time to understand. But the operational payoff -- centralized audit logging, automatic credential rotation, and elimination of secret sprawl -- makes Vault worth the investment for any FreeBSD infrastructure beyond a single server.


Frequently Asked Questions

Can Vault run in a FreeBSD jail?

Yes. Vault runs in jails without modification. Ensure the jail allows memory locking (security.bsd.unprivileged_mlock=1 or equivalent jail parameter), has persistent storage for the data directory, and has network access on port 8200.

What happens if I lose the unseal keys?

You permanently lose access to the Vault data. The unseal keys are the only way to decrypt the master encryption key. Store them in physically separate, secure locations. Consider using Vault's auto-unseal feature with a cloud KMS or an HSM to avoid manual key management.

Should I use the file or Raft storage backend on FreeBSD?

For single-node deployments, the file backend is simpler. For high availability (multiple Vault nodes), use Raft -- it provides built-in consensus with no external dependencies. Raft is the recommended default for new deployments.

How do I rotate the root token?

Generate a new root token using the unseal keys: vault operator generate-root. After generating the new root token, revoke the old one: vault token revoke . In production, avoid using the root token for daily operations -- create specific tokens with limited policies instead.

Can Vault manage SSH access on FreeBSD?

Yes. The SSH secrets engine can sign SSH public keys with a CA certificate, providing certificate-based SSH authentication. This eliminates the need to distribute and manage authorized_keys files across servers. Configure the SSH CA, create roles, and have users request signed certificates from Vault before connecting.

How much memory does Vault need on FreeBSD?

Vault uses 50-200 MB of RAM for a typical deployment with the file or Raft backend. Memory usage increases with the number of concurrent connections and the size of the secrets engine data. For a small team (under 50 users/applications), 512 MB of RAM is sufficient.

Get more FreeBSD guides

Weekly tutorials, security advisories, and package updates. No spam.