mirror of https://github.com/status-im/consul.git
Append port number to ingress host domain (#8190)
A port can be sent in the Host header as defined in the HTTP RFC, so we take any hosts that we want to match traffic to and also add another host with the listener port added. Also fix an issue with envoy integration tests not running the case-ingress-gateway-tls test.
This commit is contained in:
parent
74350bb5c3
commit
735337b170
|
@ -3,6 +3,7 @@ package xds
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
envoy "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
||||
|
@ -98,19 +99,7 @@ func routesFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto
|
|||
continue
|
||||
}
|
||||
|
||||
namespace := u.GetEnterpriseMeta().NamespaceOrDefault()
|
||||
var domains []string
|
||||
switch {
|
||||
case len(u.IngressHosts) > 0:
|
||||
// If a user has specified hosts, do not add the default
|
||||
// "<service-name>.ingress.*" prefixes
|
||||
domains = u.IngressHosts
|
||||
case namespace != structs.IntentionDefaultNamespace:
|
||||
domains = []string{fmt.Sprintf("%s.ingress.%s.*", chain.ServiceName, namespace)}
|
||||
default:
|
||||
domains = []string{fmt.Sprintf("%s.ingress.*", chain.ServiceName)}
|
||||
}
|
||||
|
||||
domains := generateUpstreamIngressDomains(listenerKey, u)
|
||||
virtualHost, err := makeUpstreamRouteForDiscoveryChain(upstreamID, chain, domains)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -124,6 +113,52 @@ func routesFromSnapshotIngressGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func generateUpstreamIngressDomains(listenerKey proxycfg.IngressListenerKey, u structs.Upstream) []string {
|
||||
var domains []string
|
||||
domainsSet := make(map[string]bool)
|
||||
|
||||
namespace := u.GetEnterpriseMeta().NamespaceOrDefault()
|
||||
switch {
|
||||
case len(u.IngressHosts) > 0:
|
||||
// If a user has specified hosts, do not add the default
|
||||
// "<service-name>.ingress.*" prefixes
|
||||
domains = u.IngressHosts
|
||||
case namespace != structs.IntentionDefaultNamespace:
|
||||
domains = []string{fmt.Sprintf("%s.ingress.%s.*", u.DestinationName, namespace)}
|
||||
default:
|
||||
domains = []string{fmt.Sprintf("%s.ingress.*", u.DestinationName)}
|
||||
}
|
||||
|
||||
for _, h := range domains {
|
||||
domainsSet[h] = true
|
||||
}
|
||||
|
||||
// Host headers may contain port numbers in them, so we need to make sure
|
||||
// we match on the host with and without the port number. Well-known
|
||||
// ports like HTTP/HTTPS are stripped from Host headers, but other ports
|
||||
// will be in the header.
|
||||
for _, h := range domains {
|
||||
_, _, err := net.SplitHostPort(h)
|
||||
// Error message from Go's net/ipsock.go
|
||||
// We check to see if a port is not missing, and ignore the
|
||||
// error from SplitHostPort otherwise, since we have previously
|
||||
// validated the Host values and should trust the user's input.
|
||||
if err == nil || !strings.Contains(err.Error(), "missing port in address") {
|
||||
continue
|
||||
}
|
||||
|
||||
domainWithPort := fmt.Sprintf("%s:%d", h, listenerKey.Port)
|
||||
|
||||
// Do not add a duplicate domain if a hostname with port is already in the
|
||||
// set
|
||||
if !domainsSet[domainWithPort] {
|
||||
domains = append(domains, domainWithPort)
|
||||
}
|
||||
}
|
||||
|
||||
return domains
|
||||
}
|
||||
|
||||
func makeUpstreamRouteForDiscoveryChain(
|
||||
routeName string,
|
||||
chain *structs.CompiledDiscoveryChain,
|
||||
|
|
|
@ -117,7 +117,11 @@ func TestRoutesFromSnapshot(t *testing.T) {
|
|||
{
|
||||
DestinationName: "foo",
|
||||
LocalBindPort: 8080,
|
||||
IngressHosts: []string{"test1.example.com", "test2.example.com"},
|
||||
IngressHosts: []string{
|
||||
"test1.example.com",
|
||||
"test2.example.com",
|
||||
"test2.example.com:8080",
|
||||
},
|
||||
},
|
||||
{
|
||||
DestinationName: "bar",
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{
|
||||
"name": "baz",
|
||||
"domains": [
|
||||
"baz.ingress.*"
|
||||
"baz.ingress.*",
|
||||
"baz.ingress.*:443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
@ -24,7 +25,8 @@
|
|||
{
|
||||
"name": "qux",
|
||||
"domains": [
|
||||
"qux.ingress.*"
|
||||
"qux.ingress.*",
|
||||
"qux.ingress.*:443"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
@ -48,7 +50,9 @@
|
|||
"name": "foo",
|
||||
"domains": [
|
||||
"test1.example.com",
|
||||
"test2.example.com"
|
||||
"test2.example.com",
|
||||
"test2.example.com:8080",
|
||||
"test1.example.com:8080"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
@ -64,7 +68,8 @@
|
|||
{
|
||||
"name": "bar",
|
||||
"domains": [
|
||||
"bar.ingress.*"
|
||||
"bar.ingress.*",
|
||||
"bar.ingress.*:8080"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"db.ingress.*"
|
||||
"db.ingress.*",
|
||||
"db.ingress.*:9191"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"db.ingress.*"
|
||||
"db.ingress.*",
|
||||
"db.ingress.*:9191"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"db.ingress.*"
|
||||
"db.ingress.*",
|
||||
"db.ingress.*:9191"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
{
|
||||
"name": "db",
|
||||
"domains": [
|
||||
"db.ingress.*"
|
||||
"db.ingress.*",
|
||||
"db.ingress.*:9191"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
|
|
|
@ -18,6 +18,15 @@ config_entries {
|
|||
}
|
||||
|
||||
listeners = [
|
||||
{
|
||||
port = 9998
|
||||
protocol = "http"
|
||||
services = [
|
||||
{
|
||||
name = "s1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
port = 9999
|
||||
protocol = "http"
|
||||
|
|
|
@ -23,12 +23,12 @@ load helpers
|
|||
}
|
||||
|
||||
@test "should be able to connect to s1 through the TLS-enabled ingress port" {
|
||||
assert_dnssan_in_cert localhost:9999 '\*.ingress.consul'
|
||||
assert_dnssan_in_cert localhost:9998 '\*.ingress.consul'
|
||||
# Use the --resolve argument to fake dns resolution for now so we can use the
|
||||
# s1.ingress.consul domain to validate the cert
|
||||
run retry_default curl --cacert <(get_ca_root) -s -f -d hello \
|
||||
--resolve s1.ingress.consul:9999:127.0.0.1 \
|
||||
https://s1.ingress.consul:9999
|
||||
--resolve s1.ingress.consul:9998:127.0.0.1 \
|
||||
https://s1.ingress.consul:9998
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "hello" ]
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ func TestEnvoy(t *testing.T) {
|
|||
"case-ingress-gateway-http",
|
||||
"case-ingress-gateway-multiple-services",
|
||||
"case-ingress-gateway-simple",
|
||||
"case-ingress-gateway-tls",
|
||||
"case-ingress-mesh-gateways-resolver",
|
||||
"case-multidc-rsa-ca",
|
||||
"case-prometheus",
|
||||
|
|
Loading…
Reference in New Issue