Skip to content

Commit

Permalink
contour: adds global auth support to fallback certificates \n When us…
Browse files Browse the repository at this point in the history
…ing Fallback certificates, the global auth was previously ignored. This is needed when using IP routing with no SNI. \n Fixes projectcontour#6512

Signed-off-by: Erik Flores <[email protected]>
  • Loading branch information
Erik Flores committed Jul 25, 2024
1 parent 260151f commit 22c99fe
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions changelogs/unreleased/6558-eflores-minor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Fallback Certificate: Add Global Ext Auth support

Applies Global Auth filters to Fallback certificate
28 changes: 28 additions & 0 deletions internal/featuretests/v3/envoy.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,34 @@ func filterchaintlsfallback(fallbackSecret *core_v1.Secret, peerValidationContex
)
}

// filterchaintlsfallbackauthz does same thing as filterchaintlsfallback but inserts a
// `ext_authz` filter with the specified configuration into the filter chain.
func filterchaintlsfallbackauthz(fallbackSecret *core_v1.Secret, authz *envoy_filter_http_ext_authz_v3.ExtAuthz, peerValidationContext *dag.PeerValidationContext, alpn ...string) *envoy_config_listener_v3.FilterChain {
return envoy_v3.FilterChainTLSFallback(
envoy_v3.DownstreamTLSContext(
&dag.Secret{Object: fallbackSecret},
envoy_transport_socket_tls_v3.TlsParameters_TLSv1_2,
envoy_transport_socket_tls_v3.TlsParameters_TLSv1_3,
nil,
peerValidationContext,
alpn...),
envoy_v3.Filters(
envoy_v3.HTTPConnectionManagerBuilder().
DefaultFilters().
AddFilter(&envoy_filter_network_http_connection_manager_v3.HttpFilter{
Name: envoy_v3.ExtAuthzFilterName,
ConfigType: &envoy_filter_network_http_connection_manager_v3.HttpFilter_TypedConfig{
TypedConfig: protobuf.MustMarshalAny(authz),
},
}).
RouteConfigName(xdscache_v3.ENVOY_FALLBACK_ROUTECONFIG).
MetricsPrefix(xdscache_v3.ENVOY_HTTPS_LISTENER).
AccessLoggers(envoy_v3.FileAccessLogEnvoy("/dev/stdout", "", nil, contour_v1alpha1.LogLevelInfo)).
Get(),
),
)
}

func httpsFilterFor(vhost string) *envoy_config_listener_v3.Filter {
return envoy_v3.HTTPConnectionManagerBuilder().
AddFilter(envoy_v3.FilterMisdirectedRequests(vhost)).
Expand Down
100 changes: 100 additions & 0 deletions internal/featuretests/v3/global_authorization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package v3

import (
"k8s.io/apimachinery/pkg/types"
"testing"

envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
Expand Down Expand Up @@ -470,6 +471,99 @@ func globalExternalAuthorizationWithTLSAuthOverride(t *testing.T, rh ResourceEve
}).Status(p).IsValid()
}

func globalExternalAuthorizationFilterTLSWithFallbackCertificate(t *testing.T, rh ResourceEventHandlerWrapper, c *Contour) {
p := fixture.NewProxy("TLSProxy").
WithFQDN("foo.com").
WithSpec(contour_v1.HTTPProxySpec{
VirtualHost: &contour_v1.VirtualHost{
Fqdn: "foo.com",
TLS: &contour_v1.TLS{
SecretName: "certificate",
EnableFallbackCertificate: true,
},
},
Routes: []contour_v1.Route{
{
Services: []contour_v1.Service{
{
Name: "s1",
Port: 80,
},
},
},
},
})

rh.OnAdd(p)

// Add Fallback Certificate Secret
fallbackSecret := featuretests.TLSSecret(t, "admin/fallbacksecret", &featuretests.ServerCertificate)
rh.OnAdd(fallbackSecret)

// Add Fallback Cert Delegation
certDelegationAll := &contour_v1.TLSCertificateDelegation{
ObjectMeta: meta_v1.ObjectMeta{
Name: "fallbackcertdelegation",
Namespace: "admin",
},
Spec: contour_v1.TLSCertificateDelegationSpec{
Delegations: []contour_v1.CertificateDelegation{{
SecretName: "fallbacksecret",
TargetNamespaces: []string{"*"},
}},
},
}

rh.OnAdd(certDelegationAll)

httpListener := defaultHTTPListener()
httpListener.FilterChains = envoy_v3.FilterChains(getGlobalExtAuthHCM())

httpsListener := &envoy_config_listener_v3.Listener{
Name: "ingress_https",
Address: envoy_v3.SocketAddress("0.0.0.0", 8443),
ListenerFilters: envoy_v3.ListenerFilters(
envoy_v3.TLSInspector(),
),
FilterChains: []*envoy_config_listener_v3.FilterChain{
filterchaintls("foo.com",
featuretests.TLSSecret(t, "certificate", &featuretests.ServerCertificate),
authzFilterFor(
"foo.com",
&envoy_filter_http_ext_authz_v3.ExtAuthz{
Services: grpcCluster("extension/auth/extension"),
ClearRouteCache: true,
IncludePeerCertificate: true,
StatusOnError: &envoy_type_v3.HttpStatus{
Code: envoy_type_v3.StatusCode_Forbidden,
},
TransportApiVersion: envoy_config_core_v3.ApiVersion_V3,
},
),
nil, "h2", "http/1.1"),
filterchaintlsfallbackauthz(fallbackSecret,
&envoy_filter_http_ext_authz_v3.ExtAuthz{
Services: grpcCluster("extension/auth/extension"),
ClearRouteCache: true,
IncludePeerCertificate: true,
StatusOnError: &envoy_type_v3.HttpStatus{
Code: envoy_type_v3.StatusCode_Forbidden,
},
TransportApiVersion: envoy_config_core_v3.ApiVersion_V3,
}, nil, "h2", "http/1.1"),
},
SocketOptions: envoy_v3.NewSocketOptions().TCPKeepalive().Build(),
}

c.Request(listenerType).Equals(&envoy_service_discovery_v3.DiscoveryResponse{
TypeUrl: listenerType,
Resources: resources(t,
httpListener,
httpsListener,
statsListener()),
}).Status(p).IsValid()
}

func TestGlobalAuthorization(t *testing.T) {
subtests := map[string]func(*testing.T, ResourceEventHandlerWrapper, *Contour){
// Default extAuthz on non TLS host.
Expand All @@ -484,6 +578,8 @@ func TestGlobalAuthorization(t *testing.T) {
"GlobalExternalAuthorizationWithMergedAuthPolicy": globalExternalAuthorizationWithMergedAuthPolicy,
// extAuthz authpolicy merge for TLS hosts.
"GlobalExternalAuthorizationWithMergedAuthPolicyTLS": globalExternalAuthorizationWithMergedAuthPolicyTLS,
// extAuthz on TLS host with Fallback Certificate enabled.
"GlobalExternalAuthorizationFilterTLSWithFallbackCertificate": globalExternalAuthorizationFilterTLSWithFallbackCertificate,
}

for n, f := range subtests {
Expand Down Expand Up @@ -520,6 +616,10 @@ func TestGlobalAuthorization(t *testing.T) {
},
},
}
httpProxyProcessor.FallbackCertificate = &types.NamespacedName{
Namespace: "admin",
Name: "fallbacksecret",
}
}
}
})
Expand Down
6 changes: 6 additions & 0 deletions internal/xdscache/v3/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,14 @@ func (c *ListenerCache) OnChange(root *dag.DAG) {
alpnProtos...,
)

var authzFilter *envoy_filter_network_http_connection_manager_v3.HttpFilter
if vh.ExternalAuthorization != nil {
authzFilter = envoy_v3.FilterExternalAuthz(vh.ExternalAuthorization)
}

cm := envoy_v3.HTTPConnectionManagerBuilder().
DefaultFilters().
AddFilter(authzFilter).
RouteConfigName(fallbackCertRouteConfigName(listener)).
MetricsPrefix(listener.Name).
AccessLoggers(cfg.newSecureAccessLog()).
Expand Down

0 comments on commit 22c99fe

Please sign in to comment.