# Certificats clients (mTLS)

> Pour un serveur partenaire qui présente un certificat. Deux façons de le vérifier, au choix ou ensemble :

Guide - Depuis la version 0.1.0 - Flexway v1.6.3 - https://flexway.io/docs/operations-client-certificates/

> Guide d'exploitation : configurer, déployer et observer la passerelle. Ce que fait la capacité côté produit : [guide produit](https://flexway.io/docs/product-overview/) ; l'appeler : [guide développeur](https://flexway.io/docs/developer-overview/).

Pour un **serveur partenaire** qui présente un certificat. Deux façons de le vérifier, au choix ou
ensemble :

| Où le certificat est vérifié | Configuration | Quand |
| --- | --- | --- |
| **L'edge** (Envoy, un ingress) termine le mTLS et l'atteste dans `x-forwarded-client-cert` | `server.trusted_proxies` = la plage de l'edge | Le cas courant en grappe |
| **La passerelle elle-même**, sur son écouteur TLS | `server.tls` (`cert_file`, `key_file`, `client_ca_file`) | Sans edge qui termine le TLS |

Chaque certificat est **déclaré** - par son URI SAN (préféré : il survit au renouvellement) ou par
son sujet - et lié à un tenant et à des opérations :

```yaml
server:
  trusted_proxies: [10.0.0.0/8]      # l'edge, et lui seul : de quiconque d'autre l'en-tête est ignoré
auth:
  mtls:
    clients:
      - { id: bank-settler, uri: "spiffe://bank.example/settler", tenant: bank, operations: [settle] }
      - { id: legacy-batch, subject: "CN=batch,O=Acme", tenant: acme, operations: [getSettlement] }
```

L'écouteur TLS de la passerelle, quand il n'y a pas d'edge (port `FLEXWAY_TLS_ADDR`, `:8443` par
défaut, à côté de `:8080`) :

```yaml
server:
  tls:
    cert_file: /etc/flexway/tls/tls.crt          # relu à sa rotation, sans redémarrage
    key_file: /etc/flexway/tls/tls.key
    client_ca_file: /etc/flexway/tls/clients-ca.pem   # l'autorité des certificats clients, relue aussi
```

Le contrat déclare l'alternative `mutualTLS` :

```yaml
components:
  securitySchemes:
    partner: { type: mutualTLS }
paths:
  /settlements:
    post:
      operationId: settle
      security: [ { partner: [] } ]    # un certificat déclaré, rien d'autre
```

**Vérif** :

| Appel | Réponse |
| --- | --- |
| Certificat déclaré, opération liée | relayé ; `X-Tenant` du certificat ; `x-forwarded-client-cert` n'atteint **jamais** l'amont |
| Certificat déclaré, opération qu'il ne nomme pas | `403` |
| Certificat valide mais non déclaré, ou aucun | `401` « requires a client certificate » |
| En-tête `x-forwarded-client-cert` venu d'ailleurs que de l'edge | ignoré - `401` |
| Certificat d'une autre autorité, sur l'écouteur TLS | la poignée de main échoue |
| Jeton sur une opération qui n'accepte que `mutualTLS` | `401` ; le jeton n'est même pas vérifié |

> **Ordre de lecture** : certificat vérifié par l'écouteur, puis `x-forwarded-client-cert` de
> l'edge, puis clé d'API, puis jeton. Le **contrat** décide quel mécanisme satisfait quelle
> alternative : un jeton ne remplace jamais une clé, ni l'inverse. La surface MCP n'accepte que des
> jetons OAuth ([Agents et MCP](https://flexway.io/docs/operations-agents-mcp/)). `server.tls` n'est pas rechargeable : l'ajouter ou le retirer demande un
> redémarrage, ses **fichiers** se relisent seuls.
