mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-02 02:42:57 +02:00
return errors in xds build methods (#1827)
This commit is contained in:
parent
e2db837d9f
commit
a8a703218f
7 changed files with 447 additions and 228 deletions
|
@ -47,7 +47,12 @@ func (srv *Server) buildDiscoveryResources() (map[string][]*envoy_service_discov
|
||||||
Resource: any,
|
Resource: any,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, listener := range srv.buildListeners(cfg.Config) {
|
|
||||||
|
listeners, err := srv.buildListeners(cfg.Config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, listener := range listeners {
|
||||||
any, _ := anypb.New(listener)
|
any, _ := anypb.New(listener)
|
||||||
resources[listenerTypeURL] = append(resources[listenerTypeURL], &envoy_service_discovery_v3.Resource{
|
resources[listenerTypeURL] = append(resources[listenerTypeURL], &envoy_service_discovery_v3.Resource{
|
||||||
Name: listener.Name,
|
Name: listener.Name,
|
||||||
|
|
|
@ -25,11 +25,17 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
rootCA := srv.filemgr.FileDataSource(rootCAPath).GetFilename()
|
rootCA := srv.filemgr.FileDataSource(rootCAPath).GetFilename()
|
||||||
|
|
||||||
t.Run("insecure", func(t *testing.T) {
|
t.Run("insecure", func(t *testing.T) {
|
||||||
assert.Nil(t, srv.buildPolicyTransportSocket(&config.Policy{
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
Destinations: mustParseURLs("http://example.com"),
|
Destinations: mustParseURLs("http://example.com"),
|
||||||
}, mustParseURL("http://example.com")))
|
}, mustParseURL("http://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Nil(t, ts)
|
||||||
})
|
})
|
||||||
t.Run("host as sni", func(t *testing.T) {
|
t.Run("host as sni", func(t *testing.T) {
|
||||||
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
|
Destinations: mustParseURLs("https://example.com"),
|
||||||
|
}, mustParseURL("https://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "tls",
|
"name": "tls",
|
||||||
|
@ -57,11 +63,14 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
"sni": "example.com"
|
"sni": "example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, srv.buildPolicyTransportSocket(&config.Policy{
|
`, ts)
|
||||||
Destinations: mustParseURLs("https://example.com"),
|
|
||||||
}, mustParseURL("https://example.com")))
|
|
||||||
})
|
})
|
||||||
t.Run("tls_server_name as sni", func(t *testing.T) {
|
t.Run("tls_server_name as sni", func(t *testing.T) {
|
||||||
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
|
Destinations: mustParseURLs("https://example.com"),
|
||||||
|
TLSServerName: "use-this-name.example.com",
|
||||||
|
}, mustParseURL("https://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "tls",
|
"name": "tls",
|
||||||
|
@ -89,12 +98,14 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
"sni": "use-this-name.example.com"
|
"sni": "use-this-name.example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, srv.buildPolicyTransportSocket(&config.Policy{
|
`, ts)
|
||||||
Destinations: mustParseURLs("https://example.com"),
|
|
||||||
TLSServerName: "use-this-name.example.com",
|
|
||||||
}, mustParseURL("https://example.com")))
|
|
||||||
})
|
})
|
||||||
t.Run("tls_skip_verify", func(t *testing.T) {
|
t.Run("tls_skip_verify", func(t *testing.T) {
|
||||||
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
|
Destinations: mustParseURLs("https://example.com"),
|
||||||
|
TLSSkipVerify: true,
|
||||||
|
}, mustParseURL("https://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "tls",
|
"name": "tls",
|
||||||
|
@ -123,12 +134,14 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
"sni": "example.com"
|
"sni": "example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, srv.buildPolicyTransportSocket(&config.Policy{
|
`, ts)
|
||||||
Destinations: mustParseURLs("https://example.com"),
|
|
||||||
TLSSkipVerify: true,
|
|
||||||
}, mustParseURL("https://example.com")))
|
|
||||||
})
|
})
|
||||||
t.Run("custom ca", func(t *testing.T) {
|
t.Run("custom ca", func(t *testing.T) {
|
||||||
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
|
Destinations: mustParseURLs("https://example.com"),
|
||||||
|
TLSCustomCA: base64.StdEncoding.EncodeToString([]byte{0, 0, 0, 0}),
|
||||||
|
}, mustParseURL("https://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "tls",
|
"name": "tls",
|
||||||
|
@ -156,13 +169,15 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
"sni": "example.com"
|
"sni": "example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, srv.buildPolicyTransportSocket(&config.Policy{
|
`, ts)
|
||||||
Destinations: mustParseURLs("https://example.com"),
|
|
||||||
TLSCustomCA: base64.StdEncoding.EncodeToString([]byte{0, 0, 0, 0}),
|
|
||||||
}, mustParseURL("https://example.com")))
|
|
||||||
})
|
})
|
||||||
t.Run("client certificate", func(t *testing.T) {
|
t.Run("client certificate", func(t *testing.T) {
|
||||||
clientCert, _ := cryptutil.CertificateFromBase64(aExampleComCert, aExampleComKey)
|
clientCert, _ := cryptutil.CertificateFromBase64(aExampleComCert, aExampleComKey)
|
||||||
|
ts, err := srv.buildPolicyTransportSocket(&config.Policy{
|
||||||
|
Destinations: mustParseURLs("https://example.com"),
|
||||||
|
ClientCertificate: clientCert,
|
||||||
|
}, mustParseURL("https://example.com"))
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "tls",
|
"name": "tls",
|
||||||
|
@ -198,10 +213,7 @@ func Test_buildPolicyTransportSocket(t *testing.T) {
|
||||||
"sni": "example.com"
|
"sni": "example.com"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, srv.buildPolicyTransportSocket(&config.Policy{
|
`, ts)
|
||||||
Destinations: mustParseURLs("https://example.com"),
|
|
||||||
ClientCertificate: clientCert,
|
|
||||||
}, mustParseURL("https://example.com")))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,12 +222,13 @@ func Test_buildCluster(t *testing.T) {
|
||||||
rootCAPath, _ := getRootCertificateAuthority()
|
rootCAPath, _ := getRootCertificateAuthority()
|
||||||
rootCA := srv.filemgr.FileDataSource(rootCAPath).GetFilename()
|
rootCA := srv.filemgr.FileDataSource(rootCAPath).GetFilename()
|
||||||
t.Run("insecure", func(t *testing.T) {
|
t.Run("insecure", func(t *testing.T) {
|
||||||
endpoints := srv.buildPolicyEndpoints(&config.Policy{
|
endpoints, err := srv.buildPolicyEndpoints(&config.Policy{
|
||||||
Destinations: mustParseURLs("http://example.com", "http://1.2.3.4"),
|
Destinations: mustParseURLs("http://example.com", "http://1.2.3.4"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
||||||
err := buildCluster(cluster, "example", endpoints, true)
|
err = srv.buildCluster(cluster, "example", endpoints, true)
|
||||||
require.NoErrorf(t, err, "cluster %+v", cluster)
|
require.NoErrorf(t, err, "cluster %+v", cluster)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
|
@ -257,14 +270,15 @@ func Test_buildCluster(t *testing.T) {
|
||||||
`, cluster)
|
`, cluster)
|
||||||
})
|
})
|
||||||
t.Run("secure", func(t *testing.T) {
|
t.Run("secure", func(t *testing.T) {
|
||||||
endpoints := srv.buildPolicyEndpoints(&config.Policy{
|
endpoints, err := srv.buildPolicyEndpoints(&config.Policy{
|
||||||
Destinations: mustParseURLs(
|
Destinations: mustParseURLs(
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
err := buildCluster(cluster, "example", endpoints, true)
|
err = srv.buildCluster(cluster, "example", endpoints, true)
|
||||||
require.NoErrorf(t, err, "cluster %+v", cluster)
|
require.NoErrorf(t, err, "cluster %+v", cluster)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
|
@ -351,11 +365,12 @@ func Test_buildCluster(t *testing.T) {
|
||||||
`, cluster)
|
`, cluster)
|
||||||
})
|
})
|
||||||
t.Run("ip addresses", func(t *testing.T) {
|
t.Run("ip addresses", func(t *testing.T) {
|
||||||
endpoints := srv.buildPolicyEndpoints(&config.Policy{
|
endpoints, err := srv.buildPolicyEndpoints(&config.Policy{
|
||||||
Destinations: mustParseURLs("http://127.0.0.1", "http://127.0.0.2"),
|
Destinations: mustParseURLs("http://127.0.0.1", "http://127.0.0.2"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
err := buildCluster(cluster, "example", endpoints, true)
|
err = srv.buildCluster(cluster, "example", endpoints, true)
|
||||||
require.NoErrorf(t, err, "cluster %+v", cluster)
|
require.NoErrorf(t, err, "cluster %+v", cluster)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
|
@ -396,11 +411,12 @@ func Test_buildCluster(t *testing.T) {
|
||||||
`, cluster)
|
`, cluster)
|
||||||
})
|
})
|
||||||
t.Run("localhost", func(t *testing.T) {
|
t.Run("localhost", func(t *testing.T) {
|
||||||
endpoints := srv.buildPolicyEndpoints(&config.Policy{
|
endpoints, err := srv.buildPolicyEndpoints(&config.Policy{
|
||||||
Destinations: mustParseURLs("http://localhost"),
|
Destinations: mustParseURLs("http://localhost"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
err := buildCluster(cluster, "example", endpoints, true)
|
err = srv.buildCluster(cluster, "example", endpoints, true)
|
||||||
require.NoErrorf(t, err, "cluster %+v", cluster)
|
require.NoErrorf(t, err, "cluster %+v", cluster)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
|
@ -431,16 +447,17 @@ func Test_buildCluster(t *testing.T) {
|
||||||
`, cluster)
|
`, cluster)
|
||||||
})
|
})
|
||||||
t.Run("outlier", func(t *testing.T) {
|
t.Run("outlier", func(t *testing.T) {
|
||||||
endpoints := srv.buildPolicyEndpoints(&config.Policy{
|
endpoints, err := srv.buildPolicyEndpoints(&config.Policy{
|
||||||
Destinations: mustParseURLs("http://example.com"),
|
Destinations: mustParseURLs("http://example.com"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
||||||
cluster.OutlierDetection = &envoy_config_cluster_v3.OutlierDetection{
|
cluster.OutlierDetection = &envoy_config_cluster_v3.OutlierDetection{
|
||||||
EnforcingConsecutive_5Xx: wrapperspb.UInt32(17),
|
EnforcingConsecutive_5Xx: wrapperspb.UInt32(17),
|
||||||
SplitExternalLocalOriginErrors: true,
|
SplitExternalLocalOriginErrors: true,
|
||||||
}
|
}
|
||||||
err := buildCluster(cluster, "example", endpoints, true)
|
err = srv.buildCluster(cluster, "example", endpoints, true)
|
||||||
require.NoErrorf(t, err, "cluster %+v", cluster)
|
require.NoErrorf(t, err, "cluster %+v", cluster)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,8 +96,11 @@ func (srv *Server) buildClusters(options *config.Options) ([]*envoy_config_clust
|
||||||
func (srv *Server) buildInternalCluster(options *config.Options, name string, dst *url.URL, forceHTTP2 bool) (*envoy_config_cluster_v3.Cluster, error) {
|
func (srv *Server) buildInternalCluster(options *config.Options, name string, dst *url.URL, forceHTTP2 bool) (*envoy_config_cluster_v3.Cluster, error) {
|
||||||
cluster := newDefaultEnvoyClusterConfig()
|
cluster := newDefaultEnvoyClusterConfig()
|
||||||
cluster.DnsLookupFamily = config.GetEnvoyDNSLookupFamily(options.DNSLookupFamily)
|
cluster.DnsLookupFamily = config.GetEnvoyDNSLookupFamily(options.DNSLookupFamily)
|
||||||
endpoints := []Endpoint{NewEndpoint(dst, srv.buildInternalTransportSocket(options, dst))}
|
endpoints, err := srv.buildInternalEndpoints(options, dst)
|
||||||
if err := buildCluster(cluster, name, endpoints, forceHTTP2); err != nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := srv.buildCluster(cluster, name, endpoints, forceHTTP2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return cluster, nil
|
return cluster, nil
|
||||||
|
@ -107,7 +110,10 @@ func (srv *Server) buildPolicyCluster(options *config.Options, policy *config.Po
|
||||||
cluster := policy.EnvoyOpts
|
cluster := policy.EnvoyOpts
|
||||||
|
|
||||||
name := getPolicyName(policy)
|
name := getPolicyName(policy)
|
||||||
endpoints := srv.buildPolicyEndpoints(policy)
|
endpoints, err := srv.buildPolicyEndpoints(policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if cluster.DnsLookupFamily == envoy_config_cluster_v3.Cluster_AUTO {
|
if cluster.DnsLookupFamily == envoy_config_cluster_v3.Cluster_AUTO {
|
||||||
cluster.DnsLookupFamily = config.GetEnvoyDNSLookupFamily(options.DNSLookupFamily)
|
cluster.DnsLookupFamily = config.GetEnvoyDNSLookupFamily(options.DNSLookupFamily)
|
||||||
|
@ -117,24 +123,38 @@ func (srv *Server) buildPolicyCluster(options *config.Options, policy *config.Po
|
||||||
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
cluster.DnsLookupFamily = envoy_config_cluster_v3.Cluster_V4_ONLY
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := buildCluster(cluster, name, endpoints, false); err != nil {
|
if err := srv.buildCluster(cluster, name, endpoints, false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return cluster, nil
|
return cluster, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildPolicyEndpoints(policy *config.Policy) []Endpoint {
|
func (srv *Server) buildInternalEndpoints(options *config.Options, dst *url.URL) ([]Endpoint, error) {
|
||||||
var endpoints []Endpoint
|
var endpoints []Endpoint
|
||||||
for _, dst := range policy.Destinations {
|
if ts, err := srv.buildInternalTransportSocket(options, dst); err != nil {
|
||||||
endpoints = append(endpoints, NewEndpoint(dst, srv.buildPolicyTransportSocket(policy, dst)))
|
return nil, err
|
||||||
|
} else {
|
||||||
|
endpoints = append(endpoints, NewEndpoint(dst, ts))
|
||||||
}
|
}
|
||||||
return endpoints
|
return endpoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildInternalTransportSocket(options *config.Options, endpoint *url.URL) *envoy_config_core_v3.TransportSocket {
|
func (srv *Server) buildPolicyEndpoints(policy *config.Policy) ([]Endpoint, error) {
|
||||||
|
var endpoints []Endpoint
|
||||||
|
for _, dst := range policy.Destinations {
|
||||||
|
if ts, err := srv.buildPolicyTransportSocket(policy, dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
endpoints = append(endpoints, NewEndpoint(dst, ts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) buildInternalTransportSocket(options *config.Options, endpoint *url.URL) (*envoy_config_core_v3.TransportSocket, error) {
|
||||||
if endpoint.Scheme != "https" {
|
if endpoint.Scheme != "https" {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
sni := endpoint.Hostname()
|
sni := endpoint.Hostname()
|
||||||
if options.OverrideCertificateName != "" {
|
if options.OverrideCertificateName != "" {
|
||||||
|
@ -178,12 +198,17 @@ func (srv *Server) buildInternalTransportSocket(options *config.Options, endpoin
|
||||||
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
||||||
TypedConfig: tlsConfig,
|
TypedConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildPolicyTransportSocket(policy *config.Policy, dst *url.URL) *envoy_config_core_v3.TransportSocket {
|
func (srv *Server) buildPolicyTransportSocket(policy *config.Policy, dst *url.URL) (*envoy_config_core_v3.TransportSocket, error) {
|
||||||
if dst == nil || dst.Scheme != "https" {
|
if dst == nil || dst.Scheme != "https" {
|
||||||
return nil
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
vc, err := srv.buildPolicyValidationContext(policy, dst)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sni := dst.Hostname()
|
sni := dst.Hostname()
|
||||||
|
@ -202,7 +227,7 @@ func (srv *Server) buildPolicyTransportSocket(policy *config.Policy, dst *url.UR
|
||||||
},
|
},
|
||||||
AlpnProtocols: []string{"http/1.1"},
|
AlpnProtocols: []string{"http/1.1"},
|
||||||
ValidationContextType: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext{
|
ValidationContextType: &envoy_extensions_transport_sockets_tls_v3.CommonTlsContext_ValidationContext{
|
||||||
ValidationContext: srv.buildPolicyValidationContext(policy, dst),
|
ValidationContext: vc,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Sni: sni,
|
Sni: sni,
|
||||||
|
@ -218,12 +243,12 @@ func (srv *Server) buildPolicyTransportSocket(policy *config.Policy, dst *url.UR
|
||||||
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
||||||
TypedConfig: tlsConfig,
|
TypedConfig: tlsConfig,
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildPolicyValidationContext(policy *config.Policy, dst *url.URL) *envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext {
|
func (srv *Server) buildPolicyValidationContext(policy *config.Policy, dst *url.URL) (*envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext, error) {
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sni := dst.Hostname()
|
sni := dst.Hostname()
|
||||||
|
@ -258,10 +283,10 @@ func (srv *Server) buildPolicyValidationContext(policy *config.Policy, dst *url.
|
||||||
validationContext.TrustChainVerification = envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext_ACCEPT_UNTRUSTED
|
validationContext.TrustChainVerification = envoy_extensions_transport_sockets_tls_v3.CertificateValidationContext_ACCEPT_UNTRUSTED
|
||||||
}
|
}
|
||||||
|
|
||||||
return validationContext
|
return validationContext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildCluster(
|
func (srv *Server) buildCluster(
|
||||||
cluster *envoy_config_cluster_v3.Cluster,
|
cluster *envoy_config_cluster_v3.Cluster,
|
||||||
name string,
|
name string,
|
||||||
endpoints []Endpoint,
|
endpoints []Endpoint,
|
||||||
|
@ -275,7 +300,10 @@ func buildCluster(
|
||||||
cluster.ConnectTimeout = defaultConnectionTimeout
|
cluster.ConnectTimeout = defaultConnectionTimeout
|
||||||
}
|
}
|
||||||
cluster.RespectDnsTtl = true
|
cluster.RespectDnsTtl = true
|
||||||
lbEndpoints := buildLbEndpoints(endpoints)
|
lbEndpoints, err := srv.buildLbEndpoints(endpoints)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cluster.Name = name
|
cluster.Name = name
|
||||||
cluster.LoadAssignment = &envoy_config_endpoint_v3.ClusterLoadAssignment{
|
cluster.LoadAssignment = &envoy_config_endpoint_v3.ClusterLoadAssignment{
|
||||||
ClusterName: name,
|
ClusterName: name,
|
||||||
|
@ -283,7 +311,10 @@ func buildCluster(
|
||||||
LbEndpoints: lbEndpoints,
|
LbEndpoints: lbEndpoints,
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
cluster.TransportSocketMatches = buildTransportSocketMatches(endpoints)
|
cluster.TransportSocketMatches, err = srv.buildTransportSocketMatches(endpoints)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if forceHTTP2 {
|
if forceHTTP2 {
|
||||||
cluster.Http2ProtocolOptions = &envoy_config_core_v3.Http2ProtocolOptions{
|
cluster.Http2ProtocolOptions = &envoy_config_core_v3.Http2ProtocolOptions{
|
||||||
|
@ -307,7 +338,7 @@ func buildCluster(
|
||||||
return cluster.Validate()
|
return cluster.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildLbEndpoints(endpoints []Endpoint) []*envoy_config_endpoint_v3.LbEndpoint {
|
func (srv *Server) buildLbEndpoints(endpoints []Endpoint) ([]*envoy_config_endpoint_v3.LbEndpoint, error) {
|
||||||
var lbes []*envoy_config_endpoint_v3.LbEndpoint
|
var lbes []*envoy_config_endpoint_v3.LbEndpoint
|
||||||
for _, e := range endpoints {
|
for _, e := range endpoints {
|
||||||
defaultPort := 80
|
defaultPort := 80
|
||||||
|
@ -343,10 +374,10 @@ func buildLbEndpoints(endpoints []Endpoint) []*envoy_config_endpoint_v3.LbEndpoi
|
||||||
}
|
}
|
||||||
lbes = append(lbes, lbe)
|
lbes = append(lbes, lbe)
|
||||||
}
|
}
|
||||||
return lbes
|
return lbes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTransportSocketMatches(endpoints []Endpoint) []*envoy_config_cluster_v3.Cluster_TransportSocketMatch {
|
func (srv *Server) buildTransportSocketMatches(endpoints []Endpoint) ([]*envoy_config_cluster_v3.Cluster_TransportSocketMatch, error) {
|
||||||
var tsms []*envoy_config_cluster_v3.Cluster_TransportSocketMatch
|
var tsms []*envoy_config_cluster_v3.Cluster_TransportSocketMatch
|
||||||
seen := map[string]struct{}{}
|
seen := map[string]struct{}{}
|
||||||
for _, e := range endpoints {
|
for _, e := range endpoints {
|
||||||
|
@ -371,5 +402,5 @@ func buildTransportSocketMatches(endpoints []Endpoint) []*envoy_config_cluster_v
|
||||||
TransportSocket: e.transportSocket,
|
TransportSocket: e.transportSocket,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return tsms
|
return tsms, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,21 +39,29 @@ func init() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildListeners(cfg *config.Config) []*envoy_config_listener_v3.Listener {
|
func (srv *Server) buildListeners(cfg *config.Config) ([]*envoy_config_listener_v3.Listener, error) {
|
||||||
var listeners []*envoy_config_listener_v3.Listener
|
var listeners []*envoy_config_listener_v3.Listener
|
||||||
|
|
||||||
if config.IsAuthenticate(cfg.Options.Services) || config.IsProxy(cfg.Options.Services) {
|
if config.IsAuthenticate(cfg.Options.Services) || config.IsProxy(cfg.Options.Services) {
|
||||||
listeners = append(listeners, srv.buildMainListener(cfg))
|
if li, err := srv.buildMainListener(cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
listeners = append(listeners, li)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.IsAuthorize(cfg.Options.Services) || config.IsDataBroker(cfg.Options.Services) {
|
if config.IsAuthorize(cfg.Options.Services) || config.IsDataBroker(cfg.Options.Services) {
|
||||||
listeners = append(listeners, srv.buildGRPCListener(cfg))
|
if li, err := srv.buildGRPCListener(cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
listeners = append(listeners, li)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners
|
return listeners, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_v3.Listener {
|
func (srv *Server) buildMainListener(cfg *config.Config) (*envoy_config_listener_v3.Listener, error) {
|
||||||
listenerFilters := []*envoy_config_listener_v3.ListenerFilter{}
|
listenerFilters := []*envoy_config_listener_v3.ListenerFilter{}
|
||||||
if cfg.Options.UseProxyProtocol {
|
if cfg.Options.UseProxyProtocol {
|
||||||
proxyCfg := marshalAny(&envoy_extensions_filters_listener_proxy_protocol_v3.ProxyProtocol{})
|
proxyCfg := marshalAny(&envoy_extensions_filters_listener_proxy_protocol_v3.ProxyProtocol{})
|
||||||
|
@ -66,8 +74,11 @@ func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Options.InsecureServer {
|
if cfg.Options.InsecureServer {
|
||||||
filter := buildMainHTTPConnectionManagerFilter(cfg.Options,
|
filter, err := srv.buildMainHTTPConnectionManagerFilter(cfg.Options,
|
||||||
getAllRouteableDomains(cfg.Options, cfg.Options.Addr), "")
|
getAllRouteableDomains(cfg.Options, cfg.Options.Addr), "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &envoy_config_listener_v3.Listener{
|
return &envoy_config_listener_v3.Listener{
|
||||||
Name: "http-ingress",
|
Name: "http-ingress",
|
||||||
|
@ -78,7 +89,7 @@ func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_
|
||||||
filter,
|
filter,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsInspectorCfg := marshalAny(new(emptypb.Empty))
|
tlsInspectorCfg := marshalAny(new(emptypb.Empty))
|
||||||
|
@ -89,58 +100,75 @@ func (srv *Server) buildMainListener(cfg *config.Config) *envoy_config_listener_
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
chains, err := srv.buildFilterChains(cfg.Options, cfg.Options.Addr,
|
||||||
|
func(tlsDomain string, httpDomains []string) (*envoy_config_listener_v3.FilterChain, error) {
|
||||||
|
filter, err := srv.buildMainHTTPConnectionManagerFilter(cfg.Options, httpDomains, tlsDomain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
filterChain := &envoy_config_listener_v3.FilterChain{
|
||||||
|
Filters: []*envoy_config_listener_v3.Filter{filter},
|
||||||
|
}
|
||||||
|
if tlsDomain != "*" {
|
||||||
|
filterChain.FilterChainMatch = &envoy_config_listener_v3.FilterChainMatch{
|
||||||
|
ServerNames: []string{tlsDomain},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlsContext := srv.buildDownstreamTLSContext(cfg, tlsDomain)
|
||||||
|
if tlsContext != nil {
|
||||||
|
tlsConfig := marshalAny(tlsContext)
|
||||||
|
filterChain.TransportSocket = &envoy_config_core_v3.TransportSocket{
|
||||||
|
Name: "tls",
|
||||||
|
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
||||||
|
TypedConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filterChain, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
li := &envoy_config_listener_v3.Listener{
|
li := &envoy_config_listener_v3.Listener{
|
||||||
Name: "https-ingress",
|
Name: "https-ingress",
|
||||||
Address: buildAddress(cfg.Options.Addr, 443),
|
Address: buildAddress(cfg.Options.Addr, 443),
|
||||||
ListenerFilters: listenerFilters,
|
ListenerFilters: listenerFilters,
|
||||||
FilterChains: buildFilterChains(cfg.Options, cfg.Options.Addr,
|
FilterChains: chains,
|
||||||
func(tlsDomain string, httpDomains []string) *envoy_config_listener_v3.FilterChain {
|
|
||||||
filter := buildMainHTTPConnectionManagerFilter(cfg.Options, httpDomains, tlsDomain)
|
|
||||||
filterChain := &envoy_config_listener_v3.FilterChain{
|
|
||||||
Filters: []*envoy_config_listener_v3.Filter{filter},
|
|
||||||
}
|
|
||||||
if tlsDomain != "*" {
|
|
||||||
filterChain.FilterChainMatch = &envoy_config_listener_v3.FilterChainMatch{
|
|
||||||
ServerNames: []string{tlsDomain},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tlsContext := srv.buildDownstreamTLSContext(cfg, tlsDomain)
|
|
||||||
if tlsContext != nil {
|
|
||||||
tlsConfig := marshalAny(tlsContext)
|
|
||||||
filterChain.TransportSocket = &envoy_config_core_v3.TransportSocket{
|
|
||||||
Name: "tls",
|
|
||||||
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
|
||||||
TypedConfig: tlsConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filterChain
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
return li
|
return li, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFilterChains(
|
func (srv *Server) buildFilterChains(
|
||||||
options *config.Options, addr string,
|
options *config.Options, addr string,
|
||||||
callback func(tlsDomain string, httpDomains []string) *envoy_config_listener_v3.FilterChain,
|
callback func(tlsDomain string, httpDomains []string) (*envoy_config_listener_v3.FilterChain, error),
|
||||||
) []*envoy_config_listener_v3.FilterChain {
|
) ([]*envoy_config_listener_v3.FilterChain, error) {
|
||||||
allDomains := getAllRouteableDomains(options, addr)
|
allDomains := getAllRouteableDomains(options, addr)
|
||||||
tlsDomains := getAllTLSDomains(options, addr)
|
tlsDomains := getAllTLSDomains(options, addr)
|
||||||
var chains []*envoy_config_listener_v3.FilterChain
|
var chains []*envoy_config_listener_v3.FilterChain
|
||||||
for _, domain := range tlsDomains {
|
for _, domain := range tlsDomains {
|
||||||
// first we match on SNI
|
// first we match on SNI
|
||||||
chains = append(chains, callback(domain, getRouteableDomainsForTLSDomain(options, addr, domain)))
|
if chain, err := callback(domain, getRouteableDomainsForTLSDomain(options, addr, domain)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
chains = append(chains, chain)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are no SNI matches we match on HTTP host
|
// if there are no SNI matches we match on HTTP host
|
||||||
chains = append(chains, callback("*", allDomains))
|
if chain, err := callback("*", allDomains); err != nil {
|
||||||
return chains
|
return nil, err
|
||||||
|
} else {
|
||||||
|
chains = append(chains, chain)
|
||||||
|
}
|
||||||
|
return chains, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildMainHTTPConnectionManagerFilter(
|
func (srv *Server) buildMainHTTPConnectionManagerFilter(
|
||||||
options *config.Options,
|
options *config.Options,
|
||||||
domains []string,
|
domains []string,
|
||||||
tlsDomain string,
|
tlsDomain string,
|
||||||
) *envoy_config_listener_v3.Filter {
|
) (*envoy_config_listener_v3.Filter, error) {
|
||||||
var virtualHosts []*envoy_config_route_v3.VirtualHost
|
var virtualHosts []*envoy_config_route_v3.VirtualHost
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
vh := &envoy_config_route_v3.VirtualHost{
|
vh := &envoy_config_route_v3.VirtualHost{
|
||||||
|
@ -152,27 +180,44 @@ func buildMainHTTPConnectionManagerFilter(
|
||||||
// if this is a gRPC service domain and we're supposed to handle that, add those routes
|
// if this is a gRPC service domain and we're supposed to handle that, add those routes
|
||||||
if (config.IsAuthorize(options.Services) && hostMatchesDomain(options.GetAuthorizeURL(), domain)) ||
|
if (config.IsAuthorize(options.Services) && hostMatchesDomain(options.GetAuthorizeURL(), domain)) ||
|
||||||
(config.IsDataBroker(options.Services) && hostMatchesDomain(options.GetDataBrokerURL(), domain)) {
|
(config.IsDataBroker(options.Services) && hostMatchesDomain(options.GetDataBrokerURL(), domain)) {
|
||||||
vh.Routes = append(vh.Routes, buildGRPCRoutes()...)
|
if rs, err := srv.buildGRPCRoutes(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
vh.Routes = append(vh.Routes, rs...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// these routes match /.pomerium/... and similar paths
|
// these routes match /.pomerium/... and similar paths
|
||||||
vh.Routes = append(vh.Routes, buildPomeriumHTTPRoutes(options, domain)...)
|
if rs, err := srv.buildPomeriumHTTPRoutes(options, domain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
vh.Routes = append(vh.Routes, rs...)
|
||||||
|
}
|
||||||
|
|
||||||
// if we're the proxy, add all the policy routes
|
// if we're the proxy, add all the policy routes
|
||||||
if config.IsProxy(options.Services) {
|
if config.IsProxy(options.Services) {
|
||||||
vh.Routes = append(vh.Routes, buildPolicyRoutes(options, domain)...)
|
if rs, err := srv.buildPolicyRoutes(options, domain); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
vh.Routes = append(vh.Routes, rs...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(vh.Routes) > 0 {
|
if len(vh.Routes) > 0 {
|
||||||
virtualHosts = append(virtualHosts, vh)
|
virtualHosts = append(virtualHosts, vh)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtualHosts = append(virtualHosts, &envoy_config_route_v3.VirtualHost{
|
|
||||||
Name: "catch-all",
|
if rs, err := srv.buildPomeriumHTTPRoutes(options, "*"); err != nil {
|
||||||
Domains: []string{"*"},
|
return nil, err
|
||||||
Routes: buildPomeriumHTTPRoutes(options, "*"),
|
} else {
|
||||||
})
|
virtualHosts = append(virtualHosts, &envoy_config_route_v3.VirtualHost{
|
||||||
|
Name: "catch-all",
|
||||||
|
Domains: []string{"*"},
|
||||||
|
Routes: rs,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var grpcClientTimeout *durationpb.Duration
|
var grpcClientTimeout *durationpb.Duration
|
||||||
if options.GRPCClientTimeout != 0 {
|
if options.GRPCClientTimeout != 0 {
|
||||||
|
@ -254,11 +299,15 @@ func buildMainHTTPConnectionManagerFilter(
|
||||||
maxStreamDuration = ptypes.DurationProto(options.WriteTimeout)
|
maxStreamDuration = ptypes.DurationProto(options.WriteTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc, err := srv.buildRouteConfiguration("main", virtualHosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
|
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
|
||||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||||
StatPrefix: "ingress",
|
StatPrefix: "ingress",
|
||||||
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
||||||
RouteConfig: buildRouteConfiguration("main", virtualHosts),
|
RouteConfig: rc,
|
||||||
},
|
},
|
||||||
HttpFilters: filters,
|
HttpFilters: filters,
|
||||||
AccessLog: buildAccessLogs(options),
|
AccessLog: buildAccessLogs(options),
|
||||||
|
@ -280,11 +329,14 @@ func buildMainHTTPConnectionManagerFilter(
|
||||||
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
||||||
TypedConfig: tc,
|
TypedConfig: tc,
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildGRPCListener(cfg *config.Config) *envoy_config_listener_v3.Listener {
|
func (srv *Server) buildGRPCListener(cfg *config.Config) (*envoy_config_listener_v3.Listener, error) {
|
||||||
filter := buildGRPCHTTPConnectionManagerFilter()
|
filter, err := srv.buildGRPCHTTPConnectionManagerFilter()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.Options.GRPCInsecure {
|
if cfg.Options.GRPCInsecure {
|
||||||
return &envoy_config_listener_v3.Listener{
|
return &envoy_config_listener_v3.Listener{
|
||||||
|
@ -295,7 +347,33 @@ func (srv *Server) buildGRPCListener(cfg *config.Config) *envoy_config_listener_
|
||||||
filter,
|
filter,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
}
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
chains, err := srv.buildFilterChains(cfg.Options, cfg.Options.Addr,
|
||||||
|
func(tlsDomain string, httpDomains []string) (*envoy_config_listener_v3.FilterChain, error) {
|
||||||
|
filterChain := &envoy_config_listener_v3.FilterChain{
|
||||||
|
Filters: []*envoy_config_listener_v3.Filter{filter},
|
||||||
|
}
|
||||||
|
if tlsDomain != "*" {
|
||||||
|
filterChain.FilterChainMatch = &envoy_config_listener_v3.FilterChainMatch{
|
||||||
|
ServerNames: []string{tlsDomain},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tlsContext := srv.buildDownstreamTLSContext(cfg, tlsDomain)
|
||||||
|
if tlsContext != nil {
|
||||||
|
tlsConfig := marshalAny(tlsContext)
|
||||||
|
filterChain.TransportSocket = &envoy_config_core_v3.TransportSocket{
|
||||||
|
Name: "tls",
|
||||||
|
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
||||||
|
TypedConfig: tlsConfig,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filterChain, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsInspectorCfg := marshalAny(new(emptypb.Empty))
|
tlsInspectorCfg := marshalAny(new(emptypb.Empty))
|
||||||
|
@ -308,33 +386,41 @@ func (srv *Server) buildGRPCListener(cfg *config.Config) *envoy_config_listener_
|
||||||
TypedConfig: tlsInspectorCfg,
|
TypedConfig: tlsInspectorCfg,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
FilterChains: buildFilterChains(cfg.Options, cfg.Options.Addr,
|
FilterChains: chains,
|
||||||
func(tlsDomain string, httpDomains []string) *envoy_config_listener_v3.FilterChain {
|
|
||||||
filterChain := &envoy_config_listener_v3.FilterChain{
|
|
||||||
Filters: []*envoy_config_listener_v3.Filter{filter},
|
|
||||||
}
|
|
||||||
if tlsDomain != "*" {
|
|
||||||
filterChain.FilterChainMatch = &envoy_config_listener_v3.FilterChainMatch{
|
|
||||||
ServerNames: []string{tlsDomain},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tlsContext := srv.buildDownstreamTLSContext(cfg, tlsDomain)
|
|
||||||
if tlsContext != nil {
|
|
||||||
tlsConfig := marshalAny(tlsContext)
|
|
||||||
filterChain.TransportSocket = &envoy_config_core_v3.TransportSocket{
|
|
||||||
Name: "tls",
|
|
||||||
ConfigType: &envoy_config_core_v3.TransportSocket_TypedConfig{
|
|
||||||
TypedConfig: tlsConfig,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filterChain
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
return li
|
return li, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildGRPCHTTPConnectionManagerFilter() *envoy_config_listener_v3.Filter {
|
func (srv *Server) buildGRPCHTTPConnectionManagerFilter() (*envoy_config_listener_v3.Filter, error) {
|
||||||
|
rc, err := srv.buildRouteConfiguration("grpc", []*envoy_config_route_v3.VirtualHost{{
|
||||||
|
Name: "grpc",
|
||||||
|
Domains: []string{"*"},
|
||||||
|
Routes: []*envoy_config_route_v3.Route{{
|
||||||
|
Name: "grpc",
|
||||||
|
Match: &envoy_config_route_v3.RouteMatch{
|
||||||
|
PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{Prefix: "/"},
|
||||||
|
Grpc: &envoy_config_route_v3.RouteMatch_GrpcRouteMatchOptions{},
|
||||||
|
},
|
||||||
|
Action: &envoy_config_route_v3.Route_Route{
|
||||||
|
Route: &envoy_config_route_v3.RouteAction{
|
||||||
|
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
||||||
|
Cluster: "pomerium-control-plane-grpc",
|
||||||
|
},
|
||||||
|
// disable the timeout to support grpc streaming
|
||||||
|
Timeout: &durationpb.Duration{
|
||||||
|
Seconds: 0,
|
||||||
|
},
|
||||||
|
IdleTimeout: &durationpb.Duration{
|
||||||
|
Seconds: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
|
tc := marshalAny(&envoy_http_connection_manager.HttpConnectionManager{
|
||||||
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
CodecType: envoy_http_connection_manager.HttpConnectionManager_AUTO,
|
||||||
StatPrefix: "grpc_ingress",
|
StatPrefix: "grpc_ingress",
|
||||||
|
@ -343,31 +429,7 @@ func buildGRPCHTTPConnectionManagerFilter() *envoy_config_listener_v3.Filter {
|
||||||
Seconds: 15,
|
Seconds: 15,
|
||||||
},
|
},
|
||||||
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
RouteSpecifier: &envoy_http_connection_manager.HttpConnectionManager_RouteConfig{
|
||||||
RouteConfig: buildRouteConfiguration("grpc", []*envoy_config_route_v3.VirtualHost{{
|
RouteConfig: rc,
|
||||||
Name: "grpc",
|
|
||||||
Domains: []string{"*"},
|
|
||||||
Routes: []*envoy_config_route_v3.Route{{
|
|
||||||
Name: "grpc",
|
|
||||||
Match: &envoy_config_route_v3.RouteMatch{
|
|
||||||
PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{Prefix: "/"},
|
|
||||||
Grpc: &envoy_config_route_v3.RouteMatch_GrpcRouteMatchOptions{},
|
|
||||||
},
|
|
||||||
Action: &envoy_config_route_v3.Route_Route{
|
|
||||||
Route: &envoy_config_route_v3.RouteAction{
|
|
||||||
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
|
||||||
Cluster: "pomerium-control-plane-grpc",
|
|
||||||
},
|
|
||||||
// disable the timeout to support grpc streaming
|
|
||||||
Timeout: &durationpb.Duration{
|
|
||||||
Seconds: 0,
|
|
||||||
},
|
|
||||||
IdleTimeout: &durationpb.Duration{
|
|
||||||
Seconds: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
}}),
|
|
||||||
},
|
},
|
||||||
HttpFilters: []*envoy_http_connection_manager.HttpFilter{{
|
HttpFilters: []*envoy_http_connection_manager.HttpFilter{{
|
||||||
Name: "envoy.filters.http.router",
|
Name: "envoy.filters.http.router",
|
||||||
|
@ -378,16 +440,16 @@ func buildGRPCHTTPConnectionManagerFilter() *envoy_config_listener_v3.Filter {
|
||||||
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
||||||
TypedConfig: tc,
|
TypedConfig: tc,
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildRouteConfiguration(name string, virtualHosts []*envoy_config_route_v3.VirtualHost) *envoy_config_route_v3.RouteConfiguration {
|
func (srv *Server) buildRouteConfiguration(name string, virtualHosts []*envoy_config_route_v3.VirtualHost) (*envoy_config_route_v3.RouteConfiguration, error) {
|
||||||
return &envoy_config_route_v3.RouteConfiguration{
|
return &envoy_config_route_v3.RouteConfiguration{
|
||||||
Name: name,
|
Name: name,
|
||||||
VirtualHosts: virtualHosts,
|
VirtualHosts: virtualHosts,
|
||||||
// disable cluster validation since the order of LDS/CDS updates isn't guaranteed
|
// disable cluster validation since the order of LDS/CDS updates isn't guaranteed
|
||||||
ValidateClusters: &wrappers.BoolValue{Value: false},
|
ValidateClusters: &wrappers.BoolValue{Value: false},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) buildDownstreamTLSContext(cfg *config.Config, domain string) *envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext {
|
func (srv *Server) buildDownstreamTLSContext(cfg *config.Config, domain string) *envoy_extensions_transport_sockets_tls_v3.DownstreamTlsContext {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
"github.com/pomerium/pomerium/internal/controlplane/filemgr"
|
"github.com/pomerium/pomerium/internal/controlplane/filemgr"
|
||||||
|
@ -21,9 +22,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
|
func Test_buildMainHTTPConnectionManagerFilter(t *testing.T) {
|
||||||
|
srv, _ := NewServer("TEST")
|
||||||
|
|
||||||
options := config.NewDefaultOptions()
|
options := config.NewDefaultOptions()
|
||||||
options.SkipXffAppend = true
|
options.SkipXffAppend = true
|
||||||
filter := buildMainHTTPConnectionManagerFilter(options, []string{"example.com"}, "*")
|
filter, err := srv.buildMainHTTPConnectionManagerFilter(options, []string{"example.com"}, "*")
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `{
|
testutil.AssertProtoJSONEqual(t, `{
|
||||||
"name": "envoy.filters.network.http_connection_manager",
|
"name": "envoy.filters.network.http_connection_manager",
|
||||||
"typedConfig": {
|
"typedConfig": {
|
||||||
|
@ -497,8 +501,10 @@ func Test_hostMatchesDomain(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildRouteConfiguration(t *testing.T) {
|
func Test_buildRouteConfiguration(t *testing.T) {
|
||||||
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
virtualHosts := make([]*envoy_config_route_v3.VirtualHost, 10)
|
virtualHosts := make([]*envoy_config_route_v3.VirtualHost, 10)
|
||||||
routeConfig := buildRouteConfiguration("test-route-configuration", virtualHosts)
|
routeConfig, err := srv.buildRouteConfiguration("test-route-configuration", virtualHosts)
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "test-route-configuration", routeConfig.GetName())
|
assert.Equal(t, "test-route-configuration", routeConfig.GetName())
|
||||||
assert.Equal(t, virtualHosts, routeConfig.GetVirtualHosts())
|
assert.Equal(t, virtualHosts, routeConfig.GetVirtualHosts())
|
||||||
assert.False(t, routeConfig.GetValidateClusters().GetValue())
|
assert.False(t, routeConfig.GetValidateClusters().GetValue())
|
||||||
|
@ -509,10 +515,11 @@ func Test_requireProxyProtocol(t *testing.T) {
|
||||||
filemgr: filemgr.NewManager(),
|
filemgr: filemgr.NewManager(),
|
||||||
}
|
}
|
||||||
t.Run("required", func(t *testing.T) {
|
t.Run("required", func(t *testing.T) {
|
||||||
li := srv.buildMainListener(&config.Config{Options: &config.Options{
|
li, err := srv.buildMainListener(&config.Config{Options: &config.Options{
|
||||||
UseProxyProtocol: true,
|
UseProxyProtocol: true,
|
||||||
InsecureServer: true,
|
InsecureServer: true,
|
||||||
}})
|
}})
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `[
|
testutil.AssertProtoJSONEqual(t, `[
|
||||||
{
|
{
|
||||||
"name": "envoy.filters.listener.proxy_protocol",
|
"name": "envoy.filters.listener.proxy_protocol",
|
||||||
|
@ -523,10 +530,11 @@ func Test_requireProxyProtocol(t *testing.T) {
|
||||||
]`, li.GetListenerFilters())
|
]`, li.GetListenerFilters())
|
||||||
})
|
})
|
||||||
t.Run("not required", func(t *testing.T) {
|
t.Run("not required", func(t *testing.T) {
|
||||||
li := srv.buildMainListener(&config.Config{Options: &config.Options{
|
li, err := srv.buildMainListener(&config.Config{Options: &config.Options{
|
||||||
UseProxyProtocol: false,
|
UseProxyProtocol: false,
|
||||||
InsecureServer: true,
|
InsecureServer: true,
|
||||||
}})
|
}})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Len(t, li.GetListenerFilters(), 0)
|
assert.Len(t, li.GetListenerFilters(), 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const (
|
||||||
httpCluster = "pomerium-control-plane-http"
|
httpCluster = "pomerium-control-plane-http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildGRPCRoutes() []*envoy_config_route_v3.Route {
|
func (srv *Server) buildGRPCRoutes() ([]*envoy_config_route_v3.Route, error) {
|
||||||
action := &envoy_config_route_v3.Route_Route{
|
action := &envoy_config_route_v3.Route_Route{
|
||||||
Route: &envoy_config_route_v3.RouteAction{
|
Route: &envoy_config_route_v3.RouteAction{
|
||||||
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
ClusterSpecifier: &envoy_config_route_v3.RouteAction_Cluster{
|
||||||
|
@ -44,47 +44,107 @@ func buildGRPCRoutes() []*envoy_config_route_v3.Route {
|
||||||
TypedPerFilterConfig: map[string]*any.Any{
|
TypedPerFilterConfig: map[string]*any.Any{
|
||||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||||
},
|
},
|
||||||
}}
|
}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPomeriumHTTPRoutes(options *config.Options, domain string) []*envoy_config_route_v3.Route {
|
func (srv *Server) buildPomeriumHTTPRoutes(options *config.Options, domain string) ([]*envoy_config_route_v3.Route, error) {
|
||||||
routes := []*envoy_config_route_v3.Route{
|
var routes []*envoy_config_route_v3.Route
|
||||||
// enable ext_authz
|
// enable ext_authz
|
||||||
buildControlPlanePathRoute("/.pomerium/jwt", true),
|
if r, err := srv.buildControlPlanePathRoute("/.pomerium/jwt", true); err != nil {
|
||||||
// disable ext_authz and passthrough to proxy handlers
|
return nil, err
|
||||||
buildControlPlanePathRoute("/ping", false),
|
} else {
|
||||||
buildControlPlanePathRoute("/healthz", false),
|
routes = append(routes, r)
|
||||||
buildControlPlanePathRoute("/.pomerium/admin", true),
|
}
|
||||||
buildControlPlanePrefixRoute("/.pomerium/admin/", true),
|
|
||||||
buildControlPlanePathRoute("/.pomerium", false),
|
// disable ext_authz and passthrough to proxy handlers
|
||||||
buildControlPlanePrefixRoute("/.pomerium/", false),
|
if r, err := srv.buildControlPlanePathRoute("/ping", false); err != nil {
|
||||||
buildControlPlanePathRoute("/.well-known/pomerium", false),
|
return nil, err
|
||||||
buildControlPlanePrefixRoute("/.well-known/pomerium/", false),
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePathRoute("/healthz", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePathRoute("/.pomerium/admin", true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePrefixRoute("/.pomerium/admin/", true); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePathRoute("/.pomerium", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePrefixRoute("/.pomerium/", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePathRoute("/.well-known/pomerium", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePrefixRoute("/.well-known/pomerium/", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
}
|
}
|
||||||
// per #837, only add robots.txt if there are no unauthenticated routes
|
// per #837, only add robots.txt if there are no unauthenticated routes
|
||||||
if !hasPublicPolicyMatchingURL(options, mustParseURL("https://"+domain+"/robots.txt")) {
|
if !hasPublicPolicyMatchingURL(options, mustParseURL("https://"+domain+"/robots.txt")) {
|
||||||
routes = append(routes, buildControlPlanePathRoute("/robots.txt", false))
|
if r, err := srv.buildControlPlanePathRoute("/robots.txt", false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if we're handling authentication, add the oauth2 callback url
|
// if we're handling authentication, add the oauth2 callback url
|
||||||
if config.IsAuthenticate(options.Services) && hostMatchesDomain(options.GetAuthenticateURL(), domain) {
|
if config.IsAuthenticate(options.Services) && hostMatchesDomain(options.GetAuthenticateURL(), domain) {
|
||||||
routes = append(routes, buildControlPlanePathRoute(options.AuthenticateCallbackPath, false))
|
if r, err := srv.buildControlPlanePathRoute(options.AuthenticateCallbackPath, false); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if we're the proxy and this is the forward-auth url
|
// if we're the proxy and this is the forward-auth url
|
||||||
if config.IsProxy(options.Services) && options.ForwardAuthURL != nil && hostMatchesDomain(options.GetForwardAuthURL(), domain) {
|
if config.IsProxy(options.Services) && options.ForwardAuthURL != nil && hostMatchesDomain(options.GetForwardAuthURL(), domain) {
|
||||||
routes = append(routes,
|
// disable ext_authz and pass request to proxy handlers that enable authN flow
|
||||||
// disable ext_authz and pass request to proxy handlers that enable authN flow
|
if r, err := srv.buildControlPlanePathAndQueryRoute("/verify", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI}); err != nil {
|
||||||
buildControlPlanePathAndQueryRoute("/verify", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI}),
|
return nil, err
|
||||||
buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI}),
|
} else {
|
||||||
buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI}),
|
routes = append(routes, r)
|
||||||
// otherwise, enforce ext_authz; pass all other requests through to an upstream
|
}
|
||||||
// handler that will simply respond with http status 200 / OK indicating that
|
if r, err := srv.buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI, urlutil.QuerySessionEncrypted, urlutil.QueryRedirectURI}); err != nil {
|
||||||
// the fronting forward-auth proxy can continue.
|
return nil, err
|
||||||
buildControlPlaneProtectedPrefixRoute("/"))
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
if r, err := srv.buildControlPlanePathAndQueryRoute("/", []string{urlutil.QueryForwardAuthURI}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise, enforce ext_authz; pass all other requests through to an upstream
|
||||||
|
// handler that will simply respond with http status 200 / OK indicating that
|
||||||
|
// the fronting forward-auth proxy can continue.
|
||||||
|
if r, err := srv.buildControlPlaneProtectedPrefixRoute("/"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
routes = append(routes, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return routes
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildControlPlaneProtectedPrefixRoute(prefix string) *envoy_config_route_v3.Route {
|
func (srv *Server) buildControlPlaneProtectedPrefixRoute(prefix string) (*envoy_config_route_v3.Route, error) {
|
||||||
return &envoy_config_route_v3.Route{
|
return &envoy_config_route_v3.Route{
|
||||||
Name: "pomerium-protected-prefix-" + prefix,
|
Name: "pomerium-protected-prefix-" + prefix,
|
||||||
Match: &envoy_config_route_v3.RouteMatch{
|
Match: &envoy_config_route_v3.RouteMatch{
|
||||||
|
@ -97,10 +157,10 @@ func buildControlPlaneProtectedPrefixRoute(prefix string) *envoy_config_route_v3
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildControlPlanePathAndQueryRoute(path string, queryparams []string) *envoy_config_route_v3.Route {
|
func (srv *Server) buildControlPlanePathAndQueryRoute(path string, queryparams []string) (*envoy_config_route_v3.Route, error) {
|
||||||
var queryParameterMatchers []*envoy_config_route_v3.QueryParameterMatcher
|
var queryParameterMatchers []*envoy_config_route_v3.QueryParameterMatcher
|
||||||
for _, q := range queryparams {
|
for _, q := range queryparams {
|
||||||
queryParameterMatchers = append(queryParameterMatchers,
|
queryParameterMatchers = append(queryParameterMatchers,
|
||||||
|
@ -126,10 +186,10 @@ func buildControlPlanePathAndQueryRoute(path string, queryparams []string) *envo
|
||||||
TypedPerFilterConfig: map[string]*any.Any{
|
TypedPerFilterConfig: map[string]*any.Any{
|
||||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||||
},
|
},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildControlPlanePathRoute(path string, protected bool) *envoy_config_route_v3.Route {
|
func (srv *Server) buildControlPlanePathRoute(path string, protected bool) (*envoy_config_route_v3.Route, error) {
|
||||||
r := &envoy_config_route_v3.Route{
|
r := &envoy_config_route_v3.Route{
|
||||||
Name: "pomerium-path-" + path,
|
Name: "pomerium-path-" + path,
|
||||||
Match: &envoy_config_route_v3.RouteMatch{
|
Match: &envoy_config_route_v3.RouteMatch{
|
||||||
|
@ -148,10 +208,10 @@ func buildControlPlanePathRoute(path string, protected bool) *envoy_config_route
|
||||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildControlPlanePrefixRoute(prefix string, protected bool) *envoy_config_route_v3.Route {
|
func (srv *Server) buildControlPlanePrefixRoute(prefix string, protected bool) (*envoy_config_route_v3.Route, error) {
|
||||||
r := &envoy_config_route_v3.Route{
|
r := &envoy_config_route_v3.Route{
|
||||||
Name: "pomerium-prefix-" + prefix,
|
Name: "pomerium-prefix-" + prefix,
|
||||||
Match: &envoy_config_route_v3.RouteMatch{
|
Match: &envoy_config_route_v3.RouteMatch{
|
||||||
|
@ -170,14 +230,14 @@ func buildControlPlanePrefixRoute(prefix string, protected bool) *envoy_config_r
|
||||||
"envoy.filters.http.ext_authz": disableExtAuthz,
|
"envoy.filters.http.ext_authz": disableExtAuthz,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var getPolicyName = func(policy *config.Policy) string {
|
var getPolicyName = func(policy *config.Policy) string {
|
||||||
return fmt.Sprintf("policy-%x", policy.RouteID())
|
return fmt.Sprintf("policy-%x", policy.RouteID())
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_route_v3.Route {
|
func (srv *Server) buildPolicyRoutes(options *config.Options, domain string) ([]*envoy_config_route_v3.Route, error) {
|
||||||
var routes []*envoy_config_route_v3.Route
|
var routes []*envoy_config_route_v3.Route
|
||||||
responseHeadersToAdd := toEnvoyHeaders(options.Headers)
|
responseHeadersToAdd := toEnvoyHeaders(options.Headers)
|
||||||
|
|
||||||
|
@ -222,19 +282,25 @@ func buildPolicyRoutes(options *config.Options, domain string) []*envoy_config_r
|
||||||
ResponseHeadersToAdd: responseHeadersToAdd,
|
ResponseHeadersToAdd: responseHeadersToAdd,
|
||||||
}
|
}
|
||||||
if policy.Redirect != nil {
|
if policy.Redirect != nil {
|
||||||
envoyRoute.Action = &envoy_config_route_v3.Route_Redirect{
|
action, err := srv.buildPolicyRouteRedirectAction(policy.Redirect)
|
||||||
Redirect: buildPolicyRouteRedirectAction(policy.Redirect),
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
envoyRoute.Action = &envoy_config_route_v3.Route_Redirect{Redirect: action}
|
||||||
} else {
|
} else {
|
||||||
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: buildPolicyRouteRouteAction(options, &policy)}
|
action, err := srv.buildPolicyRouteRouteAction(options, &policy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
envoyRoute.Action = &envoy_config_route_v3.Route_Route{Route: action}
|
||||||
}
|
}
|
||||||
|
|
||||||
routes = append(routes, envoyRoute)
|
routes = append(routes, envoyRoute)
|
||||||
}
|
}
|
||||||
return routes
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPolicyRouteRedirectAction(r *config.PolicyRedirect) *envoy_config_route_v3.RedirectAction {
|
func (srv *Server) buildPolicyRouteRedirectAction(r *config.PolicyRedirect) (*envoy_config_route_v3.RedirectAction, error) {
|
||||||
action := &envoy_config_route_v3.RedirectAction{}
|
action := &envoy_config_route_v3.RedirectAction{}
|
||||||
switch {
|
switch {
|
||||||
case r.HTTPSRedirect != nil:
|
case r.HTTPSRedirect != nil:
|
||||||
|
@ -268,10 +334,10 @@ func buildPolicyRouteRedirectAction(r *config.PolicyRedirect) *envoy_config_rout
|
||||||
if r.StripQuery != nil {
|
if r.StripQuery != nil {
|
||||||
action.StripQuery = *r.StripQuery
|
action.StripQuery = *r.StripQuery
|
||||||
}
|
}
|
||||||
return action
|
return action, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildPolicyRouteRouteAction(options *config.Options, policy *config.Policy) *envoy_config_route_v3.RouteAction {
|
func (srv *Server) buildPolicyRouteRouteAction(options *config.Options, policy *config.Policy) (*envoy_config_route_v3.RouteAction, error) {
|
||||||
clusterName := getPolicyName(policy)
|
clusterName := getPolicyName(policy)
|
||||||
routeTimeout := getRouteTimeout(options, policy)
|
routeTimeout := getRouteTimeout(options, policy)
|
||||||
idleTimeout := getRouteIdleTimeout(policy)
|
idleTimeout := getRouteIdleTimeout(policy)
|
||||||
|
@ -307,7 +373,7 @@ func buildPolicyRouteRouteAction(options *config.Options, policy *config.Policy)
|
||||||
RegexRewrite: regexRewrite,
|
RegexRewrite: regexRewrite,
|
||||||
}
|
}
|
||||||
setHostRewriteOptions(policy, action)
|
setHostRewriteOptions(policy, action)
|
||||||
return action
|
return action, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkEnvoyHeader(k, v string) *envoy_config_core_v3.HeaderValueOption {
|
func mkEnvoyHeader(k, v string) *envoy_config_core_v3.HeaderValueOption {
|
||||||
|
|
|
@ -7,9 +7,11 @@ import (
|
||||||
|
|
||||||
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
envoy_config_route_v3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
|
"github.com/pomerium/pomerium/internal/controlplane/filemgr"
|
||||||
"github.com/pomerium/pomerium/internal/testutil"
|
"github.com/pomerium/pomerium/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +24,9 @@ func policyNameFunc() func(*config.Policy) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildGRPCRoutes(t *testing.T) {
|
func Test_buildGRPCRoutes(t *testing.T) {
|
||||||
routes := buildGRPCRoutes()
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
routes, err := srv.buildGRPCRoutes()
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
@ -46,6 +50,7 @@ func Test_buildGRPCRoutes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
||||||
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
routeString := func(typ, name string, protected bool) string {
|
routeString := func(typ, name string, protected bool) string {
|
||||||
str := `{
|
str := `{
|
||||||
"name": "pomerium-` + typ + `-` + name + `",
|
"name": "pomerium-` + typ + `-` + name + `",
|
||||||
|
@ -76,7 +81,8 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
||||||
AuthenticateCallbackPath: "/oauth2/callback",
|
AuthenticateCallbackPath: "/oauth2/callback",
|
||||||
ForwardAuthURL: mustParseURL("https://forward-auth.example.com"),
|
ForwardAuthURL: mustParseURL("https://forward-auth.example.com"),
|
||||||
}
|
}
|
||||||
routes := buildPomeriumHTTPRoutes(options, "authenticate.example.com")
|
routes, err := srv.buildPomeriumHTTPRoutes(options, "authenticate.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `[
|
testutil.AssertProtoJSONEqual(t, `[
|
||||||
`+routeString("path", "/.pomerium/jwt", true)+`,
|
`+routeString("path", "/.pomerium/jwt", true)+`,
|
||||||
|
@ -105,7 +111,8 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
_ = options.Policies[0].Validate()
|
_ = options.Policies[0].Validate()
|
||||||
routes := buildPomeriumHTTPRoutes(options, "from.example.com")
|
routes, err := srv.buildPomeriumHTTPRoutes(options, "from.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `[
|
testutil.AssertProtoJSONEqual(t, `[
|
||||||
`+routeString("path", "/.pomerium/jwt", true)+`,
|
`+routeString("path", "/.pomerium/jwt", true)+`,
|
||||||
|
@ -134,7 +141,8 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
_ = options.Policies[0].Validate()
|
_ = options.Policies[0].Validate()
|
||||||
routes := buildPomeriumHTTPRoutes(options, "from.example.com")
|
routes, err := srv.buildPomeriumHTTPRoutes(options, "from.example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `[
|
testutil.AssertProtoJSONEqual(t, `[
|
||||||
`+routeString("path", "/.pomerium/jwt", true)+`,
|
`+routeString("path", "/.pomerium/jwt", true)+`,
|
||||||
|
@ -151,7 +159,9 @@ func Test_buildPomeriumHTTPRoutes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildControlPlanePathRoute(t *testing.T) {
|
func Test_buildControlPlanePathRoute(t *testing.T) {
|
||||||
route := buildControlPlanePathRoute("/hello/world", false)
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
route, err := srv.buildControlPlanePathRoute("/hello/world", false)
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "pomerium-path-/hello/world",
|
"name": "pomerium-path-/hello/world",
|
||||||
|
@ -172,7 +182,9 @@ func Test_buildControlPlanePathRoute(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildControlPlanePrefixRoute(t *testing.T) {
|
func Test_buildControlPlanePrefixRoute(t *testing.T) {
|
||||||
route := buildControlPlanePrefixRoute("/hello/world/", false)
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
route, err := srv.buildControlPlanePrefixRoute("/hello/world/", false)
|
||||||
|
require.NoError(t, err)
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
{
|
{
|
||||||
"name": "pomerium-prefix-/hello/world/",
|
"name": "pomerium-prefix-/hello/world/",
|
||||||
|
@ -197,7 +209,9 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
getPolicyName = f
|
getPolicyName = f
|
||||||
}(getPolicyName)
|
}(getPolicyName)
|
||||||
getPolicyName = policyNameFunc()
|
getPolicyName = policyNameFunc()
|
||||||
routes := buildPolicyRoutes(&config.Options{
|
|
||||||
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||||
CookieName: "pomerium",
|
CookieName: "pomerium",
|
||||||
DefaultUpstreamTimeout: time.Second * 3,
|
DefaultUpstreamTimeout: time.Second * 3,
|
||||||
Policies: []config.Policy{
|
Policies: []config.Policy{
|
||||||
|
@ -260,6 +274,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, "example.com")
|
}, "example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
[
|
[
|
||||||
|
@ -473,7 +488,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
`, routes)
|
`, routes)
|
||||||
|
|
||||||
t.Run("tcp", func(t *testing.T) {
|
t.Run("tcp", func(t *testing.T) {
|
||||||
routes = buildPolicyRoutes(&config.Options{
|
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||||
CookieName: "pomerium",
|
CookieName: "pomerium",
|
||||||
DefaultUpstreamTimeout: time.Second * 3,
|
DefaultUpstreamTimeout: time.Second * 3,
|
||||||
Policies: []config.Policy{
|
Policies: []config.Policy{
|
||||||
|
@ -488,6 +503,7 @@ func Test_buildPolicyRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, "example.com:22")
|
}, "example.com:22")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
[
|
[
|
||||||
|
@ -555,7 +571,8 @@ func TestAddOptionsHeadersToResponse(t *testing.T) {
|
||||||
getPolicyName = f
|
getPolicyName = f
|
||||||
}(getPolicyName)
|
}(getPolicyName)
|
||||||
getPolicyName = policyNameFunc()
|
getPolicyName = policyNameFunc()
|
||||||
routes := buildPolicyRoutes(&config.Options{
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||||
CookieName: "pomerium",
|
CookieName: "pomerium",
|
||||||
DefaultUpstreamTimeout: time.Second * 3,
|
DefaultUpstreamTimeout: time.Second * 3,
|
||||||
Policies: []config.Policy{
|
Policies: []config.Policy{
|
||||||
|
@ -566,6 +583,7 @@ func TestAddOptionsHeadersToResponse(t *testing.T) {
|
||||||
},
|
},
|
||||||
Headers: map[string]string{"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"},
|
Headers: map[string]string{"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload"},
|
||||||
}, "example.com")
|
}, "example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
[
|
[
|
||||||
|
@ -609,7 +627,8 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
getPolicyName = f
|
getPolicyName = f
|
||||||
}(getPolicyName)
|
}(getPolicyName)
|
||||||
getPolicyName = policyNameFunc()
|
getPolicyName = policyNameFunc()
|
||||||
routes := buildPolicyRoutes(&config.Options{
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
|
routes, err := srv.buildPolicyRoutes(&config.Options{
|
||||||
CookieName: "pomerium",
|
CookieName: "pomerium",
|
||||||
DefaultUpstreamTimeout: time.Second * 3,
|
DefaultUpstreamTimeout: time.Second * 3,
|
||||||
Policies: []config.Policy{
|
Policies: []config.Policy{
|
||||||
|
@ -652,6 +671,7 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, "example.com")
|
}, "example.com")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testutil.AssertProtoJSONEqual(t, `
|
testutil.AssertProtoJSONEqual(t, `
|
||||||
[
|
[
|
||||||
|
@ -822,19 +842,22 @@ func Test_buildPolicyRoutesRewrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
|
srv := &Server{filemgr: filemgr.NewManager()}
|
||||||
t.Run("HTTPSRedirect", func(t *testing.T) {
|
t.Run("HTTPSRedirect", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
HTTPSRedirect: proto.Bool(true),
|
HTTPSRedirect: proto.Bool(true),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
||||||
HttpsRedirect: true,
|
HttpsRedirect: true,
|
||||||
},
|
},
|
||||||
}, action)
|
}, action)
|
||||||
|
|
||||||
action = buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err = srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
HTTPSRedirect: proto.Bool(false),
|
HTTPSRedirect: proto.Bool(false),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_HttpsRedirect{
|
||||||
HttpsRedirect: false,
|
HttpsRedirect: false,
|
||||||
|
@ -842,9 +865,10 @@ func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("SchemeRedirect", func(t *testing.T) {
|
t.Run("SchemeRedirect", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
SchemeRedirect: proto.String("https"),
|
SchemeRedirect: proto.String("https"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_SchemeRedirect{
|
SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_SchemeRedirect{
|
||||||
SchemeRedirect: "https",
|
SchemeRedirect: "https",
|
||||||
|
@ -852,25 +876,28 @@ func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("HostRedirect", func(t *testing.T) {
|
t.Run("HostRedirect", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
HostRedirect: proto.String("HOST"),
|
HostRedirect: proto.String("HOST"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
HostRedirect: "HOST",
|
HostRedirect: "HOST",
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("PortRedirect", func(t *testing.T) {
|
t.Run("PortRedirect", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
PortRedirect: proto.Uint32(1234),
|
PortRedirect: proto.Uint32(1234),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
PortRedirect: 1234,
|
PortRedirect: 1234,
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("PathRedirect", func(t *testing.T) {
|
t.Run("PathRedirect", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
PathRedirect: proto.String("PATH"),
|
PathRedirect: proto.String("PATH"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PathRedirect{
|
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PathRedirect{
|
||||||
PathRedirect: "PATH",
|
PathRedirect: "PATH",
|
||||||
|
@ -878,9 +905,10 @@ func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("PrefixRewrite", func(t *testing.T) {
|
t.Run("PrefixRewrite", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
PrefixRewrite: proto.String("PREFIX_REWRITE"),
|
PrefixRewrite: proto.String("PREFIX_REWRITE"),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PrefixRewrite{
|
PathRewriteSpecifier: &envoy_config_route_v3.RedirectAction_PrefixRewrite{
|
||||||
PrefixRewrite: "PREFIX_REWRITE",
|
PrefixRewrite: "PREFIX_REWRITE",
|
||||||
|
@ -888,17 +916,19 @@ func Test_buildPolicyRouteRedirectAction(t *testing.T) {
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("ResponseCode", func(t *testing.T) {
|
t.Run("ResponseCode", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
ResponseCode: proto.Int32(301),
|
ResponseCode: proto.Int32(301),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
ResponseCode: 301,
|
ResponseCode: 301,
|
||||||
}, action)
|
}, action)
|
||||||
})
|
})
|
||||||
t.Run("StripQuery", func(t *testing.T) {
|
t.Run("StripQuery", func(t *testing.T) {
|
||||||
action := buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
action, err := srv.buildPolicyRouteRedirectAction(&config.PolicyRedirect{
|
||||||
StripQuery: proto.Bool(true),
|
StripQuery: proto.Bool(true),
|
||||||
})
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
assert.Equal(t, &envoy_config_route_v3.RedirectAction{
|
||||||
StripQuery: true,
|
StripQuery: true,
|
||||||
}, action)
|
}, action)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue