-
Notifications
You must be signed in to change notification settings - Fork 695
Description
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 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 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
TLSContextthat 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
TLSContextfor 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-certThis 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_host--- apiVersion: getambassador.io/v2 kind: TLSContext metadata name: wild-context spec: alpn_protocols: h2,http/1.1 hosts: - "*" secret: wild-certNow, when the browser reuses the connection, Ambassador will use the same
virtual_hostwhich will match for all:authoritys