From aa55332b349913318bfa116a5ed1c797f730cc6f Mon Sep 17 00:00:00 2001 From: Caleb Doxsey Date: Thu, 10 Oct 2024 17:55:34 -0600 Subject: [PATCH] core/config: allow websockets and spdy by default for k8s urls (#5325) --- config/envoyconfig/routes.go | 4 +- config/envoyconfig/routes_test.go | 114 ++++++++++++++++++++++++++- internal/httputil/reproxy/reproxy.go | 6 +- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/config/envoyconfig/routes.go b/config/envoyconfig/routes.go index 685b04696..7297b5cba 100644 --- a/config/envoyconfig/routes.go +++ b/config/envoyconfig/routes.go @@ -405,11 +405,11 @@ func (b *Builder) buildPolicyRouteRouteAction(options *config.Options, policy *c upgradeConfigs := []*envoy_config_route_v3.RouteAction_UpgradeConfig{ { UpgradeType: "websocket", - Enabled: &wrapperspb.BoolValue{Value: policy.AllowWebsockets}, + Enabled: &wrapperspb.BoolValue{Value: policy.AllowWebsockets || policy.IsForKubernetes()}, }, { UpgradeType: "spdy/3.1", - Enabled: &wrapperspb.BoolValue{Value: policy.AllowSPDY}, + Enabled: &wrapperspb.BoolValue{Value: policy.AllowSPDY || policy.IsForKubernetes()}, }, } diff --git a/config/envoyconfig/routes_test.go b/config/envoyconfig/routes_test.go index 9455e0f12..99131a385 100644 --- a/config/envoyconfig/routes_test.go +++ b/config/envoyconfig/routes_test.go @@ -15,6 +15,7 @@ import ( "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config/envoyconfig/filemgr" + "github.com/pomerium/pomerium/internal/httputil/reproxy" "github.com/pomerium/pomerium/internal/testutil" "github.com/pomerium/pomerium/pkg/cryptutil" ) @@ -302,7 +303,7 @@ func Test_buildPolicyRoutes(t *testing.T) { oneMinute := time.Minute ten := time.Second * 10 - b := &Builder{filemgr: filemgr.NewManager()} + b := &Builder{filemgr: filemgr.NewManager(), reproxy: reproxy.New()} routes, err := b.buildRoutesForPoliciesWithHost(&config.Config{Options: &config.Options{ CookieName: "pomerium", DefaultUpstreamTimeout: time.Second * 3, @@ -1302,6 +1303,117 @@ func Test_buildPolicyRoutes(t *testing.T) { ] `, routes) }) + + t.Run("kubernetes", func(t *testing.T) { + routes, err := b.buildRoutesForPoliciesWithHost(&config.Config{Options: &config.Options{ + AuthenticateURLString: "https://authenticate.example.com", + Services: "proxy", + CookieName: "pomerium", + SharedKey: cryptutil.NewBase64Key(), + Policies: []config.Policy{ + { + From: "https://k8s-in.example.com", + To: mustParseWeightedURLs(t, "https://k8s-out.example.com"), + KubernetesServiceAccountToken: "KUBERNETES_SERVICE_ACCOUNT_TOKEN", + }, + }, + }}, "k8s-in.example.com") + require.NoError(t, err) + + testutil.AssertProtoJSONEqual(t, ` + [ + { + "name": "policy-0", + "match": { + "prefix": "/" + }, + "metadata": { + "filterMetadata": { + "envoy.filters.http.lua": { + "remove_impersonate_headers": true, + "remove_pomerium_authorization": true, + "remove_pomerium_cookie": "pomerium", + "rewrite_response_headers": [] + } + } + }, + "route": { + "autoHostRewrite": true, + "cluster": "pomerium-control-plane-http", + "hashPolicy": [ + { + "header": { + "headerName": "x-pomerium-routing-key" + }, + "terminal": true + }, + { + "connectionProperties": { + "sourceIp": true + }, + "terminal": true + } + ], + "idleTimeout": "0s", + "timeout": "0s", + "upgradeConfigs": [ + { "enabled": true, "upgradeType": "websocket"}, + { "enabled": true, "upgradeType": "spdy/3.1"} + ] + }, + "requestHeadersToAdd": [ + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "x-pomerium-reproxy-policy", + "value": "2222095689633600553" + } + }, + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "x-pomerium-reproxy-policy-hmac", + "value": "/cH0S/ODZYaW4CALohG926c+TH22+/bD79Kb82k8/Eg=" + } + } + ], + "requestHeadersToRemove": [ + "x-pomerium-jwt-assertion", + "x-pomerium-jwt-assertion-for", + "x-pomerium-reproxy-policy", + "x-pomerium-reproxy-policy-hmac" + ], + "responseHeadersToAdd": [ + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + } + }, + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "X-XSS-Protection", + "value": "1; mode=block" + } + } + ], + "typedPerFilterConfig": { + "envoy.filters.http.ext_authz": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", + "checkSettings": { + "contextExtensions": { + "internal": "false", + "route_id": "2222095689633600553" + } + } + } + } + } + ] + `, routes) + }) } func Test_buildPolicyRoutesRewrite(t *testing.T) { diff --git a/internal/httputil/reproxy/reproxy.go b/internal/httputil/reproxy/reproxy.go index 4fba7c778..b2e696d75 100644 --- a/internal/httputil/reproxy/reproxy.go +++ b/internal/httputil/reproxy/reproxy.go @@ -116,7 +116,7 @@ func (h *Handler) Middleware(next http.Handler) http.Handler { // when SPDY is being used, disable HTTP/2 because the two can't be used together with the reverse proxy // Issue #2126 - disableHTTP2 := isSPDY(r) + disableHTTP2 := isSPDY(r) || isWebsocket(r) h := stdhttputil.NewSingleHostReverseProxy(&dst) h.ErrorLog = stdlog.New(log.Logger(), "", 0) @@ -147,3 +147,7 @@ func (h *Handler) Update(ctx context.Context, cfg *config.Config) { func isSPDY(r *http.Request) bool { return strings.HasPrefix(strings.ToLower(r.Header.Get(httputil.HeaderUpgrade)), "spdy/") } + +func isWebsocket(r *http.Request) bool { + return strings.HasPrefix(strings.ToLower(r.Header.Get(httputil.HeaderUpgrade)), "websocket/") +}