У меня есть ряд сервисов, которые аутентифицируются с использованием токенов OAuth Bearer. Я могу получить токены, используя либо грант учетных данных клиента OAuth, либо грант учетных данных владельца ресурса.
Однако у меня есть ряд существующих систем, которые способны выполнять вызовы, аутентифицированные только с использованием аутентифицированных соединений Mutual TLS.
Вместо того, чтобы обновлять все вызывающие приложения, чтобы иметь возможность получать токены носителя OAuth, я бы вместо этого хотел создать прокси-сервер шлюза, который:
По сути, я хочу скрыть факт использования OAuth от старых клиентов и разрешить им работать исключительно с Mutal TLS Authentication.
Существуют ли обратные прокси или способы или модули для Ngnix, Apache, Envoy или аналогичных обратных HTTP-прокси, которые позволили бы достичь этого без создания всего прокси?
Я нашел множество модулей, которые обрабатывают случай настройки Apache и Ngnix в качестве стороны ретрансляции OAuth или сервера ресурсов с использованием различных модулей, таких как
Но не удается найти примеры того, как они действуют как клиент OAuth или Open ID Connect в качестве прокси-сервера для клиента, прошедшего проверку подлинности Mutual TLS.
В частности, я хочу избежать написания прокси-части. Даже если мне придется писать сценарии реальных взаимодействий OAuth. Самое близкое, что я нашел, это сообщение в блоге о реализации OAuth RP в сценариях Envoy lua.
Я изо всех сил пытаюсь представить, что это уникальная потребность, поэтому мне интересно, есть ли какая-либо стандартная реализация этого шаблона, которую я не нашел.
Оказывается, это легко сделать с помощью 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