Does Gatekeeper proxy gRPC requests

Hi,

I would like to use Gatekeeper to secure a gRPC API. Is this supported?

Best regards,
Christian

IMHO yes, because that’s just HTTP/2. The best option is to try it.

I’ve tested it and I have an issue. Gatekeeper adds the Transfer-Encoding: chunked header to the request. This changes the request type from a single gRPC request to a streaming request. My API expects a single request and then the underlying framework quits with an error, that it cannot handle the request.

Request without Gatekeper:

:authority:            localhost:9443
authorization:         Bearer eyJhbGciOiJSUzI1NiIsInR5cCIg....
te:                    trailers
content-type:          application/grpc
user-agent:            grpc-c/9.0.0 (linux; chttp2; guantao)
grpc-accept-encoding:  identity,deflate,gzip
accept-encoding:       identity,gzip
Raw                                                                                                                                                                                    [m:auto]
\x00\x00\x00\x05\xe7
\x04root\x12\x0chttp-request\x1a>

requestUrl\x120:.
,https://postb.in/1576765679472-3624328554142\x1a\xcc

\x0erequestHeaders\x12\xb9
J\xb6

\xb3

\x1f
\x08X-SOURCE\x12\x13\x1a\x11Caribou / Camunda
\xeb?

Authorization\x12\xd9?\x1a\xd6?Bearer: eyJhbGciOiJSUzI1NiIsInR5cCIg....
"
\x0cContent-Type\x12\x12\x1a\x10application/json\x1a\x19

requestMethod\x12\x08:\x06
\x04POST\x1a'
\x0brequestBody\x12\x18:\x16
\x14{"data":"Some data"}

Request with Gatekeeper:

User-Agent:            grpc-c/9.0.0 (linux; chttp2; guantao)
Transfer-Encoding:     chunked
Authorization:         Bearer eyJhbGciOiJSUzI1NiIsInR5cCIg....
Content-Type:          application/grpc
Cookie:
Grpc-Accept-Encoding:  identity,deflate,gzip
Te:                    trailers
X-Auth-Audience:       pride-pim-caribou,account
X-Auth-Email:          service-account-pride-pim-caribou@placeholder.org
X-Auth-Expiresin:      2020-03-10 15:15:22 +0000 UTC
X-Auth-Groups:
X-Auth-Roles:          offline_access,uma_authorization,account:manage-account,account:manage-account-links,account:view-profile
X-Auth-Subject:        e10d6c11-abdf-45a4-82e4-6ff3a0e50432
X-Auth-Userid:         service-account-pride-pim-caribou
X-Auth-Username:       service-account-pride-pim-caribou
X-Forwarded-For:       ::1
X-Forwarded-Host:      localhost:3000
X-Forwarded-Proto:
Accept-Encoding:       gzip
Raw                                                                                                                                                                                    [m:auto]
\x00\x00\x00\x05\xe7
\x04root\x12\x0chttp-request\x1a>

requestUrl\x120:.
,https://postb.in/1576765679472-3624328554142\x1a\xcc

\x0erequestHeaders\x12\xb9
J\xb6

\xb3

\x1f
\x08X-SOURCE\x12\x13\x1a\x11Caribou / Camunda
\xeb?

Authorization\x12\xd9?\x1a\xd6?Bearer: eyJhbGciOiJSUzI1NiIsInR5cCIg....
"
\x0cContent-Type\x12\x12\x1a\x10application/json\x1a\x19

requestMethod\x12\x08:\x06
\x04POST\x1a'
\x0brequestBody\x12\x18:\x16
\x14{"data":"Some data"}

It looks like Golang feature (https://deliveroo.engineering/2019/02/22/go-down-the-rabbit-hole.html, https://github.com/golang/go/blob/2012227b01020eb505cf1dbe719b1fa74ed8c5f4/src/net/http/transfer.go#L107). Try request with content-length header.

Can it be the case that Gatekeeper switches the protocols? From HTTP2 to HTTP1? The second request (with Gatekeeper) is logged as:

https://localhost:9443/caribou.ProcessService/start
   2020-03-11 11:28:29 POST HTTP/1.1 ← 200

The request without Gatekeeper is logged as:

https://localhost:9443/caribou.ProcessService/start
   2020-03-11 11:36:27 POST HTTP/2.0

I use mitmproxy as reverse proxy. It listens on localhost:8080 and Gatekeeper uses upstream-url: https://localhost:8080.

My Gatekeeper config:

listen: 0.0.0.0:3000
client-id: pride-pim-caribou
client-secret: ***
encryption-key: ***
discovery-url: https://auth.keycloak.io/realms/master
upstream-url: https://localhost:8080
upstream-keepalives: false
skip-upstream-tls-verify: true
tls-cert: "$PROJECT_DIR/certs/localhost.cert.pem"
tls-private-key: "$PROJECT_DIR/certs/localhost.key.pem"
tls-ca-certificate: "$PROJECT_DIR/certs/localhost-ca.pem"
no-redirects: true
enable-default-deny: true
enabled-proxy-protocol: true
preserve-host: true

I think the following Gatekeeper code hits this issue: https://github.com/golang/go/issues/21336#issuecomment-320853173

Switched to Keycloak Dev mailing list: https://groups.google.com/forum/#!topic/keycloak-dev/BwKgmJpBBFI

IMHO HTTP/1.1 is correct. HTTP/2 starts as standard HTTP/1.1 request. But client (gatekeeper/golang reverse proxy) needs to uprade it (Upgrade: h2c header) later to HTTP/2 and that is missing here. Problem seems to be a valid question for golang dev forum, not for gatekeeper dev.

Have you read the linked GitHub post? In my opinion, this is a bug in Gatekeeper. The code says:

In this isn’t done in Gatekeeper