Преобразование 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 в Lua-скрипты Envoy.

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


person EdC    schedule 30.05.2019    source источник


Ответы (2)


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

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

Можно настроить Сетевой фильтр диспетчера HTTP-соединений, чтобы установить заголовок x-forwarded-client-cert в запросе к вышестоящей службе. В частности, настройка forward-client-cert-details to SANITIZE_SET заставит envoy установить заголовок . Что включено в заголовок, можно настроить, установив set-current-client-cert-details .

Но чтобы на самом деле 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 для включения маркера-носителя в восходящий запрос.

person EdC    schedule 08.07.2019

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

person Fernando Silva    schedule 27.08.2019