Immunizations Service — Security Model
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template
1. Authentication and Authorization
- Authentication: Keycloak JWT (RS256). Every request must carry a valid Bearer token.
- Authorization: RBAC via Keycloak realm roles + module entitlement guard (
clinical.immunizations). - Tenant isolation: PostgreSQL RLS with
app.tenant_idsession variable set from JWT claim.
2. RBAC Matrix
| Operation | CLINICIAN | NURSE | VACCINATION_OFFICER | PATIENT | ADMIN | ANALYST | DATA_MIGRATION |
|---|---|---|---|---|---|---|---|
| Record administration | Yes | Yes | Yes | No | No | No | No |
| Record refusal | Yes | Yes | Yes | No | No | No | No |
| Amend record | Yes | No | Yes | No | No | No | No |
| Correct (enter-in-error) | Yes | No | No | No | Yes | No | No |
| Import historical | Yes | No | No | No | No | No | Yes |
| View own records | Yes | Yes | Yes | Own | Yes | No | No |
| View forecast | Yes | Yes | Yes | Own | Yes | No | No |
| Add contraindication | Yes | No | No | No | No | No | No |
| View defaulters | No | No | Yes | No | Yes | No | No |
| Coverage report | No | No | No | No | Yes | Yes | No |
| Generate certificate | Yes | No | No | Own | No | No | No |
| Registry sync admin | No | No | No | No | Yes | No | No |
3. Encryption
| Data class | At rest | In transit |
|---|---|---|
| Immunization records | AES-256 (PostgreSQL TDE or volume encryption) | TLS 1.3 |
| Lot numbers | Not classified as PII; standard encryption | TLS 1.3 |
| Digital certificate JWT | Signed (RS256); not encrypted | TLS 1.3 |
| NATS event payloads | Encrypted at rest on JetStream volume | TLS 1.3 |
4. PII and Sensitive Fields
| Field | Classification | Masking rule |
|---|---|---|
patientId | PII | Resolved to name only for VACCINATION_OFFICER in defaulter list |
performerId | PII | Visible to ADMIN and CLINICIAN only |
lotNumber | Clinical data | No masking; visible to clinical roles |
notes | PII | Visible to clinical roles; hidden from ANALYST |
5. Audit Events
All state-changing operations write to the platform audit log with:
eventType(e.g.,IMMUNIZATION_RECORDED,IMMUNIZATION_CORRECTED,CONTRAINDICATION_ADDED)actorId,actorRole,tenantId,patientId,resourceId,timestampchangeDetails(diff of changed fields for amendments)
Audit records are immutable and retained for 7 years per MoPH data retention policy.
6. Data Residency
- All immunization data must reside within the Afghanistan MoPH-approved data centre jurisdiction.
- National registry sync data may transit to the national registry endpoint over a secured government network connection only.
- Cloud deployments must apply data residency constraints in Kubernetes
NodeAffinityrules.
7. GDPR / Patient Rights
| Right | Implementation |
|---|---|
| Right to access | GET /v1/immunizations?patientId= for patient-owned records |
| Right to rectification | PUT /v1/immunizations/:id (clinical correction, not patient self-service) |
| Right to erasure | Not applicable for clinical records (legal hold under MoPH mandate); pseudonymization on platform delete request |
| Right to portability | GET /fhir/R4/Immunization export; digital certificate endpoint |
8. Module Entitlement Guard
Requests to immunizations-service endpoints are rejected with 403 MODULE_NOT_ENTITLED if the tenant's Keycloak realm does not include the clinical.immunizations entitlement scope.