pki: honor skip_install_trust for explicit tls internal issuers

Site-level tls internal creates its own CA independently of
auto_https, silently ignoring skip_install_trust.

Fixes #7893
This commit is contained in:
gautamrizwani 2026-07-19 20:23:43 +05:30
parent 93c0721156
commit 43f1110999
No known key found for this signature in database
2 changed files with 119 additions and 0 deletions

View file

@ -22,6 +22,7 @@ import (
"github.com/caddyserver/caddy/v2/caddyconfig"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddypki"
"github.com/caddyserver/caddy/v2/modules/caddytls"
)
func init() {
@ -260,5 +261,33 @@ func (st ServerType) buildPKIApp(
pkiApp.CAs[ca.ID] = ca
}
// an explicit site-level internal issuer creates its own CA
// regardless of `auto_https`, so make sure `skip_install_trust`
// is honored for it too; otherwise the CA is created later at
// runtime with trust installation left on
if skipInstallTrust {
for _, p := range pairings {
for _, sblock := range p.serverBlocks {
for _, issuerCfgValue := range sblock.pile["tls.cert_issuer"] {
internalIssuer, ok := issuerCfgValue.Value.(*caddytls.InternalIssuer)
if !ok {
continue
}
caID := internalIssuer.CA
if caID == "" {
caID = caddypki.DefaultCAID
}
if _, ok := pkiApp.CAs[caID]; ok {
continue
}
ca := new(caddypki.CA)
ca.ID = caID
ca.InstallTrust = &falseBool
pkiApp.CAs[ca.ID] = ca
}
}
}
}
return pkiApp, warnings, nil
}

View file

@ -67,6 +67,96 @@ func TestParsePKIApp_maintenanceIntervalAndRenewalWindowRatio(t *testing.T) {
}
}
// adaptedPKIConfig runs the given Caddyfile through the adapter and
// returns just the parts of the resulting JSON this test cares about:
// which CAs got a certificate_authorities entry, and whether install_trust
// was set to false for each.
func adaptedPKIConfig(t *testing.T, input string) map[string]struct {
InstallTrust *bool `json:"install_trust,omitempty"`
} {
t.Helper()
adapter := caddyfile.Adapter{ServerType: ServerType{}}
out, _, err := adapter.Adapt([]byte(input), nil)
if err != nil {
t.Fatalf("Adapt failed: %v", err)
}
var cfg struct {
Apps struct {
PKI struct {
CertificateAuthorities map[string]struct {
InstallTrust *bool `json:"install_trust,omitempty"`
} `json:"certificate_authorities,omitempty"`
} `json:"pki,omitempty"`
} `json:"apps"`
}
if err := json.Unmarshal(out, &cfg); err != nil {
t.Fatalf("unmarshal config: %v", err)
}
return cfg.Apps.PKI.CertificateAuthorities
}
func TestParsePKIApp_skipInstallTrustHonoredForInternalTLSDefaultCA(t *testing.T) {
input := `{
auto_https off
skip_install_trust
}
internal.example.com {
tls internal
}
`
cas := adaptedPKIConfig(t, input)
ca, ok := cas["local"]
if !ok {
t.Fatal("expected certificate_authorities.local to exist")
}
if ca.InstallTrust == nil || *ca.InstallTrust != false {
t.Errorf("install_trust = %v, want false", ca.InstallTrust)
}
}
func TestParsePKIApp_skipInstallTrustHonoredForInternalTLSCustomCA(t *testing.T) {
input := `{
auto_https off
skip_install_trust
}
internal.example.com {
tls {
issuer internal {
ca mycustomca
}
}
}
`
cas := adaptedPKIConfig(t, input)
ca, ok := cas["mycustomca"]
if !ok {
t.Fatal("expected certificate_authorities.mycustomca to exist")
}
if ca.InstallTrust == nil || *ca.InstallTrust != false {
t.Errorf("install_trust = %v, want false", ca.InstallTrust)
}
}
func TestParsePKIApp_noPKIAppWhenNoInternalIssuerConfigured(t *testing.T) {
input := `{
auto_https off
skip_install_trust
}
localhost:8080 {
respond "no tls internal used anywhere"
}
`
cas := adaptedPKIConfig(t, input)
if len(cas) != 0 {
t.Errorf("expected no certificate_authorities, got %v", cas)
}
}
func TestParsePKIApp_renewalWindowRatioInvalid(t *testing.T) {
input := `{
pki {