Population Health Service — Security Model
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 13 security-compliance-tenancy
1. RBAC / ABAC Matrix
| Permission | Roles | ABAC Conditions |
|---|---|---|
population_health:dashboard:read | clinician, nurse, analyst, facility_admin, moph_viewer | Scoped to authorized nodeId hierarchy |
population_health:cohort:read | clinician, analyst, facility_admin, moph_viewer | isShared=true OR ownerId=caller |
population_health:cohort:write | analyst, facility_admin, moph_admin | Node scope match |
population_health:cohort:delete | facility_admin, moph_admin | Owns cohort OR has admin role |
population_health:registry:read | clinician, nurse, analyst | Node scope; requires phi:read to see patientId |
population_health:risk:write | analyst, facility_admin | Node scope |
population_health:risk:override | senior_clinician, moph_admin | Requires explicit override permission flag |
population_health:outreach:write | care_coordinator, analyst, facility_admin | Team assignment scope |
population_health:quality:read | clinician, analyst, moph_viewer, donor_viewer | Program-scoped: donor_viewer only sees donor indicator pack |
population_health:hmis:export | moph_integration, platform_admin | Platform-level; not tenant-scoped |
population_health:export:write | researcher + secondary_use:approved | Purpose must be in approved list; IRB reference required for identifiable |
phi:read | clinician, senior_analyst | Required supplement to see patient IDs in list responses |
2. Aggregate-Only Policy
For any user without phi:read permission, list responses (registries, cohort membership, outreach items) must suppress patientId and return only aggregate counts and de-identified row data. This is enforced in the application layer (mapper) — not by SQL alone.
3. Secondary-Use Consent Enforcement
| Export Type | Consent Requirement |
|---|---|
| Aggregate counts (no patientId) | No individual consent required |
| De-identified cohort dataset (k≥5) | Consent checked at cohort level; suppression if k<5 |
| Identifiable patient-level export | Explicit patient consent + approved IRB purpose required |
| HMIS aggregate push to DHIS2 | Aggregate only; no patient-level identifiers ever included |
4. Encryption Classes
| Data | Class | Mechanism |
|---|---|---|
definition_json (cohort DSL) | Standard | AES-256 at rest via PostgreSQL tablespace encryption |
patient_id in registry/risk tables | PHI-Standard | PostgreSQL column-level encryption via pgcrypto for non-aggregate tables |
| De-identified export files | Standard | Encrypted at rest in object storage; presigned URL (24h TTL) |
| DHIS2 API credentials | Secret | Stored in KMS (AWS KMS / HashiCorp Vault); never in application DB |
| Jira/override reason text | Standard | At-rest encryption |
5. Audit Events
All audit events are published via AuditPort → NATS → audit-service.
| Audit Event | Trigger |
|---|---|
COHORT_CREATED | Cohort definition created |
COHORT_UPDATED | Cohort definition version created |
COHORT_ARCHIVED | Cohort soft-deleted |
RISK_OVERRIDE_APPLIED | Manual tier override recorded |
OUTREACH_STATUS_CHANGED | FSM transition on outreach item |
EXPORT_REQUESTED | Secondary-use export job created |
EXPORT_RELEASED | De-identified dataset released |
EXPORT_BLOCKED | Export blocked due to consent or k-threshold violation |
HMIS_EXPORT_COMPLETED | DHIS2 push succeeded |
HMIS_EXPORT_FAILED | DHIS2 push failed after max retries |
CROSS_TENANT_VIOLATION | Attempt to access cross-tenant data |
PHI_ACCESS | Patient-level data returned (when phi:read used) |
6. GDPR / Data Protection Participation
| Right | Handling |
|---|---|
| Right to erasure | Patient patientId removed from all registry, risk, outreach tables on patient deletion request; audit trail preserved with pseudonym |
| Right to portability | Not applicable for aggregate analytics data |
| Data minimization | Cohort jobs fetch only the clinical fields required by the DSL predicates |
| Purpose limitation | Export purpose is recorded and checked against approved list before release |
| Data residency | All PostgreSQL data remains in MoPH-designated region; DHIS2 is MoPH-operated |
7. Data Residency (Afghanistan)
- All production data stored in Afghanistan MoPH data center or designated sovereign cloud region.
- DHIS2 is MoPH-operated; no health data leaves Afghan sovereignty except for donor reporting with explicit MoPH sign-off.
- Research exports require MoPH Data Governance Committee approval before release to external parties.
8. Tenant Isolation
- PostgreSQL RLS policies enforce
tenant_id = current_setting('app.tenant_id')on all tables. nodeIdhierarchy is additionally enforced at the application layer (not SQL alone).- Cross-tenant API requests return 403
CROSS_TENANT_SCOPE_VIOLATIONand are logged as security events.