Преобразование Mutal TLS в OAuth ClientCredentials с помощью Ngnix, Apache, Envoy или другого обратного прокси-сервера

У меня есть ряд сервисов, которые аутентифицируются с использованием токенов OAuth Bearer. Я могу получить токены, используя либо грант учетных данных клиента OAuth, либо грант учетных данных владельца ресурса.

Однако у меня есть ряд существующих систем, которые способны выполнять вызовы, аутентифицированные только с использованием аутентифицированных соединений Mutual TLS.

Вместо того, чтобы обновлять все вызывающие приложения, чтобы иметь возможность получать токены носителя OAuth, я бы вместо этого хотел создать прокси-сервер шлюза, который:

  1. Получает соединения с проверкой подлинности TLS
  2. Использует субъект сертификата для идентификации системного субъекта.
  3. Получите токен от имени этой системы, используя учетные данные клиента или грант владельца ресурса.
  4. Выполните вызов базовой службы и верните результаты клиенту.

По сути, я хочу скрыть факт использования OAuth от старых клиентов и разрешить им работать исключительно с Mutal TLS Authentication.

Существуют ли обратные прокси или способы или модули для Ngnix, Apache, Envoy или аналогичных обратных HTTP-прокси, которые позволили бы достичь этого без создания всего прокси?

Я нашел множество модулей, которые обрабатывают случай настройки Apache и Ngnix в качестве стороны ретрансляции OAuth или сервера ресурсов с использованием различных модулей, таких как

Но не удается найти примеры того, как они действуют как клиент OAuth или Open ID Connect в качестве прокси-сервера для клиента, прошедшего проверку подлинности Mutual TLS.

В частности, я хочу избежать написания прокси-части. Даже если мне придется писать сценарии реальных взаимодействий OAuth. Самое близкое, что я нашел, это сообщение в блоге о реализации OAuth RP в сценариях Envoy lua.

Я изо всех сил пытаюсь представить, что это уникальная потребность, поэтому мне интересно, есть ли какая-либо стандартная реализация этого шаблона, которую я не нашел.

Как установить LAMP Stack 1/2 на Azure Linux VM
Как установить LAMP Stack 1/2 на Azure Linux VM
В дополнение к нашему предыдущему сообщению о намерении Azure прекратить поддержку Azure Database для MySQL в качестве единого сервера после 16...
1
0
648
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Оказывается, это легко сделать с помощью Envoy Proxy. В частности, используя функцию HTTP-фильтры внешней авторизации.

Прокси-сервер Envoy можно настроить для завершения SSL и запроса сертификата клиента, установив Нисходящий контекст TLS для прослушивателя и установив require_client_certificate на true.

Можно настроить Сетевой фильтр диспетчера HTTP-соединений для установки заголовка x-forwarded-client-cert в запросе к вышестоящей службе. В частности, установка вперед-клиент-сертификат-детали на SANITIZE_SET заставит посланника установить заголовок. То, что входит в заголовок, можно настроить, установив установить-текущий-клиент-сертификат-детали.

Но чтобы на самом деле Envoy выполнял обмен токенами, нам нужно настроить фильтр внешней авторизации. Это позволяет посланнику вызывать службу с подробностями запроса (включая сертификат), и эта служба может решить, разрешен ли запрос или нет. Важно отметить, что когда это разрешено, он может добавлять заголовки к запросу, сделанному вышестоящим службам, что позволяет ему добавлять токен носителя, необходимый для oauth.

Существуют версии фильтра внешней авторизации как для сетевого фильтра, так и для HTTP-фильтра. Вы должны использовать HTTP, если хотите добавить заголовки к восходящему запросу.

Полученный конфиг посланника выглядит так:

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          forward_client_cert_details: SANITIZE_SET # Include details of the client certificate in the x-forwarded-client-cert header when calling the upstream service
          set_current_client_cert_details:
            subject: True # Include the subject of the certificate in the x-forwarded-client-cert header rather than just the certificate hash.
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: service_backend
          http_filters:
          - name: envoy.ext_authz # Call an authorization service to do the OAuth token exchange
            config:
              grpc_service:
                envoy_grpc:
                  cluster_name: auth_service
                timeout: 5s # The timeout before envoy will give up waiting for an auth service response and deny access
          - name: envoy.router
      tls_context:
        require_client_certificate: True # Require downstream callers to provide a client certificate
        common_tls_context:
          validation_context:
            trusted_ca:
              filename: /etc/envoy/certs/ca-chain.cert.pem # CA certificate that client certificate must be signed with to be accepted
          tls_certificates:
          - certificate_chain:
              filename: /etc/envoy/certs/server-cert.pem
            private_key:
              filename: /etc/envoy/certs/server-key.pem
            password:
              inline_string: password
  clusters:
  - name: auth_service
    connect_timeout: 1s # The timeout before envoy will give up trying to make a TCP  connectio to an auth service
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    http2_protocol_options: {} # GRPC services must be HTTP/2 so force HTTP/2
    load_assignment:
      cluster_name: auth_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: localhost
                port_value: 8080

Хитрость заключается в том, чтобы реализовать службу GRPC, которая реализует Протокол внешней авторизации для обмена токенами и либо отклонить запрос, либо предоставить заголовок Authorization для включения токена носителя в восходящий запрос.

Если вам это все еще нужно, я создал сервер авторизации, который работает с использованием локальной базы данных аутентификации. Его очень легко преобразовать, чтобы вызвать OIDC и получить токен для внедрения. https://github.com./fams/tlsjwt-gw

Другие вопросы по теме