Aller au contenu principal

Configuration de Sécurité

Ce guide couvre les paramètres de sécurité introduits dans les Correctifs de Sécurité P0 Team Coca (ADR-018).

Résumé

Toutes les fonctionnalités de sécurité sont activées par défaut avec des paramètres sécurisés. Vous n'avez besoin de les configurer que si vous personnalisez votre environnement.

Référence Rapide​

FonctionnalitéParamètreDéfautRollback
Audience JWTALLOWED_AUDIENCESstoa-mcp-gateway,accountDéfinir à ""
CORSCORS_ORIGINSListe blancheDéfinir à "*"
Limites SSESSE_LIMITER_ENABLEDtrueDéfinir à false
Proxies de ConfianceSSE_TRUSTED_PROXIES"" (aucun)Configurer les CIDRs

Validation de l'Audience JWT (CAB-938)​

Ce que ça Fait​

Valide que les tokens JWT ont été émis spécifiquement pour le MCP Gateway, empêchant la réutilisation des tokens d'autres clients Keycloak.

Configuration​

# Variables d'environnement
ALLOWED_AUDIENCES=stoa-mcp-gateway,account

# Ou dans settings.py
allowed_audiences: str = "stoa-mcp-gateway,account"

Paramètres​

ParamètreTypeDéfautDescription
ALLOWED_AUDIENCESstringstoa-mcp-gateway,accountListe d'audiences JWT valides séparées par des virgules

Configuration Keycloak​

Assurez-vous que votre client Keycloak est configuré pour inclure l'audience :

{
"clientId": "stoa-mcp-gateway",
"protocolMappers": [
{
"name": "audience-mapper",
"protocol": "openid-connect",
"protocolMapper": "oidc-audience-mapper",
"config": {
"included.client.audience": "stoa-mcp-gateway",
"access.token.claim": "true"
}
}
]
}

Test​

# Décoder un token et vérifier l'audience
echo $TOKEN | cut -d. -f2 | base64 -d | jq '.aud'
# Doit inclure : "stoa-mcp-gateway"

Rollback​

Si la validation JWT casse l'authentification :

# Désactiver la validation de l'audience (temporaire !)
export ALLOWED_AUDIENCES=""
attention

Désactiver la validation de l'audience est un risque de sécurité. À utiliser uniquement pour le débogage.


Configuration CORS (CAB-950)​

Ce que ça Fait​

Restreint les origines pouvant effectuer des requêtes cross-origin vers l'API, empêchant les attaques CSRF et d'exfiltration de données.

Configuration​

# Variables d'environnement
CORS_ORIGINS=https://console.stoa.dev,https://portal.stoa.dev
CORS_ALLOW_METHODS=GET,POST,PUT,DELETE,OPTIONS
CORS_ALLOW_HEADERS=Authorization,Content-Type,X-Request-ID,X-Tenant-ID
CORS_EXPOSE_HEADERS=X-Request-ID,X-Trace-ID
CORS_MAX_AGE=600

Paramètres​

ParamètreTypeDéfautDescription
CORS_ORIGINSstringVoir ci-dessousOrigines autorisées séparées par des virgules
CORS_ALLOW_METHODSstringGET,POST,PUT,DELETE,OPTIONSMéthodes HTTP autorisées
CORS_ALLOW_HEADERSstringAuthorization,Content-Type,...En-têtes de requête autorisés
CORS_EXPOSE_HEADERSstringX-Request-ID,X-Trace-IDEn-têtes exposés au navigateur
CORS_MAX_AGEint600Durée du cache preflight (secondes)

Origines par Défaut​

https://console.stoa.dev
https://portal.stoa.dev
https://console.gostoa.dev
https://portal.gostoa.dev

Développement Local​

Pour le développement local, ajoutez des origines localhost :

CORS_ORIGINS=https://console.stoa.dev,http://localhost:3000,http://localhost:5173

Test​

# Tester le preflight CORS
curl -X OPTIONS ${STOA_API_URL}/v1/tools \
-H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: GET" \
-v

# Doit retourner 403 ou Access-Control-Allow-Origin manquant

Rollback​

# Autoriser toutes les origines (NON RECOMMANDÉ !)
export CORS_ORIGINS="*"
danger

N'utilisez jamais CORS_ORIGINS="*" en production. Cela permet à n'importe quel site web d'effectuer des requêtes authentifiées vers votre API.


Limites de Connexions SSE (CAB-939)​

Ce que ça Fait​

Prévient les attaques d'épuisement de connexions (Slowloris) en limitant les connexions SSE par IP, par tenant et globalement.

Configuration​

# Variables d'environnement
SSE_LIMITER_ENABLED=true
SSE_TRUSTED_PROXIES=10.100.0.0/16 # CIDR de votre cluster

Paramètres​

ParamètreTypeDéfautDescription
SSE_LIMITER_ENABLEDbooltrueActiver/désactiver le rate limiting
SSE_TRUSTED_PROXIESstring""CIDRs des proxies de confiance pour X-Forwarded-For

Limites Intégrées​

Ces limites sont codées en dur mais peuvent être ajustées dans le code :

LimiteValeurDescription
MAX_PER_IP10Connexions max depuis une seule IP
MAX_PER_TENANT100Connexions max par tenant
MAX_TOTAL5000Limite de connexions globale
IDLE_TIMEOUT30sFermer les connexions inactives après
MAX_DURATION1hDurée maximale de connexion
RATE_LIMIT_PER_MIN5Nouvelles connexions par IP par minute

Proxies de Confiance​

important

Si vous êtes derrière un load balancer ou un contrôleur ingress, vous devez configurer les proxies de confiance pour obtenir les IPs client exactes.

# Exemple EKS
SSE_TRUSTED_PROXIES=10.100.0.0/16

# Exemple GKE
SSE_TRUSTED_PROXIES=10.0.0.0/8

# Plusieurs CIDRs
SSE_TRUSTED_PROXIES=10.100.0.0/16,172.16.0.0/12

Si non configuré, le limiteur utilisera l'IP de connexion directe (qui peut être votre load balancer).

Test​

# Tester le rate limit (doit obtenir 429 à la 11ème connexion)
for i in {1..15}; do
curl -N "${STOA_API_URL}/mcp/sse" \
-H "Authorization: Bearer $TOKEN" &
done

# Vérifier les connexions actives (si vous avez accès)
curl ${STOA_API_URL}/metrics | grep stoa_sse

Codes de Réponse​

CodeSignificationEn-tête
429Too Many RequestsRetry-After: 60

Rollback​

# Désactiver le rate limiting SSE
export SSE_LIMITER_ENABLED=false

Sécurité des Conteneurs (CAB-945)​

Pod Security Standards​

STOA applique le Pod Security Standard restricted sur le namespace stoa-system :

apiVersion: v1
kind: Namespace
metadata:
name: stoa-system
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted

Contexte de Sécurité des Deployments​

Tous les deployments STOA utilisent ce contexte de sécurité :

spec:
automountServiceAccountToken: false # Sauf si nécessaire
securityContext:
runAsNonRoot: true
fsGroup: 1000

containers:
- securityContext:
runAsUser: 1000
runAsGroup: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
seccompProfile:
type: RuntimeDefault

Network Policies​

Le control plane est isolé avec NetworkPolicy :

# Ingress : Uniquement depuis MCP Gateway et Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: stoa-mcp-gateway
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx

# Egress : Uniquement vers les services connus
egress:
- to:
- podSelector:
matchLabels:
app: postgresql
- to:
- podSelector:
matchLabels:
app: redis
# ... et DNS

Vérification​

# Vérifier l'application PSS
kubectl get ns stoa-system -o jsonpath='{.metadata.labels}' | jq

# Vérifier le contexte de sécurité
kubectl get pod -n stoa-system -o jsonpath='{.items[0].spec.securityContext}'

# Tester NetworkPolicy (doit échouer depuis un pod aléatoire)
kubectl run test --rm -it --image=alpine -- wget -O- http://stoa-control-plane:8080

Monitoring​

Métriques Prometheus (P1)​

Ces métriques seront ajoutées dans une release de suivi :

# Connexions SSE actives
stoa_sse_connections_total{tenant="acme"}

# Connexions SSE rejetées
stoa_sse_rejected_total{reason="ip_limit"}

# Échecs de validation JWT
stoa_jwt_validation_failures_total{reason="invalid_audience"}

Alertes​

Alertes recommandées :

- alert: STOAHighSSERejectionRate
expr: rate(stoa_sse_rejected_total[5m]) > 10
labels:
severity: warning
annotations:
summary: Taux de rejet SSE élevé (possible attaque)

- alert: STOAJWTValidationFailures
expr: rate(stoa_jwt_validation_failures_total[5m]) > 5
labels:
severity: warning
annotations:
summary: Échecs de validation JWT détectés

Dépannage​

Erreurs de Validation JWT​

Symptôme : 401 Unauthorized avec le message "Invalid audience"

Solution :

  1. Vérifier l'audience du token : echo $TOKEN | cut -d. -f2 | base64 -d | jq '.aud'
  2. Vérifier la configuration du mapper client Keycloak
  3. Désactiver temporairement : ALLOWED_AUDIENCES=""

Erreurs CORS​

Symptôme : La console du navigateur affiche des erreurs "CORS policy"

Solution :

  1. Vérifier que l'origine est dans la liste blanche : echo $CORS_ORIGINS
  2. Ajouter l'origine : CORS_ORIGINS="...,https://your-domain.com"
  3. Vérifier les fautes de frappe (http vs https)

Rate Limiting SSE​

Symptôme : 429 Too Many Requests avec Retry-After: 60

Solution :

  1. Vérifier s'il s'agit de trafic légitime ou d'une attaque
  2. Vérifier la détection de l'IP client : curl -v ... | grep X-Forwarded-For
  3. Configurer les proxies de confiance : SSE_TRUSTED_PROXIES=...
  4. Désactiver temporairement : SSE_LIMITER_ENABLED=false

Sécurité des Conteneurs​

Symptôme : Le pod ne démarre pas avec "container has runAsNonRoot and image will run as root"

Solution :

  1. Utiliser une image de base non-root
  2. Ajouter USER 1000 au Dockerfile
  3. Définir runAsUser dans le deployment

Références​


Dernière mise à jour : 2026-01-25 — Audit de Sécurité Team Coca