Skip to content

Security Best Practices

Overview

Security is built into every layer of the DineTogether infrastructure. This guide covers security best practices and configurations.

Container Security

Run as Non-Root User

# Dockerfile
FROM node:18-alpine

# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001

# Change ownership
WORKDIR /app
COPY --chown=nodejs:nodejs . .

# Switch to non-root user
USER nodejs

EXPOSE 3000
CMD ["node", "server.js"]

Security Context in Kubernetes

# In docker-compose.yml labels or K8s manifest
securityContext:
  runAsNonRoot: true
  runAsUser: 1001
  runAsGroup: 1001
  fsGroup: 1001
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop:
      - ALL

Secrets Management

Never Commit Secrets

# .gitignore
.env
.env.*
*.key
*.pem
*.cert
secrets/

Use GitHub Secrets

# Set secrets securely
gh secret set DATABASE_URL
gh secret set API_KEY
gh secret set JWT_SECRET

Kubernetes Secrets

# Create secrets
kubectl create secret generic app-secrets \
  --from-literal=database-url='postgresql://...' \
  --from-literal=api-key='...' \
  --namespace=test-staging

# Use in deployment
envFrom:
  - secretRef:
      name: app-secrets

Network Security

Internal vs External Services

# Public service (with ingress network)
services:
  frontend:
    networks:
      - default
      - ingress  # Public access

# Internal service (no ingress)
  database:
    networks:
      - default  # Internal only

HTTPS Only

# Automatic HTTPS redirect
metadata:
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"

Image Security

Use Specific Tags

# Bad
image: node:latest

# Good
image: node:18.17.1-alpine

Scan Images

# In GitHub Actions
- name: Run Trivy vulnerability scanner
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
    format: 'sarif'
    output: 'trivy-results.sarif'

Private Registry

  • All images stored in private GHCR
  • Authentication required to pull
  • Automatic cleanup of old images

Access Control

GitHub Repository

# Protect main branch
gh api repos/{owner}/{repo}/branches/main/protection \
  --method PUT \
  --field enforce_admins=true \
  --field required_status_checks='{
    "strict": true,
    "contexts": ["build", "test"]
  }'

Kubernetes RBAC

# ServiceAccount with limited permissions
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-service-account
  namespace: test-staging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: app-role
  namespace: test-staging
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]

Application Security

Environment Variables

// Validate required environment variables
const required = ['DATABASE_URL', 'JWT_SECRET', 'API_KEY'];

for (const varName of required) {
  if (!process.env[varName]) {
    throw new Error(`Missing required environment variable: ${varName}`);
  }
}

Input Validation

// Always validate and sanitize input
app.use(express.json({ limit: '10mb' }));
app.use(helmet());
app.use(cors({
  origin: process.env.ALLOWED_ORIGINS?.split(',') || false
}));

Rate Limiting

# Traefik middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: rate-limit
spec:
  rateLimit:
    average: 100
    period: 1m
    burst: 50

SSL/TLS Configuration

Strong Ciphers Only

# Traefik TLS options
apiVersion: traefik.containo.us/v1alpha1
kind: TLSOption
metadata:
  name: default
spec:
  minVersion: VersionTLS12
  cipherSuites:
    - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305

Security Headers

# Traefik middleware
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: security-headers
spec:
  headers:
    frameDeny: true
    contentTypeNosniff: true
    browserXssFilter: true
    stsSeconds: 31536000
    stsIncludeSubdomains: true
    stsPreload: true
    customFrameOptionsValue: "SAMEORIGIN"
    customResponseHeaders:
      X-Content-Type-Options: "nosniff"
      X-Frame-Options: "DENY"
      X-XSS-Protection: "1; mode=block"
      Referrer-Policy: "strict-origin-when-cross-origin"
      Permissions-Policy: "geolocation=(), microphone=(), camera=()"

Monitoring & Auditing

Log Security Events

// Log authentication attempts
app.post('/login', (req, res) => {
  const { email } = req.body;
  console.log(JSON.stringify({
    event: 'login_attempt',
    email: email,
    ip: req.ip,
    timestamp: new Date().toISOString()
  }));
});

Monitor Suspicious Activity

# Check for failed auth attempts
kubectl logs deployment/api -n test-staging | grep "login_failed" | tail -20

# Monitor pod exec attempts
kubectl get events --all-namespaces | grep "exec"

Database Security

Connection Security

environment:
  - DATABASE_URL=postgresql://user:pass@postgres:5432/db?sslmode=require

Separate Users

-- Create read-only user for analytics
CREATE USER analytics_user WITH PASSWORD 'secure_password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analytics_user;

-- Create app user with limited permissions
CREATE USER app_user WITH PASSWORD 'secure_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;

CI/CD Security

Minimal Token Permissions

# GitHub Actions permissions
permissions:
  contents: read
  packages: write
  # Only what's needed

Secure Workflows

# Pin action versions
uses: actions/checkout@v4.1.0  # Not @v4

# Verify actions
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab  # v4.1.0

Incident Response

Quick Actions

# Isolate compromised pod
kubectl delete pod <pod-name> -n test-staging

# Revoke access
kubectl delete secret ghcr-secret -n test-staging

# Rotate secrets
gh secret set DEPLOY_TOKEN --repo dine-together/myapp

Investigation

# Check recent changes
kubectl get events -n test-staging --sort-by='.lastTimestamp'

# Audit logs
kubectl logs deployment/api -n test-staging --since=1h | grep -E "(error|unauthorized|forbidden)"

# Check modified files
kubectl exec <pod-name> -n test-staging -- find / -mtime -1 -type f 2>/dev/null

Security Checklist

Development

  • [ ] No hardcoded secrets
  • [ ] Dependencies up to date
  • [ ] Input validation implemented
  • [ ] Error messages don't leak info
  • [ ] Logging doesn't include sensitive data

Docker

  • [ ] Using specific base image tags
  • [ ] Running as non-root user
  • [ ] Minimal image (alpine preferred)
  • [ ] No unnecessary packages
  • [ ] Multi-stage builds

Kubernetes

  • [ ] Security context configured
  • [ ] Resource limits set
  • [ ] Network policies defined
  • [ ] Secrets properly managed
  • [ ] RBAC configured

Application

  • [ ] HTTPS only
  • [ ] Security headers configured
  • [ ] Rate limiting enabled
  • [ ] CORS properly configured
  • [ ] Authentication required

Common Vulnerabilities

Exposed Secrets

Wrong:

const apiKey = "sk_live_abcd1234";

Right:

const apiKey = process.env.API_KEY;
if (!apiKey) throw new Error('API_KEY not configured');

SQL Injection

Wrong:

const query = `SELECT * FROM users WHERE email = '${email}'`;

Right:

const query = 'SELECT * FROM users WHERE email = $1';
const result = await db.query(query, [email]);

Path Traversal

Wrong:

app.get('/file/:name', (req, res) => {
  res.sendFile(req.params.name);
});

Right:

app.get('/file/:name', (req, res) => {
  const safeName = path.basename(req.params.name);
  const filePath = path.join(UPLOAD_DIR, safeName);
  res.sendFile(filePath);
});

Compliance

Data Protection

  1. Encryption at Rest
  2. Database encryption
  3. Volume encryption
  4. Backup encryption

  5. Encryption in Transit

  6. TLS 1.2+ only
  7. Certificate validation
  8. Secure protocols

  9. Access Control

  10. Principle of least privilege
  11. Regular access reviews
  12. Audit logging

Next Steps

  1. Security Scanning
  2. Set up vulnerability scanning
  3. Implement SAST/DAST
  4. Regular penetration testing

  5. Monitoring

  6. Security event monitoring
  7. Anomaly detection
  8. Alert configuration

  9. Training

  10. Security best practices
  11. Incident response procedures
  12. Regular security updates

Resources