You can store Linux usernames and passwords in Hashicorp Vault, and the workflow is very clean once you get the hang of it. I am working to improve automation and reproducibility in my homelab infrastructure, using Vault as the single source of truth for credentials.
You may find more detailed documentation directly from hashicorp.
KV – Secrets Engines | Vault | HashiCorp Developer
SSH secrets engine | Vault | HashiCorp Developer
1. Make sure KV v2 is enabled
Most Vault installs already have this, but if not:
vault secrets enable -path=secret kv-v2
You only do this once.
2. Add a Linux server credential (username + password)
Let’s say you want to store credentials for a server called web01.
Option A — Store username + password as separate fields
vault kv put secret/linux/web01 \
username="owen" \
password="SuperSecurePassword123"
Option B — Store multiple accounts under one server
vault kv put secret/linux/web01 \
root_password="RootPass123" \
deploy_user="deploy" \
deploy_password="DeployPass456"
Option C — Store credentials for multiple servers
vault kv put secret/linux/db01 username="dbadmin" password="DBpass123"
vault kv put secret/linux/proxy01 username="proxy" password="ProxyPass123"
vault kv put secret/linux/mail01 username="mail" password="MailPass123"
You can structure the paths however you want. A common pattern is:
secret/linux/<hostname>/<account>
Example:
vault kv put secret/linux/web01/root password="RootPass123"
vault kv put secret/linux/web01/ansible password="AnsiblePass456"
3. Verify the secret was stored
vault kv get secret/linux/web01
Or for a subpath:
vault kv get secret/linux/web01/root
4. List secrets under a path
vault kv list secret/linux/
Or deeper:
vault kv list secret/linux/web01
5. Use these secrets in Ansible (no hardcoding)
Here’s how you pull the password at runtime:
- name: Get Linux password from Vault
set_fact:
creds: "{{ lookup('community.hashi_vault.hashi_vault', 'secret=secret/data/linux/web01 token={{ vault_token }} url=http://100.x.x.x:8200') }}"
Then use it:
- name: Create user
user:
name: "{{ creds.data.username }}"
password: "{{ creds.data.password | password_hash('sha512') }}"
This keeps your playbooks clean and your Git repo free of secrets.
6. Rotate passwords easily
When you want to rotate a password:
vault kv put secret/linux/web01 password="NewPassword789"
Then run your Ansible playbook again to push the new password to the server.
This gives you a simple, reproducible rotation workflow.
Recommended structure for Linux credentials
A clean, scalable pattern:
secret/linux/<hostname>/<account>
Example:
vault kv put secret/linux/web01/root password="RootPass123"
vault kv put secret/linux/web01/ansible password="AnsiblePass456"
vault kv put secret/linux/web02/root password="AnotherRootPass"
This makes it easy to:
- Rotate per‑host credentials
- Rotate per‑account credentials
- Pull secrets dynamically in Ansible
- Keep everything organized\
List Secrets
vault kv list secret/
Enable SSH Secrets Engine
Use Vault as an SSH Certificate Authority (SSH CA)
This is the enterprise‑grade way to handle SSH.
No private keys stored.
No long‑lived credentials.
No distributing keys.
No passphrases.
No hardcoding.
Vault issues short‑lived SSH certificates on demand.
SSH Certificates (Vault SSH CA)
How it works
- Users still generate their own keypair.
- Instead of distributing public keys, they send the public key to Vault.
- Vault signs it using its SSH CA private key.
- Vault returns an SSH certificate with:
- username/principal
- allowed hosts
- TTL/expiration
- role restrictions
- critical options
- extensions (e.g., permit-agent-forwarding)
Servers trust only ONE thing:
The CA public key, placed in:
/etc/ssh/ca.pub
And referenced in:
TrustedUserCAKeys /etc/ssh/ca.pub
What this solves
- Zero key distribution Users keep their private key; servers trust the CA.
- No static authorized_keys files.
- No more authorized_keys files Servers don’t store user keys anymore.
- Short‑lived access Certificates expire automatically (minutes/hours).
- Instant revocation Disable a Vault role → all issued certs become useless.
- Centralized identity Vault enforces who can request what.
- Metadata baked into the cert Principals, TTL, restrictions, etc.
It’s the same model GitHub, Google, and large enterprises use.
Setting Up Vault SSH CA
Vault’s SSH secrets engine does not generate SSH keypairs for users.
Instead, Vault acts as an SSH Certificate Authority (SSH CA).
That means:
- Vault holds a single private key (the signing key)
- Vault uses that private key to sign users’ public keys
- The resulting output is an SSH certificate, not a raw keypair
This signing key is the CA private key that proves the certificate is legitimate.
The workflow in simple terms
1. User generates their own SSH keypair
On their machine:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
2. User sends the public key to Vault
Vault signs it:
vault write ssh/sign/myrole \
public_key=@~/.ssh/id_ed25519.pub
3. Vault returns an SSH certificate
This certificate is signed using the CA private key stored at:
ssh/config/ca
You can list the public key with the command:
vault read ssh/config/ca
4. Your servers trust the CA public key
Placed in:
/etc/ssh/ca.pub
And referenced in sshd_config:
TrustedUserCAKeys /etc/ssh/ca.pub
5. When a user connects
The server checks:
- Is the certificate signed by the CA?
- Is it still valid?
- Does it match allowed principals?
- Does it match allowed roles?
If yes → login allowed
If no → rejected
Key insight
The Vault SSH signing key is the CA private key.
It signs certificates — it does NOT generate or validate user keypairs.
If the vault is sealed, it will not be able to sign user public keys and return certificates. If your certificate expires in this time and you don’t have a backup keypair, you will not be able to ssh into vault.
In my case, I will be keeping a backup ssh keypair in an air gapped environment in the case that vault is sealed and I need to unseal it manually.
Your servers trust the CA public key, not the user’s key.
1. Enable the SSH secrets engine
vault secrets enable ssh
2. Generate a CA keypair
vault write ssh/config/ca generate_signing_key=true
3. Install the CA public key on your servers
vault read -field=public_key ssh/config/ca > /etc/ssh/trusted-user-ca-keys.pem
Add to /etc/ssh/sshd_config:
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
Restart SSH:
systemctl restart sshd
4. Create a signing role
Admin role
vault write ssh/roles/admin \
key_type=ca \
allow_user_certificates=true \
allowed_users="*" \
default_extensions='{"permit-pty": "", "permit-agent-forwarding": "", "permit-port-forwarding"}' \
default_user="ubuntu" \
ttl=30m
Ansible/Dev role
vault write ssh/roles/dev-role \
key_type=ca \
allow_user_certificates=true \
allowed_users=”ansible,ubuntu” \
default_user=”ansible” \
ttl=”1h” \
max_ttl=”24h”
List Roles
vault list ssh/roles
vault read ssh/roles/admin
5. Generate and Sign SSH Keys
Generate new SSH key pair:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
vault write -field=signed_key ssh/sign/admin \ public_key=@$HOME/.ssh/id_ed25519.pub \
valid_principlals=”debian,ubuntu” \
> $HOME/.ssh/id_ed25519-cert.pub
Verify the cert if needed
ssh-keygen -L -f id_ed25519-cert.pub
*Note: Connecting with ssh using the cert is as simple as putting the id_ed25519-cert.pub key in the same directory as the private key as long as it shares the same base name.
Clou-Init with CA key
This guide has an example cloud-init snippit
HashiCorp Vault SSH Certificate Authority: Complete Setup Guide
Click here for a guide on configuring Authentication using Authentik in vault.
Leave a Reply