From 92ec99a29a58e5636a88ae031bbe4b02890d03d8 Mon Sep 17 00:00:00 2001 From: Emeka Date: Thu, 5 Jun 2025 16:31:19 +0100 Subject: [PATCH] feat: Health-infracstructure-setup --- scripts/redis-backup.sh | 0 .../# .env.example | 79 +++++ .../# monitoring/alertmanager.yml | 40 +++ .../# monitoring/prometheus.yml | 38 +++ .../# nginx/hospital.conf | 63 ++++ src/Hospital-Infracstructure-Setup/Readme.md | 25 ++ .../docker-compose.yml | 314 ++++++++++++++++++ .../postgres/init/01-init-db.sql | 79 +++++ .../postgres/postgresql.conf | 48 +++ .../scripts/backup.sh | 56 ++++ .../scripts/redis-backup.sh | 41 +++ 11 files changed, 783 insertions(+) create mode 100644 scripts/redis-backup.sh create mode 100644 src/Hospital-Infracstructure-Setup/# .env.example create mode 100644 src/Hospital-Infracstructure-Setup/# monitoring/alertmanager.yml create mode 100644 src/Hospital-Infracstructure-Setup/# monitoring/prometheus.yml create mode 100644 src/Hospital-Infracstructure-Setup/# nginx/hospital.conf create mode 100644 src/Hospital-Infracstructure-Setup/Readme.md create mode 100644 src/Hospital-Infracstructure-Setup/docker-compose.yml create mode 100644 src/Hospital-Infracstructure-Setup/postgres/init/01-init-db.sql create mode 100644 src/Hospital-Infracstructure-Setup/postgres/postgresql.conf create mode 100644 src/Hospital-Infracstructure-Setup/scripts/backup.sh create mode 100644 src/Hospital-Infracstructure-Setup/scripts/redis-backup.sh diff --git a/scripts/redis-backup.sh b/scripts/redis-backup.sh new file mode 100644 index 0000000..e69de29 diff --git a/src/Hospital-Infracstructure-Setup/# .env.example b/src/Hospital-Infracstructure-Setup/# .env.example new file mode 100644 index 0000000..92298d7 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/# .env.example @@ -0,0 +1,79 @@ +# Hospital Management System Environment Variables + +# Database Configuration +DB_PASSWORD=your_secure_database_password_here +POSTGRES_PASSWORD=your_secure_database_password_here + +# Redis Configuration +REDIS_PASSWORD=your_secure_redis_password_here + +# Application Security +JWT_SECRET=your_jwt_secret_key_here +ENCRYPTION_KEY=your_32_character_encryption_key_here + +# Monitoring +GRAFANA_PASSWORD=your_grafana_admin_password_here + +# Backup Configuration +BACKUP_ENCRYPTION_PASSPHRASE=your_backup_encryption_passphrase_here + +# SSL Certificate paths (generate before deployment) +# openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ +# -keyout certs/server.key -out certs/server.crt + +--- +# Setup Instructions + +## 1. Initial Setup +```bash +# Create required directories +sudo mkdir -p /opt/hospital/{data/{postgres,redis},backups/{postgres,redis},logs} +sudo chown -R $USER:$USER /opt/hospital + +# Create certificate directory +mkdir -p certs + +# Generate SSL certificates +openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout certs/server.key -out certs/server.crt \ + -subj "/C=US/ST=State/L=City/O=Hospital/CN=hospital.local" + +# Copy environment file and configure +cp .env.example .env +# Edit .env with your secure passwords +``` + +## 2. Deploy the System +```bash +# Build and start all services +docker-compose up -d + +# Verify all services are healthy +docker-compose ps + +# Check logs +docker-compose logs -f hospital-app +``` + +## 3. Access Points +- Hospital App: https://localhost (redirects to HTTPS) +- Grafana Monitoring: http://localhost:3001 +- Prometheus: http://localhost:9090 +- AlertManager: http://localhost:9093 + +## 4. Security Features +- PostgreSQL with TLS encryption and SCRAM-SHA-256 authentication +- Row-level security and audit logging +- Redis with password authentication +- Automated encrypted backups +- SSL/TLS termination at proxy level +- Security headers and rate limiting + +## 5. Monitoring Features +- Application metrics and health checks +- Database performance monitoring +- System resource monitoring +- Medical-grade alerting with email notifications +- Automated backup verification + +This configuration provides a production-ready hospital management system with enterprise-grade security, monitoring, and backup capabilities. \ No newline at end of file diff --git a/src/Hospital-Infracstructure-Setup/# monitoring/alertmanager.yml b/src/Hospital-Infracstructure-Setup/# monitoring/alertmanager.yml new file mode 100644 index 0000000..20f70d2 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/# monitoring/alertmanager.yml @@ -0,0 +1,40 @@ +global: + smtp_smarthost: 'localhost:587' + smtp_from: 'alerts@hospital.local' + +route: + group_by: ['alertname'] + group_wait: 10s + group_interval: 10s + repeat_interval: 1h + receiver: 'medical-alerts' + routes: + - match: + severity: critical + receiver: 'critical-medical-alerts' + +receivers: +- name: 'medical-alerts' + email_configs: + - to: 'admin@hospital.local' + subject: 'Hospital System Alert: {{ .GroupLabels.alertname }}' + body: | + Alert: {{ .GroupLabels.alertname }} + Severity: {{ .CommonLabels.severity }} + Instance: {{ .CommonLabels.instance }} + Summary: {{ .CommonAnnotations.summary }} + Description: {{ .CommonAnnotations.description }} + +- name: 'critical-medical-alerts' + email_configs: + - to: 'critical@hospital.local' + subject: 'CRITICAL Hospital System Alert: {{ .GroupLabels.alertname }}' + body: | + CRITICAL ALERT - IMMEDIATE ACTION REQUIRED + + Alert: {{ .GroupLabels.alertname }} + Instance: {{ .CommonLabels.instance }} + Summary: {{ .CommonAnnotations.summary }} + Description: {{ .CommonAnnotations.description }} + + This is a critical medical system alert requiring immediate attention. diff --git a/src/Hospital-Infracstructure-Setup/# monitoring/prometheus.yml b/src/Hospital-Infracstructure-Setup/# monitoring/prometheus.yml new file mode 100644 index 0000000..6b1ea8a --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/# monitoring/prometheus.yml @@ -0,0 +1,38 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +rule_files: + - "hospital_alerts.yml" + +alerting: + alertmanagers: + - static_configs: + - targets: + - alertmanager:9093 + +scrape_configs: + - job_name: 'hospital-app' + static_configs: + - targets: ['hospital-app:3000'] + metrics_path: '/metrics' + scrape_interval: 30s + + - job_name: 'postgres' + static_configs: + - targets: ['postgres-exporter:9187'] + scrape_interval: 30s + + - job_name: 'redis' + static_configs: + - targets: ['redis-exporter:9121'] + scrape_interval: 30s + + - job_name: 'node' + static_configs: + - targets: ['node-exporter:9100'] + scrape_interval: 30s + + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] \ No newline at end of file diff --git a/src/Hospital-Infracstructure-Setup/# nginx/hospital.conf b/src/Hospital-Infracstructure-Setup/# nginx/hospital.conf new file mode 100644 index 0000000..3d1e0c4 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/# nginx/hospital.conf @@ -0,0 +1,63 @@ +upstream hospital_app { + server hospital-app:3000; +} + +server { + listen 80; + server_name hospital.local; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl http2; + server_name hospital.local; + + ssl_certificate /etc/nginx/certs/server.crt; + ssl_certificate_key /etc/nginx/certs/server.key; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options DENY; + add_header X-XSS-Protection "1; mode=block"; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"; + + # Rate limiting + limit_req_zone $binary_remote_addr zone=hospital:10m rate=10r/m; + limit_req zone=hospital burst=20 nodelay; + + location / { + proxy_pass http://hospital_app; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + + # Timeouts + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + } + + location /health { + access_log off; + proxy_pass http://hospital_app/health; + } + + # Monitoring endpoints + location /metrics { + allow 172.20.0.0/16; + deny all; + proxy_pass http://hospital_app/metrics; + } +} diff --git a/src/Hospital-Infracstructure-Setup/Readme.md b/src/Hospital-Infracstructure-Setup/Readme.md new file mode 100644 index 0000000..da230c1 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/Readme.md @@ -0,0 +1,25 @@ +# Multi-stage Dockerfile for NestJS Hospital Management System +FROM node:18-alpine AS base +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production && npm cache clean --force + +FROM node:18-alpine AS build +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +FROM node:18-alpine AS production +RUN addgroup -g 1001 -S nodejs +RUN adduser -S nestjs -u 1001 +WORKDIR /app +COPY --from=base /app/node_modules ./node_modules +COPY --from=build --chown=nestjs:nodejs /app/dist ./dist +COPY --from=build --chown=nestjs:nodejs /app/package*.json ./ +USER nestjs +EXPOSE 3000 +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node dist/health-check.js +CMD ["node", "dist/main.js"] diff --git a/src/Hospital-Infracstructure-Setup/docker-compose.yml b/src/Hospital-Infracstructure-Setup/docker-compose.yml new file mode 100644 index 0000000..0750c2d --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/docker-compose.yml @@ -0,0 +1,314 @@ +version: '3.8' + +services: + # Main Hospital Management Application + hospital-app: + build: + context: . + dockerfile: Dockerfile + target: production + container_name: hospital-management-app + restart: unless-stopped + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - DATABASE_URL=postgresql://hospital_user:${DB_PASSWORD}@postgres:5432/hospital_db?sslmode=require + - REDIS_URL=redis://redis:6379 + - JWT_SECRET=${JWT_SECRET} + - ENCRYPTION_KEY=${ENCRYPTION_KEY} + - TLS_CERT_PATH=/app/certs/server.crt + - TLS_KEY_PATH=/app/certs/server.key + volumes: + - ./certs:/app/certs:ro + - ./logs:/app/logs + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - hospital-network + healthcheck: + test: ["CMD", "curl", "-f", "https://localhost:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # PostgreSQL with Medical Data Encryption + postgres: + image: postgres:15-alpine + container_name: hospital-postgres + restart: unless-stopped + environment: + - POSTGRES_DB=hospital_db + - POSTGRES_USER=hospital_user + - POSTGRES_PASSWORD=${DB_PASSWORD} + - POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 --auth-local=scram-sha-256 + volumes: + - postgres_data:/var/lib/postgresql/data + - ./postgres/init:/docker-entrypoint-initdb.d:ro + - ./postgres/certs:/var/lib/postgresql/certs:ro + - ./postgres/postgresql.conf:/etc/postgresql/postgresql.conf:ro + ports: + - "5432:5432" + command: > + postgres + -c ssl=on + -c ssl_cert_file=/var/lib/postgresql/certs/server.crt + -c ssl_key_file=/var/lib/postgresql/certs/server.key + -c ssl_ca_file=/var/lib/postgresql/certs/ca.crt + -c config_file=/etc/postgresql/postgresql.conf + -c shared_preload_libraries=pg_stat_statements + -c log_statement=all + -c log_min_duration_statement=1000 + networks: + - hospital-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U hospital_user -d hospital_db"] + interval: 10s + timeout: 5s + retries: 5 + + # Redis for Medical Session Management + redis: + image: redis:7-alpine + container_name: hospital-redis + restart: unless-stopped + command: > + redis-server + --requirepass ${REDIS_PASSWORD} + --appendonly yes + --appendfsync everysec + --maxmemory 512mb + --maxmemory-policy allkeys-lru + --tcp-keepalive 60 + --timeout 0 + --tcp-backlog 511 + volumes: + - redis_data:/data + - ./redis/redis.conf:/etc/redis/redis.conf:ro + ports: + - "6379:6379" + networks: + - hospital-network + healthcheck: + test: ["CMD", "redis-cli", "--raw", "incr", "ping"] + interval: 10s + timeout: 3s + retries: 5 + + # Database Backup Service + postgres-backup: + image: postgres:15-alpine + container_name: hospital-backup + restart: unless-stopped + environment: + - PGPASSWORD=${DB_PASSWORD} + - BACKUP_RETENTION_DAYS=30 + - BACKUP_SCHEDULE=0 2 * * * + volumes: + - postgres_backups:/backups + - ./scripts/backup.sh:/usr/local/bin/backup.sh:ro + command: > + sh -c " + apk add --no-cache dcron && + echo '0 2 * * * /usr/local/bin/backup.sh' | crontab - && + crond -f -d 8 + " + depends_on: + postgres: + condition: service_healthy + networks: + - hospital-network + + # Redis Backup Service + redis-backup: + image: redis:7-alpine + container_name: hospital-redis-backup + restart: unless-stopped + environment: + - REDIS_PASSWORD=${REDIS_PASSWORD} + - BACKUP_RETENTION_DAYS=7 + volumes: + - redis_backups:/backups + - ./scripts/redis-backup.sh:/usr/local/bin/redis-backup.sh:ro + command: > + sh -c " + apk add --no-cache dcron && + echo '0 */6 * * * /usr/local/bin/redis-backup.sh' | crontab - && + crond -f -d 8 + " + depends_on: + redis: + condition: service_healthy + networks: + - hospital-network + + # Prometheus Monitoring + prometheus: + image: prom/prometheus:latest + container_name: hospital-prometheus + restart: unless-stopped + ports: + - "9090:9090" + volumes: + - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--storage.tsdb.retention.time=30d' + - '--web.enable-lifecycle' + networks: + - hospital-network + + # Grafana for Medical System Monitoring + grafana: + image: grafana/grafana:latest + container_name: hospital-grafana + restart: unless-stopped + ports: + - "3001:3000" + environment: + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} + - GF_USERS_ALLOW_SIGN_UP=false + - GF_SECURITY_DISABLE_GRAVATAR=true + - GF_ANALYTICS_REPORTING_ENABLED=false + - GF_SECURITY_COOKIE_SECURE=true + - GF_SECURITY_STRICT_TRANSPORT_SECURITY=true + volumes: + - grafana_data:/var/lib/grafana + - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro + - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources:ro + depends_on: + - prometheus + networks: + - hospital-network + + # AlertManager for Medical-Grade Alerts + alertmanager: + image: prom/alertmanager:latest + container_name: hospital-alertmanager + restart: unless-stopped + ports: + - "9093:9093" + volumes: + - ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro + - alertmanager_data:/alertmanager + command: + - '--config.file=/etc/alertmanager/alertmanager.yml' + - '--storage.path=/alertmanager' + - '--web.external-url=http://localhost:9093' + networks: + - hospital-network + + # Node Exporter for System Metrics + node-exporter: + image: prom/node-exporter:latest + container_name: hospital-node-exporter + restart: unless-stopped + ports: + - "9100:9100" + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + command: + - '--path.procfs=/host/proc' + - '--path.rootfs=/rootfs' + - '--path.sysfs=/host/sys' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + networks: + - hospital-network + + # Postgres Exporter for Database Metrics + postgres-exporter: + image: prometheuscommunity/postgres-exporter:latest + container_name: hospital-postgres-exporter + restart: unless-stopped + environment: + - DATA_SOURCE_NAME=postgresql://hospital_user:${DB_PASSWORD}@postgres:5432/hospital_db?sslmode=require + ports: + - "9187:9187" + depends_on: + postgres: + condition: service_healthy + networks: + - hospital-network + + # Redis Exporter for Cache Metrics + redis-exporter: + image: oliver006/redis_exporter:latest + container_name: hospital-redis-exporter + restart: unless-stopped + environment: + - REDIS_ADDR=redis://redis:6379 + - REDIS_PASSWORD=${REDIS_PASSWORD} + ports: + - "9121:9121" + depends_on: + redis: + condition: service_healthy + networks: + - hospital-network + + # Nginx Reverse Proxy with SSL Termination + nginx: + image: nginx:alpine + container_name: hospital-nginx + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/hospital.conf:/etc/nginx/conf.d/default.conf:ro + - ./certs:/etc/nginx/certs:ro + - ./logs/nginx:/var/log/nginx + depends_on: + - hospital-app + networks: + - hospital-network + +networks: + hospital-network: + driver: bridge + ipam: + config: + - subnet: 172.20.0.0/16 + +volumes: + postgres_data: + driver: local + driver_opts: + type: none + o: bind + device: /opt/hospital/data/postgres + redis_data: + driver: local + driver_opts: + type: none + o: bind + device: /opt/hospital/data/redis + postgres_backups: + driver: local + driver_opts: + type: none + o: bind + device: /opt/hospital/backups/postgres + redis_backups: + driver: local + driver_opts: + type: none + o: bind + device: /opt/hospital/backups/redis + prometheus_data: + driver: local + grafana_data: + driver: local + alertmanager_data: + driver: local diff --git a/src/Hospital-Infracstructure-Setup/postgres/init/01-init-db.sql b/src/Hospital-Infracstructure-Setup/postgres/init/01-init-db.sql new file mode 100644 index 0000000..8b8df42 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/postgres/init/01-init-db.sql @@ -0,0 +1,79 @@ +- Initialize Hospital Database with Encryption + +-- Enable required extensions +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; +CREATE EXTENSION IF NOT EXISTS "pg_stat_statements"; + +-- Create encrypted storage for sensitive medical data +CREATE TABLE IF NOT EXISTS patient_records ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + patient_id VARCHAR(50) NOT NULL UNIQUE, + encrypted_data BYTEA NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + data_hash VARCHAR(64) NOT NULL +); + +-- Create audit log table +CREATE TABLE IF NOT EXISTS audit_log ( + id SERIAL PRIMARY KEY, + table_name VARCHAR(50) NOT NULL, + operation VARCHAR(10) NOT NULL, + user_id VARCHAR(50), + timestamp TIMESTAMP WITH TIME ZONE DEFAULT NOW(), + old_values JSONB, + new_values JSONB, + ip_address INET +); + +-- Create function for data encryption +CREATE OR REPLACE FUNCTION encrypt_medical_data(data TEXT, key TEXT) +RETURNS BYTEA AS $$ +BEGIN + RETURN pgp_sym_encrypt(data, key, 'compress-algo=1, cipher-algo=aes256'); +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create function for data decryption +CREATE OR REPLACE FUNCTION decrypt_medical_data(encrypted_data BYTEA, key TEXT) +RETURNS TEXT AS $$ +BEGIN + RETURN pgp_sym_decrypt(encrypted_data, key); +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create audit trigger function +CREATE OR REPLACE FUNCTION audit_trigger_function() +RETURNS TRIGGER AS $$ +BEGIN + IF TG_OP = 'DELETE' THEN + INSERT INTO audit_log (table_name, operation, user_id, old_values, ip_address) + VALUES (TG_TABLE_NAME, TG_OP, current_user, row_to_json(OLD), inet_client_addr()); + RETURN OLD; + ELSIF TG_OP = 'UPDATE' THEN + INSERT INTO audit_log (table_name, operation, user_id, old_values, new_values, ip_address) + VALUES (TG_TABLE_NAME, TG_OP, current_user, row_to_json(OLD), row_to_json(NEW), inet_client_addr()); + RETURN NEW; + ELSIF TG_OP = 'INSERT' THEN + INSERT INTO audit_log (table_name, operation, user_id, new_values, ip_address) + VALUES (TG_TABLE_NAME, TG_OP, current_user, row_to_json(NEW), inet_client_addr()); + RETURN NEW; + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +-- Apply audit trigger to patient_records +CREATE TRIGGER patient_records_audit_trigger + AFTER INSERT OR UPDATE OR DELETE ON patient_records + FOR EACH ROW EXECUTE FUNCTION audit_trigger_function(); + +-- Set up Row Level Security +ALTER TABLE patient_records ENABLE ROW LEVEL SECURITY; + +-- Create policy for data access +CREATE POLICY patient_data_policy ON patient_records + FOR ALL TO hospital_user + USING (true) + WITH CHECK (true); diff --git a/src/Hospital-Infracstructure-Setup/postgres/postgresql.conf b/src/Hospital-Infracstructure-Setup/postgres/postgresql.conf new file mode 100644 index 0000000..4c01b27 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/postgres/postgresql.conf @@ -0,0 +1,48 @@ +# PostgreSQL Configuration for Medical Data + +# Connection Settings +listen_addresses = '*' +port = 5432 +max_connections = 200 +shared_buffers = 256MB +effective_cache_size = 1GB +work_mem = 4MB +maintenance_work_mem = 64MB + +# SSL/TLS Configuration +ssl = on +ssl_cert_file = '/var/lib/postgresql/certs/server.crt' +ssl_key_file = '/var/lib/postgresql/certs/server.key' +ssl_ca_file = '/var/lib/postgresql/certs/ca.crt' +ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' +ssl_prefer_server_ciphers = on +ssl_min_protocol_version = 'TLSv1.2' + +# Logging for Audit Trail +log_statement = 'all' +log_min_duration_statement = 1000 +log_checkpoints = on +log_connections = on +log_disconnections = on +log_lock_waits = on +log_temp_files = 0 +log_autovacuum_min_duration = 0 +log_error_verbosity = verbose +log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ' +log_destination = 'stderr' +logging_collector = on +log_directory = '/var/log/postgresql' +log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' +log_rotation_age = 1d +log_rotation_size = 100MB + +# Performance +checkpoint_completion_target = 0.9 +wal_buffers = 16MB +default_statistics_target = 100 +random_page_cost = 1.1 +effective_io_concurrency = 200 + +# Security +password_encryption = scram-sha-256 +row_security = on diff --git a/src/Hospital-Infracstructure-Setup/scripts/backup.sh b/src/Hospital-Infracstructure-Setup/scripts/backup.sh new file mode 100644 index 0000000..37d30a5 --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/scripts/backup.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Hospital PostgreSQL Backup Script +set -e + +DB_HOST="postgres" +DB_NAME="hospital_db" +DB_USER="hospital_user" +BACKUP_DIR="/backups" +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="hospital_db_backup_${DATE}.sql.gz" +RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-30} + +echo "Starting backup process at $(date)" + +# Create backup directory if it doesn't exist +mkdir -p ${BACKUP_DIR} + +# Perform encrypted backup +pg_dump -h ${DB_HOST} -U ${DB_USER} -d ${DB_NAME} \ + --verbose --format=custom --compress=9 \ + --no-owner --no-privileges \ + | gzip > ${BACKUP_DIR}/${BACKUP_FILE} + +# Verify backup +if [ -f "${BACKUP_DIR}/${BACKUP_FILE}" ]; then + echo "Backup completed successfully: ${BACKUP_FILE}" + echo "Backup size: $(du -h ${BACKUP_DIR}/${BACKUP_FILE} | cut -f1)" +else + echo "Backup failed!" + exit 1 +fi + +# Encrypt backup file +gpg --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 \ + --s2k-digest-algo SHA512 --s2k-count 65536 \ + --symmetric --output "${BACKUP_DIR}/${BACKUP_FILE}.gpg" \ + "${BACKUP_DIR}/${BACKUP_FILE}" + +# Remove unencrypted backup +rm "${BACKUP_DIR}/${BACKUP_FILE}" + +# Clean up old backups +find ${BACKUP_DIR} -name "hospital_db_backup_*.sql.gz.gpg" \ + -type f -mtime +${RETENTION_DAYS} -delete + +echo "Backup process completed at $(date)" + +# Test backup integrity +echo "Testing backup integrity..." +if gpg --quiet --batch --decrypt "${BACKUP_DIR}/${BACKUP_FILE}.gpg" > /dev/null 2>&1; then + echo "Backup integrity test passed" +else + echo "Backup integrity test failed!" + exit 1 +fi diff --git a/src/Hospital-Infracstructure-Setup/scripts/redis-backup.sh b/src/Hospital-Infracstructure-Setup/scripts/redis-backup.sh new file mode 100644 index 0000000..49e7f6d --- /dev/null +++ b/src/Hospital-Infracstructure-Setup/scripts/redis-backup.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Hospital Redis Backup Script +set -e + +REDIS_HOST="redis" +REDIS_PORT="6379" +BACKUP_DIR="/backups" +DATE=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="redis_dump_${DATE}.rdb" +RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-7} + +echo "Starting Redis backup process at $(date)" + +# Create backup directory +mkdir -p ${BACKUP_DIR} + +# Trigger Redis save +redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDIS_PASSWORD} BGSAVE + +# Wait for backup to complete +while [ $(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDIS_PASSWORD} LASTSAVE) -eq $(redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDIS_PASSWORD} LASTSAVE) ]; do + sleep 1 +done + +# Copy dump file +docker cp hospital-redis:/data/dump.rdb ${BACKUP_DIR}/${BACKUP_FILE} + +# Encrypt backup +gpg --cipher-algo AES256 --symmetric \ + --output "${BACKUP_DIR}/${BACKUP_FILE}.gpg" \ + "${BACKUP_DIR}/${BACKUP_FILE}" + +# Remove unencrypted backup +rm "${BACKUP_DIR}/${BACKUP_FILE}" + +# Clean up old backups +find ${BACKUP_DIR} -name "redis_dump_*.rdb.gpg" \ + -type f -mtime +${RETENTION_DAYS} -delete + +echo "Redis backup completed at $(date)"