Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Medilync Cloud Infrastructure

My solution for Medilync was to create a secure infrastructure that supports three distinct interaction types with the company's connected environment:

  1. Public Visitors (Patients):
    Can access the public static website over HTTPS. They have no access to the /login or /dashboard endpoints and do not possess credentials. This ensures clear separation between the informational frontend and any data-handling backends.

  2. Medical Professionals (Doctors, Nurses, Lab Techs):
    Access the internal web application via OpenVPN only. Once connected, they can reach /login and /dashboard, where the Flask web app authenticates them and grants role-based access to patient records. All connections are encrypted in transit, and authentication is enforced using TLS certificates issued by an internal intermediate CA.

  3. Developers & System Administrators:
    Also connect via OpenVPN, but only receive access to developer and staging environments. Their roles are scoped tightly—developers cannot access patient records, and sysadmins connect via a jump-box to manage and monitor systems without touching sensitive medical data.



Subnet Design & Virtual Machines

The infrastructure is segmented into three subnets for strict traffic separation, aligning with Zero Trust principles.


Network Topology Figure 1: Medilync topology blueprint.


PUBLIC Edge Subnet — 10.10.10.0/24

VPN Server — 10.10.10.99

  • Runs openvpn
  • NAT and port forwarding configured via sysctl.conf and ufw by editing /etc/ufw/before.rules
  • Certificates issued by internal CA (step-ca) with full trust chain
  • Only entry point into the internal private network
  • DNS: vpn.mrcrlr.com
# etc/ufw/before.rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/24 -o <INTERFACE> -j MASQUERADE
COMMIT
# VPN partial core config server-side
port 1194				# OpenVPN server port
proto udp				# Protocol: use UDP (preferred for VPNs)
dev tun					# Use TUN device (layer 3 routing)

ca ca-chain.crt	            # Full certificate chain (root + intermediate)
cert vpn.crt	               # Server certificate
key vpn.key		               # Server private key

dh none                        # No DH params (using ECDH with tls-groups)
tls-groups X25519:prime256v1   # ECDH curves to prefer (modern and fast)

tls-auth ta.key 0              # TLS w shared key (HMAC, 0 = server side)
tls-version-min 1.2            # Enforce minimum TLS version
cipher AES-256-GCM             # Preferred cipher (AEAD)
auth SHA256                    # HMAC digest (used with cipher for AEAD)

Load Balancer — 10.10.10.11

  • Runs nginx as HTTPS reverse proxy, certs provided by Let's Encrypt
  • Public Access: Serves static site
  • Internal Access: Forwards VPN-connected requests to /login and /dashboard only
  • DNS: medilync.mrcrlr.com
# /etc/nginx/sites-available/medilync 
# Configuration snippet
upstream flask_backend {
    server app1.medilync.local:443;
    server app2.medilync.local:443;
    server app3.medilync.local:443;
}

NAT Gateway — 10.10.10.80

  • Routes outbound internet traffic for internal systems using nftables
  • Strictly enforces no inbound connections via both security groups and nftables.conf
# /etc/nftables.conf
# Partial config for outbound routing with NAT
table inet nat {
    chain prerouting {
        type nat hook prerouting priority filter; policy accept;
    }
    chain postrouting {
        type nat hook postrouting priority srcnat; policy accept;
        ip saddr { 10.10.20.0/24, 10.10.30.0/24 } oifname "ens5" masquerade
    }
}

PRIVATE Services Subnet — 10.10.20.0/24

Jump Box — 10.10.20.99

  • Collects logs from all VMs via rsyslog over RELP+TLS
  • Used for internal system access (via ProxyJump)
  • All ssh keys managed by 1password
  • Auditable access point for sysadmins
# /etc/rsyslog.d/60-relp-server.conf
module(load="imrelp")  # Load RELP input module
# Template to write logs into per-host files
# --- additional configs here --- #
# Ruleset to apply log writing
# --- additional configs here --- #
# RELP input with TLS
input(
  type="imrelp"
  port="6514"
  tls="on"
  tls.caCert="/etc/rsyslog-tls/ca-cert.pem"
  tls.myCert="/etc/rsyslog-tls/rsyslog-jump.crt"
  tls.myPrivKey="/etc/rsyslog-tls/rsyslog-jump.key"
  tls.authmode="name"
  tls.permittedpeer="*.medilync.local"
  ruleset="remote-logs"
)

Golden Server (Development) — 10.10.20.20

  • Developer environment
  • Pull requests only from GitHub "staging" branch via fine-grained access token
  • Runs Flask via gunicorn + systemd under medilync.service
  • Nginx serves flask-app (HTTPS only) on port 5000
  • Can connect to the database with restricted test credentials

App Servers 1–3 (Production) — 10.10.20.11–13

  • Production web app instances
  • Automated pull requests from GitHub repo "main" branch using a systemd deploy timer with access control tightly scoped by FGAT – read-only permissions
  • Each deploy installs requirements.txt and restarts Flask app - runs via gunicorn
  • Nginx serves web app (HTTPS only) on port 5000, internal access only

PRIVATE Data Subnet — 10.10.30.0/24

PostgreSQL Database — 10.10.30.11

  • Contains two tables:
    • Patients — Sensitive medical data
    • Access_Audit — Tracks and governs access levels, passwords scrypt hashed
  • Access controlled by web app logic using RBAC rules
  • 5 tiers of access rights (e.g., Patients: health, admin, dev, breakglass. Access_Audit: flask-app) govern table visibility
  • Enforced encryption at rest via underlying VM volume configuration

Summary of Security Controls

Control Type Implementation
Segmentation Three isolated subnets with SGs enforcing one-way flows
Encrypted Transport OpenVPN + HTTPS + RELP over TLS
Encrypted Storage All EBS volumes encrypted by platform-managed keys
IAM & Role Separation VPN user roles mapped to different scopes in app + infra (not yet implemented)
Zero Trust Access No direct public access to internal resources; VPN-only admin access
Logging & Monitoring Centralized, TLS-encrypted logging via rsyslog RELP, stored securely on jump box


IAM Roles, Access, and Security Principles

The following table summarizes the IAM roles, their access paths, scopes, permissions, and the security principles applied in the Medilync cloud infrastructure. This design follows RBAC (Role-Based Access Control), ABAC (Attribute-Based Access Control via tags), Least Privilege, and enforces MFA for all privileged roles and VPN access.

Role Access Path & Resources Access Level Justification (Least Privilege) IAM Management Approach
Admin SSH to all VMs and Web Portals (staging and prod) all VPN only, all AWS resources, KMS, PKI and root CA, logs, IAM Full (infra and app, but no personal data access in database) Needs to manage all infrastructure, users, and security. IAM group, full policy, MFA, ABAC tags
Developer SSH to Golden box and Web portal (staging and prod) all via VPN only, Github repo SSH, tightly scoped database access for testing Needs to develop/test code, no access to production database or prod VMs. IAM group, tag-based ABAC, scoped policy, MFA
Healthcare Web portal via VPN only Full patient access but time-limited sessions, tightly monitored Needs to access patient data, no infrastructure access or dev resources. IAM group, tag-based ABAC, MFA
Breakglass All VMs (via VPN + jump box), AWS resources, KMS, logs, direct database access Full (infra, app, and direct DB) Emergency-only: used for critical incidents when normal access is insufficient. Highly monitored, requires justification, and is time-limited. IAM group, breakglass policy, strict logging, MFA, ABAC tags, approval workflow
Finance Web portal via VPN only Read-only. However accounting data could be pulled to a separate database for better separation of access controls. (e.g., S3 Bucket with services such as Glue and Athena) Needs to view data necessary for billing, no infrastructure or patient data access. IAM group, MFA, read-only policy, ABAC tags
Auditor SSH to Jump box only (with VPN) Read-only. Although, here again, we could push logs to a separate DB for better access control. Must review logs and audit company activity for compliance, no write access. IAM group, MFA, read-only policy, ABAC tags

Additional Clarification: Role Mapping and Security Principles

  • RBAC: All users are assigned to groups that grant only the permissions required for their job function, enforced both in AWS IAM, unique issued VPN cert, and in the web application throu the access_audit table in the database.
  • ABAC: All AWS resources should be tagged (e.g., environment=prod, role=healthcare), and IAM policies use these tags to restrict access. For example, developers can only access resources tagged environment=dev.
  • Least Privilege: Permissions are scoped as narrowly as possible. Healthcare staff can only access patient data via the web app, no access to the database or servers directly. Developers cannot access production data or VMs.
  • MFA: Multi-factor authentication is enforced for all privileged roles (Admin, Healthcare) and for VPN access.

Note: Breakglass Role

The Breakglass role is reserved for emergency situations where standard roles (Admin, Healthcare, etc.) are insufficient to resolve a critical incident (e.g., database corruption, ransomware, or urgent patient data recovery). This role grants full access to all infrastructure, including direct database access, and is protected by the following controls:

  • MFA and Approval: Access requires multi-factor authentication and explicit approval (e.g., via ticket or manager sign-off).
  • Strict Logging: All actions are logged and monitored in real time. Alerts are generated for any use of this role.
  • Time-limited: Access is granted only for the minimum time necessary and is immediately revoked after the incident.
  • Justification Required: Users must provide a business justification for breakglass access, which is reviewed post-incident.

This ensures that the principle of least privilege is maintained under normal operations, while still allowing for rapid response in emergencies.



Medilync AWS Resources

Resource map: Resource Map Subnets: Subnets Routes: Routes Virtual machines: Instances Security groups: Security Groups


OpenVPN connection Figure 2: Connecting to VPN from local machine.


SSH into VPN-Gateway Figure 3: SSH into VPN-gateway.


SSH into Load Balancer Figure 4: SSH into Load Balancer.


SSH into NAT-Gateway Figure 5: SSH into NAT-Gateway.


SSH into Golden Server Figure 6: SSH into Golden Server (Dev/Staging Environment).


SSH into App Server 1 SSH into App Server 2 SSH into App Server 3 Figure 7, 8, 9: SSH into App Server 1, 2, and 3 (Production).


Employee logins via VPN with database queries Figure 10: Demonstrating role-based access control in web application.


Postgresql TLS encrypted querying Figure 11: All databse traffic is fully encrypted and authenticated via internal CA signed certs.


Database logs sent to jump box Figure 12: All logs encrypted over rsyslog RELP over TLS.


SSH into Database Server Figure 13: SSH into Databse Server.


SSH into VMs Figure 14: SSH into all machines through VPN tunnel with ProxyJump. SSH keys managed by 1Password


About

Secure cloud infrastrucutre solution for Medilync built using terraform

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages