{"id":21354961,"url":"https://github.com/salrashid123/envoy_ext_proc","last_synced_at":"2025-07-12T22:32:30.023Z","repository":{"id":91309837,"uuid":"328827878","full_name":"salrashid123/envoy_ext_proc","owner":"salrashid123","description":"Envoy External Processing Filter","archived":false,"fork":false,"pushed_at":"2024-03-19T12:38:10.000Z","size":68,"stargazers_count":23,"open_issues_count":1,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-03-20T12:26:08.959Z","etag":null,"topics":["envoy","envoyproxy","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/salrashid123.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-01-12T00:30:17.000Z","updated_at":"2024-03-06T03:53:02.000Z","dependencies_parsed_at":"2024-03-19T12:26:09.146Z","dependency_job_id":"4d94899e-c1a9-4ccf-8149-02bcb01b2928","html_url":"https://github.com/salrashid123/envoy_ext_proc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_ext_proc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_ext_proc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_ext_proc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/salrashid123%2Fenvoy_ext_proc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/salrashid123","download_url":"https://codeload.github.com/salrashid123/envoy_ext_proc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225839601,"owners_count":17532308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["envoy","envoyproxy","golang"],"created_at":"2024-11-22T04:15:25.264Z","updated_at":"2025-07-12T22:32:30.012Z","avatar_url":"https://github.com/salrashid123.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"### Envoy External Processing Filter\n\nA really basic implementation of envoy [External Processing Filter](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_proc/v3/ext_proc.proto#envoy-v3-api-msg-extensions-filters-http-ext-proc-v3-externalprocessor).  This capability allows you to define an external gRPC server which can selectively process headers and payload/body of requests (see [External Processing Filter PRD](https://docs.google.com/document/d/1IZqm5IUnG9gc2VqwGaN5C2TZAD9_QbsY9Vvy5vr9Zmw/edit#heading=h.3zlthggr9vvv).  Basically, your own unrestricted filter.\n\n```\n          ext_proc \n             ^\n             |\nclient -\u003e  envoy -\u003e upstream\n```\n\n\u003e\u003e NOTE, this filter is really early and has a lot of features to implement!\n\n- Source: [ext_proc.cc](https://github.com/envoyproxy/envoy/blob/main/source/extensions/filters/http/ext_proc/ext_proc.cc)\n\n---\n\nAll we will demonstrate in this repo is the most basic functionality: manipulate headers and body-content on the request/response.  I know, there are countless other ways to do this with envoy but just as a demonstration of writing the external gRPC server that this functionality uses. If interested, pls read on:\n\nThe scenario is like this\n\n\nA) Manipulate outbound headers and body\n\n```\n          ext_proc   (delete specific header from client to upstream; append body content sent to upstream)\n             ^\n             |\nclient -\u003e  envoy -\u003e upstream\n```\n\nB) Manipulate response headers and body\n\n```\n          ext_proc   (delete specific header from upstream to client; append body content sent to client)\n             ^\n             |\nclient \u003c-  envoy \u003c- upstream\n```\n\n\n---\n\nSpecifically for (A), if a header key= \"user\" is sent by the client **AND** if the request is a POST, the external processing filter will\n - redact that header\n - append 'foo' to the body and send that to `httpbin.org/post`\n\n\nIf A is triggered, the couple of headers from httpbin are removed and the content type is set to text.  Finally, the response body has the text `qux` appended to it.\n\n\nIf the request type is GET or if the header 'user' is not present no modifications are made\n\n---\n\nFirst this code was just committed in PR [14385](https://github.com/envoyproxy/envoy/pull/14385) so we will need envoy from latest:\n\n```bash\ndocker cp `docker create envoyproxy/envoy:v1.33-latest`:/usr/local/bin/envoy /tmp\n```\n\nNow start the external gRPC server\n\n```bash\ngo run grpc_server.go\n```\n\nThis will start the gRPC server which will receive the requests from envoy.  \n\nNow start envoy\n\n```bash\n./envoy -c server.yaml -l debug\n```\n\nThe config w'ere using allows the external processor to progressively override headers sent over\n\n```yaml\n          http_filters:\n          - name: envoy.filters.http.ext_proc\n            typed_config:\n              \"@type\": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor\n              failure_mode_allow: false\n              allow_mode_override: true\n              allowed_override_modes: \n              - request_header_mode: \"SEND\"\n                response_header_mode: \"SEND\"\n                request_body_mode: \"BUFFERED\"\n                response_body_mode: \"BUFFERED\"\n                request_trailer_mode: \"SKIP\"\n                response_trailer_mode: \"SKIP\"              \n              processing_mode:\n                request_header_mode: \"SEND\"\n                response_header_mode: \"SEND\"\n                request_body_mode: \"BUFFERED\"\n                response_body_mode: \"BUFFERED\"\n                request_trailer_mode: \"SKIP\"\n                response_trailer_mode: \"SKIP\"\n              grpc_service:\n                envoy_grpc:                  \n                  cluster_name: ext_proc_cluster\n```\n\nSend in some requests\n\n\n\u003e\u003e note, in each of tests, the upstream is `httpbin.org` which will just echo back the inbound request to the caller and display the headers and body *it got* back as the json response (i.,e the json response below is what httpbin saw)\n\n1) GET Request\n\nIn this case, we should not expect any modifications to take place.\n\n```bash\n$ curl -v -H \"host: http.domain.com\"  --resolve  http.domain.com:8080:127.0.0.1  http://http.domain.com:8080/get\n\n\u003e GET /get HTTP/1.1\n\u003e Host: http.domain.com\n\u003e User-Agent: curl/7.74.0\n\u003e Accept: */*\n\n\n\u003c HTTP/1.1 200 OK\n\u003c date: Wed, 31 Mar 2021 16:59:50 GMT\n\u003c content-type: application/json\n\u003c content-length: 311\n\u003c server: envoy\n\u003c access-control-allow-origin: *\n\u003c access-control-allow-credentials: true\n\u003c x-envoy-upstream-service-time: 31\n\n{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Host\": \"http.domain.com\", \n    \"User-Agent\": \"curl/7.74.0\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6064aa86-1e8e99652e2c7ee003a2750f\", \n    \"X-Envoy-Expected-Rq-Timeout-Ms\": \"15000\"\n  }, \n  \"origin\": \"108.51.98.171\", \n  \"url\": \"https://http.domain.com/get\"\n}\n```\n\n2) GET Request with user header\n\nHere we're also not expecting changes\n\n```bash\n$ curl -v -H \"host: http.domain.com\"  --resolve  http.domain.com:8080:127.0.0.1  -H \"user: sal\" http://http.domain.com:8080/get\n\n\u003e GET /get HTTP/1.1\n\u003e Host: http.domain.com\n\u003e User-Agent: curl/7.74.0\n\u003e Accept: */*\n\u003e user: sal\n\n\u003c HTTP/1.1 200 OK\n\u003c date: Wed, 31 Mar 2021 17:00:37 GMT\n\u003c content-type: application/json\n\u003c content-length: 331\n\u003c server: envoy\n\u003c access-control-allow-origin: *\n\u003c access-control-allow-credentials: true\n\u003c x-envoy-upstream-service-time: 24\n\n{\n  \"args\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Host\": \"http.domain.com\", \n    \"User\": \"sal\", \n    \"User-Agent\": \"curl/7.74.0\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6064aab5-1c5e1204091c69600d45b6ba\", \n    \"X-Envoy-Expected-Rq-Timeout-Ms\": \"15000\"\n  }, \n  \"origin\": \"108.51.98.171\", \n  \"url\": \"https://http.domain.com/get\"\n}\n```\n\n3) POST Request with user header\n\nIn this case,we send in a POST but no user header so also no difference\n\n```bash\n$ curl -v -H \"host: http.domain.com\" -H \"content-type: text/plain\" --resolve  http.domain.com:8080:127.0.0.1  -d 'foo' http://http.domain.com:8080/post\n\n\u003e POST /post HTTP/1.1\n\u003e Host: http.domain.com\n\u003e User-Agent: curl/7.74.0\n\u003e Accept: */*\n\u003e content-type: text/plain\n\u003e Content-Length: 3\n\n\u003c HTTP/1.1 200 OK\n\u003c date: Wed, 31 Mar 2021 17:03:06 GMT\n\u003c content-type: application/json\n\u003c content-length: 441\n\u003c server: envoy\n\u003c access-control-allow-origin: *\n\u003c access-control-allow-credentials: true\n\u003c x-envoy-upstream-service-time: 8\n\n{\n  \"args\": {}, \n  \"data\": \"foo\", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Content-Length\": \"3\", \n    \"Content-Type\": \"text/plain\", \n    \"Host\": \"http.domain.com\", \n    \"User-Agent\": \"curl/7.74.0\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6064ab4a-6df7e0d437a8ad2637c35fce\", \n    \"X-Envoy-Expected-Rq-Timeout-Ms\": \"15000\"\n  }, \n  \"json\": null, \n  \"origin\": \"108.51.98.171\", \n  \"url\": \"https://http.domain.com/post\"\n}\n```\n\n4) Finally, \n\nWe send a post request and the 'user' header below\n\nWhat happens is that the external processing filter will\n\n1. In `*pb.ProcessingRequest_RequestHeaders`,  \n  - detect and remove `user` header\n  - instruct further processing of the request body\n\n2. In `*pb.ProcessingRequest_RequestBody`,\n  - append `bar` to the inbound request body\n  - add a new header `added-header`\n\n3. In `*pb.ProcessingRequest_ResponseHeaders`,\n  - remove the following headers sent by httpbin:  `\"access-control-allow-origin\", \"access-control-allow-credentials\"`\n  - update the content-length value by addin in the byte-length contained in the data we're going to later add to the body (i.e, add by #bytes in `qux`) \n\n4. In `*pb.ProcessingRequest_ResponseBody`\n  - Append `qux` to the response body sent by httpbin\n\n\n\n```bash\n$ curl -v -H \"host: http.domain.com\" -H \"content-type: text/plain\" \\\n  --resolve  http.domain.com:8080:127.0.0.1   -H \"user: sal\" -d 'foo' http://http.domain.com:8080/post\n\n\u003e POST /post HTTP/1.1\n\u003e Host: http.domain.com\n\u003e User-Agent: curl/8.14.1\n\u003e Accept: */*\n\u003e content-type: text/plain\n\u003e user: sal\n\u003e Content-Length: 3\n\n* upload completely sent off: 3 bytes\n\u003c HTTP/1.1 200 OK\n\u003c date: Fri, 04 Jul 2025 13:12:11 GMT\n\u003c server: envoy\n\u003c x-envoy-upstream-service-time: 177\n\u003c content-type: text/plain\n\u003c content-length: 490\n\n{\n  \"args\": {}, \n  \"data\": \"foo baaar \", \n  \"files\": {}, \n  \"form\": {}, \n  \"headers\": {\n    \"Accept\": \"*/*\", \n    \"Added-Header\": \"my new header\", \n    \"Content-Length\": \"10\", \n    \"Content-Type\": \"text/plain\", \n    \"Host\": \"http.domain.com\", \n    \"User-Agent\": \"curl/8.14.1\", \n    \"X-Amzn-Trace-Id\": \"Root=1-6867d32b-600054140d75cd4d13d6dfc6\", \n    \"X-Envoy-Expected-Rq-Timeout-Ms\": \"15000\"\n  }, \n  \"json\": null, \n  \"origin\": \"66.44.26.235\", \n  \"url\": \"https://http.domain.com/post\"\n}\n\n qux\n```\n\n---\n\nThats it, i'll be adding on more features as they become available to this repo.\n\n--- \n\n## Building docker image\n```\ndocker build --tag extproc .\ndocker run -it -p 18080:18080 extproc\n```\n\n\n## Other links\nOther reference envoy samples\n\n- [Envoy WASM and LUA filters for Certificate Bound Tokens](https://github.com/salrashid123/envoy_cert_bound_token)\n- [Envoy mTLS](https://github.com/salrashid123/envoy_mtls)\n- [Envoy control plane \"hello world\"](https://github.com/salrashid123/envoy_control)\n- [Envoy for Google Cloud Identity Aware Proxy](https://github.com/salrashid123/envoy_iap)\n- [Envoy External Authorization server (envoy.ext_authz) with OPA HelloWorld](https://github.com/salrashid123/envoy_external_authz)\n- [Envoy RBAC](https://github.com/salrashid123/envoy_rbac)\n- [Envoy Global rate limiting helloworld](https://github.com/salrashid123/envoy_ratelimit)\n- [Envoy EDS \"hello world\"](https://github.com/salrashid123/envoy_discovery)\n- [Envoy WASM with external gRPC server](https://github.com/salrashid123/envoy_wasm)\n- [Redis AUTH and mTLS with Envoy](https://github.com/salrashid123/envoy_redis)\n\n- [gRPC per method observability with envoy, Istio, OpenCensus and GKE](https://github.com/salrashid123/grpc_stats_envoy_istio#envoy)\n- [gRPC XDS](https://github.com/salrashid123/grpc_xds)\n- [gRPC ALTS](https://github.com/salrashid123/grpc_alts)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fenvoy_ext_proc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsalrashid123%2Fenvoy_ext_proc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsalrashid123%2Fenvoy_ext_proc/lists"}