Add gRPC support
Preflight checklist
- [x] I agree to follow this project's Code of Conduct.
- [x] I have read and am following this repository's Contribution Guidelines."
- [x] I have discussed this feature request with the community.
Describe the background of your feature request
Heimdall currently focuses on securing HTTP-based traffic. However, many modern microservice architectures also use gRPC for (inter-service) communication due to its efficiency, streaming capabilities, and strong typing.
Describe your idea
Extend Heimdall to support gRPC traffic alongside existing HTTP-based capabilities.
Are there any workarounds or alternatives?
Not yet tested, but there might be some workarounds, which you can see described in the "Additional Context" section below.
Version
0.17.0
Additional Context
Below is a status quo related to grpc support.
In principle an unary grpc request looks as following (These examples are taken from grpc docs).
HEADERS (flags = END_HEADERS)
:method = POST
:scheme = http
:path = /google.pubsub.v2.PublisherService/CreateTopic
:authority = pubsub.googleapis.com
grpc-timeout = 1S
content-type = application/grpc+proto
grpc-encoding = gzip
authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v
DATA (flags = END_STREAM)
<Length-Prefixed Message>
and a response like this
HEADERS (flags = END_HEADERS)
:status = 200
grpc-encoding = gzip
content-type = application/grpc+proto
DATA
<Length-Prefixed Message>
HEADERS (flags = END_STREAM, END_HEADERS)
grpc-status = 0 # OK
trace-proto-bin = jher831yy13JHy3hc
In go, http1 and http2 requests and responses are represented by the same http.Request and http.Response types internally used by heimdall. That means, heimdall can already support grpc calls on a rule level. E.g. the above request could be matched and handled by the following rule:
- id: my grpc rule
match:
routes:
- path: /google.pubsub.v2.PublisherService/CreateTopic
methods: ["POST"]
hosts:
- type: exact
value: pubsub.googleapis.com
execute:
# whatever
on_error:
# whatever
The main limitations surface when creating the response, as grpc is using http2 as tunneling protocol:
- grpc requires that the
:statuspseudo header is always set to200, and - the
grpc-statustrailer header is used to signal the actual response status instead.
This is not yet natively supported by heimdall as the :status pseudo header will be set based on the result of the authentication & authorization pipeline result (definitions in the execute property), respectively the result of the error handling pipeline (definitions in the on_error property).
There is also a limitation related to the ability of heimdall to map raised errors to HTTP response codes globally. This mapping should apply to grpc-status instead of the HTTP status code.
Since grpc is a binary protocol, respectively the transferred data is a protobuf message, heimdall is unable to decode it, if a step in a pipeline makes use of .Request.Body function. Though, this might be an acceptable limitation.
The corresponding options and how to proceed are discussed in the gRPC Support channel in heimdall's Discord.