Security overview
Keydra holds the credentials to every server it manages. What that means for encryption at rest, sessions, outbound requests and the key that protects everything else.
What Keydra protects, and how#
Keydra holds the credentials to every server it manages. That makes it a target, and the measures below are the ones that follow from taking that seriously.
- Credentials encrypted at rest
-
AES-256-GCM under the instance key, and never returned by any API. See What Keydra stores.
- Passwords hashed
-
Argon2id, verified on a worker thread.
- A session is a row, not only a cookie
-
Ending a session takes effect on the next request, and setting a password ends every session that came before it. See Your sessions.
- Permissions rebuilt per request
-
Revoking access does not wait for a sign-out.
- Headers the browser enforces
-
A content security policy,
X-Content-Type-Options: nosniff, and the rest are set as headers rather than assumed. The policy is a configuration property, so a deployment that serves assets from elsewhere widens the one directive it needs instead of turning the header off. - Cookies
-
The session cookie is
HttpOnly, so no script can read it, andSameSite=Lax, so no other site can send it. It isSecurein production. - Addresses somebody typed are checked before they are called
-
Webhooks, issuer discovery and object-store endpoints all go through one guard. Link-local is refused and has no setting —
169.254.169.254answers with the machine’s cloud credentials, and configuring an alert is an operator’s job rather than an administrator’s. The check runs when the address is stored and again before the request, because a row can predate the check. - Broadcasts name the target they are about
-
A notification about one target reaches only the sockets whose owner may see that target. A viewer granted one server hears nothing about any other.
- Secrets never reach a log
-
Not a target password, not a token, not a passphrase. The command watcher redacts them before they leave the engine.
- The operations that empty a keyspace can be made to wait
-
A target can refuse to be emptied until its own name is typed, or until somebody other than the person who asked agrees to it. Neither is a permission, so turning one on locks nobody out — see Operations that wait for a second person.
Rotating the instance key#
KEYDRA_SECRET_KEY encrypts every stored credential. A key that cannot be rotated is a key
nobody rotates, which is the same as not having one after the first person leaves.
An encrypted value names the key that wrote it, so more than one can be readable at once. That is what makes a rotation something other than an outage.
-
You hold
crypto:rotate. An administrator’s alone: a rotation rewrites every credential in the instance.
-
Generate a new key:
openssl rand -base64 32 -
Deploy with the new key writing and the old one still reading:
KEYDRA_SECRET_KEY=<the new key> KEYDRA_PREVIOUS_SECRET_KEYS=<the old key>This deployment works before anything is re-encrypted. Existing values keep decrypting with the key that wrote them.
-
In the interface, run the re-encryption. It moves every encrypted column — target passwords, tunnel credentials, provider client secrets, destination credentials — onto the new key and reports how many it moved.
-
Remove
KEYDRA_PREVIOUS_SECRET_KEYSand deploy again.
The instance starts, every target still connects, and every tunnel still opens. That the next start needed no previous key is the proof the rotation finished.
Do not remove the previous key before the re-encryption has reported that it moved everything. A half-finished rotation with the old key gone is a database nothing can read.