Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #6617 and #6659 #6661

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions apis/projectcontour/v1/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ func (v *VirtualHost) DisableAuthorization() bool {
return false
}

// IsConfigured returns whether service ref is configured
func (r *ExtensionServiceReference) IsConfigured() bool {
return r.Name != ""
}

// AuthorizationContext returns the authorization policy context (if present).
func (v *VirtualHost) AuthorizationContext() map[string]string {
if v.AuthorizationConfigured() {
Expand Down
7 changes: 7 additions & 0 deletions changelogs/unreleased/6661-SamMHD-minor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Disable ExtAuth by default if GlobalExtAuth.AuthPolicy.Disabled is set

Global external authorization or vhost-level authorization is enabled by default unless an AuthPolicy explicitly disables it. By default, `disabled` is set to `GlobalExtAuth.AuthPolicy.Disabled`. This global setting can be overridden by vhost-level AuthPolicy, which can further be overridden by route-specific AuthPolicy. Therefore, the final authorization state is determined by the most specific policy applied at the route level.
SamMHD marked this conversation as resolved.
Show resolved Hide resolved

## Disable External Authorization in UpgradeHTTPS

From now on, Contour will configure Envoy to handle HTTPS Redirection without authorization on routes. (previously if GlobalExtAuth was set, Envoy would check request with ext_auth before redirection which could result in 401 instead of redirection)
SamMHD marked this conversation as resolved.
Show resolved Hide resolved
25 changes: 20 additions & 5 deletions internal/dag/httpproxy_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,16 +852,31 @@ func (p *HTTPProxyProcessor) computeRoutes(
// enable it on the route and propagate defaults
// downwards.
if rootProxy.Spec.VirtualHost.AuthorizationConfigured() || p.GlobalExternalAuthorization != nil {
// Global external or vhost-level authorization is enabled by default
// unless an AuthPolicy explicitly disables it. By default, `disabled`
// is set to false, meaning authorization is active. This global setting
// can be overridden by vhost-level AuthPolicy, which can further be
// overridden by route-specific AuthPolicy.
// Therefore, the final authorization state is determined by the
// most specific policy applied at the route level.
disabled := false

if p.GlobalExternalAuthorization != nil && p.GlobalExternalAuthorization.AuthPolicy != nil {
disabled = p.GlobalExternalAuthorization.AuthPolicy.Disabled
}

// When the ext_authz filter is added to a
// vhost, it is in enabled state, but we can
// disable it per route. We emulate disabling
// it at the vhost layer by defaulting the state
// from the root proxy.
disabled := rootProxy.Spec.VirtualHost.DisableAuthorization()
if rootProxy.Spec.VirtualHost.AuthorizationConfigured() {
disabled = rootProxy.Spec.VirtualHost.DisableAuthorization()
}

// Take the default for enabling authorization
// from the virtual host. If this route has a
// policy, let that override.
// from the virtualhost/global-extauth. If this
// route has a policy, let that override.
if route.AuthPolicy != nil {
disabled = route.AuthPolicy.Disabled
}
Expand Down Expand Up @@ -1441,14 +1456,14 @@ func determineExternalAuthTimeout(responseTimeout string, validCond *contour_v1.
}

func (p *HTTPProxyProcessor) computeSecureVirtualHostAuthorization(validCond *contour_v1.DetailedCondition, httpproxy *contour_v1.HTTPProxy, svhost *SecureVirtualHost) bool {
if httpproxy.Spec.VirtualHost.AuthorizationConfigured() && !httpproxy.Spec.VirtualHost.DisableAuthorization() {
if httpproxy.Spec.VirtualHost.AuthorizationConfigured() && !httpproxy.Spec.VirtualHost.DisableAuthorization() && httpproxy.Spec.VirtualHost.Authorization.ExtensionServiceRef.IsConfigured() {
authorization := p.computeVirtualHostAuthorization(httpproxy.Spec.VirtualHost.Authorization, validCond, httpproxy)
if authorization == nil {
return false
}

svhost.ExternalAuthorization = authorization
} else if p.GlobalExternalAuthorization != nil && !httpproxy.Spec.VirtualHost.DisableAuthorization() {
} else if p.GlobalExternalAuthorization != nil {
globalAuthorization := p.computeVirtualHostAuthorization(p.GlobalExternalAuthorization, validCond, httpproxy)
if globalAuthorization == nil {
return false
Expand Down
21 changes: 19 additions & 2 deletions internal/envoy/v3/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,18 @@ func buildRoute(dagRoute *dag.Route, vhostName string, secure bool) *envoy_confi
// envoy.RouteRoute. Currently the DAG processor adds any HTTP->HTTPS
// redirect routes to *both* the insecure and secure vhosts.
route.Action = UpgradeHTTPS()

// Disable External Authorization it is being redirected to HTTPS route
route.TypedPerFilterConfig = map[string]*anypb.Any{}
route.TypedPerFilterConfig[ExtAuthzFilterName] = routeAuthzDisabled()
case dagRoute.DirectResponse != nil:
route.TypedPerFilterConfig = map[string]*anypb.Any{}

// Apply per-route authorization policy modifications.
if dagRoute.AuthDisabled {
route.TypedPerFilterConfig["envoy.filters.http.ext_authz"] = routeAuthzDisabled()
route.TypedPerFilterConfig[ExtAuthzFilterName] = routeAuthzDisabled()
} else if len(dagRoute.AuthContext) > 0 {
route.TypedPerFilterConfig["envoy.filters.http.ext_authz"] = routeAuthzContext(dagRoute.AuthContext)
route.TypedPerFilterConfig[ExtAuthzFilterName] = routeAuthzContext(dagRoute.AuthContext)
}

route.Action = routeDirectResponse(dagRoute.DirectResponse)
Expand Down Expand Up @@ -592,6 +596,19 @@ func UpgradeHTTPS() *envoy_config_route_v3.Route_Redirect {
}
}

// DisabledExtAuthConfig returns a route TypedPerFilterConfig that disables ExtAuth
func DisabledExtAuthConfig() map[string]*anypb.Any {
return map[string]*anypb.Any{
ExtAuthzFilterName: protobuf.MustMarshalAny(
&envoy_filter_http_ext_authz_v3.ExtAuthzPerRoute{
Override: &envoy_filter_http_ext_authz_v3.ExtAuthzPerRoute_Disabled{
Disabled: true,
},
},
),
}
}

// headerValueList creates a list of Envoy HeaderValueOptions from the provided map.
func headerValueList(hvm map[string]string, app bool) []*envoy_config_core_v3.HeaderValueOption {
var hvs []*envoy_config_core_v3.HeaderValueOption
Expand Down
40 changes: 19 additions & 21 deletions internal/featuretests/v3/authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,6 @@ func authzOverrideDisabled(t *testing.T, rh ResourceEventHandlerWrapper, c *Cont
// same authorization enablement as the root proxy, and
// the other path should have the opposite enablement.

disabledConfig := withFilterConfig(envoy_v3.ExtAuthzFilterName,
&envoy_filter_http_ext_authz_v3.ExtAuthzPerRoute{
Override: &envoy_filter_http_ext_authz_v3.ExtAuthzPerRoute_Disabled{
Disabled: true,
},
})

c.Request(routeType).Equals(&envoy_service_discovery_v3.DiscoveryResponse{
TypeUrl: routeType,
Resources: resources(t,
Expand All @@ -287,7 +280,7 @@ func authzOverrideDisabled(t *testing.T, rh ResourceEventHandlerWrapper, c *Cont
&envoy_config_route_v3.Route{
Match: routePrefix("/default"),
Action: routeCluster("default/app-server/80/da39a3ee5e"),
TypedPerFilterConfig: disabledConfig,
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
),
),
Expand All @@ -297,7 +290,7 @@ func authzOverrideDisabled(t *testing.T, rh ResourceEventHandlerWrapper, c *Cont
&envoy_config_route_v3.Route{
Match: routePrefix("/disabled"),
Action: routeCluster("default/app-server/80/da39a3ee5e"),
TypedPerFilterConfig: disabledConfig,
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
&envoy_config_route_v3.Route{
Match: routePrefix("/default"),
Expand All @@ -309,22 +302,26 @@ func authzOverrideDisabled(t *testing.T, rh ResourceEventHandlerWrapper, c *Cont
"ingress_http",
envoy_v3.VirtualHost(disabled,
&envoy_config_route_v3.Route{
Match: routePrefix("/enabled"),
Action: withRedirect(),
Match: routePrefix("/enabled"),
Action: withRedirect(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
&envoy_config_route_v3.Route{
Match: routePrefix("/default"),
Action: withRedirect(),
Match: routePrefix("/default"),
Action: withRedirect(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
),
envoy_v3.VirtualHost(enabled,
&envoy_config_route_v3.Route{
Match: routePrefix("/disabled"),
Action: withRedirect(),
Match: routePrefix("/disabled"),
Action: withRedirect(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
&envoy_config_route_v3.Route{
Match: routePrefix("/default"),
Action: withRedirect(),
Match: routePrefix("/default"),
Action: withRedirect(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
),
),
Expand Down Expand Up @@ -406,8 +403,9 @@ func authzMergeRouteContext(t *testing.T, rh ResourceEventHandlerWrapper, c *Con
"ingress_http",
envoy_v3.VirtualHost(fqdn,
&envoy_config_route_v3.Route{
Match: routePrefix("/"),
Action: withRedirect(),
Match: routePrefix("/"),
Action: withRedirect(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
},
),
),
Expand All @@ -433,8 +431,8 @@ func authzInvalidReference(t *testing.T, rh ResourceEventHandlerWrapper, c *Cont

invalid.Spec.VirtualHost.Authorization.ExtensionServiceRef = contour_v1.ExtensionServiceReference{
APIVersion: "foo/bar",
Namespace: "",
Name: "",
Namespace: "missing",
Name: "extension",
}

rh.OnDelete(invalid)
Expand Down
5 changes: 3 additions & 2 deletions internal/featuretests/v3/envoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ func routeHostRewriteHeader(cluster, hostnameHeader string) *envoy_config_route_

func upgradeHTTPS(match *envoy_config_route_v3.RouteMatch) *envoy_config_route_v3.Route {
return &envoy_config_route_v3.Route{
Match: match,
Action: envoy_v3.UpgradeHTTPS(),
Match: match,
Action: envoy_v3.UpgradeHTTPS(),
TypedPerFilterConfig: envoy_v3.DisabledExtAuthConfig(),
}
}

Expand Down
Loading