Concepts
Core concepts behind SikkerKey's security model.
Vault
Your vault is your account's encrypted secrets storage. Each user gets a unique vault ID (e.g. vault_a1b2c3d4e5f6g7h8) that machines use to identify which vault they belong to. A machine can be registered with multiple vaults, each with its own keypair and identity.
Projects
Projects group secrets and machines into logical environments. A project might represent:
- An environment:
production,staging,development - A service:
payment-api,auth-service - A team:
backend,infrastructure
Each project has its own independent encryption key. Secrets belong to exactly one project. Machines can be added to multiple projects, but their secret access is still per-secret within each project.
Secret Types
SikkerKey has four secret types.
Secrets
A single encrypted value with a name. API keys, passwords, connection strings, tokens. Read with getSecret(). Optionally enable automatic rotation so SikkerKey generates a new value on a schedule.
Structured Secrets
Multiple named fields encrypted as a single blob (e.g. host, username, password). Individual fields can be read via getFields() or getField() without parsing the full value:
creds = sk.get_fields("sk_db_prod")
host = creds["host"]
password = creds["password"]
Optionally enable automatic rotation on a per-field basis. You choose which fields rotate (e.g. password) and which stay static (e.g. host, username).
Managed Secrets
Database credentials that SikkerKey rotates on a schedule and pushes to your database automatically. Always structured with username and password fields. A CLI agent runs locally next to your database, monitors for rotations, and applies the new password via the appropriate SQL command (e.g. ALTER ROLE for PostgreSQL). The database is never exposed to the internet.
TTL Secrets
One-time self-destructing secrets for sharing credentials with people who don't have access to your vault. You paste or generate a value, set a self-destruct timer (1 minute to 24 hours), and get a link plus a passphrase. The recipient opens the link, enters the passphrase, and sees the secret. It's then permanently destroyed. A wrong passphrase also destroys it immediately. TTL secrets are encrypted with AES-256-GCM at rest, the passphrase is hashed with Argon2id, and machines cannot access them. They exist for human-to-human credential handoff, not programmatic access.
Encryption
SikkerKey uses envelope encryption with three layers:
- Each secret gets a random AES-256-GCM data key
- The data key encrypts the secret value, with the secret ID bound as Additional Authenticated Data (AAD)
- The project's master key encrypts the data key
- Both encrypted blobs are stored
The AAD binding means an encrypted value cannot be swapped between secrets. Decryption fails if the secret ID doesn't match.
Every change creates a new version. Previous versions are preserved for rollback, subject to your plan's version retention limit.
Automatic Rotation
Any secret or structured secret can optionally have automatic rotation enabled. You configure:
- Interval: how often to rotate (minimum 5 minutes)
- Length: generated value length (default 32)
- Charset:
symbols(default),alphanumeric,numbers, oruuid - Fields (structured secrets only): which fields rotate, others stay static
Secrets with active rotation cannot be manually replaced or rotated. Each rotation creates a new version.
Managed secrets always have rotation enabled.
Soft Delete
Deleted secrets are moved to trash and remain recoverable for 30 days. After 30 days, the secret and all its version history are permanently deleted. Machine access grants and rotation schedules are removed immediately on deletion.
Machines
A machine is any server, container, or process that needs to read secrets. During bootstrap:
- The machine generates an Ed25519 keypair locally
- The public key is sent to SikkerKey
- The private key stays on the machine at
~/.sikkerkey/vaults/{vaultId}/private.pem
The private key is never transmitted. SikkerKey only stores the public key.
Newly registered machines start as pending. They cannot authenticate until the vault owner approves them from the dashboard. Machines can be disabled at any time, immediately revoking their ability to authenticate.
Machine Authentication
Every request is signed with the machine's private key. No tokens, no API keys, no sessions.
| Header | Purpose |
|---|---|
X-Machine-Id | Identifies the machine |
X-Timestamp | Prevents replay (5-minute window) |
X-Nonce | Single-use, prevents duplicate requests |
X-Signature | Ed25519 signature of method:path:timestamp:nonce:bodyHash |
The server verifies:
- Lockout: 3 failed attempts from the same IP within 5 minutes triggers a 30-minute lockout
- Machine status: must be approved and enabled
- Signature: verified against the stored public key
- Timestamp: must be within 5 minutes of server time
- Nonce: must not have been used before (tracked in the database, survives restarts)
- Account status: the vault owner's account must be active
An intercepted request is useless. The timestamp expires, the nonce is consumed, and the signature can't be forged without the private key.
Access Requirements
For a machine to read a single secret, all of the following must be true:
- Valid Ed25519 signature with a fresh nonce
- Machine is approved and enabled
- Vault owner's account is active
- Machine is added to the project containing the secret
- Machine has an explicit grant to that specific secret
There is no wildcard access, no "grant all", no inheritance. Each machine-to-secret relationship is explicit.
Teams
Vault owners can invite other SikkerKey users by email. When the invite is accepted, the user becomes a team member of that vault.
Secret Access
Adding a team member to a project gives them full secret management within that project: view metadata, create, delete, replace, version history, and notes. There are no granular secret-level permissions. Project membership is the access boundary.
Important: "view" means secret metadata (name, note, version, machine count). The dashboard never displays decrypted secret values. Reading the actual plaintext always requires an authenticated machine with an explicit per-secret grant.
A team member can only see the projects they've been added to. Each project's encryption is independent, so access to one project reveals nothing about another.
Machine Permissions
Machine permissions are separate and must be explicitly granted per project:
| Permission | Allows |
|---|---|
machine_view | See machines in the project |
machine_add | Add their own machines to the project |
machine_remove | Remove machines from the project |
machine_configure | Change which secrets a machine can access |
A team member with no machine permissions can still fully manage secrets in their assigned projects.
Suspension
When a vault owner's account is suspended, all access to that vault is blocked immediately. Team members cannot access the vault's projects or secrets. Machine authentication is blocked. Team members are not informed of the suspension reason.
Audit Log
Every action is recorded in an append-only audit log with a severity level:
| Severity | Examples |
|---|---|
| Critical | Auth failures, project deletions, 2FA disabled, vault destroyed |
| High | Machine registrations, secret deletions, permission grants, password changes |
| Medium | Project changes, team invites, agent status changes, sync config deletions |
| Low | Machine approvals, bootstrap tokens |
| Info | Secret reads, logins, secret creates, sync config reads |
Each entry records the user ID, machine ID, secret ID, action, severity, source IP, detail string, and timestamp.
Audit entries are pushed to the dashboard in real time via server-sent events. Email alerts can be configured per-action so you're notified immediately when critical events occur.
Audit log retention is based on your subscription plan and is pruned automatically.