mTLS

mTLS (Mutual TLS) — расширение TLS где не только сервер, но и клиент предъявляет свой сертификат. Гарантирует что обе стороны — те, за кого себя выдают. Стандарт для service-to-service внутри Kubernetes, микросервисов, API-gateway'ев, платёжных сетей, IoT.

Как отличается от обычного TLS

Обычный TLS:
    Client → ClientHello
    Server → ServerHello, Certificate, ...
    Server ← аутентифицирован по своему серверному серту
    Client ← остаётся анонимным (или проверяется отдельно паролем/токеном)

mTLS:
    Client → ClientHello
    Server → ServerHello, Certificate, CertificateRequest, ...
    Client → Certificate (свой!), CertificateVerify, ...
    Обе стороны проверены криптографически

Handshake TLS 1.3 с mTLS

  1. Client → ClientHello.
  2. Server → ServerHello, EncryptedExtensions, CertificateRequest, Certificate, CertificateVerify, Finished.
  3. Client проверяет серверный сертификат.
  4. Client → Certificate (свой сертификат с private-key), CertificateVerify (подпись доказывающая владение ключом), Finished.
  5. Server проверяет клиентский сертификат и подпись.
  6. Обмен данными.

Аутентификация против авторизации

mTLS даёт только аутентификацию — «этот клиент имеет ключ соответствующий CN=service-A». Что разрешено service-A делать — уже логика приложения (или policy engine типа OPA, Istio AuthorizationPolicy).

Где используется

Настройка на nginx

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Серверный серт
    ssl_certificate     /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    # CA чтобы проверять клиентские серты
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client on;              # обязательно
    # ssl_verify_client optional;      # клиент может, но не обязан
    ssl_verify_depth 2;

    location / {
        proxy_pass http://backend;
        proxy_set_header X-Client-Cert-CN $ssl_client_s_dn;
        proxy_set_header X-Client-Cert-Fingerprint $ssl_client_fingerprint;
    }
}

curl с клиентским сертом

curl --cert client.crt --key client.key \
     --cacert ca.crt \
     https://api.example.com/v1/data

Генерация клиентского серта

# CA
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
    -nodes -keyout ca.key -out ca.crt \
    -subj "/CN=My CA"

# Клиентский CSR
openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr \
    -subj "/CN=service-a"

# Подписать CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
    -CAcreateserial -out client.crt -days 365 -sha256

PKI-инфраструктура

При масштабе mTLS нужен полноценный PKI:

SPIFFE / SPIRE

SPIFFE (Secure Production Identity Framework For Everyone) — стандарт идентичности для service mesh. Формат ID: spiffe://example.com/service-a.

SPIRE — reference implementation. Автоматически выдаёт короткие сертификаты (SVID) каждому workload'у. Ротирует, отзывает при завершении.

Плюсы / минусы

ПлюсМинус
БезопасностьСтрогая криптоидентификация обоих концовУтечка private-key = полное владение
Отсутствие shared secretsНет паролей/API-ключейУправление ключами и PKI сложнее
Замена паролямНельзя «случайно запушить в git» текстомПриложение должно уметь TLS-клиентские серты
Zero TrustКаждое соединение — новая проверкаOverhead: handshake CPU
АудитПо CN легко трекать какой сервис делал запросРотация сертов операционная работа

Не путать с

См. также