Security & Compliance 4 min read

Zero-Trust Architecture: How We Secure Multi-Tenant Education Data

A deep-dive into how Cognaxa implements zero-trust security principles — from PostgreSQL Row-Level Security to session isolation — to protect institutional data at every layer.

P
Priya Sharma
Head of Security

In enterprise education platforms, security isn’t a feature — it’s the foundation. When you’re handling student records, assessment data, and institutional credentials across multiple organizations on a shared infrastructure, the margin for error is zero.

At Genfinish, we built Cognaxa from the ground up with a zero-trust architecture. This means every request, every query, and every data access is verified against the principle of least privilege. Here’s how we do it.

The Multi-Tenancy Challenge

Most SaaS platforms handle multi-tenancy at the application layer — a WHERE tenant_id = ? clause appended to every query. This works until someone forgets a filter, a join leaks data, or a new engineer writes a raw query without the guard clause.

We decided early that application-level filtering is not sufficient for enterprise security requirements.

PostgreSQL Row-Level Security (RLS)

Instead of relying on application code to enforce tenant isolation, we push that responsibility down to the database itself using PostgreSQL’s Row-Level Security:

-- Enable RLS on the courses table
ALTER TABLE courses ENABLE ROW LEVEL SECURITY;

-- Create a policy that restricts visibility to the current tenant
CREATE POLICY tenant_isolation ON courses
  USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

-- Force RLS even for table owners
ALTER TABLE courses FORCE ROW LEVEL SECURITY;

Every table that holds tenant-specific data has RLS policies. Before any query executes, our database middleware sets the tenant context:

// Set tenant context before every query
await pool.query(
  `SET LOCAL app.current_tenant_id = $1`,
  [user.tenantId]
);

This means even if application code has a bug — a missing filter, a poorly constructed join — the database will not return data from another tenant. The isolation is enforced at the storage layer, not the application layer.

Session Architecture

Our session model follows zero-trust principles:

  1. Opaque tokens: Sessions use UUID tokens stored in Redis, not JWTs. This means sessions can be revoked instantly — there’s no window of valid-but-revoked tokens
  2. Server-side validation: Every request validates the session token against Redis. No client-side trust
  3. Scoped sessions: Each session is bound to a specific tenant. Cross-tenant access requires re-authentication
  4. Configurable TTL: Session lifetimes can be tuned per deployment (24h default, up to 30 days for low-risk environments)
// Session validation middleware (simplified)
const session = await redis.get(`session:${token}`);
if (!session) {
  return res.status(401).json({ error: 'Session expired' });
}

const user = JSON.parse(session);
// Set tenant context for all subsequent database queries
req.user = user;

Defense in Depth

Zero-trust means layers. Here’s what sits between a request and your data:

LayerMechanismPurpose
EdgeRate limiting (5000 req/15min)DDoS mitigation
TransportTLS 1.3Encryption in transit
ApplicationHelmet.js security headersXSS, clickjacking prevention
AuthenticationBearer token + Redis lookupIdentity verification
AuthorizationRole-based middlewarePermission enforcement
DatabasePostgreSQL RLSTenant data isolation
Passwordsbcrypt (12 rounds)Credential hashing
2FATOTP (speakeasy)Second factor verification

Exam Integrity: A Special Case

Proctored exams introduce additional security challenges. Our proctoring system implements:

  • Server-synced timers: The exam clock runs on the server, not the client. Browser DevTools can’t manipulate time
  • Face detection: Real-time face monitoring using face-api.js with violation logging
  • Tab-switch detection: Every tab switch is recorded with a timestamp
  • Snapshot capture: Periodic webcam snapshots stored in S3 for manual review

All violation data is stored as JSONB in the attempt record, giving administrators a complete audit trail.

What’s Next

We’re actively working on:

  • SOC 2 Type II compliance — Formalizing our security controls for enterprise audit requirements
  • SSO integration — SAML 2.0 and OIDC support for institutional identity providers
  • End-to-end encryption for sensitive assessment content at rest

Security is a journey, not a destination. Every feature we ship goes through threat modeling, and every quarter we review our attack surface. Because in education, trust isn’t optional — it’s the product.


Questions about our security architecture? Reach out to our team — we’re happy to discuss our approach in detail with your security team.

#zero-trust #RLS #multi-tenancy #PostgreSQL #security
PS
Priya Sharma
Head of Security

Head of Security at Genfinish. Leads the SOC 2, ISO 27001, and security architecture program. Writes about database-layer tenant isolation, incident response, and the realities of enterprise compliance.

Enjoyed this post?

Engineering notes and shipping updates from the Genfinish team — one email, every other week.

Subscribe →