Skip to content

Security Hardening

Secure your New Hires Reporting System deployment for production.

Production Security Checklist

  • [ ] HTTPS enabled with valid SSL certificate
  • [ ] Services bind to localhost only (127.0.0.1)
  • [ ] Reverse proxy configured
  • [ ] Debug mode disabled (DEBUG=false)
  • [ ] AWS credentials stored securely in .env
  • [ ] File permissions restricted (.env = 600)
  • [ ] .env file not shared or exposed
  • [ ] Docker containers run as non-root (future)
  • [ ] Regular security updates applied
  • [ ] Firewall configured
  • [ ] Rate limiting enabled (reverse proxy)
  • [ ] Access logs monitored
  • [ ] Database backups encrypted and secure
  • [ ] AWS IAM least-privilege permissions

Network Security

Firewall Configuration

# Allow only necessary ports
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp   # HTTP (redirect to HTTPS)
sudo ufw allow 443/tcp  # HTTPS
sudo ufw enable

Localhost Binding (Production)

Ensure services only accept local connections:

# docker-compose.prod.yml
ports:
  - "127.0.0.1:8000:8000"  # Backend API
  - "127.0.0.1:8080:8080"  # Frontend (React + Nginx)

Never expose directly:

# ❌ DON'T DO THIS IN PRODUCTION
ports:
  - "8000:8000"  # Exposes backend to internet
  - "8080:8080"  # Exposes frontend to internet

Database (already internal-only):

# ✅ Good: No port mapping (internal only)
db:
  # No ports exposed - only accessible within Docker network


Application Security

Disable Debug Mode

# In .env (production)
DEBUG=false
ENVIRONMENT=production
LOG_LEVEL=INFO

Debug mode risks: - Exposes stack traces - Shows internal paths - Reveals configuration - Provides detailed error messages - Leaks AWS credentials in logs


Credentials Management

# Secure .env permissions
chmod 600 .env
chown your-user:your-user .env

# Verify permissions
ls -la .env
# Should show: -rw------- (600)

# Keep .env file secure
# - Never share in emails or chat
# - Never commit to version control
# - Store backup in secure password manager
# - Use different credentials per environment

Rotate AWS Credentials

# Every 90 days:
# 1. Create new AWS access key in IAM console
# 2. Test new key in staging first
# 3. Update production .env with new credentials
# 4. Restart services to load new credentials
# 5. Verify workers can connect to Bedrock
# 6. Delete old access key in IAM console

# Rotation script example:
# 1. Create new key
aws iam create-access-key --user-name newhires-app

# 2. Update .env
sed -i 's/AWS_ACCESS_KEY_ID=.*/AWS_ACCESS_KEY_ID=NEW_KEY/' .env
sed -i 's/AWS_SECRET_ACCESS_KEY=.*/AWS_SECRET_ACCESS_KEY=NEW_SECRET/' .env

# 3. Restart
docker-compose -f docker-compose.prod.yml restart workers

# 4. Verify
docker logs newhires-workers --tail=20

# 5. Delete old key
aws iam delete-access-key --access-key-id OLD_KEY --user-name newhires-app

HTTPS/TLS Security

Force HTTPS

Nginx configuration:

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$server_name$request_uri;
}

Strong TLS Configuration

# Modern TLS only
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;

# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;

Security Headers

Add to reverse proxy:

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self'" always;

CORS Security

Backend configuration (production):

# Allow only your frontend domain
origins = ["https://your-domain.com"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # Not "*"
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Content-Type", "Authorization"],
)

File Upload Security

Size Limits

# Nginx
client_max_body_size 50M;
# Caddy
request_body {
    max_size 50MB
}

File Type Validation

System validates: - ✅ Plain text files only - ✅ Fixed-width format - ✅ UTF-8 encoding - ❌ No executables - ❌ No archives - ❌ No images - ❌ No scripts


Rate Limiting

Nginx Rate Limiting

# Limit requests per IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=upload_limit:10m rate=5r/m;

server {
    # API endpoints
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
    }

    # File uploads (stricter limit)
    location /api/v1/files {
        limit_req zone=upload_limit burst=2 nodelay;
    }
}

Monitoring & Logging

Enable Access Logs

# Log all requests
access_log /var/log/nginx/newhires-access.log;
error_log /var/log/nginx/newhires-error.log;

Monitor for Suspicious Activity

# Watch for repeated failures
sudo tail -f /var/log/nginx/access.log | grep "40[134]"

# High request rates
sudo tail -f /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn

# Check for unusual user agents
sudo tail -f /var/log/nginx/access.log | grep -i -E "bot|crawler|scanner"

Docker Security

Run as Non-Root (Future)

# Create non-root user
RUN useradd -m -u 1000 appuser
USER appuser

Scan Images for Vulnerabilities

# Using Trivy
trivy image 878796852397.dkr.ecr.us-east-1.amazonaws.com/newhires-backend:latest

# Using Docker Scout
docker scout cves 878796852397.dkr.ecr.us-east-1.amazonaws.com/newhires-backend:latest

Limit Container Resources

# In docker-compose.prod.yml
services:
  workers:
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: '2.0'
        reservations:
          memory: 1G
          cpus: '1.0'

Secrets Management

Environment Variables Only

# ✅ Good: .env file with AWS credentials
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
POSTGRES_PASSWORD=SecurePassword123!

# ❌ Bad: Hardcoded in application code
access_key = "AKIA..."  # Never do this

# ❌ Bad: Shared via email or chat
# Never send .env files through insecure channels

# ❌ Bad: Committed to version control
# Always add .env to .gitignore

AWS IAM Best Practices

Least Privilege Policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "BedrockModelInvocationOnly",
      "Effect": "Allow",
      "Action": [
        "bedrock:InvokeModel"
      ],
      "Resource": [
        "arn:aws:bedrock:us-east-1::foundation-model/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
        "arn:aws:bedrock:us-east-1::foundation-model/us.meta.llama4-scout-17b-instruct-v1:0"
      ]
    }
  ]
}

Don't grant: - ❌ bedrock:* (too broad) - ❌ bedrock:CreateModel (not needed) - ❌ Administrator access - ❌ Access to other AWS services unless required


Future: Secrets Manager

For enterprise deployments, consider:

  • AWS Secrets Manager - Integrates with AWS Bedrock
  • HashiCorp Vault - Multi-cloud support
  • Azure Key Vault - Azure deployments
  • Google Secret Manager - GCP deployments

Data Protection

Sensitive Data Handling

The system processes: - ✅ Employee names - ✅ SSNs (Social Security Numbers) - ✅ Addresses - ✅ Employer data - ✅ Validation errors and corrections

Protections: - ✅ HTTPS encryption in transit - ✅ PostgreSQL database with authentication - ✅ Database stored in Docker volume (encrypted at rest optional) - ✅ No data sent to third parties (except AWS Bedrock for corrections) - ✅ Regular database backups - ⚠️ AWS Bedrock processes correction data (see AWS data handling policies)

Data Retention: - Files: Stored until manually deleted - Corrections: Stored in database - Logs: Rotated based on configuration (default: 3 files × 10MB)


AWS Bedrock Data Privacy

When using AWS Bedrock: - Data sent: Only specific record fields needing correction - AWS retention: AWS does not store or train on Bedrock API requests - Compliance: AWS Bedrock is HIPAA eligible and SOC 2 compliant - Region: Data stays in us-east-1 region

See: AWS Bedrock Data Privacy


Compliance Considerations

If handling sensitive data:

  • GDPR: EU data protection (right to deletion, data minimization)
  • CCPA: California privacy (disclosure requirements)
  • HIPAA: If health data involved (AWS Bedrock supports BAA)
  • SOC 2: Security auditing (AWS Bedrock is SOC 2 certified)
  • PCI DSS: If payment data involved (not typical for this use case)

Recommendations: - Document data flows and retention - Implement data deletion procedures - Maintain audit logs - Conduct privacy impact assessments - Review AWS Bedrock compliance documentation


Database Security

PostgreSQL Security

# Strong database password in .env
POSTGRES_PASSWORD=$(openssl rand -base64 32)

# Verify database is not exposed
docker ps | grep newhires-db
# Should show: 5432/tcp (no 0.0.0.0 binding)

# Encrypted backups
docker exec newhires-db pg_dump -U newhires newhires | \
  gpg --symmetric --cipher-algo AES256 > backup_$(date +%Y%m%d).sql.gpg

# Test backup integrity regularly
gpg --decrypt backup_20241124.sql.gpg | head -20

Database Access Control

-- Verify only newhires user exists
SELECT usename FROM pg_user;

-- Check database permissions
\l+ newhires

-- Review table permissions
\dp correction_jobs

Incident Response

Security Incident Plan

  1. Detect: Monitor logs and alerts
  2. Check access logs for unusual patterns
  3. Monitor AWS CloudTrail for Bedrock API anomalies
  4. Review worker logs for errors

  5. Contain: Isolate affected systems

  6. Disable compromised AWS credentials immediately
  7. Stop affected containers: docker-compose -f docker-compose.prod.yml down
  8. Block suspicious IPs in firewall

  9. Investigate: Analyze logs and access

  10. Export all logs for analysis
  11. Review AWS CloudTrail logs
  12. Check for data exfiltration

  13. Remediate: Patch vulnerabilities

  14. Rotate all credentials
  15. Update Docker images
  16. Apply security patches

  17. Document: Record incident details

  18. Timeline of events
  19. Impact assessment
  20. Actions taken

  21. Review: Update procedures

  22. Update security policies
  23. Improve monitoring
  24. Train team on lessons learned

Emergency Contacts

Document: - Security team contacts - AWS Support (if Enterprise support plan) - On-call procedures - Escalation paths - Communication templates


Regular Maintenance

Security Update Schedule

Task Frequency Command
OS security patches Weekly sudo apt update && sudo apt upgrade
Docker image updates Monthly Update IMAGE_TAG in .env
AWS credential rotation Every 90 days See rotation script above
SSL certificate renewal Auto Let's Encrypt auto-renewal
Dependency updates Monthly Rebuild Docker images
Security audit Quarterly Full security review
Backup test restore Monthly Test database restore
Vulnerability scan Weekly trivy image ...

Vulnerability Scanning

Automated Scans

# Weekly cron job
0 2 * * 0 trivy image --severity HIGH,CRITICAL \
  878796852397.dkr.ecr.us-east-1.amazonaws.com/newhires-backend:latest \
  > /var/log/security-scan.log

# Scan workers too
0 2 * * 0 trivy image --severity HIGH,CRITICAL \
  878796852397.dkr.ecr.us-east-1.amazonaws.com/newhires-workers:latest \
  >> /var/log/security-scan.log

Best Practices Summary

Network & Access

  • ✅ Always use HTTPS in production
  • ✅ Bind services to localhost only
  • ✅ Use reverse proxy (Nginx/Caddy)
  • ✅ Configure firewall (ufw/iptables)
  • ✅ Implement rate limiting

Application

  • ✅ Disable debug mode in production
  • ✅ Use strong TLS configuration
  • ✅ Add security headers
  • ✅ Restrict CORS properly
  • ✅ Validate file uploads

Credentials & Secrets

  • ✅ Use AWS IAM least-privilege policies
  • ✅ Rotate AWS credentials every 90 days
  • ✅ Secure .env file (chmod 600)
  • ✅ Never commit secrets to git
  • ✅ Use different credentials per environment

Data & Database

  • ✅ Use strong database passwords
  • ✅ Backup database regularly
  • ✅ Encrypt backups
  • ✅ Test restore procedures
  • ✅ Document data retention policies

Monitoring

  • ✅ Monitor access logs
  • ✅ Set up AWS CloudTrail logging
  • ✅ Scan for vulnerabilities
  • ✅ Configure security alerts
  • ✅ Review logs regularly

Maintenance

  • ✅ Keep systems updated
  • ✅ Patch security vulnerabilities
  • ✅ Update Docker images monthly
  • ✅ Rotate credentials quarterly
  • ✅ Document procedures

Security Audit Checklist

### Network
- [ ] Firewall configured
- [ ] Only necessary ports open (80, 443, 22)
- [ ] Services bind to localhost (8000, 8080)
- [ ] Reverse proxy properly configured
- [ ] HTTPS enforced

### Application
- [ ] Debug mode disabled
- [ ] LOG_LEVEL set to INFO or WARNING
- [ ] Security headers configured
- [ ] CORS properly restricted
- [ ] Rate limiting enabled
- [ ] File upload limits set

### AWS & Credentials
- [ ] AWS IAM least-privilege policy
- [ ] AWS credentials in .env only
- [ ] .env file permissions = 600
- [ ] .env not committed to git
- [ ] Credentials rotated in last 90 days
- [ ] Old credentials revoked

### Database
- [ ] Strong PostgreSQL password
- [ ] Database not exposed externally
- [ ] Regular backups configured
- [ ] Backup encryption enabled
- [ ] Restore tested recently

### Monitoring
- [ ] Access logs enabled
- [ ] Error logs monitored
- [ ] AWS CloudTrail enabled
- [ ] Security scanning automated
- [ ] Alerts configured
- [ ] Incident response plan documented

### Updates & Maintenance
- [ ] OS patches applied
- [ ] Docker images updated to latest IMAGE_TAG
- [ ] Dependencies current
- [ ] SSL certificates valid
- [ ] Vulnerability scans clean

Next Steps