Accès à l’API interne

Présentation

Certaines opérations d’administration de la plateforme (par exemple la réinitialisation de l’OTP d’un utilisateur) sont exposées par l’API sous le préfixe /api/internal. Ces endpoints sont privilégiés : ils sont destinés à être appelés par des systèmes d’automatisation de confiance (scripts d’exploitation, orchestrateurs, outils internes), et non par les navigateurs ou les clients finals qui utilisent le portail.

Le besoin couvert par cette fonctionnalité est donc le suivant : donner accès à /api/internal sans l’exposer sur la surface publique habituelle (le portail ou le host API standard), et en protégeant cet accès par une authentification renforcée et indépendante de celle des utilisateurs normaux.

Pour cela, /api/internal est publié sur un nom d’hôte dédié (API_INTERNAL_URL), distinct du portail et du host API standard, et peut être protégé par trois couches complémentaires :

  • une liste d’IP autorisées (filtrage réseau) ;

  • un mTLS dédié (authentification mutuelle TLS avec sa propre PKI, séparée de la PKI interne classique) ;

  • une clé HMAC applicative, vérifiée par l’API elle-même.

Aucune de ces couches n’est obligatoire individuellement, mais elles se cumulent : on peut par exemple n’activer que le filtrage IP, ou ajouter le mTLS pour une authentification forte au niveau du transport.

Principe de fonctionnement

Lorsque la fonctionnalité est activée, une route Traefik dédiée est créée :

Host(`API_INTERNAL_URL`) && PathPrefix(`/api/internal`)

Cette route est posée :

  • sur le service portal lorsque le déploiement est de type infra_manager (le portail relaie déjà /api/* vers l’API) ;

  • sur le service api lorsque le déploiement sépare les rôles (api_manager + portal_manager) ; la route est alors ouverte uniquement côté api_manager.

Le nom d’hôte API_INTERNAL_URL sert de point d’entrée isolé : c’est lui qui porte l’authentification mTLS dédiée. Cette isolation par nom d’hôte est nécessaire car le choix de la PKI cliente se fait au moment de la négociation TLS (sur la base du nom d’hôte), avant que le chemin /api/internal ne soit connu. Il n’est donc pas possible de réserver une PKI différente à un simple chemin sur un hôte déjà utilisé.

Variables de configuration

API_INTERNAL_ENABLED

Active la fonctionnalité. Valeur booléenne (true / false). Par défaut : false.

API_INTERNAL_URL

Nom d’hôte dédié sur lequel /api/internal est publié (par exemple apiinternal.example.com). Obligatoire dès lors que la route doit être ouverte. Doit être différent du nom d’hôte du portail (PORTAL_URL) et du host API standard reemo_api.

API_INTERNAL_RESTRICT_IP

Liste d’adresses ou de plages IP autorisées à atteindre /api/internal, au format CIDR séparé par des virgules (par exemple "10.0.0.0/8,192.168.10.20/32"). Une requête provenant d’une IP non listée reçoit un 403. Laisser vide pour ne pas filtrer.

API_INTERNAL_SSL_CERT

Chemin vers le certificat serveur que Traefik présente sur le nom d’hôte API_INTERNAL_URL. Son SAN doit contenir API_INTERNAL_URL.

API_INTERNAL_SSL_KEY

Chemin vers la clé privée associée au certificat serveur ci-dessus.

API_INTERNAL_SSL_CA

Chemin vers la CA utilisée pour valider le certificat client présenté par l’appelant (mTLS). C’est cette variable qui active réellement le mTLS dédié : si elle est renseignée, seuls les clients présentant un certificat signé par cette CA sont acceptés.

Note

Les trois variables API_INTERNAL_SSL_* sont optionnelles. Si elles ne sont pas renseignées, la route reste ouverte mais sans la PKI dédiée. Pour obtenir un mTLS avec une PKI séparée de la PKI interne classique, il faut renseigner au minimum API_INTERNAL_SSL_CA (et fournir un certificat serveur valide pour le nom d’hôte, voir Certificats requis).

API_INTERNAL_HMAC

Clé HMAC partagée, vérifiée par l’API au niveau applicatif sur les appels /api/internal. Stockée comme secret. Cette couche est indépendante du mTLS : un appelant doit présenter le bon HMAC en plus de satisfaire les contrôles de transport.

Comportement selon la topologie

Déploiement mono-site (infra_manager)

La route /api/internal est ouverte sur le portail, sur le nom d’hôte API_INTERNAL_URL. Le portail relaie ensuite la requête vers l’API.

Dans ce mode, PORTAL_URL doit être renseigné avec un nom d’hôte exact. Si le portail est configuré en mode « wildcard » (sans PORTAL_URL), la route dédiée n’est pas créée, car le routeur wildcard entrerait en conflit avec l’authentification mTLS du nom d’hôte dédié.

Déploiement scindé (api_manager + portal_manager)

La route /api/internal est ouverte uniquement sur api_manager, directement sur le service API. Le portal_manager n’ouvre pas la route.

Note

Sur api_manager, le host API standard impose déjà un mTLS avec la PKI interne classique. La route dédiée API_INTERNAL_URL ajoute, sur son propre nom d’hôte, un mTLS avec la PKI dédiée (API_INTERNAL_SSL_CA), ce qui permet d’avoir deux PKI distinctes : l’une pour le trafic API habituel, l’autre pour l’API interne.

Fermeture de l’accès par le canal public

Pour garantir que /api/internal ne soit joignable que par le nom d’hôte dédié, l’accès au chemin /api/internal est refusé (403) sur le nom d’hôte public (portail, ou host API standard selon la topologie).

Warning

Si un composant légitime appelle /api/internal par le host public (et non par API_INTERNAL_URL ni en direct sur le conteneur), cette fermeture le bloquera. Vérifiez le chemin emprunté par vos appelants avant d’activer ce comportement.

Certificats requis

Deux éléments distincts interviennent dans le mTLS :

Le certificat serveur (API_INTERNAL_SSL_CERT / API_INTERNAL_SSL_KEY)

C’est ce que Traefik présente au client. Son SAN doit contenir API_INTERNAL_URL, et il doit être émis par une autorité que l’appelant fait confiance (le --cacert côté client). Si aucun certificat correspondant au nom d’hôte n’est fourni, Traefik présente un certificat auto-signé, et le client ne pourra valider la connexion qu’en désactivant la vérification (à éviter).

La CA de validation client (API_INTERNAL_SSL_CA)

C’est l’autorité qui doit avoir signé le certificat client présenté par l’appelant. Un certificat client signé par une autre autorité (par exemple la PKI interne classique) sera rejeté sur ce nom d’hôte.

Exemple de configuration

api_manager:
  vars:
    API_INTERNAL_ENABLED: true
    API_INTERNAL_URL: "apiinternal.example.com"
    API_INTERNAL_RESTRICT_IP: "10.0.0.0/8,192.168.10.20/32"
    API_INTERNAL_SSL_CERT: "/chemin/local/apiinternal.crt"
    API_INTERNAL_SSL_KEY: "/chemin/local/apiinternal.key"
    API_INTERNAL_SSL_CA: "/chemin/local/apiinternal_ca.crt"
    API_INTERNAL_HMAC: "<clé HMAC partagée>"

Vérification

Une fois le déploiement effectué, un appel authentifié doit aboutir à l’API sans avoir à désactiver la vérification TLS :

curl -v \
  --cacert /chemin/ca.pem \
  --cert /chemin/client.crt \
  --key /chemin/client.key \
  https://apiinternal.example.com/api/internal/users/reset-otp

Points de contrôle pendant le handshake :

  • Request CERT côté serveur : le serveur réclame bien le certificat client (mTLS actif) ;

  • le certificat serveur présenté correspond à API_INTERNAL_URL et est validé par votre --cacert (pas de message self-signed certificate) ;

  • la connexion aboutit ; un code applicatif (par exemple 401 si le HMAC est absent ou invalide) confirme que la requête a bien atteint l’API.

Note

Un 401 Unauthorized provient de l’API (contrôle HMAC applicatif) et non de Traefik : il indique que le transport (routage, mTLS, filtrage IP) a réussi et que seul l’en-tête d’authentification applicatif fait défaut.

Points d’attention

  • API_INTERNAL_URL doit être distinct de PORTAL_URL et de API_DOCKER_NAME. Réutiliser un nom d’hôte existant provoque un conflit d’options TLS sur ce nom et le mTLS dédié ne s’appliquerait pas de façon fiable.

  • Le mTLS dédié et la PKI interne classique sont indépendants : un même certificat client n’est pas valable sur les deux. Distribuez aux appelants de l’API interne un certificat signé par API_INTERNAL_SSL_CA.

  • Le filtrage IP, le mTLS et le HMAC sont cumulatifs. Pour un endpoint d’administration, il est recommandé de combiner au minimum le mTLS dédié et le HMAC.

  • En mode infra_manager, PORTAL_URL doit être un nom d’hôte exact pour que l’isolation par nom d’hôte fonctionne.