Version: 1.0 Date: November 10, 2025
This guide describes the security baseline configuration for Accellens in all environments: AI safety filters, PII redaction, audit logging, security scanning, and Swagger UI security.
PII Detection and Redaction:
- Uses Presidio Analyzer for PII detection
- Automatic redaction before sending to LLM
- Supported types: email, phone, SSN, credit card, IP addresses
Toxicity Detection:
- OpenAI Moderation API (primary, if available)
- Detoxify (fallback)
- Keyword-based check (fallback)
# In config.py
ai_enable_safety_filters: bool = True
openai_api_key: str | None = None # For moderation APISafety filters are automatically applied in AIProviderRouter:
from ai.src.router import AIProviderRouter
router = AIProviderRouter(enable_safety=True)
# PII and toxicity checks are performed automaticallyAll safety violations are logged with full details:
logger.warning("PII detected and redacted in prompt", extra={"entities": len(pii_entities)})
logger.warning("Toxicity detected in prompt", extra={"method": "openai_moderation", "categories": {...}})Middleware for automatic PII redaction from request/response:
import { piiRedactionMiddleware } from '@gateway/middleware/pii-redaction.middleware';
// Registration in Fastify
fastify.addHook('onRequest', piiRedactionMiddleware);A similar pipeline is implemented for all FastAPI microservices:
apps/services/middleware/pii_redaction.pyintercepts POST/PUT/PATCH/DELETE, redacts body and query, stores result inrequest.state.apps/services/middleware/audit_logging.pycreates entries inaudit_logsafter successful write operations, using redacted payload + list of detected PII types, request id, user/org from headers (X-Actor-Id,X-Organization-Id) and IP address.
Thus, services meet requirements 1.3.12/1.3.13 for multi-tenant isolation and security baseline.
- Email addresses
- Phone numbers
- Credit card numbers
- SSN
- IP addresses (optional)
Middleware automatically:
- Detects PII in request body
- Detects PII in query parameters
- Logs detected PII types
- Stores information for audit logging
Local secrets:
- Stored in
.envfiles - Gitignored (added to
.gitignore) - Minimal security requirements
Recommendations:
- Do not commit
.envfiles - Use
.env.exampleas a template - Rotate secrets when necessary
- Use
secrets_provider=env(default inapps/services/config.py)
SOPS + Sealed Secrets:
# Install SOPS
brew install sops # macOS
apt-get install sops # Linux
# Install Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# Encrypt secret
kubectl create secret generic accellens-secrets \
--from-literal=db-password='<REPLACE_WITH_PASSWORD>' \
--dry-run=client -o yaml | \
kubeseal -o yaml > sealed-secret.yamlFastAPI configuration (test):
# apps/services/config.py
secrets_provider = "sops"
sops_secrets_path = "./secrets/test.accellens.sops.json"The file specified in sops_secrets_path must be pre-decrypted by SOPS (e.g., via sops -d ... > test.accellens.sops.json) and contain JSON/YAML structure with keys listed in secrets_remote_keys.
AWS Secrets Manager:
# Create secret
aws secretsmanager create-secret \
--name accellens/staging/db-credentials \
--secret-string '{"username":"<USERNAME>","password":"<PASSWORD>"}'
# Get secret
aws secretsmanager get-secret-value \
--secret-id accellens/staging/db-credentialsFastAPI configuration (prod/pre-prod):
# apps/services/config.py
secrets_provider = "aws"
aws_secrets_manager_secret_arn = "arn:aws:secretsmanager:eu-central-1:123456789012:secret:accellens/prod/runtime"
aws_secrets_manager_region = "eu-central-1"
secrets_remote_keys = "database_url,redis_url,rabbitmq_url,s3_secret_key,openai_api_key"HashiCorp Vault (optional):
secrets_provider = "vault"
vault_addr = "https://vault.example.com"
vault_token = "<CICD or Kubernetes service account token>"
vault_secret_path = "kv/data/accellens/prod/runtime" # KV v2 supportedRotation Policies (for prod):
aws secretsmanager rotate-secret \
--secret-id accellens/prod/db-credentials \
--rotation-lambda-arn arn:aws:lambda:region:account:function:rotate-secret- Module
apps/services/utils/secrets_provider.pyimplements abstraction for loading secrets from AWS Secrets Manager, HashiCorp Vault, or SOPS. apps/services/config.pyautomatically callsSecretsProvideron initialization ifsecrets_provideris notenv. Allowed values:env,aws,vault,sops.- Keys listed in
secrets_remote_keysare supported (default:database_url,redis_url,rabbitmq_url,s3_secret_key,openai_api_key,anthropic_api_key,elevenlabs_api_key). Keys must match by name (case insensitive). - When using SOPS, it is recommended to install
PyYAMLif the file is stored in YAML; JSON is supported out of the box. - Secrets loading errors are logged but do not block startup (fallback to
.envvalues), meeting the "infrastructure must come up" requirement even if Secret Manager is temporarily unavailable.
- Create Kubernetes secret with certificates (server cert/key + root CA for client certificates):
kubectl create secret generic accellens-prod-internal-tls \
--from-file=tls.crt=./certs/services.crt \
--from-file=tls.key=./certs/services.key \
--from-file=ca.crt=./certs/rootCA.crt- Enable mounting via Helm (
infra/k8s/environments/<env>/values.yaml):
services:
tls:
enabled: true
secretName: accellens-prod-internal-tls
mountPath: /etc/accellens/tls
env:
TLS_ENABLED: 'true'
TLS_CERT_FILE: /etc/accellens/tls/tls.crt
TLS_KEY_FILE: /etc/accellens/tls/tls.key
TLS_CA_FILE: /etc/accellens/tls/ca.crt
TLS_REQUIRE_CLIENT_CERT: 'true'
CELERY_TLS_ENABLED: 'true'
CELERY_TLS_CA_FILE: /etc/accellens/tls/ca.crt
CELERY_TLS_CERT_FILE: /etc/accellens/tls/tls.crt
CELERY_TLS_KEY_FILE: /etc/accellens/tls/tls.key
celeryWorker:
tls:
enabled: true
secretName: accellens-prod-internal-tls
env:
CELERY_TLS_ENABLED: 'true'
CELERY_TLS_CA_FILE: /etc/accellens/tls/ca.crt
CELERY_TLS_CERT_FILE: /etc/accellens/tls/tls.crt
CELERY_TLS_KEY_FILE: /etc/accellens/tls/tls.key- Environment Variables (see also
docs/deployment/environment-variables.md):
| Variable | Purpose |
|---|---|
TLS_ENABLED |
Enables HTTPS at FastAPI/uvicorn level |
TLS_CERT_FILE |
Path to server certificate (PEM) |
TLS_KEY_FILE |
Path to private key |
TLS_CA_FILE |
Root CA for client cert validation |
TLS_REQUIRE_CLIENT_CERT |
true for mTLS (TLS_CA_FILE required) |
CELERY_TLS_ENABLED |
Enables TLS for RabbitMQ/Redis connections |
CELERY_TLS_CA_FILE |
CA to verify broker |
CELERY_TLS_CERT_FILE |
Client cert for RabbitMQ |
CELERY_TLS_KEY_FILE |
Client key for RabbitMQ |
- RabbitMQ/Redis addresses: use
amqps://andrediss://schemes with issued certificates. Celery automatically applies TLS settings ifCELERY_TLS_ENABLED=trueis set. - mTLS in FastAPI:
apps/services/common.pyenables client certificate verification ifTLS_REQUIRE_CLIENT_CERT=true.TLS_CA_FILEmust contain the CA that signed Gateway/Sidecar certificates. - Observability: update
prometheus/otelendpoints tohttps://services:8000and ensure sidecar (Envoy/Istio) trusts the specified CA.
-
AWS Secrets Manager (prod/pre-prod):
- Create new secret version (
aws secretsmanager put-secret-value ...). - Update
secrets_remote_keysif new fields added. - Run
scripts/run-security-tests.sh(verify secrets are picked up). - Update Helm values (
aws_secrets_manager_secret_arn) and runhelm upgrade. - Log rotation in runbook (time, owner, ticket link).
- Create new secret version (
-
Vault (QA/dev clusters):
- Issue new kv record
vault kv put. - Regenerate access token if expiring.
- Run smoke (
scripts/run-security-tests.sh) +helm upgrade. - Update team access (Vault policies).
- Issue new kv record
-
SOPS (test/local):
- Decrypt file, update values, encrypt back
sops -e. - Recreate sealed secret/secret (
kubectl apply -f ...). - Save file hash in CHANGELOG (integrity check).
- Decrypt file, update values, encrypt back
-
General Rules:
- Keep rotation log (date, author, what changed).
- Revoke old credentials (IAM, DB, RabbitMQ) after confirming successful deploy.
- Automatically notify SRE/DevOps (Slack + ticket) about successful rotation completion.
Critically Important: Passwords are sent in clear text in JSON payload during login. This is standard practice, but only when using HTTPS.
-
Production Environment:
- HTTPS Mandatory for all authentication endpoints (
/api/v1/auth/login,/api/v1/auth/register) - Gateway automatically blocks HTTP requests to auth endpoints in production
- Use reverse proxy (nginx/traefik) or Kubernetes Ingress with TLS for SSL termination
- HTTPS Mandatory for all authentication endpoints (
-
Development Environment:
- HTTP allowed only for
localhostand127.0.0.1 - For remote access use HTTPS (e.g., via ngrok or local reverse proxy)
- HTTP allowed only for
-
What HTTPS protects:
- Traffic encryption between client and server
- Protection against password interception (man-in-the-middle attacks)
- Protection against request modification
Gateway automatically checks connection security:
// Checks:
// 1. request.protocol === 'https'
// 2. X-Forwarded-Proto header === 'https' (for reverse proxy)
// 3. X-Forwarded-Ssl header === 'on' (alternative method)In Production: If HTTPS is not detected, request is blocked with error 403:
{
"error": "Forbidden",
"message": "HTTPS is required for authentication endpoints in production. Please use HTTPS to protect your credentials."
}Ingress with TLS (recommended):
# infra/k8s/environments/prod/values.yaml
ingress:
enabled: true
className: nginx
tls:
- secretName: accellens-tls
hosts:
- api.accellens.dev
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-redirect: 'true'Verify after deploy:
# Check if HTTPS works
curl -I https://api.accellens.dev/api/v1/auth/login
# Check certificate
openssl s_client -connect api.accellens.dev:443 -servername api.accellens.devOption 1: ngrok (for testing with remote devices):
ngrok http 8000
# Use https://xxxx.ngrok.io for accessOption 2: Local reverse proxy with self-signed certificate:
# nginx.conf
server {
listen 8443 ssl;
server_name localhost;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto https;
}
}- Rate Limiting: Configured (5 requests per minute on
/api/v1/auth/login) - Password Hashing: Passwords never stored in clear text on server (bcrypt)
- Audit Logging: All login attempts logged (success and failure)
- PII Redaction: Passwords automatically removed from logs
- HTTPS used for all auth endpoints in production
- Kubernetes Ingress configured with TLS certificates
- Verified that HTTP requests to auth endpoints are blocked in production
- Certificates renew automatically (Let's Encrypt)
- Rate limiting active
- Audit logging enabled
Basic logging:
- Logging of all user actions
- Storage in PostgreSQL (optional)
- Local logs to files
Extended logging:
- All user actions
- Security events (auth failures, rate limits)
- API access logs
- Storage in PostgreSQL + centralized logs
Production-like audit logging:
- All user actions
- Security events with full details
- API access logs with IP addresses
- PII redaction in logs
- Storage in PostgreSQL + centralized logs
Full audit logging with SIEM integration:
- All user actions
- Security events with escalation
- API access logs
- PII redaction mandatory
- Storage in PostgreSQL + centralized logs + SIEM
- Retention: minimum 1 year for compliance
SIEM Integration:
# SIEM export configuration
SIEM_ENABLED=true
SIEM_ENDPOINT=https://siem.example.com/api/logs
SIEM_API_KEY=<secret>Python (Bandit):
- name: Run Bandit
run: bandit -r . -f json -o bandit-report.jsonQuick run of local pipeline:
./scripts/run-security-tests.sh— runs Bandit with high severity + pytest-markersecurity.
TypeScript/JavaScript (ESLint security plugins):
eslint-plugin-securityfor detecting vulnerabilities- Automatically runs in lint workflow
Dependabot:
- Automatic PRs for dependency updates
- Configured in
.github/dependabot.yml
Trivy:
- Python and Node.js dependency scanning
- Known vulnerability detection (CVE)
- GitHub Security integration
Trivy for Dockerfiles:
- Docker configuration scanning
- Vulnerability detection in base images
- Best practices check
Checkov:
- Terraform configuration scanning
- Security misconfiguration detection
- Compliance check (CIS, AWS Security Best Practices)
Regular security audit process (triage monthly + deep dive quarterly) is described separately:
docs/deployment/security-audit-process.md
Mandatory Settings:
- Strong Password:
# Generate strong password (32+ chars)
openssl rand -base64 32
# Set in environment
export SWAGGER_AUTH_PASSWORD="<generated-password>"- Change Username:
# Do not use 'admin'
export SWAGGER_AUTH_USERNAME="accellens-api-docs"- Rate Limiting:
- Automatically configured: 10 requests per minute
- Brute force protection
- Logging of all attempts
- Audit Logging:
- All access attempts logged
- Auth failures tracked
- Rate limit violations logged
Nginx/Cloudflare:
location /api/docs {
allow 192.168.1.0/24; # Internal network
allow 10.0.0.0/8; # VPN network
deny all;
# Basic Auth still required
auth_basic "Swagger UI";
auth_basic_user_file /etc/nginx/.htpasswd;
}Cloudflare Access Rules:
- Configure IP whitelist in Cloudflare dashboard
- Apply to
/api/docs/*routes
Prometheus Alerts:
- alert: SwaggerUIBruteForce
expr: rate(swagger_auth_failures_total[5m]) > 5
for: 5m
labels:
severity: warning
annotations:
summary: 'Multiple failed Swagger UI access attempts'Audit Log Queries:
-- Find multiple failed attempts
SELECT ip_address, COUNT(*) as failures
FROM audit_logs
WHERE event_type = 'auth_failure'
AND metadata->>'resource' = 'swagger_ui'
AND created_at > NOW() - INTERVAL '1 hour'
GROUP BY ip_address
HAVING COUNT(*) > 10;Procedure:
- Generate new password
- Update in AWS Secrets Manager / Vault
- Update in Kubernetes secrets
- Restart gateway pods
- Notify team about new password (via secure channel)
Automation:
# Password rotation script
./scripts/rotate-swagger-password.sh- Never commit secrets to git
- Use secrets managers for all environments except dev
- Rotate secrets regularly (minimum quarterly for prod)
- Least privilege access to secrets
- Redaction before logging all user data
- Redaction before sending to LLM all prompts
- Audit logging of all PII detection instances
- Compliance with GDPR, HIPAA (where applicable)
- Regular scanning (weekly minimum)
- Automatic updates via Dependabot
- Rapid fix of critical vulnerabilities
- Documentation of all security exceptions
Important: There is a critical difference between deprecation warnings and security vulnerabilities:
Deprecation Warnings (Informational):
- Package is marked as deprecated and will be removed in future
- NOT a security vulnerability
- May indicate package is no longer supported
- Requires migration planning, but not critical
Security Vulnerabilities (Critical):
- Real security threats that can be exploited
- Require immediate fix
- Can lead to system compromise
Security Check:
# Check security (distinguishes deprecation and vulnerabilities)
npm run security:check
# Strict check (fails on critical vulnerabilities)
npm run security:check:strict
# Standard npm audit check
npm audit
# Auto-fix known vulnerabilities
npm audit fix
# Update packages with overrides
npm run updateAutomatic Check in CI/CD:
- Workflow
.github/workflows/security.ymlautomatically checks security - Critical and high vulnerabilities block deploy (if configured)
- Deprecation warnings are shown as info messages
Results Handling:
-
Security Vulnerabilities (Critical/High):
- Fix immediately via
npm audit fixor update overrides inpackage.json - If auto-fix impossible, replace package with alternative
- Document in security exceptions if fix impossible
- Fix immediately via
-
Deprecation Warnings:
- Plan migration to supported alternative
- Does not block deploy, but requires attention
- Track via Dependabot updates
Known Issues and Solutions:
The project uses npm overrides to automatically fix the following vulnerabilities:
uglify-js→ forced version 3.19.3underscore→ forced version 1.13.7xmldom→ replaced with@xmldom/xmldom@0.8.11
These fixes are applied automatically via overrides in package.json during npm install.
Important: Project uses npm 10.9.4 (constraint in package.json: "npm": ">=10.0.0 <11.0.0"). Issue with applying overrides to deep dependencies detected in npm 11.x.
- Immutable logs for production
- Retention policies according to compliance requirements
- Regular review of audit logs for suspicious activity
- SIEM integration for production
- PII redaction mandatory
- Right to deletion
- Data retention policies
- Audit logging of all PII accesses
- Enhanced PII detection
- Encrypted storage
- Access controls
- Audit trails
- Security controls
- Access management
- Monitoring and alerting
- Incident response procedures
Check:
ai_enable_safety_filters=truein config- Presidio installed (
pip install presidio-analyzer presidio-anonymizer) - OpenAI API key configured (for moderation API)
Check:
- Presidio Analyzer initialized
- Logs show initialization errors
- Text is in English (Presidio works best with English)
Check:
- PostgreSQL available
AUDIT_LOG_USE_POSTGRESQL=true- DB access permissions
- Error logs in gateway
- Enhanced PII detection for other languages
- Automated security scanning in pre-commit hooks
- Security dashboard in Grafana
- Integration with security information systems
- Automated incident response