Critical severityNVD Advisory· Published May 30, 2023· Updated Jan 10, 2025
Incorrect Authorization with specially crafted requests
CVE-2023-33189
Description
Pomerium is an identity and context-aware access proxy. With specially crafted requests, incorrect authorization decisions may be made by Pomerium. This issue has been patched in versions 0.17.4, 0.18.1, 0.19.2, 0.20.1, 0.21.4 and 0.22.2.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/pomerium/pomeriumGo | >= 0.22.0, < 0.22.2 | 0.22.2 |
github.com/pomerium/pomeriumGo | >= 0.21.0, < 0.21.4 | 0.21.4 |
github.com/pomerium/pomeriumGo | >= 0.20.0, < 0.20.1 | 0.20.1 |
github.com/pomerium/pomeriumGo | >= 0.19.0, < 0.19.2 | 0.19.2 |
github.com/pomerium/pomeriumGo | >= 0.18.0, < 0.18.1 | 0.18.1 |
github.com/pomerium/pomeriumGo | < 0.17.4 | 0.17.4 |
Affected products
1Patches
1d315e683357aMerge pull request from GHSA-pvrc-wvj2-f59p
13 files changed · +501 −287
authorize/evaluator/evaluator.go+70 −39 modified@@ -22,17 +22,12 @@ import ( "github.com/pomerium/pomerium/pkg/policy/criteria" ) -// notFoundOutput is what's returned if a route isn't found for a policy. -var notFoundOutput = &Result{ - Deny: NewRuleResult(true, criteria.ReasonRouteNotFound), - Headers: make(http.Header), -} - // Request contains the inputs needed for evaluation. type Request struct { - Policy *config.Policy - HTTP RequestHTTP - Session RequestSession + IsInternal bool + Policy *config.Policy + HTTP RequestHTTP + Session RequestSession } // RequestHTTP is the HTTP field in the request. @@ -125,8 +120,60 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) ctx, span := trace.StartSpan(ctx, "authorize.Evaluator.Evaluate") defer span.End() + eg, ctx := errgroup.WithContext(ctx) + + var policyOutput *PolicyResponse + eg.Go(func() error { + var err error + if req.IsInternal { + policyOutput, err = e.evaluateInternal(ctx, req) + } else { + policyOutput, err = e.evaluatePolicy(ctx, req) + } + return err + }) + + var headersOutput *HeadersResponse + eg.Go(func() error { + var err error + headersOutput, err = e.evaluateHeaders(ctx, req) + return err + }) + + err := eg.Wait() + if err != nil { + return nil, err + } + + res := &Result{ + Allow: policyOutput.Allow, + Deny: policyOutput.Deny, + Headers: headersOutput.Headers, + Traces: policyOutput.Traces, + } + return res, nil +} + +func (e *Evaluator) evaluateInternal(_ context.Context, req *Request) (*PolicyResponse, error) { + // these endpoints require a logged-in user + if req.HTTP.Path == "/.pomerium/webauthn" || req.HTTP.Path == "/.pomerium/jwt" { + if req.Session.ID == "" { + return &PolicyResponse{ + Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated), + }, nil + } + } + + return &PolicyResponse{ + Allow: NewRuleResult(true, criteria.ReasonPomeriumRoute), + }, nil +} + +func (e *Evaluator) evaluatePolicy(ctx context.Context, req *Request) (*PolicyResponse, error) { if req.Policy == nil { - return notFoundOutput, nil + return &PolicyResponse{ + Deny: NewRuleResult(true, criteria.ReasonRouteNotFound), + }, nil } id, err := req.Policy.RouteID() @@ -136,7 +183,9 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) policyEvaluator, ok := e.policyEvaluators[id] if !ok { - return notFoundOutput, nil + return &PolicyResponse{ + Deny: NewRuleResult(true, criteria.ReasonRouteNotFound), + }, nil } clientCA, err := e.getClientCA(req.Policy) @@ -149,41 +198,23 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) return nil, fmt.Errorf("authorize: error validating client certificate: %w", err) } - eg, ectx := errgroup.WithContext(ctx) - - var policyOutput *PolicyResponse - eg.Go(func() error { - var err error - policyOutput, err = policyEvaluator.Evaluate(ectx, &PolicyRequest{ - HTTP: req.HTTP, - Session: req.Session, - IsValidClientCertificate: isValidClientCertificate, - }) - return err - }) - - var headersOutput *HeadersResponse - eg.Go(func() error { - headersReq := NewHeadersRequestFromPolicy(req.Policy, req.HTTP.Hostname) - headersReq.Session = req.Session - var err error - headersOutput, err = e.headersEvaluators.Evaluate(ectx, headersReq) - return err + return policyEvaluator.Evaluate(ctx, &PolicyRequest{ + HTTP: req.HTTP, + Session: req.Session, + IsValidClientCertificate: isValidClientCertificate, }) +} - err = eg.Wait() +func (e *Evaluator) evaluateHeaders(ctx context.Context, req *Request) (*HeadersResponse, error) { + headersReq := NewHeadersRequestFromPolicy(req.Policy, req.HTTP.Hostname) + headersReq.Session = req.Session + res, err := e.headersEvaluators.Evaluate(ctx, headersReq) if err != nil { return nil, err } - carryOverJWTAssertion(headersOutput.Headers, req.HTTP.Headers) + carryOverJWTAssertion(res.Headers, req.HTTP.Headers) - res := &Result{ - Allow: policyOutput.Allow, - Deny: policyOutput.Deny, - Headers: headersOutput.Headers, - Traces: policyOutput.Traces, - } return res, nil }
authorize/evaluator/headers_evaluator.go+11 −9 modified@@ -30,16 +30,18 @@ type HeadersRequest struct { // NewHeadersRequestFromPolicy creates a new HeadersRequest from a policy. func NewHeadersRequestFromPolicy(policy *config.Policy, hostname string) *HeadersRequest { input := new(HeadersRequest) - input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication - input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH || - policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV - input.Issuer = hostname - input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken - for _, wu := range policy.To { - input.ToAudience = "https://" + wu.URL.Hostname() + if policy != nil { + input.EnableGoogleCloudServerlessAuthentication = policy.EnableGoogleCloudServerlessAuthentication + input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH || + policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV + input.Issuer = hostname + input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken + for _, wu := range policy.To { + input.ToAudience = "https://" + wu.URL.Hostname() + } + input.PassAccessToken = policy.GetSetAuthorizationHeader() == configpb.Route_ACCESS_TOKEN + input.PassIDToken = policy.GetSetAuthorizationHeader() == configpb.Route_ID_TOKEN } - input.PassAccessToken = policy.GetSetAuthorizationHeader() == configpb.Route_ACCESS_TOKEN - input.PassIDToken = policy.GetSetAuthorizationHeader() == configpb.Route_ID_TOKEN return input }
authorize/evaluator/policy_evaluator_test.go+4 −4 modified@@ -111,7 +111,7 @@ func TestPolicyEvaluator(t *testing.T) { }) require.NoError(t, err) assert.Equal(t, &PolicyResponse{ - Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonNonPomeriumRoute, criteria.ReasonUserUnauthorized), + Allow: NewRuleResult(false, criteria.ReasonEmailUnauthorized, criteria.ReasonUserUnauthorized), Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired), Traces: []contextutil.PolicyEvaluationTrace{{}}, }, output) @@ -172,7 +172,7 @@ func TestPolicyEvaluator(t *testing.T) { }) require.NoError(t, err) assert.Equal(t, &PolicyResponse{ - Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute), + Allow: NewRuleResult(false), Deny: NewRuleResult(true, criteria.ReasonAccept), Traces: []contextutil.PolicyEvaluationTrace{{}, {ID: "p1", Deny: true}}, }, output) @@ -203,7 +203,7 @@ func TestPolicyEvaluator(t *testing.T) { }) require.NoError(t, err) assert.Equal(t, &PolicyResponse{ - Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute), + Allow: NewRuleResult(false), Deny: NewRuleResult(true, criteria.ReasonAccept, criteria.ReasonInvalidClientCertificate), Traces: []contextutil.PolicyEvaluationTrace{{Deny: true}, {ID: "p1", Deny: true}}, }, output) @@ -289,7 +289,7 @@ func TestPolicyEvaluator(t *testing.T) { }) require.NoError(t, err) assert.Equal(t, &PolicyResponse{ - Allow: NewRuleResult(false, criteria.ReasonNonPomeriumRoute, criteria.ReasonUserUnauthenticated), + Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated), Deny: NewRuleResult(false, criteria.ReasonValidClientCertificateOrNoneRequired), Traces: []contextutil.PolicyEvaluationTrace{{Allow: false}}, }, output)
authorize/grpc.go+7 −3 modified@@ -11,6 +11,7 @@ import ( "github.com/pomerium/pomerium/authorize/evaluator" "github.com/pomerium/pomerium/config" + "github.com/pomerium/pomerium/config/envoyconfig" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/sessions" "github.com/pomerium/pomerium/internal/telemetry/requestid" @@ -93,6 +94,7 @@ func (a *Authorize) getEvaluatorRequestFromCheckRequest( ) (*evaluator.Request, error) { requestURL := getCheckRequestURL(in) req := &evaluator.Request{ + IsInternal: envoyconfig.ExtAuthzContextExtensionsIsInternal(in.GetAttributes().GetContextExtensions()), HTTP: evaluator.NewRequestHTTP( in.GetAttributes().GetRequest().GetHttp().GetMethod(), requestURL, @@ -106,15 +108,16 @@ func (a *Authorize) getEvaluatorRequestFromCheckRequest( ID: sessionState.ID, } } - req.Policy = a.getMatchingPolicy(requestURL) + req.Policy = a.getMatchingPolicy(envoyconfig.ExtAuthzContextExtensionsRouteID(in.Attributes.GetContextExtensions())) return req, nil } -func (a *Authorize) getMatchingPolicy(requestURL url.URL) *config.Policy { +func (a *Authorize) getMatchingPolicy(routeID uint64) *config.Policy { options := a.currentOptions.Load() for _, p := range options.GetAllPolicies() { - if p.Matches(requestURL) { + id, _ := p.RouteID() + if id == routeID { return &p } } @@ -159,6 +162,7 @@ func getCheckRequestURL(req *envoy_service_auth_v3.CheckRequest) url.URL { path := h.GetPath() if idx := strings.Index(path, "?"); idx != -1 { u.RawPath, u.RawQuery = path[:idx], path[idx+1:] + u.RawQuery = u.Query().Encode() } else { u.RawPath = path }
config/envoyconfig/listeners.go+11 −23 modified@@ -13,11 +13,9 @@ import ( envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3" envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" - envoy_extensions_filters_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" envoy_http_connection_manager "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3" envoy_extensions_transport_sockets_tls_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3" envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3" - "github.com/golang/protobuf/ptypes/any" "github.com/golang/protobuf/ptypes/wrappers" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" @@ -32,27 +30,16 @@ import ( const listenerBufferLimit uint32 = 32 * 1024 -var ( - disableExtAuthz *any.Any - tlsParams = &envoy_extensions_transport_sockets_tls_v3.TlsParameters{ - CipherSuites: []string{ - "ECDHE-ECDSA-AES256-GCM-SHA384", - "ECDHE-RSA-AES256-GCM-SHA384", - "ECDHE-ECDSA-AES128-GCM-SHA256", - "ECDHE-RSA-AES128-GCM-SHA256", - "ECDHE-ECDSA-CHACHA20-POLY1305", - "ECDHE-RSA-CHACHA20-POLY1305", - }, - TlsMinimumProtocolVersion: envoy_extensions_transport_sockets_tls_v3.TlsParameters_TLSv1_2, - } -) - -func init() { - disableExtAuthz = marshalAny(&envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute{ - Override: &envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute_Disabled{ - Disabled: true, - }, - }) +var tlsParams = &envoy_extensions_transport_sockets_tls_v3.TlsParameters{ + CipherSuites: []string{ + "ECDHE-ECDSA-AES256-GCM-SHA384", + "ECDHE-RSA-AES256-GCM-SHA384", + "ECDHE-ECDSA-AES128-GCM-SHA256", + "ECDHE-RSA-AES128-GCM-SHA256", + "ECDHE-ECDSA-CHACHA20-POLY1305", + "ECDHE-RSA-CHACHA20-POLY1305", + }, + TlsMinimumProtocolVersion: envoy_extensions_transport_sockets_tls_v3.TlsParameters_TLSv1_2, } // BuildListeners builds envoy listeners from the given config. @@ -312,6 +299,7 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter( SkipXffAppend: cfg.Options.SkipXffAppend, XffNumTrustedHops: cfg.Options.XffNumTrustedHops, LocalReplyConfig: b.buildLocalReplyConfig(cfg.Options, false), + NormalizePath: wrapperspb.Bool(true), } if fullyStatic {
config/envoyconfig/per_filter_config.go+53 −0 added@@ -0,0 +1,53 @@ +package envoyconfig + +import ( + "strconv" + + envoy_extensions_filters_http_ext_authz_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3" + "github.com/golang/protobuf/ptypes/any" +) + +// PerFilterConfigExtAuthzName is the name of the ext authz filter to apply config to +const PerFilterConfigExtAuthzName = "envoy.filters.http.ext_authz" + +// PerFilterConfigExtAuthzContextExtensions returns a per-filter config for ext authz that disables ext-authz. +func PerFilterConfigExtAuthzContextExtensions(authzContextExtensions map[string]string) *any.Any { + return marshalAny(&envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute{ + Override: &envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute_CheckSettings{ + CheckSettings: &envoy_extensions_filters_http_ext_authz_v3.CheckSettings{ + ContextExtensions: authzContextExtensions, + }, + }, + }) +} + +// PerFilterConfigExtAuthzDisabled returns a per-filter config for ext authz that disables ext-authz. +func PerFilterConfigExtAuthzDisabled() *any.Any { + return marshalAny(&envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute{ + Override: &envoy_extensions_filters_http_ext_authz_v3.ExtAuthzPerRoute_Disabled{ + Disabled: true, + }, + }) +} + +// MakeExtAuthzContextExtensions makes the ext authz context extensions. +func MakeExtAuthzContextExtensions(internal bool, routeID uint64) map[string]string { + return map[string]string{ + "internal": strconv.FormatBool(internal), + "route_id": strconv.FormatUint(routeID, 10), + } +} + +// ExtAuthzContextExtensionsIsInternal returns true if the context extensions indicates the route is internal. +func ExtAuthzContextExtensionsIsInternal(extAuthzContextExtensions map[string]string) bool { + return extAuthzContextExtensions != nil && extAuthzContextExtensions["internal"] == "true" +} + +// ExtAuthzContextExtensionsRouteID returns the route id for the context extensions. +func ExtAuthzContextExtensionsRouteID(extAuthzContextExtensions map[string]string) uint64 { + if extAuthzContextExtensions == nil { + return 0 + } + routeID, _ := strconv.ParseUint(extAuthzContextExtensions["route_id"], 10, 64) + return routeID +}
config/envoyconfig/route_configurations_test.go+32 −11 modified@@ -26,6 +26,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { Policies: []config.Policy{ { From: "https://*.example.com", + To: mustParseWeightedURLs(t, "https://www.example.com"), }, }, }} @@ -40,15 +41,13 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { "name": "catch-all", "domains": ["*"], "routes": [ - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium/jwt", true, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium/webauthn", true, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/ping", false, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/healthz", false, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium", false, false))+`, - `+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.pomerium/", false, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.well-known/pomerium", false, false))+`, - `+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.well-known/pomerium/", false, false))+`, - `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/robots.txt", false, false))+`, + `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/ping", false))+`, + `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/healthz", false))+`, + `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.pomerium", false))+`, + `+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.pomerium/", false))+`, + `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/.well-known/pomerium", false))+`, + `+protojson.Format(b.buildControlPlanePrefixRoute(cfg.Options, "/.well-known/pomerium/", false))+`, + `+protojson.Format(b.buildControlPlanePathRoute(cfg.Options, "/robots.txt", false))+`, { "name": "policy-0", "match": { @@ -79,7 +78,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { ], "route": { "autoHostRewrite": true, - "cluster": "route-0", + "cluster": "route-5feb9fe8bd89aa97", "hashPolicy": [ { "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true }, { "connectionProperties": { "sourceIp": true }, "terminal": true } @@ -89,6 +88,17 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { { "enabled": false, "upgradeType": "websocket" }, { "enabled": false, "upgradeType": "spdy/3.1" } ] + }, + "typedPerFilterConfig": { + "envoy.filters.http.ext_authz": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", + "checkSettings": { + "contextExtensions": { + "internal": "false", + "route_id": "6911793875091303063" + } + } + } } }, { @@ -121,7 +131,7 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { ], "route": { "autoHostRewrite": true, - "cluster": "route-0", + "cluster": "route-5feb9fe8bd89aa97", "hashPolicy": [ { "header": { "headerName": "x-pomerium-routing-key" }, "terminal": true }, { "connectionProperties": { "sourceIp": true }, "terminal": true } @@ -131,6 +141,17 @@ func TestBuilder_buildMainRouteConfiguration(t *testing.T) { { "enabled": false, "upgradeType": "websocket" }, { "enabled": false, "upgradeType": "spdy/3.1" } ] + }, + "typedPerFilterConfig": { + "envoy.filters.http.ext_authz": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", + "checkSettings": { + "contextExtensions": { + "internal": "false", + "route_id": "6911793875091303063" + } + } + } } } ]
config/envoyconfig/routes.go+26 −29 modified@@ -45,7 +45,7 @@ func (b *Builder) buildGRPCRoutes() ([]*envoy_config_route_v3.Route, error) { }, Action: action, TypedPerFilterConfig: map[string]*any.Any{ - "envoy.filters.http.ext_authz": disableExtAuthz, + PerFilterConfigExtAuthzName: PerFilterConfigExtAuthzDisabled(), }, }}, nil } @@ -65,20 +65,16 @@ func (b *Builder) buildPomeriumHTTPRoutes( } if !isFrontingAuthenticate { routes = append(routes, - // enable ext_authz - b.buildControlPlanePathRoute(options, "/.pomerium/jwt", true, requireStrictTransportSecurity), - b.buildControlPlanePathRoute(options, urlutil.WebAuthnURLPath, true, requireStrictTransportSecurity), - // disable ext_authz and passthrough to proxy handlers - b.buildControlPlanePathRoute(options, "/ping", false, requireStrictTransportSecurity), - b.buildControlPlanePathRoute(options, "/healthz", false, requireStrictTransportSecurity), - b.buildControlPlanePathRoute(options, "/.pomerium", false, requireStrictTransportSecurity), - b.buildControlPlanePrefixRoute(options, "/.pomerium/", false, requireStrictTransportSecurity), - b.buildControlPlanePathRoute(options, "/.well-known/pomerium", false, requireStrictTransportSecurity), - b.buildControlPlanePrefixRoute(options, "/.well-known/pomerium/", false, requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, "/ping", requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, "/healthz", requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, "/.pomerium", requireStrictTransportSecurity), + b.buildControlPlanePrefixRoute(options, "/.pomerium/", requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, "/.well-known/pomerium", requireStrictTransportSecurity), + b.buildControlPlanePrefixRoute(options, "/.well-known/pomerium/", requireStrictTransportSecurity), ) // per #837, only add robots.txt if there are no unauthenticated routes if !hasPublicPolicyMatchingURL(options, url.URL{Scheme: "https", Host: host, Path: "/robots.txt"}) { - routes = append(routes, b.buildControlPlanePathRoute(options, "/robots.txt", false, requireStrictTransportSecurity)) + routes = append(routes, b.buildControlPlanePathRoute(options, "/robots.txt", requireStrictTransportSecurity)) } } @@ -109,8 +105,8 @@ func (b *Builder) buildPomeriumAuthenticateHTTPRoutes( } if urlMatchesHost(u, host) { return []*envoy_config_route_v3.Route{ - b.buildControlPlanePathRoute(options, options.AuthenticateCallbackPath, false, requireStrictTransportSecurity), - b.buildControlPlanePathRoute(options, "/", false, requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, options.AuthenticateCallbackPath, requireStrictTransportSecurity), + b.buildControlPlanePathRoute(options, "/", requireStrictTransportSecurity), }, nil } } @@ -120,7 +116,6 @@ func (b *Builder) buildPomeriumAuthenticateHTTPRoutes( func (b *Builder) buildControlPlanePathRoute( options *config.Options, path string, - protected bool, requireStrictTransportSecurity bool, ) *envoy_config_route_v3.Route { r := &envoy_config_route_v3.Route{ @@ -136,19 +131,16 @@ func (b *Builder) buildControlPlanePathRoute( }, }, ResponseHeadersToAdd: toEnvoyHeaders(options.GetSetResponseHeaders(requireStrictTransportSecurity)), - } - if !protected { - r.TypedPerFilterConfig = map[string]*any.Any{ - "envoy.filters.http.ext_authz": disableExtAuthz, - } + TypedPerFilterConfig: map[string]*any.Any{ + PerFilterConfigExtAuthzName: PerFilterConfigExtAuthzContextExtensions(MakeExtAuthzContextExtensions(true, 0)), + }, } return r } func (b *Builder) buildControlPlanePrefixRoute( options *config.Options, prefix string, - protected bool, requireStrictTransportSecurity bool, ) *envoy_config_route_v3.Route { r := &envoy_config_route_v3.Route{ @@ -164,11 +156,9 @@ func (b *Builder) buildControlPlanePrefixRoute( }, }, ResponseHeadersToAdd: toEnvoyHeaders(options.GetSetResponseHeaders(requireStrictTransportSecurity)), - } - if !protected { - r.TypedPerFilterConfig = map[string]*any.Any{ - "envoy.filters.http.ext_authz": disableExtAuthz, - } + TypedPerFilterConfig: map[string]*any.Any{ + PerFilterConfigExtAuthzName: PerFilterConfigExtAuthzContextExtensions(MakeExtAuthzContextExtensions(true, 0)), + }, } return r } @@ -288,6 +278,11 @@ func (b *Builder) buildRouteForPolicyAndMatch( return nil, err } + routeID, err := policy.RouteID() + if err != nil { + return nil, err + } + requireStrictTransportSecurity := cryptutil.HasCertificateForServerName(certs, fromURL.Hostname()) route := &envoy_config_route_v3.Route{ @@ -323,9 +318,12 @@ func (b *Builder) buildRouteForPolicyAndMatch( } if isFrontingAuthenticate { route.TypedPerFilterConfig = map[string]*any.Any{ - "envoy.filters.http.ext_authz": disableExtAuthz, + PerFilterConfigExtAuthzName: PerFilterConfigExtAuthzDisabled(), } } else { + route.TypedPerFilterConfig = map[string]*any.Any{ + PerFilterConfigExtAuthzName: PerFilterConfigExtAuthzContextExtensions(MakeExtAuthzContextExtensions(false, routeID)), + } luaMetadata["remove_pomerium_cookie"] = &structpb.Value{ Kind: &structpb.Value_StringValue{ StringValue: cfg.Options.CookieName, @@ -344,8 +342,7 @@ func (b *Builder) buildRouteForPolicyAndMatch( } if policy.IsForKubernetes() { - policyID, _ := policy.RouteID() - for _, hdr := range b.reproxy.GetPolicyIDHeaders(policyID) { + for _, hdr := range b.reproxy.GetPolicyIDHeaders(routeID) { route.RequestHeadersToAdd = append(route.RequestHeadersToAdd, &envoy_config_core_v3.HeaderValueOption{ Header: &envoy_config_core_v3.HeaderValue{
config/envoyconfig/routes_test.go+285 −81 modified@@ -16,7 +16,6 @@ import ( "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config/envoyconfig/filemgr" "github.com/pomerium/pomerium/internal/testutil" - "github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/pkg/cryptutil" ) @@ -56,43 +55,43 @@ func Test_buildGRPCRoutes(t *testing.T) { func Test_buildPomeriumHTTPRoutes(t *testing.T) { b := &Builder{filemgr: filemgr.NewManager()} - routeString := func(typ, name string, protected bool) string { + routeString := func(typ, name string) string { str := `{ - "name": "pomerium-` + typ + `-` + name + `", - "match": { - "` + typ + `": "` + name + `" + "name": "pomerium-` + typ + `-` + name + `", + "match": { + "` + typ + `": "` + name + `" + }, + "responseHeadersToAdd": [ + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + } }, - "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" - } + { + "appendAction": "OVERWRITE_IF_EXISTS_OR_ADD", + "header": { + "key": "X-XSS-Protection", + "value": "1; mode=block" } - ], - "route": { - "cluster": "pomerium-control-plane-http" } - ` - if !protected { - str += `, - "typedPerFilterConfig": { - "envoy.filters.http.ext_authz": { - "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", - "disabled": true + ], + "route": { + "cluster": "pomerium-control-plane-http" + }, + "typedPerFilterConfig": { + "envoy.filters.http.ext_authz": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", + "checkSettings": { + "contextExtensions": { + "internal": "true", + "route_id": "0" + } } } - ` - } - str += "}" + } + }` return str } t.Run("authenticate", func(t *testing.T) { @@ -105,17 +104,15 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", true)+`, - `+routeString("path", urlutil.WebAuthnURLPath, true)+`, - `+routeString("path", "/ping", false)+`, - `+routeString("path", "/healthz", false)+`, - `+routeString("path", "/.pomerium", false)+`, - `+routeString("prefix", "/.pomerium/", false)+`, - `+routeString("path", "/.well-known/pomerium", false)+`, - `+routeString("prefix", "/.well-known/pomerium/", false)+`, - `+routeString("path", "/robots.txt", false)+`, - `+routeString("path", "/oauth2/callback", false)+`, - `+routeString("path", "/", false)+` + `+routeString("path", "/ping")+`, + `+routeString("path", "/healthz")+`, + `+routeString("path", "/.pomerium")+`, + `+routeString("prefix", "/.pomerium/")+`, + `+routeString("path", "/.well-known/pomerium")+`, + `+routeString("prefix", "/.well-known/pomerium/")+`, + `+routeString("path", "/robots.txt")+`, + `+routeString("path", "/oauth2/callback")+`, + `+routeString("path", "/")+` ]`, routes) }) t.Run("proxy fronting authenticate", func(t *testing.T) { @@ -144,15 +141,13 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", true)+`, - `+routeString("path", urlutil.WebAuthnURLPath, true)+`, - `+routeString("path", "/ping", false)+`, - `+routeString("path", "/healthz", false)+`, - `+routeString("path", "/.pomerium", false)+`, - `+routeString("prefix", "/.pomerium/", false)+`, - `+routeString("path", "/.well-known/pomerium", false)+`, - `+routeString("prefix", "/.well-known/pomerium/", false)+`, - `+routeString("path", "/robots.txt", false)+` + `+routeString("path", "/ping")+`, + `+routeString("path", "/healthz")+`, + `+routeString("path", "/.pomerium")+`, + `+routeString("prefix", "/.pomerium/")+`, + `+routeString("path", "/.well-known/pomerium")+`, + `+routeString("prefix", "/.well-known/pomerium/")+`, + `+routeString("path", "/robots.txt")+` ]`, routes) }) @@ -172,22 +167,20 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", true)+`, - `+routeString("path", urlutil.WebAuthnURLPath, true)+`, - `+routeString("path", "/ping", false)+`, - `+routeString("path", "/healthz", false)+`, - `+routeString("path", "/.pomerium", false)+`, - `+routeString("prefix", "/.pomerium/", false)+`, - `+routeString("path", "/.well-known/pomerium", false)+`, - `+routeString("prefix", "/.well-known/pomerium/", false)+` + `+routeString("path", "/ping")+`, + `+routeString("path", "/healthz")+`, + `+routeString("path", "/.pomerium")+`, + `+routeString("prefix", "/.pomerium/")+`, + `+routeString("path", "/.well-known/pomerium")+`, + `+routeString("prefix", "/.well-known/pomerium/")+` ]`, routes) }) } func Test_buildControlPlanePathRoute(t *testing.T) { options := config.NewDefaultOptions() b := &Builder{filemgr: filemgr.NewManager()} - route := b.buildControlPlanePathRoute(options, "/hello/world", false, false) + route := b.buildControlPlanePathRoute(options, "/hello/world", false) testutil.AssertProtoJSONEqual(t, ` { "name": "pomerium-path-/hello/world", @@ -216,7 +209,12 @@ func Test_buildControlPlanePathRoute(t *testing.T) { "typedPerFilterConfig": { "envoy.filters.http.ext_authz": { "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", - "disabled": true + "checkSettings": { + "contextExtensions": { + "internal": "true", + "route_id": "0" + } + } } } } @@ -226,7 +224,7 @@ func Test_buildControlPlanePathRoute(t *testing.T) { func Test_buildControlPlanePrefixRoute(t *testing.T) { options := config.NewDefaultOptions() b := &Builder{filemgr: filemgr.NewManager()} - route := b.buildControlPlanePrefixRoute(options, "/hello/world/", false, false) + route := b.buildControlPlanePrefixRoute(options, "/hello/world/", false) testutil.AssertProtoJSONEqual(t, ` { "name": "pomerium-prefix-/hello/world/", @@ -255,7 +253,12 @@ func Test_buildControlPlanePrefixRoute(t *testing.T) { "typedPerFilterConfig": { "envoy.filters.http.ext_authz": { "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", - "disabled": true + "checkSettings": { + "contextExtensions": { + "internal": "true", + "route_id": "0" + } + } } } } @@ -301,6 +304,7 @@ func TestTimeouts(t *testing.T) { Policies: []config.Policy{ { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Path: "/test", UpstreamTimeout: getDuration(tc.upstream), IdleTimeout: getDuration(tc.idle), @@ -356,47 +360,55 @@ func Test_buildPolicyRoutes(t *testing.T) { Policies: []config.Policy{ { From: "https://ignore.example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Path: "/some/path", AllowWebsockets: true, PreserveHostHeader: true, PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Prefix: "/some/prefix/", SetRequestHeaders: map[string]string{"HEADER-KEY": "HEADER-VALUE"}, UpstreamTimeout: &oneMinute, PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Regex: `^/[a]+$`, PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Prefix: "/some/prefix/", RemoveRequestHeaders: []string{"HEADER-KEY"}, UpstreamTimeout: &oneMinute, PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Path: "/some/path", AllowSPDY: true, PreserveHostHeader: true, PassIdentityHeaders: true, }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Path: "/some/path", AllowSPDY: true, AllowWebsockets: true, @@ -405,6 +417,7 @@ func Test_buildPolicyRoutes(t *testing.T) { }, { From: "https://example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), Path: "/websocket-timeout", AllowWebsockets: true, PreserveHostHeader: true, @@ -474,7 +487,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "11444765232398592404" + } + } + } + } }, { "name": "policy-2", @@ -534,7 +558,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2990091139764155677" + } + } + } + } }, { "name": "policy-3", @@ -600,7 +635,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2544588842279234006" + } + } + } + } }, { "name": "policy-4", @@ -661,7 +707,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "10244970664102670752" + } + } + } + } }, { "name": "policy-5", @@ -721,7 +778,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2544588842279234006" + } + } + } + } }, { "name": "policy-6", @@ -780,7 +848,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2990091139764155677" + } + } + } + } }, { "name": "policy-7", @@ -840,7 +919,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2990091139764155677" + } + } + } + } }, { "name": "policy-8", @@ -900,7 +990,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "1052418080698022187" + } + } + } + } } ] `, routes) @@ -915,6 +1016,7 @@ func Test_buildPolicyRoutes(t *testing.T) { Policies: []config.Policy{ { From: "https://authenticate.example.com", + To: mustParseWeightedURLs(t, "https://authenticate.internal"), PassIdentityHeaders: true, }, }, @@ -997,10 +1099,12 @@ func Test_buildPolicyRoutes(t *testing.T) { Policies: []config.Policy{ { From: "tcp+https://example.com:22", + To: mustParseWeightedURLs(t, "https://to.example.com"), PassIdentityHeaders: true, }, { From: "tcp+https://example.com:22", + To: mustParseWeightedURLs(t, "https://to.example.com"), PassIdentityHeaders: true, UpstreamTimeout: &ten, }, @@ -1069,7 +1173,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2226589900561460978" + } + } + } + } }, { "name": "policy-1", @@ -1130,7 +1245,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "2226589900561460978" + } + } + } + } } ] `, routes) @@ -1149,6 +1275,7 @@ func Test_buildPolicyRoutes(t *testing.T) { Policies: []config.Policy{ { From: "https://from.example.com", + To: mustParseWeightedURLs(t, "https://to.example.com"), }, }, }}, nil, "from.example.com") @@ -1216,7 +1343,18 @@ func Test_buildPolicyRoutes(t *testing.T) { "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": "15508081512033148378" + } + } + } + } } ] `, routes) @@ -1335,7 +1473,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } }, { "name": "policy-1", @@ -1395,7 +1544,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } }, { "name": "policy-2", @@ -1460,7 +1620,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } }, { "name": "policy-3", @@ -1520,7 +1691,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } }, { "name": "policy-4", @@ -1580,7 +1762,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } }, { "name": "policy-5", @@ -1645,7 +1838,18 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) { "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": "285016060542193864" + } + } + } + } } ] `, routes)
config/envoyconfig/testdata/main_http_connection_manager_filter.json+1 −0 modified@@ -120,6 +120,7 @@ ] }, "requestTimeout": "30s", + "normalizePath": true, "rds": { "configSource": { "ads": {},
config/policy_ppl.go+0 −4 modified@@ -13,10 +13,6 @@ func (p *Policy) ToPPL() *parser.Policy { ppl := &parser.Policy{} allowRule := parser.Rule{Action: parser.ActionAllow} - allowRule.Or = append(allowRule.Or, - parser.Criterion{ - Name: "pomerium_routes", - }) if p.AllowPublicUnauthenticatedAccess { allowRule.Or = append(allowRule.Or, parser.Criterion{
config/policy_ppl_test.go+1 −19 modified@@ -57,24 +57,6 @@ default allow = [false, set()] default deny = [false, set()] -pomerium_routes_0 = [true, {"pomerium-route"}] { - session := get_session(input.session.id) - session.id != "" - contains(input.http.url, "/.pomerium/") -} - -else = [true, {"pomerium-route"}] { - contains(input.http.url, "/.pomerium/") - not contains(input.http.url, "/.pomerium/jwt") - not contains(input.http.url, "/.pomerium/webauthn") -} - -else = [false, {"user-unauthenticated"}] { - contains(input.http.url, "/.pomerium/") -} - -else = [false, {"non-pomerium-route"}] - accept_0 = [true, {"accept"}] cors_preflight_0 = [true, {"cors-request"}] { @@ -380,7 +362,7 @@ else = [false, {"email-unauthorized"}] { else = [false, {"user-unauthenticated"}] or_0 = v { - results := [pomerium_routes_0, accept_0, cors_preflight_0, authenticated_user_0, domain_0, domain_1, domain_2, domain_3, domain_4, claim_0, claim_1, claim_2, claim_3, user_0, email_0, user_1, email_1, user_2, email_2, user_3, email_3, user_4, email_4] + results := [accept_0, cors_preflight_0, authenticated_user_0, domain_0, domain_1, domain_2, domain_3, domain_4, claim_0, claim_1, claim_2, claim_3, user_0, email_0, user_1, email_1, user_2, email_2, user_3, email_3, user_4, email_4] normalized := [normalize_criterion_result(x) | x := results[i]] v := merge_with_or(normalized) }
pkg/policy/criteria/pomerium_routes.go+0 −65 removed@@ -1,65 +0,0 @@ -package criteria - -import ( - "github.com/open-policy-agent/opa/ast" - - "github.com/pomerium/pomerium/internal/urlutil" - "github.com/pomerium/pomerium/pkg/policy/generator" - "github.com/pomerium/pomerium/pkg/policy/parser" - "github.com/pomerium/pomerium/pkg/policy/rules" -) - -type pomeriumRoutesCriterion struct { - g *Generator -} - -func (pomeriumRoutesCriterion) DataType() generator.CriterionDataType { - return generator.CriterionDataTypeUnused -} - -func (pomeriumRoutesCriterion) Name() string { - return "pomerium_routes" -} - -func (c pomeriumRoutesCriterion) GenerateRule(_ string, _ parser.Value) (*ast.Rule, []*ast.Rule, error) { - r1 := c.g.NewRule(c.Name()) - r1.Head.Value = NewCriterionTerm(true, ReasonPomeriumRoute) - r1.Body = ast.Body{ - ast.MustParseExpr(`session := get_session(input.session.id)`), - ast.MustParseExpr(`session.id != ""`), - ast.MustParseExpr(`contains(input.http.url, "/.pomerium/")`), - } - - r2 := c.g.NewRule(c.Name()) - r2.Head.Value = NewCriterionTerm(true, ReasonPomeriumRoute) - r2.Body = ast.Body{ - ast.MustParseExpr(`contains(input.http.url, "/.pomerium/")`), - ast.MustParseExpr(`not contains(input.http.url, "/.pomerium/jwt")`), - ast.MustParseExpr(`not contains(input.http.url, "` + urlutil.WebAuthnURLPath + `")`), - } - r1.Else = r2 - - r3 := c.g.NewRule(c.Name()) - r3.Head.Value = NewCriterionTerm(false, ReasonUserUnauthenticated) - r3.Body = ast.Body{ - ast.MustParseExpr(`contains(input.http.url, "/.pomerium/")`), - } - r2.Else = r3 - - r4 := c.g.NewRule(c.Name()) - r4.Head.Value = NewCriterionTerm(false, ReasonNonPomeriumRoute) - r3.Else = r4 - - return r1, []*ast.Rule{ - rules.GetSession(), - }, nil -} - -// PomeriumRoutes returns a Criterion on that allows access to pomerium routes. -func PomeriumRoutes(generator *Generator) Criterion { - return pomeriumRoutesCriterion{g: generator} -} - -func init() { - Register(PomeriumRoutes) -}
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-pvrc-wvj2-f59pghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-33189ghsaADVISORY
- github.com/pomerium/pomerium/commit/d315e683357a9b587ba9ef399a8813bcc52fdebbghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.17.4ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.18.1ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.19.2ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.20.1ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.21.4ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/releases/tag/v0.22.2ghsax_refsource_MISCWEB
- github.com/pomerium/pomerium/security/advisories/GHSA-pvrc-wvj2-f59pghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.