diff --git a/authorize/evaluator/evaluator.go b/authorize/evaluator/evaluator.go index 6d3d4d6e3..7a62a12e6 100644 --- a/authorize/evaluator/evaluator.go +++ b/authorize/evaluator/evaluator.go @@ -31,9 +31,10 @@ var notFoundOutput = &Result{ // 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. @@ -124,42 +125,48 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) ctx, span := trace.StartSpan(ctx, "authorize.Evaluator.Evaluate") defer span.End() - if req.Policy == nil { - return notFoundOutput, nil - } - - id, err := req.Policy.RouteID() - if err != nil { - return nil, fmt.Errorf("authorize: error computing policy route id: %w", err) - } - - policyEvaluator, ok := e.policyEvaluators[id] - if !ok { - return notFoundOutput, nil - } - - clientCA, err := e.getClientCA(req.Policy) - if err != nil { - return nil, err - } - - isValidClientCertificate, err := isValidClientCertificate(clientCA, req.HTTP.ClientCertificate) - if err != nil { - return nil, fmt.Errorf("authorize: error validating client certificate: %w", err) - } - eg, ectx := errgroup.WithContext(ctx) var policyOutput *PolicyResponse - eg.Go(func() error { + if req.IsInternal { var err error - policyOutput, err = policyEvaluator.Evaluate(ectx, &PolicyRequest{ - HTTP: req.HTTP, - Session: req.Session, - IsValidClientCertificate: isValidClientCertificate, + policyOutput, err = e.evaluateInternal(ctx, req) + if err != nil { + return nil, err + } + } else if req.Policy == nil { + return notFoundOutput, nil + } else { + id, err := req.Policy.RouteID() + if err != nil { + return nil, fmt.Errorf("authorize: error computing policy route id: %w", err) + } + + policyEvaluator, ok := e.policyEvaluators[id] + if !ok { + return notFoundOutput, nil + } + + clientCA, err := e.getClientCA(req.Policy) + if err != nil { + return nil, err + } + + isValidClientCertificate, err := isValidClientCertificate(clientCA, req.HTTP.ClientCertificate) + if err != nil { + return nil, fmt.Errorf("authorize: error validating client certificate: %w", err) + } + + eg.Go(func() error { + var err error + policyOutput, err = policyEvaluator.Evaluate(ectx, &PolicyRequest{ + HTTP: req.HTTP, + Session: req.Session, + IsValidClientCertificate: isValidClientCertificate, + }) + return err }) - return err - }) + } var headersOutput *HeadersResponse eg.Go(func() error { @@ -170,7 +177,7 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) return err }) - err = eg.Wait() + err := eg.Wait() if err != nil { return nil, err } @@ -186,6 +193,21 @@ func (e *Evaluator) Evaluate(ctx context.Context, req *Request) (*Result, error) 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/jwt" { + if req.Session.ID == "" { + return &PolicyResponse{ + Allow: NewRuleResult(false, criteria.ReasonUserUnauthenticated), + }, nil + } + } + + return &PolicyResponse{ + Allow: NewRuleResult(true, criteria.ReasonPomeriumRoute), + }, nil +} + func (e *Evaluator) getClientCA(policy *config.Policy) (string, error) { if policy != nil && policy.TLSDownstreamClientCA != "" { bs, err := base64.StdEncoding.DecodeString(policy.TLSDownstreamClientCA) diff --git a/authorize/evaluator/headers_evaluator.go b/authorize/evaluator/headers_evaluator.go index 42d5e5029..44fb1d013 100644 --- a/authorize/evaluator/headers_evaluator.go +++ b/authorize/evaluator/headers_evaluator.go @@ -31,18 +31,20 @@ type HeadersRequest struct { // NewHeadersRequestFromPolicy creates a new HeadersRequest from a policy. func NewHeadersRequestFromPolicy(policy *config.Policy) *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 - if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil { - input.FromAudience = u.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 + if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil { + input.FromAudience = u.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.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 return input } diff --git a/authorize/evaluator/policy_evaluator_test.go b/authorize/evaluator/policy_evaluator_test.go index f0d7e2c69..5f745287d 100644 --- a/authorize/evaluator/policy_evaluator_test.go +++ b/authorize/evaluator/policy_evaluator_test.go @@ -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) diff --git a/authorize/grpc.go b/authorize/grpc.go index d8c448bfe..fa66680a8 100644 --- a/authorize/grpc.go +++ b/authorize/grpc.go @@ -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" @@ -117,6 +118,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, @@ -183,6 +185,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 } diff --git a/config/envoyconfig/listeners.go b/config/envoyconfig/listeners.go index 567f45583..1e02d706d 100644 --- a/config/envoyconfig/listeners.go +++ b/config/envoyconfig/listeners.go @@ -386,6 +386,7 @@ func (b *Builder) buildMainHTTPConnectionManagerFilter( SkipXffAppend: options.SkipXffAppend, XffNumTrustedHops: options.XffNumTrustedHops, LocalReplyConfig: b.buildLocalReplyConfig(options, requireStrictTransportSecurity), + NormalizePath: wrapperspb.Bool(true), }), nil } diff --git a/config/envoyconfig/listeners_test.go b/config/envoyconfig/listeners_test.go index 8b3ae002c..e6696ff7c 100644 --- a/config/envoyconfig/listeners_test.go +++ b/config/envoyconfig/listeners_test.go @@ -215,6 +215,7 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) { } } ], + "normalizePath": true, "requestTimeout": "30s", "routeConfig": { "name": "main", @@ -244,15 +245,6 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) { } }], "routes": [ - { - "name": "pomerium-path-/.pomerium/jwt", - "match": { - "path": "/.pomerium/jwt" - }, - "route": { - "cluster": "pomerium-control-plane-http" - } - }, { "name": "pomerium-path-/ping", "match": { @@ -264,7 +256,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -279,7 +275,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -294,7 +294,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -309,7 +313,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -324,7 +332,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -339,7 +351,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -354,7 +370,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } } @@ -385,15 +405,6 @@ func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) { } }], "routes": [ - { - "name": "pomerium-path-/.pomerium/jwt", - "match": { - "path": "/.pomerium/jwt" - }, - "route": { - "cluster": "pomerium-control-plane-http" - } - }, { "name": "pomerium-path-/ping", "match": { @@ -405,7 +416,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -420,7 +435,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -435,7 +454,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -450,7 +473,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -465,7 +492,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -480,7 +511,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } }, @@ -495,7 +530,11 @@ func Test_buildMainHTTPConnectionManagerFilter(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" + } + } } } } diff --git a/config/envoyconfig/per_filter_config.go b/config/envoyconfig/per_filter_config.go new file mode 100644 index 000000000..7621f5928 --- /dev/null +++ b/config/envoyconfig/per_filter_config.go @@ -0,0 +1,43 @@ +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), + } +} + +// 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" +} diff --git a/config/envoyconfig/routes.go b/config/envoyconfig/routes.go index be702eb74..f95dbb02e 100644 --- a/config/envoyconfig/routes.go +++ b/config/envoyconfig/routes.go @@ -58,19 +58,16 @@ func (b *Builder) buildPomeriumHTTPRoutes(options *config.Options, domain string } if !isFrontingAuthenticate { routes = append(routes, - // enable ext_authz - b.buildControlPlanePathRoute("/.pomerium/jwt", true), - // disable ext_authz and passthrough to proxy handlers - b.buildControlPlanePathRoute("/ping", false), - b.buildControlPlanePathRoute("/healthz", false), - b.buildControlPlanePathRoute("/.pomerium", false), - b.buildControlPlanePrefixRoute("/.pomerium/", false), - b.buildControlPlanePathRoute("/.well-known/pomerium", false), - b.buildControlPlanePrefixRoute("/.well-known/pomerium/", false), + b.buildControlPlanePathRoute("/ping"), + b.buildControlPlanePathRoute("/healthz"), + b.buildControlPlanePathRoute("/.pomerium"), + b.buildControlPlanePrefixRoute("/.pomerium/"), + b.buildControlPlanePathRoute("/.well-known/pomerium"), + b.buildControlPlanePrefixRoute("/.well-known/pomerium/"), ) // per #837, only add robots.txt if there are no unauthenticated routes if !hasPublicPolicyMatchingURL(options, url.URL{Scheme: "https", Host: domain, Path: "/robots.txt"}) { - routes = append(routes, b.buildControlPlanePathRoute("/robots.txt", false)) + routes = append(routes, b.buildControlPlanePathRoute("/robots.txt")) } } // if we're handling authentication, add the oauth2 callback url @@ -80,8 +77,8 @@ func (b *Builder) buildPomeriumHTTPRoutes(options *config.Options, domain string } if config.IsAuthenticate(options.Services) && hostMatchesDomain(authenticateURL, domain) { routes = append(routes, - b.buildControlPlanePathRoute(options.AuthenticateCallbackPath, false), - b.buildControlPlanePathRoute("/", false), + b.buildControlPlanePathRoute(options.AuthenticateCallbackPath), + b.buildControlPlanePathRoute("/"), ) } // if we're the proxy and this is the forward-auth url @@ -164,7 +161,7 @@ func (b *Builder) buildControlPlanePathAndQueryRoute(path string, queryparams [] }, nil } -func (b *Builder) buildControlPlanePathRoute(path string, protected bool) *envoy_config_route_v3.Route { +func (b *Builder) buildControlPlanePathRoute(path string) *envoy_config_route_v3.Route { r := &envoy_config_route_v3.Route{ Name: "pomerium-path-" + path, Match: &envoy_config_route_v3.RouteMatch{ @@ -177,16 +174,14 @@ func (b *Builder) buildControlPlanePathRoute(path string, protected bool) *envoy }, }, }, - } - 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(prefix string, protected bool) *envoy_config_route_v3.Route { +func (b *Builder) buildControlPlanePrefixRoute(prefix string) *envoy_config_route_v3.Route { r := &envoy_config_route_v3.Route{ Name: "pomerium-prefix-" + prefix, Match: &envoy_config_route_v3.RouteMatch{ @@ -199,11 +194,9 @@ func (b *Builder) buildControlPlanePrefixRoute(prefix string, protected bool) *e }, }, }, - } - 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 } diff --git a/config/envoyconfig/routes_test.go b/config/envoyconfig/routes_test.go index 3830ac66e..a775f8c2b 100644 --- a/config/envoyconfig/routes_test.go +++ b/config/envoyconfig/routes_test.go @@ -54,28 +54,26 @@ 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 { - str := `{ + routeString := func(typ, name string) string { + return `{ "name": "pomerium-` + typ + `-` + name + `", "match": { "` + typ + `": "` + name + `" }, "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 + "envoy.filters.http.ext_authz": { + "@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute", + "checkSettings": { + "contextExtensions": { + "internal": "true" + } } } - ` - } - str += "}" - return str + } + }` } t.Run("authenticate", func(t *testing.T) { options := &config.Options{ @@ -88,16 +86,15 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", 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) { @@ -127,14 +124,13 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", 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) }) @@ -155,20 +151,19 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) { require.NoError(t, err) testutil.AssertProtoJSONEqual(t, `[ - `+routeString("path", "/.pomerium/jwt", 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) { b := &Builder{filemgr: filemgr.NewManager()} - route := b.buildControlPlanePathRoute("/hello/world", false) + route := b.buildControlPlanePathRoute("/hello/world") testutil.AssertProtoJSONEqual(t, ` { "name": "pomerium-path-/hello/world", @@ -181,7 +176,11 @@ 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" + } + } } } } @@ -190,7 +189,7 @@ func Test_buildControlPlanePathRoute(t *testing.T) { func Test_buildControlPlanePrefixRoute(t *testing.T) { b := &Builder{filemgr: filemgr.NewManager()} - route := b.buildControlPlanePrefixRoute("/hello/world/", false) + route := b.buildControlPlanePrefixRoute("/hello/world/") testutil.AssertProtoJSONEqual(t, ` { "name": "pomerium-prefix-/hello/world/", @@ -203,7 +202,11 @@ 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" + } + } } } } diff --git a/config/policy_ppl.go b/config/policy_ppl.go index 200019092..e791e626e 100644 --- a/config/policy_ppl.go +++ b/config/policy_ppl.go @@ -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{ diff --git a/config/policy_ppl_test.go b/config/policy_ppl_test.go index bea1cf4fe..0d47538c3 100644 --- a/config/policy_ppl_test.go +++ b/config/policy_ppl_test.go @@ -57,15 +57,6 @@ default allow = [false, set()] default deny = [false, set()] -pomerium_routes_0 = [true, {"pomerium-route"}] { - contains(input.http.url, "/.pomerium/") - not contains(input.http.url, "/.pomerium/jwt") -} - -else = [false, {"non-pomerium-route"}] { - true -} - accept_0 = [true, {"accept"}] cors_preflight_0 = [true, {"cors-request"}] { @@ -413,7 +404,7 @@ 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) } diff --git a/pkg/policy/criteria/pomerium_routes.go b/pkg/policy/criteria/pomerium_routes.go deleted file mode 100644 index 76b91d047..000000000 --- a/pkg/policy/criteria/pomerium_routes.go +++ /dev/null @@ -1,46 +0,0 @@ -package criteria - -import ( - "github.com/open-policy-agent/opa/ast" - - "github.com/pomerium/pomerium/pkg/policy/generator" - "github.com/pomerium/pomerium/pkg/policy/parser" -) - -var pomeriumRoutesBody = ast.Body{ - ast.MustParseExpr(` - contains(input.http.url, "/.pomerium/") - `), - ast.MustParseExpr(` - not contains(input.http.url, "/.pomerium/jwt") - `), -} - -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) { - rule := NewCriterionRule(c.g, c.Name(), - ReasonPomeriumRoute, ReasonNonPomeriumRoute, - pomeriumRoutesBody) - - return rule, nil, 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) -}