Architettura di Sicurezza
Emblema implementa un'architettura di sicurezza multi-layer basata su standard enterprise, con autenticazione centralizzata via Keycloak, autorizzazione granulare RBAC, e cifratura end-to-end per proteggere dati sensibili e operazioni AI.
Panoramica Sicurezza
Livelli di Sicurezza
1. Perimeter Security
Traefik Reverse Proxy fornisce il primo livello di protezione:
# Configurazione sicurezza perimetrale
traefik:
command:
- --log.level=INFO
- --accesslog=true
- --metrics.prometheus=true
- --entrypoints.web.http.redirections.entryPoint.to=websecure
- --entrypoints.websecure.http.tls.options=default@file
labels:
# Middleware sicurezza applicati automaticamente
- "traefik.http.middlewares.security.headers.frameDeny=true"
- "traefik.http.middlewares.security.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.security.headers.browserXssFilter=true"
- "traefik.http.middlewares.security.headers.forceSTSHeader=true"
- "traefik.http.middlewares.security.headers.stsSeconds=31536000"
Rate Limiting per prevenire attacchi DDoS:
# config/traefik/dynamic/rate-limit.yml
http:
middlewares:
api-rate-limit:
rateLimit:
burst: 100
average: 50
period: 1m
auth-rate-limit:
rateLimit:
burst: 10
average: 5
period: 1m
2. Network Security
Segmentazione di Rete tramite Docker networks:
networks:
emblema:
external: true
ipam:
config:
- subnet: 172.18.0.0/16
redis-net:
internal: true # Rete privata per Redis cluster
ipam:
config:
- subnet: 172.19.0.0/16
Firewall Rules a livello container:
# Esempio isolamento servizi sensibili
database-services:
networks:
- emblema
labels:
- "traefik.enable=false" # Non esposti pubblicamente
ports: [] # Nessuna porta host
Autenticazione (Authentication)
Keycloak Identity Provider
Emblema utilizza Keycloak 26.2 come Identity Provider centralizzato:
keycloak:
image: quay.io/keycloak/keycloak:26.2
environment:
KC_HOSTNAME: ${KEYCLOAK_HOSTNAME}
KC_HTTP_ENABLED: true
KC_HOSTNAME_STRICT_HTTPS: false
KC_PROXY_HEADERS: "xforwarded"
KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN}
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres-keycloak/keycloak_db
Realm Configuration
{
"realm": "emblema",
"enabled": true,
"clients": [
{
"clientId": "web_client",
"name": "Emblema Web",
"enabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "${EMBLEMA_WEB_AUTH_KEYCLOAK_SECRET}",
"redirectUris": [
"https://${EMBLEMA_WEB_HOSTNAME}/api/auth/callback/keycloak"
],
"standardFlowEnabled": true,
"serviceAccountsEnabled": true,
"authorizationServicesEnabled": true,
"protocol": "openid-connect"
}
]
}
OpenID Connect Flow
JWT Token Management
// Configurazione NextAuth con Keycloak
export const authOptions: NextAuthOptions = {
providers: [
KeycloakProvider({
clientId: process.env.AUTH_KEYCLOAK_ID!,
clientSecret: process.env.AUTH_KEYCLOAK_SECRET!,
issuer: process.env.AUTH_KEYCLOAK_ISSUER,
}),
],
callbacks: {
async jwt({ token, account }) {
if (account) {
token.accessToken = account.access_token;
token.refreshToken = account.refresh_token;
token.expiresAt = account.expires_at;
}
return token;
},
async session({ session, token }) {
session.accessToken = token.accessToken;
session.groups = token.groups || [];
return session;
},
},
};
Autorizzazione (Authorization)
Role-Based Access Control (RBAC)
Emblema implementa un sistema RBAC granulare con tre livelli:
1. Group-Level Authorization
// Middleware controllo gruppi autorizzati
const authGroupMiddleware: NextMiddleware = async (req) => {
const session = await auth();
if (session && !hasAuthorizedGroups(session.groups)) {
return NextResponse.redirect(new URL("/unauthorized", req.url));
}
};
// Validazione gruppi
export const hasAuthorizedGroups = (groups: string[]): boolean => {
const authorizedGroups = ["emblema-users", "emblema-admin"];
return groups.some((group) => authorizedGroups.includes(group));
};
2. Entity-Level Permissions
// Sistema permessi per tipo di entità
export enum EntityType {
Meeting = "Meeting",
KnowledgeBase = "KnowledgeBase",
File = "File",
Document = "Document",
Chunk = "Chunk",
EntityPermission = "EntityPermission",
RecordPermission = "RecordPermission",
}
// Controllo permessi per tipo entità
export const hasEntityTypePermission = async ({
userId,
entityType,
create,
read,
update,
delete: deletePermission,
}: {
userId: string;
entityType: EntityType;
create?: boolean;
read?: boolean;
update?: boolean;
delete?: boolean;
}) => {
const entityPermission = await entityPermissionHandler.get({
userId,
entityType,
});
if (!entityPermission) return false;
// Verifica ogni permesso richiesto
for (const permission of Object.keys(permissions)) {
if (!entityPermission[permission as keyof EntityPermission]) {
return false;
}
}
return true;
};
3. Record-Level Permissions
// Permessi granulari per singoli record
export const hasRecordPermission = async ({
userId,
entityId,
entityType,
...permissions
}: {
userId: string;
entityId: string;
entityType?: EntityType;
create?: boolean;
read?: boolean;
update?: boolean;
delete?: boolean;
}) => {
const recordPermission = await recordPermissionHandler.get({
userId,
parentId: entityId,
});
// Controllo ownership se no permessi espliciti
if (!recordPermission) {
const data = await getDataHandler(entityType).get(entityId);
return data?.createdBy === userId;
}
return checkPermissions(recordPermission, permissions);
};
Permission Matrix
| Risorsa | Create | Read | Update | Delete | Note |
|---|---|---|---|---|---|
| File | User | Owner/Shared | Owner | Owner | Upload documenti |
| Document | Auto | Owner/Shared | Owner | Owner | Post-elaborazione |
| KnowledgeBase | User | Owner/Shared | Owner | Owner | Collezioni documenti |
| Meeting | User | Owner/Shared | Owner | Owner | Trascrizioni audio |
| Chunk | System | Owner/Shared | Owner | System | Contenuti vettoriali |
| EntityPermission | Admin | Admin | Admin | Admin | Gestione permessi |
API Route Protection
// Pattern protezione API route
export async function GET(
request: Request,
{ params }: { params: { entityId: string } },
) {
const session = await auth();
if (!session?.user?.id) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Verifica permessi specifici
const { hasPermission, data } = await checkUserEntityPermission({
entityType: EntityType.Document,
entityId: params.entityId,
userId: session.user.id,
permissions: { read: true },
});
if (!hasPermission) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
return NextResponse.json(data);
}
Crittografia e Protezione Dati
Transport Layer Security (TLS)
Terminazione TLS centralizzata su Traefik:
# Configurazione TLS sicura
tls:
options:
default:
minVersion: "VersionTLS12"
cipherSuites:
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
- "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
curvePreferences:
- "CurveP521"
- "CurveP384"
HTTP Security Headers:
http:
middlewares:
security:
headers:
frameDeny: true
contentTypeNosniff: true
browserXssFilter: true
forceSTSHeader: true
stsSeconds: 31536000
stsIncludeSubdomains: true
contentSecurityPolicy: |
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' wss: https:;
Data Encryption at Rest
Database Encryption:
# PostgreSQL con TLS e encryption
postgres-vector:
environment:
POSTGRES_DB_ENCRYPTION: "on"
POSTGRES_SSL_MODE: "require"
command: |
postgres
-c ssl=on
-c ssl_cert_file=/etc/ssl/certs/server-cert.pem
-c ssl_key_file=/etc/ssl/private/server-key.pem
MinIO Object Storage:
minio:
environment:
MINIO_SERVER_SIDE_ENCRYPTION: "on"
MINIO_KMS_SECRET_KEY: "${MINIO_KMS_SECRET_KEY}"
command: |
server /data
--console-address ":9090"
--certs-dir /root/.minio/certs
Secrets Management
Environment-based Secrets:
# Pattern sicurezza per secrets
# Mai hardcoded nei file di configurazione
# Database passwords
POSTGRES_PASSWORD=secure_random_string_32_chars
REDIS_MASTER_PASSWORD=secure_random_string_32_chars
# JWT secrets
AUTH_SECRET=base64_encoded_secret_key
KEYCLOAK_ADMIN_PASSWORD=secure_admin_password
# API keys
LITELLM_MASTER_KEY=secure_api_key
HASURA_ADMIN_SECRET=secure_graphql_secret
# Encryption keys
MINIO_KMS_SECRET_KEY=32_byte_encryption_key
Secrets Rotation Policy:
# Automated secrets rotation (future implementation)
secrets-rotation:
schedule: "0 2 * * 0" # Weekly on Sunday 2 AM
targets:
- postgres_password
- redis_password
- jwt_secret
- api_keys
Network Security & CORS
CORS Configuration
# config/traefik/dynamic/cors.yml
http:
middlewares:
cors:
headers:
accessControlAllowOriginList:
- "https://${EMBLEMA_WEB_HOSTNAME}"
- "https://${DOCS_HOSTNAME}"
- "https://${KEYCLOAK_HOSTNAME}"
accessControlAllowMethods:
- "GET"
- "POST"
- "PUT"
- "DELETE"
- "OPTIONS"
accessControlAllowHeaders:
- "Content-Type"
- "Authorization"
- "X-Requested-With"
accessControlAllowCredentials: true
accessControlMaxAge: 86400
Content Security Policy
// CSP header per prevenire XSS
const cspHeader = `
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' ${KEYCLOAK_HOSTNAME};
style-src 'self' 'unsafe-inline';
img-src 'self' data: https: blob:;
font-src 'self' data:;
connect-src 'self' ${HASURA_HOSTNAME} ${KEYCLOAK_HOSTNAME} wss:;
media-src 'self' blob:;
worker-src 'self' blob:;
child-src 'self';
frame-ancestors 'none';
form-action 'self';
upgrade-insecure-requests;
`;
Audit e Compliance
Security Logging
# Logging strutturato per audit
x-logging: &security-logging
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
labels: "service,security_event,user_id,timestamp"
# Pattern log eventi sicurezza
services:
www-emblema:
logging: *security-logging
environment:
LOG_LEVEL: "info"
SECURITY_LOG_ENABLED: "true"
Security Event Types:
- Authentication Events: Login, logout, token refresh
- Authorization Events: Permission denied, role changes
- Data Access: CRUD operations on sensitive data
- Administrative Actions: User management, permission changes
- Security Violations: Failed auth attempts, suspicious activity
Compliance Requirements
// GDPR compliance helpers
export const logDataAccess = async ({
userId,
entityType,
entityId,
action,
ipAddress,
}: {
userId: string;
entityType: EntityType;
entityId: string;
action: "create" | "read" | "update" | "delete";
ipAddress: string;
}) => {
await auditLogHandler.create({
userId,
entityType,
entityId,
action,
ipAddress,
timestamp: new Date(),
userAgent: request.headers.get("user-agent"),
});
};
Security Monitoring
Intrusion Detection
# Fail2Ban-like protection via Traefik
http:
middlewares:
auth-protection:
rateLimit:
burst: 5
average: 1
period: 60s
sourceCriterion:
ipStrategy:
depth: 1
Security Metrics
// Metriche sicurezza per Prometheus
const securityMetrics = {
auth_attempts_total: "Counter for authentication attempts",
auth_failures_total: "Counter for authentication failures",
permission_denials_total: "Counter for authorization denials",
suspicious_activity_total: "Counter for suspicious activity",
active_sessions_gauge: "Gauge for currently active sessions",
};
Health Checks Security
# Health check che non espongono info sensibili
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# Non includere dettagli interni nella risposta
Security Best Practices
Development Security
-
Secure Coding Standards:
- Input validation e sanitization
- SQL injection prevention
- XSS protection
- CSRF tokens
-
Dependency Security:
# Scan dipendenze vulnerabilità
pnpm audit
docker scout cves -
Container Security:
# Utenti non-privilegiati
RUN adduser --system --uid 1001 appuser
USER appuser
# Filesystem read-only
RUN chmod -R 755 /app && chown -R appuser:appgroup /app
Operational Security
- Regular Updates: Aggiornamenti automatici sicurezza
- Backup Encryption: Backup cifrati e testati
- Incident Response: Procedure risposta incidenti
- Penetration Testing: Test penetrazione periodici
Air-Gap Deployment
Per ambienti air-gapped:
# Configurazione offline-first
services:
emblema-services:
environment:
HF_HUB_OFFLINE: "1"
TRANSFORMERS_OFFLINE: "1"
CERT_RESOLVER: "" # Custom certificates only
volumes:
- ./models:/models:ro # Pre-cached AI models
- ./certs:/certs:ro # Custom SSL certificates
Security Incident Response
Incident Types
- Authentication Bypass
- Privilege Escalation
- Data Breach
- Service Compromise
- DDoS Attack
Response Procedures
# Emergency response commands
docker compose logs --since=1h | grep -i "error\|fail\|unauthorized"
docker compose exec www-emblema sh -c "tail -f /var/log/security.log"
# Isolate compromised service
docker compose stop suspected-service
# Rotate secrets immediately
./scripts/rotate-secrets.sh --emergency
# Enable enhanced logging
export LOG_LEVEL=debug
docker compose restart
Riferimenti
- OWASP Top 10
- Keycloak Documentation
- OAuth 2.0 Security Best Practices
- Docker Security
- NIST Cybersecurity Framework
Prossimi Passi
- Architettura Docker - Container security patterns
- Topologia di Rete - Network security implementation
- Requisiti di Sistema - Security hardware requirements