NetStacksNetStacks

Credential Vault

How the NetStacks vault encrypts credentials: a free local vault unlocked by a master password (Argon2id + AES-256-GCM), Touch ID, and the enterprise Controller.

Overview

The credential vault is where NetStacks stores secrets — SSH passwords, key passphrases, jump-host passwords, SNMP community strings, secure notes, and AI/SMTP API keys — encrypted at rest. Nothing sensitive is written to disk in plaintext.

There are two distinct vaults, and which one applies depends on how you run NetStacks:

  • Local vault (free). The standalone NetStacks Terminal is free and open source (Apache-2.0). It keeps a local vault in SQLite, unlocked with a master password you choose. The vault is on your machine; no server is involved.
  • Enterprise Controller vault. When the Terminal runs in enterprise mode against a NetStacks Controller, shared and personal credentials live on the Controller. The Terminal only ever receives metadata — never raw secrets — following a zero-standing-privileges model.

Both vaults share the same cryptographic core:

  • AES-256-GCM authenticated encryption for every stored secret
  • Argon2id (memory-hard) key derivation
  • A unique 96-bit (12-byte) nonce per encryption, so identical plaintexts never produce identical ciphertext
Which vault am I using?

If you launched the NetStacks Terminal on its own and were asked to set a master password, you are using the local vault. If you signed in to a Controller, credentials are managed centrally by the enterprise vault and the local master-password screens do not apply.

How Encryption Works

Authenticated encryption (AES-256-GCM)

Every secret is encrypted with AES-256-GCM (Galois/Counter Mode), an authenticated cipher that provides confidentiality and integrity. A fresh, random 12-byte nonce is generated for each encryption, so encrypting the same value twice yields two different ciphertexts. If even one byte of the stored ciphertext is tampered with, GCM authentication-tag verification fails and decryption is rejected.

Key derivation (Argon2id)

The encryption key is never the master password itself. The password is run through Argon2id, a memory-hard key-derivation function that resists GPU and ASIC brute-force attacks, together with a random 32-byte salt. The result is a 256-bit AES key.

On disk, each encrypted record is laid out as salt (32 bytes) || nonce (12 bytes) || ciphertext. The salt travels with the record so the key can be re-derived on decryption; it is not secret. The password and the derived key are never written to disk.

Open-source crypto

The Terminal's encryption is a thin wrapper over an audited, open-source credential-vault crate. Argon2id derivation, the 32-byte salt, the 12-byte AES-256-GCM nonce, and the wrong-password / corrupted-data failure modes are all covered by unit tests in the public source. See Source Code & Cryptography.

Fast path after unlock

Argon2id is intentionally slow. To avoid paying that cost on every operation, the vault derives the key once when you unlock it and caches the resulting key in memory for the session. Subsequent encrypt/decrypt operations reuse the cached key. Locking the vault discards it.

The Local Vault (Free)

The local vault is unlocked by a single master password that you set the first time you store a secret. It is managed from Settings → Security in the Terminal.

Setting the master password

The first time you save a credential (for example, a password on a credential profile), you are prompted to create a master password. The backend enforces a minimum length of 12 characters — even scripted or direct-API setup cannot create a shorter one.

There is no password reset

The master password is the only key to your secrets. It is never stored — only a verification marker encrypted with it is kept. If you forget it, the encrypted credentials cannot be recovered; your only option is to wipe the vault (confirming with the current password) or start fresh. Choose a password you can recall and back it up in a personal password manager.

Locking and unlocking

While the vault is unlocked, the Terminal can read and write secrets for the session. Locking it clears the in-memory key; the next attempt to use a stored secret returns a VAULT_LOCKED error until you unlock again. You can lock the vault manually from Settings.

  • Status reports whether a master password has been set and whether the vault is currently unlocked.
  • Unlock re-derives the key from your password (rate-limited after repeated failures).
  • Lock discards the cached key immediately.

Changing the master password

Rotating the master password re-encrypts every stored value — credentials, tokens, API keys, and secure notes — under the new key in a single atomic transaction. If any part fails, the vault stays on the old password. The vault must be unlocked first, and the new password must also meet the 12-character minimum.

Wiping the vault

Wiping deletes every vault-encrypted value and resets the master-password marker. You must supply the current password to confirm. Afterward the vault reports no master password set, and you can establish a fresh one. Use this only when you have lost access or want a clean slate.

Touch ID Unlock (macOS)

On macOS, you can unlock the local vault with Touch ID instead of typing your master password each time. This is a convenience layer on top of the password — the master password remains the recovery path.

How it works

When you enable Touch ID, the Terminal verifies your master password (by unlocking the vault), then stores that password in the macOS Keychain. Each subsequent unlock shows a system Touch ID prompt; on success, the stored password is retrieved and used to unlock the vault. The fingerprint check is enforced by LAContext.evaluatePolicy with biometrics-only policy — there is no in-prompt system-password fallback, so your master password stays the recovery path on the unlock screen.

Enabling and disabling

  • Enable — confirm with your master password and a Touch ID prompt; the password is filed in the Keychain and the vault.biometric_enabled setting flips on.
  • Unlock — a Touch ID prompt; on cancel or failure you fall back to entering the master password.
  • Disable — removes the Keychain entry and clears the setting. No fingerprint is required to turn it off.
macOS only; self-healing

Biometric unlock is available only on macOS builds; on Windows and Linux the status reports supported: false and the feature is hidden. If you change your master password elsewhere, a stale Touch ID entry will fail to unlock the vault — the Terminal then deletes the stale entry, clears the setting, and falls back to manual password entry so you can re-enroll cleanly.

Local Vault API

The Terminal exposes the local vault over its loopback agent API. These endpoints are what the desktop UI calls; they are useful for scripting setup or debugging. All secret-bearing request fields are redacted from logs.

Check vault status

vault-statushttp
GET /vault/status

# Response
{
  "has_master_password": true,
  "unlocked": false
}

Set the master password (first-time setup)

Rejected with a validation error if the password is shorter than 12 characters or if a master password already exists.

set-master-passwordhttp
POST /vault/password
Content-Type: application/json

{ "password": "correct horse battery staple" }

# 204 No Content on success
# 400 if password < 12 chars or already set

Unlock and lock

unlock-lockhttp
POST /vault/unlock
Content-Type: application/json

{ "password": "correct horse battery staple" }
# 204 No Content; repeated failures are rate-limited

POST /vault/lock
# 204 No Content; clears the in-memory key

Change the master password (re-encrypts everything)

change-master-passwordhttp
PUT /vault/password
Content-Type: application/json

{
  "old_password": "correct horse battery staple",
  "new_password": "a longer brand new passphrase"
}
# 204 No Content; vault must be unlocked first

Wipe the vault

wipe-vaulthttp
POST /vault/wipe
Content-Type: application/json

{ "confirm_password": "correct horse battery staple" }
# 204 No Content; deletes every encrypted value

Touch ID (macOS)

biometrichttp
GET /vault/biometric/status
# { "supported": true, "enrolled": false, "enabled": false }

POST /vault/biometric/enable
{ "password": "correct horse battery staple" }
# Verifies password, stores it in the Keychain behind Touch ID

POST /vault/biometric/unlock
# Triggers the Touch ID prompt, then unlocks the vault

DELETE /vault/biometric
# Removes the Keychain entry and clears the setting

Enterprise Controller Vault Enterprise

Enterprise mode

This section applies only when the Terminal is connected to a NetStacks Controller. In enterprise mode the local vault is disabled; credentials are stored centrally on the Controller, and the Terminal receives metadata only.

Zero standing privileges

The Controller stores credential secrets server-side. The Terminal lists credentials it has access to and receives only safe metadata — name, type, host, username — never the raw secret. When a connection is made, the secret is used on the user's behalf without being exposed to the Terminal.

Credential types

The Controller supports these credential types:

  • ssh_password
  • ssh_key
  • api_token
  • snmp_community
  • generic_secret

Accessible credentials

The Terminal discovers what the signed-in user can use through the access endpoints. Access is derived from the user's roles and the folders those roles are granted.

accessible-credentialshttp
# List all credentials the current user can use (metadata only)
GET /api/credentials/accessible
# -> { "items": [ { "id": "...", "name": "...", "credential_type": "ssh_password",
#                   "host": "...", "username": "admin" }, ... ] }

# The user's default SSH credential (first accessible, alphabetical)
GET /api/credentials/accessible/default
# -> AccessibleCredential | null

Personal credentials ("My Credentials")

Each user can keep their own private credentials on the Controller. They are owned by the user and are not shared.

personal-credentialshttp
GET    /api/credentials/personal           # list your own
POST   /api/credentials/personal           # create
PUT    /api/credentials/personal/:id       # update
DELETE /api/credentials/personal/:id       # delete

# Create body
{
  "name": "Lab jump box",
  "credential_type": "ssh_password",
  "username": "netops",
  "host": "10.20.0.5",
  "port": 22,
  "secret": "••••••••",
  "enable_secret": "••••••••",
  "description": "Personal lab access"
}

Revealing a password (audit-gated, reason required)

Revealing a raw secret is always audit-logged and requires a free-text reason. An empty reason is rejected with a 400. The reveal event records the user, credential, timestamp, and the supplied reason.

reveal-with-reasonhttp
# Reveal a personal credential's secret
POST /api/credentials/personal/:id/reveal
{ "reason": "Rotating password in upstream IPAM" }
# 400 if reason is empty

# Reveal a shared credential's secret (admin/operator)
# Requires the ViewCredentials permission + Full access to the credential + a reason
POST /api/admin/credentials/:id/reveal
{ "reason": "Incident INC-4821 break-glass access" }
# 403 if the caller lacks Full access

Folder-level sharing

Shared credentials are organized into folders. A folder is granted to one or more roles, and each grant carries a can_view_password flag. Members of a granted role can use the credentials in that folder; only grants with can_view_password enabled (Full access) may reveal the raw secret — and only then with a reason. See Credential Folders for the full model.

Questions & Answers

Q: What encryption does the NetStacks vault use?
A: AES-256-GCM for every stored secret, with a unique random 12-byte nonce per encryption, and Argon2id (memory-hard) key derivation with a random 32-byte salt.
Q: How is the local vault unlocked?
A: With a master password you choose. It is run through Argon2id to derive the 256-bit AES key, which is cached in memory only while the vault is unlocked. The password itself is never stored. On macOS you can also unlock with Touch ID.
Q: Is the local vault free?
A: Yes. The standalone NetStacks Terminal is free and open source (Apache-2.0), and its local vault is included. There is no server, license, or account required.
Q: Is there a minimum master-password length?
A: Yes — 12 characters, enforced by the backend so it cannot be bypassed by the UI, scripts, or a direct API call.
Q: What happens if I forget the master password?
A: There is no reset. The password is never stored, so encrypted secrets cannot be recovered. You can wipe the vault (confirming with the current password) and start over, but the existing secrets are lost. Back up your master password in a personal password manager.
Q: How do I rotate the master password?
A: Unlock the vault, then change the password. Every stored value is re-encrypted under the new key in one atomic transaction; if anything fails, the vault stays on the old password.
Q: Is Touch ID available on Windows or Linux?
A: No. Biometric unlock is implemented only on macOS. On other platforms the status reports it as unsupported and the option is hidden.
Q: In enterprise mode, can the Terminal see raw secrets?
A: No. The Controller returns metadata only (name, type, host, username). Revealing a raw secret is a separate, audit-logged action that requires a written reason and, for shared credentials, Full access to the credential.

Troubleshooting

"Vault is locked" when saving a credential

Storing a profile credential returns a VAULT_LOCKED error when the local vault has not been unlocked this session. Open Settings → Security and unlock with your master password (or Touch ID), then retry.

"Master password must be at least 12 characters"

Setup and password-change both enforce the 12-character minimum on the backend. Choose a longer passphrase — a few unrelated words work well and are easy to remember.

"Master password already set"

A master password already exists, so the set-password call is rejected. To replace it, change the password (requires the current one) or wipe the vault (also requires the current password) and set a new one.

Repeated unlock failures are throttled

After several consecutive wrong-password unlock attempts, the agent applies a cooldown before it will even attempt decryption again. Wait for the cooldown to clear and enter the correct password.

Touch ID stopped working after changing the password

A stale Keychain entry from before the change will fail to unlock the vault. The Terminal detects this, deletes the stale entry, and turns the setting off so you fall back to the master password. Re-enable Touch ID from Settings to enroll again.

Enterprise: "No accessible credentials"

If a connection fails because no credential is available, the signed-in user's roles have not been granted any credential folder. Ask an administrator to grant the relevant folder to one of the user's roles (see Credential Folders).

Enterprise: reveal returns 400 or 403

A reveal with an empty reason returns 400 — supply a non-empty reason. A 403 on a shared credential means the caller lacks Full access (the can_view_password grant) to that credential.

Learn more about credential types and related features: