Category: DSPT Evidence Checklist
Reference: Standard 9: IT Protection
Requirement: Firewalls and boundary protection are in place
Evidence Type: IT supplier statement confirming firewall configuration, or network diagram
Platform: gp_booking_app — Multi-tenant GP Booking Platform
Date: 14 May 2026
Prepared by: Veripath Technical Operations
Organisation: Veripath Ltd
Platform: gp_booking_app (Multi-tenant GP Booking Platform)
Hosting Provider: Fasthosts Internet Ltd (UK) — NGCS VPS
Date: 14 May 2026
The gp_booking_app platform is hosted on a dedicated Fasthosts NGCS (Next Generation Cloud Server) virtual private server within the United Kingdom. The hypervisor layer provides physical isolation from other tenants at the virtualisation level. All data processing and storage occurs within the UK jurisdiction.
| Parameter | Detail |
|---|---|
| Hosting Provider | Fasthosts Internet Ltd |
| Server Type | NGCS VPS (Dedicated) |
| IP Address | 88.208.212.211 |
| Jurisdiction | United Kingdom |
| Hypervisor | Hardware-level tenant isolation |
A host-based firewall (UFW — Uncomplicated Firewall) is active on the VPS with a default-deny inbound policy. Only explicitly permitted traffic may reach the host.
Inbound Rules:
| Port | Service | Source | Purpose |
|---|---|---|---|
| 22/TCP | SSH | Any | Administrative access (key-based auth only) |
| 80/TCP | HTTP | Any | Redirect to HTTPS |
| 443/TCP | HTTPS | Any | TLS-terminated web traffic |
| — | All internal | 172.16.0.0/12, 172.17.0.0/16, 172.18.0.0/16, 172.20.0.0/16 | Docker container inter-communication |
All other inbound ports are denied by default. This includes PostgreSQL (5432), Redis (6379), and all other services which are only accessible from within private Docker networks.
A fail2ban service monitors SSH authentication logs and applies temporary IP bans after repeated failed login attempts, mitigating brute-force and credential-stuffing attacks against the administrative interface.
All application services run within isolated Docker bridge networks. Each container only exposes the ports necessary for its function, and inter-container communication is restricted to defined Docker networks.
| Network | Subnet | Services |
|---|---|---|
| gp_booking_network | 172.18.0.0/16 | nginx, Gunicorn (Django), PostgreSQL, Keycloak, Wiki.js |
| (default bridge) | 172.17.0.0/16 | Docker default (internal use) |
All external HTTP/S traffic is terminated at an nginx reverse proxy configured with the following security controls:
max-age=31536000; includeSubDomains) — forces HTTPSThe platform serves multiple GP surgeries from a single application instance. Tenant isolation is enforced at multiple layers:
| Layer | Mechanism | Status |
|---|---|---|
| Sector identification | Subdomain routing via TenantMiddleware | Hardened |
| Authentication | Keycloak SSO with separate OIDC clients per sector | Hardened |
| Role-based access | RBACMiddleware — role-URL pattern enforcement | Hardened |
| Practice-level data isolation | Practice-scoped querysets via StaffRoleRecord → Practice → Clinic | Hardened |
| Dental sector API | BelongsToDentalSector permission + practice-scoped querysets | Hardened |
| Celery task context | with_tenant() context manager for thread-local tenant | Hardened |
| Cross-boundary audit | RBAC violations logged to AuditLog model | Hardened |
| Role | Data Scope | Boundary Enforced By |
|---|---|---|
| PATIENT | Own records only | View-level filtering |
| CLINICIAN | Own patients only | View-level filtering |
| RECEPTIONIST | Practice-level appointments | PracticeScopedQuerySetMixin |
| PRACTICE_MANAGER | Practice-level appointments + config | PracticeScopedQuerySetMixin |
| DENTAL_STAFF | Own dental practice only | BelongsToDentalSector + DentalProvider.user |
| SYSTEM_ADMIN / SIRO | System-wide | Superuser bypass (audited) |
| Item | Rationale |
|---|---|
| Cloud firewall / security group | Not provided by Fasthosts NGCS tier; compensated by UFW host firewall |
| PostgreSQL listen_addresses | PostgreSQL listens on all interfaces (0.0.0.0:5432); access restricted by UFW to Docker subnet and pg_hba.conf |
Note: This diagram is too large to render properly in Wiki.js. It will be re-implemented as an interactive diagram in Directus/Nuxt.
User → Internet → Fasthosts VPS → UFW Firewall (port 443 only)
→ nginx Reverse Proxy (TLS termination, security headers)
→ Gunicorn / Django (DEBUG=False, RBAC, Practice-Scoped Querysets)
→ PostgreSQL (Docker-internal, access restricted by UFW)
| # | Boundary | Enforced By | Traffic Direction |
|---|---|---|---|
| 1 | Internet → VPS | UFW (default deny, allow 22/80/443 only) | Inbound |
| 2 | VPS → Docker | nginx reverse proxy (TLS, security headers) | Inbound |
| 3 | Docker internal | Docker bridge networks (172.18.0.0/16) | Internal |
| 4 | Application users | Keycloak OIDC authentication | Authentication |
| 5 | Cross-practice | StaffRoleRecord → PracticeScopedQuerySetMixin | Authorisation |
| 6 | Cross-sector | TenantMiddleware + SectorDatabaseRouter | Authorisation |
| 7 | Dental API | BelongsToDentalSector permission | Authorisation |
| 8 | All boundaries | AuditLog (BOUNDARY_VIOLATION, PRACTICE_BOUNDARY) | Audit |
This statement was prepared on 14 May 2026 following the remediation and testing activities documented in the DSPT Firewall & Boundary Protection Assessment (see /tasks/dspt-firewall-boundary-assessment). A re-assessment and update of this statement is recommended every 12 months or upon significant infrastructure change.