Security
Nucleus provides defense-in-depth security: row-level security (RLS), column-level data masking, tenant-aware encryption, and immutable audit logging.
Row-Level Security (RLS)
Control which rows each user can see and modify.
Enable RLS
ENABLE RLS ON patients;
Create Policies
-- Doctors can see all patients
CREATE POLICY doctor_read ON patients
FOR SELECT
TO doctor
USING (true);
-- Patients can only see their own records
CREATE POLICY patient_read ON patients
FOR SELECT
TO patient
USING (patient_id = current_user_id());
-- Nurses can only see patients in their department
CREATE POLICY nurse_read ON patients
FOR SELECT
TO nurse
USING (department = current_tenant());
Policy Types
| Type | Behavior | |------|----------| | Permissive (default) | At least one permissive policy must pass | | Restrictive | All restrictive policies must pass |
Policies combine: (any permissive passes) AND (all restrictive pass).
Predicate Types
| Predicate | Description |
|-----------|-------------|
| column = 'value' | Column equals constant |
| column = current_user() | Column matches session user |
| column = current_tenant() | Column matches session tenant |
| has_role('admin') | Session must have role |
| Combined with AND / OR | Compose predicates |
Superuser Bypass
Users with the superuser role bypass all RLS policies.
Column-Level Data Masking
Mask sensitive columns based on the querying user's role.
Masking Rules
| Rule | Input | Output |
|------|-------|--------|
| Redact | 555-0123 | [REDACTED] |
| Email | tyler@example.com | t***@example.com |
| Partial (show first 2, last 2) | 555-0123 | 55****23 |
| Hash | John Smith | a1b2c3d4 |
Apply Masking
-- Analysts see masked SSNs
CREATE MASKING POLICY ssn_mask ON employees(ssn)
FOR ROLE analyst
USING PARTIAL(show_first=0, show_last=4, mask_char='*');
-- Support staff see masked emails
CREATE MASKING POLICY email_mask ON customers(email)
FOR ROLE support
USING EMAIL;
Masking is applied transparently — queries return masked values without application code changes.
Encryption
Tenant-Aware Key Management
Nucleus supports per-tenant encryption keys with rotation:
-- Register a tenant key
SELECT register_tenant_key('tenant_42', decode('...base64key...', 'base64'));
-- Rotate to a new key (old key archived for decryption)
SELECT rotate_key('tenant_42', decode('...newkey...', 'base64'));
Key Rotation
Key rotation is a managed process:
- Begin — New key registered, old key marked for archival
- Re-encrypt — Pages re-encrypted in background (progress tracked)
- Complete — Old key archived, new key active
Old keys are retained for decrypting data written before rotation.
Encrypted Indexes
Nucleus supports encrypted indexes that store index entries in ciphertext. Search operations decrypt at query time — the index file on disk contains no plaintext.
Audit Logging
Immutable, append-only audit log for compliance and forensics.
What's Logged
Every query execution records:
| Field | Description |
|-------|-------------|
| timestamp | When the query ran |
| user | Who ran it |
| action | Query type (SELECT, INSERT, UPDATE, DELETE, DDL) |
| table | Affected table |
| query | Full SQL text |
| rows_affected | Number of rows modified |
| success | Whether the query succeeded |
Querying the Audit Log
-- Recent activity by user
SELECT * FROM nucleus_audit_log WHERE user = 'alice' ORDER BY timestamp DESC LIMIT 100;
-- All changes to a table
SELECT * FROM nucleus_audit_log WHERE table_name = 'patients' AND action IN ('INSERT', 'UPDATE', 'DELETE');
Audit entries are immutable — they cannot be updated or deleted.
Session Context
Security features use session context to evaluate policies:
-- Set session properties
SET SESSION user = 'alice';
SET SESSION role = 'doctor';
SET SESSION tenant_id = 'hospital_42';
Context properties available to RLS predicates and masking rules:
| Function | Returns |
|----------|---------|
| current_user() | Session user |
| current_tenant() | Session tenant ID |
| has_role('name') | Whether session has role |
Cluster Security
Inter-Node TLS
In clustered deployments, replication traffic is encrypted with TLS. Configure via:
[cluster.tls]
cert = "/path/to/node.crt"
key = "/path/to/node.key"
ca = "/path/to/ca.crt"
All Raft messages, WAL streaming, and gossip use encrypted channels.