This document provides security guidance for deploying rtpipeline in production environments.
- Security Overview
- Default Configuration Security
- Production Deployment Security
- Authentication & Authorization
- Network Security
- Data Protection
- Container Security
- Monitoring & Incident Response
- HIPAA Compliance Considerations
- Security Checklist
rtpipeline is designed with security in mind:
- ✅ Container isolation: Runs in Docker containers with minimal privileges
- ✅ Non-root user: Operates as UID 1000 (non-root)
- ✅ Capability dropping: Only essential Linux capabilities enabled
- ✅ Path traversal protection: Prevents directory traversal attacks
- ✅ Input validation: File type and size validation
- ✅ Secure file handling: Uses
secure_filename()for uploads
┌─────────────────────────────────────────────┐
│ Network Layer (Your Responsibility) │
│ ├─ Firewall │
│ ├─ HTTPS/TLS │
│ └─ Authentication (Reverse Proxy) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ rtpipeline Web UI (Port 8080) │
│ ├─ Input Validation │
│ ├─ Path Traversal Protection │
│ └─ Secure File Upload │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Docker Container (Security Hardened) │
│ ├─ Non-root user (UID 1000) │
│ ├─ Minimal capabilities │
│ ├─ Read-only code mount │
│ └─ Resource limits │
└─────────────────────────────────────────────┘
The default docker-compose.yml configuration is designed for:
- ✅ Local development on a single workstation
- ✅ Trusted network environments (hospital intranet)
- ✅ Research use on isolated systems
- ❌ NOT for internet-facing deployments without additional security
-
No Authentication
- Web UI has no built-in authentication
- Anyone with network access to port 8080 can upload files and submit jobs
- Mitigation: Only expose to trusted networks
-
HTTP Only (No HTTPS)
- Communication is unencrypted
- Risk: Data can be intercepted on the network
- Mitigation: Use in trusted networks or add reverse proxy with TLS
-
Secret Key
- Flask generates random secret key if not provided
- Impact: Sessions are invalidated on container restart
- Mitigation: Set
SECRET_KEYenvironment variable for persistence
- ✅ Authentication (reverse proxy or API token)
- ✅ HTTPS/TLS encryption
- ✅ Firewall rules
- ✅ Audit logging
- ✅ Regular updates
Internet → [Firewall] → [nginx + HTTPS + Auth] → rtpipeline (localhost:8080)
Benefits:
- Industry-standard approach
- Mature authentication options
- TLS termination
- Rate limiting
- WAF integration possible
Internet → [VPN Gateway] → [Private Network] → rtpipeline (port 8080)
Benefits:
- Simple to implement
- Leverages existing VPN infrastructure
- Network-level isolation
[Hospital Intranet] → rtpipeline (no internet access)
Benefits:
- Maximum isolation
- Suitable for air-gapped environments
- Compliance-friendly
1. Create password file:
sudo apt-get install apache2-utils
htpasswd -c /etc/nginx/.htpasswd rtuser2. Configure nginx:
# /etc/nginx/sites-available/rtpipeline
server {
listen 443 ssl http2;
server_name rtpipeline.yourdomain.com;
# TLS configuration
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Authentication
auth_basic "rtpipeline Access";
auth_basic_user_file /etc/nginx/.htpasswd;
# Rate limiting
limit_req zone=rtpipeline_limit burst=20 nodelay;
# Reverse proxy
location / {
proxy_pass http://localhost:8080;
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;
# Upload size (must match rtpipeline limit)
client_max_body_size 50G;
# Timeouts for long-running uploads/processing
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
# HTTP redirect
server {
listen 80;
server_name rtpipeline.yourdomain.com;
return 301 https://$server_name$request_uri;
}3. Rate limiting configuration:
# In http block of /etc/nginx/nginx.conf
http {
limit_req_zone $binary_remote_addr zone=rtpipeline_limit:10m rate=10r/s;
# ...
}4. Enable and restart:
sudo ln -s /etc/nginx/sites-available/rtpipeline /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxModify docker-compose.yml:
environment:
- API_TOKEN=your-secure-random-token-hereGenerate secure token:
python3 -c "import secrets; print(secrets.token_urlsafe(32))"Client usage:
curl -H "Authorization: Bearer your-secure-random-token-here" \
-F "files[]=@data.zip" \
https://rtpipeline.yourdomain.com/api/uploadFor enterprise deployments, consider:
- oauth2-proxy with Google/Azure AD
- Keycloak integration
- Hospital SSO integration
Example with oauth2-proxy:
services:
oauth2-proxy:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
command:
- --provider=google
- --client-id=YOUR_CLIENT_ID
- --client-secret=YOUR_CLIENT_SECRET
- --upstream=http://rtpipeline:8080
- --http-address=0.0.0.0:4180
- --cookie-secret=YOUR_COOKIE_SECRET
ports:
- "443:4180"1. Ubuntu/Debian (ufw):
# Allow SSH (if managing remotely)
sudo ufw allow 22/tcp
# Allow HTTPS only (if using reverse proxy)
sudo ufw allow 443/tcp
# DO NOT expose rtpipeline directly
# sudo ufw allow 8080/tcp # ❌ NEVER DO THIS
# Enable firewall
sudo ufw enable2. CentOS/RHEL (firewalld):
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload3. Docker-specific:
Update docker-compose.yml to bind to localhost only:
services:
rtpipeline:
ports:
- "127.0.0.1:8080:8080" # Only accessible from localhostFor hospital/enterprise environments:
┌──────────────────────────────────────┐
│ DMZ (Public-facing) │
│ └─ Reverse Proxy (nginx) │
└──────────────────────────────────────┘
↓ (Firewall)
┌──────────────────────────────────────┐
│ Application Tier │
│ └─ rtpipeline Container │
└──────────────────────────────────────┘
↓ (Firewall)
┌──────────────────────────────────────┐
│ Data Tier │
│ └─ Persistent Storage (NFS/NAS) │
└──────────────────────────────────────┘
1. Encrypt storage volumes:
# LUKS encryption for Linux
sudo cryptsetup luksFormat /dev/sdb
sudo cryptsetup open /dev/sdb rtpipeline_data
sudo mkfs.ext4 /dev/mapper/rtpipeline_data2. Docker volume encryption:
volumes:
output:
driver: local
driver_opts:
type: none
device: /encrypted/path
o: bind1. Always use HTTPS for web access (see nginx config above)
2. VPN for administrative access:
# Example: WireGuard VPN
sudo apt install wireguard
# Configure WireGuard...1. Automatic cleanup:
# Cron job to delete old jobs after 30 days
0 2 * * * find /data/output -type d -mtime +30 -exec rm -rf {} \;2. Audit logging:
services:
rtpipeline:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"Use the built-in anonymization script for de-identification:
python scripts/anonymize_pipeline_results.py \
--input Data_Snakemake \
--output Data_Snakemake_anonymized \
--overwrite --verboseFeatures:
- Rewrites patient identifiers
- Anonymizes DICOM headers
- Generates re-identification key (store securely!)
The default Docker configuration already includes:
- ✅ Non-root user (UID 1000)
- ✅
no-new-privileges:true - ✅ Minimal capabilities (drops ALL, adds only required)
- ✅ Read-only code mounts
- ✅ Resource limits (CPU, memory)
1. Scan Docker image for vulnerabilities:
# Using Trivy
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image kstawiski/rtpipeline:latest
# Using Snyk
snyk container test kstawiski/rtpipeline:latest2. Enable Docker Content Trust:
export DOCKER_CONTENT_TRUST=13. AppArmor/SELinux profiles:
services:
rtpipeline:
security_opt:
- apparmor=docker-default
- no-new-privileges:true4. Rootless Docker (advanced):
# Run Docker daemon as non-root user
dockerd-rootless.sh1. Enable audit logging:
services:
rtpipeline:
logging:
driver: syslog
options:
syslog-address: "tcp://your-syslog-server:514"
tag: "rtpipeline"2. Monitor for suspicious activity:
# Watch for failed authentication attempts (if using basic auth)
tail -f /var/log/nginx/error.log | grep "auth"
# Monitor file uploads
tail -f /data/logs/*.log | grep "upload"
# Watch container logs
docker logs -f rtpipeline1. Suspected compromise:
# Immediate actions
docker-compose down # Stop container
docker ps -a # Check for other containers
sudo iptables -L # Verify firewall rules
find /data -mtime -1 # Check recent file modifications
# Preserve evidence
docker logs rtpipeline > incident_$(date +%Y%m%d).log
tar czf evidence_$(date +%Y%m%d).tar.gz /data/logs2. Contact information:
- IT Security Team: [your-security-team@hospital.com]
- System Administrator: [admin@hospital.com]
- Vendor Support: GitHub Issues
- ✅ Unique user identification: Implement user authentication
- ✅ Emergency access: Document break-glass procedures
- ✅ Automatic logoff: Configure session timeouts
- ✅ Encryption: Use HTTPS + volume encryption
# Enhanced logging for HIPAA
services:
rtpipeline:
logging:
driver: json-file
options:
max-size: "50m"
max-file: "10"
labels: "hipaa-audit"
environment:
- LOG_LEVEL=INFO # Capture all API calls- ✅ Checksum verification: Verify uploaded DICOM integrity
- ✅ Digital signatures: Consider signing output files
- ✅ Version control: Track configuration changes
- ✅ Encryption in transit: HTTPS/TLS 1.2+
- ✅ Integrity controls: Checksums for data transfer
1. Security risk analysis:
- Document threat model
- Perform annual security reviews
2. Workforce training:
- Train staff on secure upload procedures
- Document incident response procedures
3. Business associate agreements:
- If using cloud hosting, execute BAA with provider
- ✅ Facility access controls: Secure server room
- ✅ Workstation security: Lock computers when unattended
- ✅ Device and media controls: Encrypt backup drives
Maintain:
- Security policies and procedures
- Access control lists (who has access)
- Audit logs (retained for 6 years)
- Incident response logs
- Training records
- Security risk assessment completed
- Network architecture reviewed
- Firewall rules configured
- HTTPS/TLS certificates obtained
- Authentication method selected and tested
- Logging and monitoring configured
- Incident response plan documented
- Staff trained on security procedures
- Docker image scanned for vulnerabilities
- Container runs as non-root user
- Reverse proxy configured with TLS
- Authentication enforced
- Firewall rules active
- Port 8080 NOT exposed to internet
- Volume encryption enabled (if required)
- Audit logging active
- Monitor logs daily for anomalies
- Review access logs weekly
- Update Docker images monthly
- Scan for vulnerabilities quarterly
- Review security policies annually
- Test incident response procedures annually
- Audit user access quarterly
- DICOM sources validated/trusted
- PHI minimization implemented (anonymization)
- Retention policies enforced
- Backup encryption verified
- Disposal procedures documented
1. Install nginx and certbot:
sudo apt update
sudo apt install nginx certbot python3-certbot-nginx2. Get TLS certificate:
sudo certbot --nginx -d rtpipeline.yourdomain.com3. Configure basic authentication:
sudo htpasswd -c /etc/nginx/.htpasswd rtuser4. Update docker-compose.yml:
services:
rtpipeline:
ports:
- "127.0.0.1:8080:8080" # Localhost only5. Copy nginx config:
sudo cp docs/nginx-rtpipeline.conf /etc/nginx/sites-available/rtpipeline
sudo ln -s /etc/nginx/sites-available/rtpipeline /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx6. Start rtpipeline:
docker-compose up -d7. Test:
curl -u rtuser:password https://rtpipeline.yourdomain.com/health- OWASP Docker Security Cheat Sheet
- CIS Docker Benchmark
- NIST SP 800-190: Application Container Security
- HHS HIPAA Security Rule Guidance
If you discover a security vulnerability in rtpipeline:
- DO NOT open a public GitHub issue
- Email the maintainer directly (see repository for contact)
- Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
Response time: 72 hours for acknowledgment, 30 days for fix (critical issues)
Last Updated: 2025-11-19 Version: 1.0