This document outlines security best practices and configurations for EzyBackend deployment.
- All services run as non-root users in containers
- Database authentication enabled (MongoDB + Redis)
- Network isolation with Docker networks
- Health checks implemented for all services
- SSL/TLS certificates configured
- Firewall rules configured (UFW/iptables)
- Strong JWT secrets generated
- Environment variables for all secrets
- Input validation and sanitization
- Rate limiting configured
- CORS properly configured
- Security headers enabled (Helmet.js)
- MongoDB authentication enabled
- Redis password protection
- Database connections encrypted
- Regular security updates
- Backup encryption
All sensitive data should be stored in environment variables:
# Generate strong secrets
JWT_SECRET=$(openssl rand -base64 64)
ENCRYPTION_KEY=$(openssl rand -base64 32)
MONGO_PASSWORD=$(openssl rand -base64 32)
REDIS_PASSWORD=$(openssl rand -base64 32)# docker-compose.prod.yml
services:
data-service:
secrets:
- jwt_secret
- mongo_password
environment:
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
jwt_secret:
external: true
mongo_password:
external: true# Store secrets in Vault
vault kv put secret/ezybackend \
jwt_secret="your-jwt-secret" \
mongo_password="your-mongo-password"
# Retrieve in application
export JWT_SECRET=$(vault kv get -field=jwt_secret secret/ezybackend)// In application code
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
const getSecret = async (secretName) => {
const result = await secretsManager.getSecretValue({
SecretId: secretName
}).promise();
return JSON.parse(result.SecretString);
};# docker-compose.yml
mongodb:
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
command: >
mongod
--auth
--bind_ip_all
--tlsMode requireTLS
--tlsCertificateKeyFile /etc/ssl/mongodb.pemredis:
command: >
redis-server
--requirepass ${REDIS_PASSWORD}
--tls-port 6380
--port 0
--tls-cert-file /etc/ssl/redis.crt
--tls-key-file /etc/ssl/redis.key# UFW rules for production
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw deny 4730/tcp # Block direct access to data service
sudo ufw deny 3000/tcp # Block direct access to user service
sudo ufw enable# nginx.conf
server {
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Content-Security-Policy "default-src 'self'";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# Hide server information
server_tokens off;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req zone=api burst=20 nodelay;
}// security.js
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const cors = require('cors');
module.exports = (app) => {
// Security headers
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);
// CORS configuration
app.use(cors({
origin: process.env.CORS_ORIGIN || 'http://localhost:3000',
credentials: true,
optionsSuccessStatus: 200
}));
};// validation.js
const joi = require('joi');
const mongoSanitize = require('express-mongo-sanitize');
// Sanitize MongoDB queries
app.use(mongoSanitize());
// Validation schemas
const userSchema = joi.object({
email: joi.string().email().required(),
password: joi.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/).required(),
name: joi.string().min(2).max(50).required()
});
// Validation middleware
const validate = (schema) => {
return (req, res, next) => {
const { error } = schema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}
next();
};
};// security-logger.js
const winston = require('winston');
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'security.log' }),
new winston.transports.Console()
]
});
// Log security events
const logSecurityEvent = (event, details) => {
securityLogger.warn('SECURITY_EVENT', {
event,
details,
timestamp: new Date().toISOString(),
ip: details.ip,
userAgent: details.userAgent
});
};
module.exports = { logSecurityEvent };// intrusion-detection.js
const rateLimit = require('express-rate-limit');
const slowDown = require('express-slow-down');
// Aggressive rate limiting for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
skipSuccessfulRequests: true
});
// Progressive delay for repeated requests
const speedLimiter = slowDown({
windowMs: 15 * 60 * 1000, // 15 minutes
delayAfter: 2, // allow 2 requests per 15 minutes at full speed
delayMs: 500 // slow down subsequent requests by 500ms per request
});
app.use('/auth/', authLimiter);
app.use('/auth/', speedLimiter);# .github/workflows/security-updates.yml
name: Security Updates
on:
schedule:
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM
jobs:
security-updates:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: |
npm audit --audit-level=moderate
npm audit fix
- name: Create PR if fixes available
uses: peter-evans/create-pull-request@v4
with:
title: 'Security: Automated dependency updates'# .github/workflows/container-scan.yml
name: Container Security Scan
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build image
run: docker build -t ezybackend/data-service ./data-service
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'ezybackend/data-service'
format: 'sarif'
output: 'trivy-results.sarif'-
Immediate Response
- Isolate affected systems
- Preserve evidence
- Assess scope of breach
- Notify stakeholders
-
Investigation
- Analyze logs
- Identify attack vector
- Determine data accessed
- Document findings
-
Recovery
- Patch vulnerabilities
- Reset compromised credentials
- Restore from clean backups
- Monitor for persistence
-
Post-Incident
- Update security measures
- Conduct lessons learned
- Update incident response plan
- Notify authorities if required
- Security Team: [email protected]
- Emergency: +1-XXX-XXX-XXXX
- Bug Bounty: https://ezybackend.io/security
Remember: Security is an ongoing process, not a one-time setup. Regularly review and update these configurations.