When you have multiple domains use the same certificate (e.g. the server has a certificate that can be used for domain domain.com and subdomains a.domain.com and b.domain.com) and the server supports HTTP/2, the browser will reuse the same connection for requests to domain.com, a.domain.com, and b.domain.com. See this blog post for more info.
If you have created an individual virtual_host for each of these domains in Ambassador (via Host resources or TLSContexts) Ambassador will reuse the same virtual_host, but with a different host in the request and you will get a 404.
In more detail, if you create a TLSContext like the below:
---
apiVersion: getambassador.io/v2
kind: TLSContext
metadata:
name: context
spec:
alpn_protocols: h2,http/1.1
hosts:
- domain.com
- a.domain.com
- b.domain.com
secret: ambassador-cert
You will get an Ambassador configured where:
- Ambassador will create three
virtual_hosts, one for each of the hosts.
ambassador-cert is pointing at a certificate that works for domain.com, a.domain.com and b.domain.com so Ambassador is able to use the same certificate for each of these virtual_hosts
alpn_protocols: h2,http/1.1 is set so the browser will use HTTP/2 for the connection to Ambassador
Now, when you send a request to https://a.domain.com/ambassador/v0/diag/ in a web browser, it opens a single HTTP/2 connection to Ambassador with :authority: a.domain.com. Ambassador then looks for a route in virtual_host: a.domain.com, find the route to /ambassador/v0, and correctly sends the request to the diagnostics page.
Now if you change the url to https://b.domain.com/ambassador/v0/diag/, the browser will reuse this same HTTP/2 connection to Ambassador but with :authority: b.domain.com. Ambassador then, reusing the same connection to virtual_host: a.domain.com, looks for a route in virtual_host: a.domain.com but since the :authority headers do not match any routes, returns a 404.
To Reproduce
Reproduction is pretty simple.
-
Deploy Ambassador
-
Get a certificate for *.domain.com
-
Create a TLSContext that uses that certificate and sets
- alpn_protocols: h2,http/1.1
- hosts: [ a.domain.com, b.domain.com]
-
Send a request to https://a.domain.com/ambassador/v0/diag/ in a browser and get the diag page
-
Change the url to https://b.domain.com/ambassador/v0/diag/ and get a 404
Workaround
Since this issue revolves around how Ambassador is creating virtual_hosts and using the same certificate, a couple of possible workarounds exist that could be used until this is resolved.
-
Create a different certificate and TLSContext for each domain
---
apiVersion: getambassador.io/v2
kind: TLSContext
metadata
name: domain-context
spec:
alpn_protocols: h2,http/1.1
hosts:
- domain.com
secret: domain-cert
---
apiVersion: getambassador.io/v2
kind: TLSContext
metadata
name: a-domain-context
spec:
alpn_protocols: h2,http/1.1
hosts:
- a.domain.com
secret: a-domain-cert
---
apiVersion: getambassador.io/v2
kind: TLSContext
metadata
name: b-domain-context
spec:
alpn_protocols: h2,http/1.1
hosts:
- b.domain.com
secret: b-domain-cert
This will make is so the browser does not reuse the same connection for a.domain.com and b.domain.com since it cannot use the same certificate.
-
Use a wildcard in the TLSContext so that domain.com, a.domain.com, and b.domain.com use the same virtual_host
---
apiVersion: getambassador.io/v2
kind: TLSContext
metadata
name: wild-context
spec:
alpn_protocols: h2,http/1.1
hosts:
- "*"
secret: wild-cert
Now, when the browser reuses the connection, Ambassador will use the same virtual_host which will match for all :authoritys
When you have multiple domains use the same certificate (e.g. the server has a certificate that can be used for domain
domain.comand subdomainsa.domain.comandb.domain.com) and the server supports HTTP/2, the browser will reuse the same connection for requests todomain.com,a.domain.com, andb.domain.com. See this blog post for more info.If you have created an individual
virtual_hostfor each of these domains in Ambassador (viaHostresources orTLSContexts) Ambassador will reuse the samevirtual_host, but with a differenthostin the request and you will get a404.In more detail, if you create a
TLSContextlike the below:You will get an Ambassador configured where:
virtual_hosts, one for each of thehosts.ambassador-certis pointing at a certificate that works fordomain.com,a.domain.comandb.domain.comso Ambassador is able to use the same certificate for each of thesevirtual_hostsalpn_protocols: h2,http/1.1is set so the browser will useHTTP/2for the connection to AmbassadorNow, when you send a request to https://a.domain.com/ambassador/v0/diag/ in a web browser, it opens a single HTTP/2 connection to Ambassador with
:authority: a.domain.com. Ambassador then looks for a route invirtual_host: a.domain.com, find the route to/ambassador/v0, and correctly sends the request to the diagnostics page.Now if you change the url to https://b.domain.com/ambassador/v0/diag/, the browser will reuse this same HTTP/2 connection to Ambassador but with
:authority: b.domain.com. Ambassador then, reusing the same connection tovirtual_host: a.domain.com, looks for a route invirtual_host: a.domain.combut since the:authorityheaders do not match any routes, returns a 404.To Reproduce
Reproduction is pretty simple.
Deploy Ambassador
Get a certificate for
*.domain.comCreate a
TLSContextthat uses that certificate and setsSend a request to https://a.domain.com/ambassador/v0/diag/ in a browser and get the diag page
Change the url to https://b.domain.com/ambassador/v0/diag/ and get a 404
Workaround
Since this issue revolves around how Ambassador is creating
virtual_hostsand using the same certificate, a couple of possible workarounds exist that could be used until this is resolved.Create a different certificate and
TLSContextfor each domainThis will make is so the browser does not reuse the same connection for a.domain.com and b.domain.com since it cannot use the same certificate.
Use a wildcard in the
TLSContextso thatdomain.com,a.domain.com, andb.domain.comuse the samevirtual_hostNow, when the browser reuses the connection, Ambassador will use the same
virtual_hostwhich will match for all:authoritys