Security
Purpose
Section titled “Purpose”Summarize the security model and the controls that protect tenant data and the platform.
Overview
Section titled “Overview”Security in Get2Dial rests on layered isolation:
- Request scoping — every
/api/v1request carries a JWT; the control plane derives the tenant from thetidclaim and never from a pinned config. Aplatform_admin(in the reserved Platform tenant) may act cross-tenant via an explicit?tenant_id=override. - Row-level security — Postgres RLS on tenant tables keyed on the
app.tenant_idsession variable; a NULL setting returns no rows (fail-closed). - Per-tenant Redis ACLs and NATS subject permissions scoped to
t.<tenant>.>— a cross-tenant access fails rather than leaking. - Network boundaries — application ports bind to loopback; Caddy
terminates TLS and is the only public surface. The edge holds no shared-infra
secret (enforced in CI by
check-edge-no-shared-secrets.sh); it reads config via node-authenticated API calls (ADR-011).
Configuration
Section titled “Configuration”AUTH_JWT_SECRET=... # HS256 signing key, >= 16 bytesAUTH_JWT_TTL_SECONDS=43200 # access-token lifetime (12h)AUTH_BCRYPT_COST=12 # password hashing costHTTP_ALLOWED_ORIGINS=... # strict CORS allow-list (comma-separated)DB_SSLMODE=require # encrypted DB connections between hostsMAIL_SECRET_KEY=... # AES-256-GCM encrypts per-tenant SMTP passwords at restExamples
Section titled “Examples”Node (edge) authentication is a separate scheme from user JWTs: the node agent
presents a raw API key as a bearer token, matched against the SHA-256 digest in
nodes.api_key_hash. Every /api/v1/nodes/* endpoint forces tenant and node
identity from the authenticated node, so an edge can only ever touch its own
tenant’s data.
- JWTs are stateless — logout is audit-only; there is no server-side revocation yet. Keep TTLs sane and rotate the signing secret carefully (rotation invalidates outstanding tokens).
- Failed logins are rate-limited (10 attempts → 15-minute lockout) and return generic errors to avoid email/workspace enumeration.
- Keep CORS origins strict — wildcard echoes the Origin back because credentials are allowed.