Billing Service — Security Model
Status: populated Owner: Platform Engineering + Security Last updated: 2026-04-18 Companion: 13 Security
1. Authentication
Kong enforces JWT or API key authentication on all REST endpoints. This service re-validates X-Tenant-Id against JWT tenant_id claim (defense in depth).
NATS consumer: cluster-internal; no external access. NATS TLS + auth credentials injected via Vault sidecar.
2. Authorization (RBAC)
| Scope | Action | Role |
|---|---|---|
billing:read | Usage query, invoice list/download | account.admin, account.viewer |
billing:admin | Pricing CRUD, operator cost CRUD | platform.billing_admin |
platform.finance | Void invoice | platform.finance (separate from billing_admin) |
| Cross-account read | Any account's billing data | platform.admin (audit-logged) |
3. Tenant Isolation
tenant_idcolumn on all tables with RLS policy.- Query always includes
WHERE tenant_id = $1AND RLS enforced at PG level. - Integration test
test/integration/tenant-isolation.spec.tsverifies cross-tenant read returns empty/404.
4. Financial Data Controls
- Pricing table changes are audit-logged:
created_by,created_at, version history viaeffectiveTo. - Invoice void requires
platform.financerole + mandatoryreasonfield; voided records retained withvoided_by,voided_at. - All
PATCHto pricing creates a new versioned row rather than mutating existing data (append-only pattern). - NATS ingestion uses
ON CONFLICT DO NOTHING— no retroactive billing changes via replay.
5. Encryption
| Class | Mechanism |
|---|---|
| In-flight | TLS 1.2+ (Kong + internal mTLS) |
| At rest (PG) | Transparent disk encryption (EBS/GCP PD) |
| S3 objects (PDFs) | SSE-S3 or SSE-KMS on bucket |
| Secrets | Vault → env at pod start |
6. Threat Model
| Threat | Control |
|---|---|
| Tampered billing event (inflated segment count) | Source of truth is dlr-processor; operator logs cross-reference; segment_count validated range 1–10 |
| Price manipulation via pricing API | platform.billing_admin role required; all changes audit-logged |
| Unauthorized invoice download | S3 presigned URLs scoped to authenticated account; TTL 15 min |
| Unauthorized invoice void | platform.finance role; audit trail retained even after void |
| NATS message injection | Cluster-internal NATS; TLS + Vault credentials; schema validation on ingest |
| SQL injection | Prisma parameterization; billing_admin endpoint guarded by input validation |
7. GDPR / Data Retention
billing_eventsretained for regulatory accounting period (7 years minimum); not subject to short-term GDPR erasure.- On
tenant_erased.v1event: customer-facing PII (accountId FK retained for audit;tenantIdanonymized per legal guidance). - Invoice PDFs in S3: retention policy set to 7 years on bucket lifecycle.