Skip to content

Project with multiple domains failing with pages cache enabled

The problem

The root cause of the "multiple domains on the same project" failing when the cache is enabled, is that we're caching the /api/internal/pages payload under the project id, among other stuff. Which means that the cached certificates are always returned for all the domains in the same project.

For example, I added two domains in the same project:

domain cert (first line)
foo.bar MIIDYTCCAkmgAwIBAgIUIdH6Eae0BfFz+tT7CoivAZBWPi8wDQYJKoZIhvcNAQEL
aaaa.bbbb MIIDazCCAlOgAwIBAgIUTkwJffm429SM4IytBUhMVseOJnEwDQYJKoZIhvcNAQEL
  • With the cache disabled
$ curl -s "http://gdk.test:3000/api/v4/internal/pages?host=aaaa.bbbb" | jq '.certificate | split("\r\n")[1] '
"MIIDazCCAlOgAwIBAgIUTkwJffm429SM4IytBUhMVseOJnEwDQYJKoZIhvcNAQEL"

$ curl -s "http://gdk.test:3000/api/v4/internal/pages?host=foo.bar" | jq '.certificate | split("\r\n")[1] '
"MIIDYTCCAkmgAwIBAgIUIdH6Eae0BfFz+tT7CoivAZBWPi8wDQYJKoZIhvcNAQEL"
  • With the cache enabled
$ curl -s "http://gdk.test:3000/api/v4/internal/pages?host=aaaa.bbbb" | jq '.certificate | split("\r\n")[1] '
"MIIDYTCCAkmgAwIBAgIUIdH6Eae0BfFz+tT7CoivAZBWPi8wDQYJKoZIhvcNAQEL"

$ curl -s "http://gdk.test:3000/api/v4/internal/pages?host=foo.bar" | jq '.certificate | split("\r\n")[1] '
"MIIDYTCCAkmgAwIBAgIUIdH6Eae0BfFz+tT7CoivAZBWPi8wDQYJKoZIhvcNAQEL"

Proposed Solution

The cache is created in the lib/api/internal/pages from either the Namespace or the PagesDomain.

Namespace.find_by_pages_host(params[:host]) || PagesDomain.find_by_domain_case_insensitive(params[:host])

When the cache was created from the PagesDomain, we were using the project.id associated to the PagesDomain in the cache key. Since one project might have many PageDomains, the solution would be to, instead of using the project.id, use the domain.id in the cache key.

This way, instead of Gitlab::Pages::CacheControl.for_project we could have Gitlab::Pages::CacheControl.for_domain.

One important detail is to ensure that all the events that invalidate the cache relate to a PagesDomain should now also expose the domain.id.

Edited by Kassio Borges