Is your feature request related to a problem? Please describe.
When zot is run as a shared registry / pull-through cache that fronts more than one domain, http.tls only supports a single server certificate and a single client-CA. So today, to serve N domains — each needing its own server cert, and (for mTLS) its own client-CA trust domain — you have to either:
- run one zot instance per domain (N× the footprint, split metadata/storage/state), or
- terminate TLS/mTLS in a front proxy (e.g. Traefik) and talk plaintext to zot — which moves cert management out of zot and, more importantly, collapses the per-domain mTLS trust domains: zot can no longer distinguish which CA a client authenticated against, so per-domain client identities can't flow into zot's own
accessControl.
Concretely: we operate a single zot as an on-demand cache in front of several upstream registries reached under different domains (e.g. hub.a.com, hub.b.com), where each domain has its own server cert and its own client-CA (independent CI identities). One cert + one client-CA can't express that.
Describe the solution you'd like
Add an optional http.tls.additionalCerts list, each entry {domain, cert, key, cacert}, selected per-connection by SNI at the TLS handshake (a GetConfigForClient-style resolver):
Behaviour:
- SNI dispatch selects the per-domain
tls.Config: exact match → single left-most-label wildcard (*.example.com) → default fallback.
- Each entry isolates both the server cert and
ClientCAs, so mTLS for each domain is verified against that domain's CA only — independent trust domains, per-domain client identities usable by accessControl.
- Server certs keep the existing fsnotify hot-reload.
- Fully backward compatible: when
additionalCerts is empty, the legacy single-certificate path is used unchanged (zero behaviour difference).
Describe alternatives you've considered
- One zot per domain — N× resource cost and operational overhead, and splits storage/metaDB/cache state that we specifically want shared.
- TLS/mTLS termination in a front proxy — extra hop, cert management leaves zot, and (the blocker) per-domain mTLS trust domains collapse: zot no longer sees which CA the client authenticated against, so per-domain identities can't drive zot's
accessControl.
- A single SAN/multi-SAN server cert — solves server-side hostnames but cannot give each domain an independent client-CA / mTLS trust domain.
Additional context
We have a working implementation on a local branch and are happy to open a PR if there's interest:
config: TLSConfig.AdditionalCerts []TLSCertPair{Domain,Cert,Key,CACert}; deep-copy in CopyTLSConfig; IsMTLSAuthEnabled counts per-domain CAs.
api: a new SNI resolver selecting a per-connection tls.Config by ServerName (exact → wildcard → default), isolating server cert + ClientCAs per domain; fsnotify reload preserved.
controller: resolver wired behind an AdditionalCerts guard; legacy single-cert path untouched when the list is empty.
cli: validateTLS requires domain+cert+key per entry and rejects duplicate domains.
- examples + docs + unit tests (SNI selection incl. wildcard/fallback, per-domain mTLS isolation).
Is this something the maintainers would be open to upstreaming? Happy to align on the config shape and naming before sending the PR.
Is your feature request related to a problem? Please describe.
When zot is run as a shared registry / pull-through cache that fronts more than one domain,
http.tlsonly supports a single server certificate and a single client-CA. So today, to serve N domains — each needing its own server cert, and (for mTLS) its own client-CA trust domain — you have to either:accessControl.Concretely: we operate a single zot as an on-demand cache in front of several upstream registries reached under different domains (e.g.
hub.a.com,hub.b.com), where each domain has its own server cert and its own client-CA (independent CI identities). One cert + one client-CA can't express that.Describe the solution you'd like
Add an optional
http.tls.additionalCertslist, each entry{domain, cert, key, cacert}, selected per-connection by SNI at the TLS handshake (aGetConfigForClient-style resolver):Behaviour:
tls.Config: exact match → single left-most-label wildcard (*.example.com) → default fallback.ClientCAs, so mTLS for each domain is verified against that domain's CA only — independent trust domains, per-domain client identities usable byaccessControl.additionalCertsis empty, the legacy single-certificate path is used unchanged (zero behaviour difference).Describe alternatives you've considered
accessControl.Additional context
We have a working implementation on a local branch and are happy to open a PR if there's interest:
config:TLSConfig.AdditionalCerts []TLSCertPair{Domain,Cert,Key,CACert}; deep-copy inCopyTLSConfig;IsMTLSAuthEnabledcounts per-domain CAs.api: a new SNI resolver selecting a per-connectiontls.ConfigbyServerName(exact → wildcard → default), isolating server cert +ClientCAsper domain; fsnotify reload preserved.controller: resolver wired behind anAdditionalCertsguard; legacy single-cert path untouched when the list is empty.cli:validateTLSrequiresdomain+cert+keyper entry and rejects duplicate domains.Is this something the maintainers would be open to upstreaming? Happy to align on the config shape and naming before sending the PR.