What is Selkie?
Selkie is a zero-trust access management system designed for organizations that grant developers access to multiple infrastructures, platforms, environments, and client systems.
Core Mission
Track who has access to what, with which credentials, since when — while fully isolating secret decryption from server control.
Critical Guarantee
The backend never sees plaintext secrets or user private keys. All decryption happens exclusively client-side.
Key Features
Client-Side Encryption
All cryptographic operations happen in your browser or CLI
Immutable Versioning
Every change creates a new version for complete audit trails
Plugin Architecture
Extensible system for SSH, AWS, Kubernetes integrations
Complete Audit Logs
Every action is logged for forensic analysis
Paranoid Mode
True zero-trust where even admins cannot recover secrets
Secret Rotation
Track secret age with version history
System Philosophy & Goals
Selkie is built on eleven core principles that guide every design decision:
1. Zero-Knowledge Backend
Secrets stored in the database and processed by the backend must remain encrypted. A full compromise of the database and backend server does not give attackers access to credentials.
2. Immutable Secret Versions
Any change creates a new secret version. Historical versions remain for audit and forensic purposes. This ensures perfect reconstruction of who had access to which secret at any point in time.
3. Flexible Object Model
Selkie models abstract resources called "objects" which carry type information, fields, and secret versions. Types define schemas and optional triggers. Plugins can introduce new types.
4. Cryptographic Access Grants
Users gain access to objects through assignments. Assignments create cryptographic grants for specific secret versions. Revoking assignments removes future access.
5. Plugin-Based External Actions
The base system only manages objects, secrets, and ACLs. All real-world access modifications (SSH authorized_keys, AWS IAM revocation, etc.) are implemented through plugins.
6. Complete Audit Trail
Every access, rotation, assignment, or compromise must be stored as an auditable event. Operators can see the age of secrets, recent rotations, and compromise history.
7. Client-Side Cryptography
Clients (CLI & Web) perform: user keypair generation, DEK generation, secret encryption, DEK wrapping, and secret decryption. The backend never decrypts anything.
8. Schema-Driven Object Types
Different types (SSH access, AWS keys, username/password, etc.) define field and secret schemas using JSONSchema. New types may be added at runtime through plugins.
9. Dual Recovery Modes
Each object individually controls whether its secrets are recoverable or paranoid. Non-paranoid objects can be recovered by administrators via OMK. Paranoid objects are recoverable ONLY by the user — true zero-trust.
10. Secret Age Visibility
Secret version age is displayed prominently. Rotations are encouraged and monitored. Stale secrets must be clearly identifiable.
11. Server-Side Plugin Secrets
Server-side plugins may access specific secrets through an explicit assignment model using a Plugin Master Key (PMK). This enables automation while maintaining zero-trust for user secrets.
High-Level Architecture
Monorepo Structure
Selkie is organized as a monorepo containing all components:
selkie/ ├── packages/ │ ├── backend/ # NestJS API server │ ├── web/ # Next.js web client │ ├── cli/ # Node.js CLI client │ └── shared/ # Shared TypeScript types & crypto utilities ├── plugins/ # Server-side plugins │ ├── ssh-access/ │ ├── aws-iam/ │ └── ... └── docs/ # Documentation
Component Overview
Backend (NestJS)
- User management
- Object creation & storage
- Secret version management
- Assignment & access grants
- Event emission & audit logs
- Plugin loading & execution
- Never decrypts anything
Web Client (Next.js)
- Browser-based secret decryption
- Object browser & management
- Assignment UI
- Audit history viewing
- Daemon detection for automation
- Zero-trust operations
CLI Client (Node.js)
- Command-line secret management
- Keypair generation
- Automation & scripting
- Direct plugin execution
- Secure token storage
Selkie Daemon (optional)
- Local background service
- Bridges Web UI to local operations
- Executes client-side plugins
- Maintains keys in memory
- Localhost-only API
Cryptographic Model
Selkie's cryptographic design separates the user password from the keys that encrypt secrets, creating multiple layers of protection.
Key Components
Key Encryption Key - Derived from the user's password using Argon2id. Never stored anywhere. Used only to encrypt/decrypt the UMK.
User Master Key - Random 256-bit key generated for each user. Stored encrypted by KEK. Used to encrypt the user's private key.
User Keypair - RSA-4096 asymmetric keypair. Private key encrypted with UMK. Public key used by others to wrap DEKs for this user.
Data Encryption Key - Random 256-bit symmetric key generated per secret version. Encrypts the actual secret using AES-256-GCM.
Org Master Key - System-wide RSA-4096 keypair. Enables break-glass recovery for non-paranoid objects only. Generated once at system init.
Plugin Master Key - System-wide keypair for server-side plugin access to designated secrets. Enables automation while keeping user secrets secure.
Secret Decryption Flow
Client-Side Decryption Steps
User logs in
Receives encrypted UMK, encrypted private key, and KDF parameters
Derive KEK
Client derives KEK from password using Argon2id with stored parameters
Decrypt UMK
Use KEK to decrypt the User Master Key
Decrypt Private Key
Use UMK to decrypt user's private key (A_priv)
Fetch Secret
Receive ciphertext, nonce, and wrapped DEK for user
Unwrap DEK
Use private key to decrypt the wrapped DEK
Decrypt Secret
Use DEK with AES-256-GCM to decrypt the plaintext secret
Zero-Knowledge Guarantee
The backend never sees: KEK, UMK plaintext, private key plaintext, DEK plaintext, or any secret material. All decryption happens exclusively in the client.
BIP39 Mnemonic Backup
User Recovery
Only the UMK is encoded into the mnemonic backup (not the private key).
Recovery process:
- Restore UMK from mnemonic words
- Re-encrypt UMK with new password
- Fetch encrypted private key from server
- Decrypt private key using restored UMK
- Regain access to all secrets
OMK Recovery
OMK mnemonic is generated once at system initialization and shown only once to the administrator.
This enables break-glass recovery of non-paranoid objects only. Paranoid objects remain unrecoverable even with OMK.
Security Model
Paranoid vs Non-Paranoid Objects
Each object in Selkie has a paranoid boolean flag that fundamentally changes its security properties:
Non-Paranoid (Default)
- Uploads
wrappedDekForUser - Uploads
wrappedDekForOMK - Recoverable by user via their mnemonic
- Recoverable by admin via OMK mnemonic
- Suitable for team credentials
Paranoid Mode
- Uploads
wrappedDekForUseronly - No OMK-wrapped DEK exists
- Recoverable ONLY by user
- Admins cannot recover even with OMK
- True zero-trust for sensitive secrets
What the Backend Never Sees
What the Backend Stores
Trust Distribution
Complete Trust Isolation
Server-side plugins: Trusted by organization, orchestrate events, limited secret access via PMK
Client-side plugins: Trusted by user, execute with user's decrypted keys locally
Selkie Daemon: Trusted local process, acts as user's agent for automation
Backend: Zero-knowledge, never sees plaintext material, manages encrypted data only
Groups — Organizing Objects
Groups provide a hierarchical structure for organizing objects by client, project, environment, or any logical boundary. Groups enable bulk assignment management and improve user experience when managing large numbers of secrets.
Group Concepts
Hierarchical Organization
Groups can contain objects and other groups, creating nested hierarchies like "Acme Corp → Production → AWS"
Bulk Assignment
Assign users to groups instead of individual objects for efficient access management
Security Preserved
Groups are organizational only — they don't affect the cryptographic model or paranoid settings
Group Statistics
View object counts, stale secrets, and compromised items at the group level
Inheritance Depth
When assigning users to groups, you choose how deep the access extends:
Direct Only
- Access only to objects directly in this group
- Does NOT include objects in subgroups
- Best for limited, specific access
- User must be assigned to each subgroup separately
Recursive
- Access to objects in this group AND all subgroups
- Includes all nested subgroups at any depth
- Best for broad access to an entire hierarchy
- Automatically includes future subgroups
Group Assignment Operations
Assigning Users to Groups
When assigning a user to a group, you can optionally grant access to existing objects and secrets:
Removing Users from Groups
When removing a user from a group, you choose what to revoke:
Security Considerations
- ✓Groups do NOT bypass the cryptographic model — individual SecretAccessGrants are still the source of truth
- ✓Paranoid objects in groups still require individual user mnemonics for recovery
- ✓OMK recovery operates at the object level, not group level
- ✓Group assignments are a convenience layer — actual access is cryptographically enforced per-user
Dual Plugin Architecture
Selkie features a dual plugin architecture: server-side plugins for orchestration and client-side plugins for privileged automation requiring decrypted secrets.
Server-Side Plugins
Backend Plugin Capabilities
- Define new object types (SSH access, AWS IAM, etc.)
- Define field and secret schemas
- Register event handlers for orchestration
- Access plugin-designated secrets via PMK
- Never see user secrets directly
Server plugins are loaded from the plugins/ directory and can listen to events like object.assigned,secret.rotated, etc.
Client-Side Plugins
Local Execution Capabilities
- Add/remove SSH authorized_keys on servers
- Rotate AWS IAM access keys
- Manage Kubernetes RBAC entries
- Call corporate APIs with credentials
- Any operation requiring plaintext secrets
Client plugins execute on the user's machine where secrets are decrypted, preserving Selkie's core zero-trust model.
Plugin Master Key (PMK)
Server-Side Secret Access
The PMK enables server-side plugins to access specific secrets for automation:
- Slack webhook URLs for notifications
- Cloud provider API keys for automation
- Monitoring service tokens
- Internal API keys for integrations
Plugin secrets are less secure than user secrets but more secure than .env files — they're encrypted at rest, require explicit assignment, and are fully audited.
Selkie Daemon
Browser-Only Mode
Default experience for most users:
- Secrets decrypt in browser memory
- View, copy, rotate, manage secrets
- Manage assignments
- View audit history
- No automation features
Daemon-Enhanced Mode
Power user experience:
- Web UI detects running daemon
- Enables privileged automation
- SSH provisioning, IAM rotation
- Plugin actions execute locally
- Zero-trust maintained
Client Applications
CLI Client
# Installation npm install -g selkie-cli # Login selkie login # List objects selkie objects list # Get a secret selkie secrets get <object-id> # Rotate a secret selkie secrets rotate <object-id> # Assign user to object selkie assign <object-id> --user <email> --role CONSUMER
CLI Features
- Keypair generation
- KEK derivation & UMK decryption
- Secret encryption & decryption
- Object creation & management
- Secret rotation
- Assignment management
- Direct plugin execution
- Secure token storage in OS keychain
Web Client
Full-featured browser application with zero-trust decryption:
Dashboard
Compromised and stale secret warnings, quick stats
Object Browser
View and manage all objects you have access to
Secret Modal
Secure reveal with glass blur effect, copy protection
Audit History
Complete timeline of access and modifications
Assignments
Manage who has access to what
Version History
Previous versions read-only, rotation timeline
Data Model (MongoDB)
Selkie uses MongoDB with the following core collections:
Users Collection
User identity, authentication, and encrypted crypto context:
email, displayName, passwordHash, encrypted_UMK, encryptedPrivateKey, publicKey, status, timestampsSystemConfig Collection
Single document with system-wide configuration:
organizationName, organizationSlug, wrappedOMK, omk_publicKey, securityPolicies, timestampsObjectTypes Collection
Schema definitions for each object type:
name, fieldSchema (JSONSchema), secretSchema (JSONSchema), pluginMetadata, timestampsObjects Collection
The resources being managed:
type, name, fields, currentSecretVersion, status, paranoid, compromisedAt, createdBy, timestampsSecretVersions Collection
Immutable encrypted secrets:
objectId, version, ciphertext, nonce, algorithm, schemaVersion, status, createdBy, timestampsSecretAccessGrants Collection
Per-user DEK wraps:
secretVersionId, userId, wrappedDekForUser, wrappedDekForOMK (if not paranoid), timestampsObjectAssignments Collection
User-to-object access mapping:
objectId, userId, role (OWNER/MAINTAINER/CONSUMER), createdAt, removedAtAuditEvents Collection
Immutable event log:
eventType, actorUserId, objectId, secretVersionId, payload, timestampCore Operational Flows
User Registration
Generate Keys (Client)
Create random UMK, generate RSA-4096 keypair
Derive KEK (Client)
Use Argon2id with password to derive KEK
Encrypt Keys (Client)
Encrypt UMK with KEK, encrypt private key with UMK
Send to Backend
Upload encrypted UMK + encrypted private key + public key
Store User (Backend)
Store user with password hash and KDF parameters
Show Mnemonic (Client)
Display BIP39 recovery words for UMK backup
Creating Objects with Secrets
Fetch Type Schema
Get field and secret schema for the object type
Validate Fields
Ensure all fields match the type schema
Generate DEK (Client)
Create random 256-bit Data Encryption Key
Encrypt Secret (Client)
Use DEK with AES-256-GCM to encrypt secret data
Wrap DEKs (Client)
Encrypt DEK with user's public key (and OMK if not paranoid)
Send to Backend
Upload ciphertext, nonce, wrapped DEKs
Store (Backend)
Create object, secret version, and access grants
Secret Rotation
Generate New DEK
Client creates fresh 256-bit key
Encrypt New Secret
Use new DEK to encrypt updated secret value
Wrap for All Users
Encrypt DEK with each assigned user's public key
Upload New Version
Backend creates new SecretVersion, updates currentVersion
Emit Event
Backend emits secret.rotated for plugin handlers
Assigning Users
Create Assignment
Backend records user-object-role mapping
Generate DEK Wrap
Client wraps current DEK with new user's public key
Store Access Grant
Backend stores wrapped DEK for the new user
Emit Event
Backend emits object.assigned
Plugin Actions
Plugins may trigger external actions (SSH key provisioning, etc.)
Future Roadmap
Selkie is built to evolve without breaking cryptographic assumptions:
Near-Term
- Additional object type plugins
- More integration plugins
- Enhanced audit dashboards
- Team management features
Mid-Term
- Multi-factor crypto authentication
- Hardware-backed UMK decryption (YubiKey)
- Client plugin marketplace
- Kubernetes & cloud provider agents
Long-Term
- Multi-organization support
- Multi-region deployments
- Browser extension for daemon-less operations
- Mobile app with limited plugin support
Always Maintained
- Zero-trust guarantees
- Backward compatibility
- No migration breaking crypto
- Client-side decryption only
Ready to Get Started?
Experience zero-trust secret management where you control the keys and the backend never sees your secrets.