Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions caddyconfig/httpcaddyfile/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
var certSelector caddytls.CustomCertSelectionPolicy
var acmeIssuer *caddytls.ACMEIssuer
var keyType string
var keyFile string
var internalIssuer *caddytls.InternalIssuer
var issuers []certmagic.Issuer
var certManagers []certmagic.Manager
Expand Down Expand Up @@ -272,6 +273,13 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
}
keyType = arg[0]

case "key_file":
arg := h.RemainingArgs()
if len(arg) != 1 {
return nil, h.ArgErr()
}
keyFile = arg[0]

case "eab":
arg := h.RemainingArgs()
if len(arg) != 2 {
Expand Down Expand Up @@ -591,6 +599,13 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
})
}

if keyFile != "" {
configVals = append(configVals, ConfigValue{
Class: "tls.key_file",
Value: keyFile,
})
}

// on-demand TLS
if onDemand {
configVals = append(configVals, ConfigValue{
Expand Down
1 change: 1 addition & 0 deletions caddyconfig/httpcaddyfile/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func init() {
RegisterGlobalOption("on_demand_tls", parseOptOnDemand)
RegisterGlobalOption("local_certs", parseOptTrue)
RegisterGlobalOption("key_type", parseOptSingleString)
RegisterGlobalOption("key_file", parseOptSingleString)
RegisterGlobalOption("auto_https", parseOptAutoHTTPS)
RegisterGlobalOption("metrics", parseMetricsOptions)
RegisterGlobalOption("servers", parseServerOptions)
Expand Down
12 changes: 11 additions & 1 deletion caddyconfig/httpcaddyfile/tlsapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ func (st ServerType) buildTLSApp(
ap.KeyType = keyTypeVals[0].Value.(string)
}

if keyFileVals, ok := sblock.pile["tls.key_file"]; ok {
ap.KeyFile = keyFileVals[0].Value.(string)
}

if renewalWindowRatioVals, ok := sblock.pile["tls.renewal_window_ratio"]; ok {
ap.RenewalWindowRatio = renewalWindowRatioVals[0].Value.(float64)
} else if globalRenewalWindowRatio, ok := options["renewal_window_ratio"]; ok {
Expand Down Expand Up @@ -611,9 +615,10 @@ func newBaseAutomationPolicy(
issuers, hasIssuers := options["cert_issuer"]
_, hasLocalCerts := options["local_certs"]
keyType, hasKeyType := options["key_type"]
keyFile, hasKeyFile := options["key_file"]
ocspStapling, hasOCSPStapling := options["ocsp_stapling"]
renewalWindowRatio, hasRenewalWindowRatio := options["renewal_window_ratio"]
hasGlobalAutomationOpts := hasIssuers || hasLocalCerts || hasKeyType || hasOCSPStapling || hasRenewalWindowRatio
hasGlobalAutomationOpts := hasIssuers || hasLocalCerts || hasKeyType || hasKeyFile || hasOCSPStapling || hasRenewalWindowRatio

globalACMECA := options["acme_ca"]
globalACMECARoot := options["acme_ca_root"]
Expand All @@ -636,6 +641,10 @@ func newBaseAutomationPolicy(
ap.KeyType = keyType.(string)
}

if hasKeyFile {
ap.KeyFile = keyFile.(string)
}

if hasIssuers && hasLocalCerts {
return nil, fmt.Errorf("global options are ambiguous: local_certs is confusing when combined with cert_issuer, because local_certs is also a specific kind of issuer")
}
Expand Down Expand Up @@ -727,6 +736,7 @@ outer:
bytes.Equal(aps[i].StorageRaw, aps[j].StorageRaw) &&
aps[i].MustStaple == aps[j].MustStaple &&
aps[i].KeyType == aps[j].KeyType &&
aps[i].KeyFile == aps[j].KeyFile &&
aps[i].OnDemand == aps[j].OnDemand &&
aps[i].ReusePrivateKeys == aps[j].ReusePrivateKeys &&
aps[i].RenewalWindowRatio == aps[j].RenewalWindowRatio {
Expand Down
37 changes: 27 additions & 10 deletions modules/caddytls/automation.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@
// Supported values: `ed25519`, `p256`, `p384`, `rsa2048`, `rsa4096`.
KeyType string `json:"key_type,omitempty"`

// Path to a custom private key file to use for TLS management.
// If specified, Caddy will not generate a new key but will use this one.
KeyFile string `json:"key_file,omitempty"`

// Optionally configure a separate storage module associated with this
// manager, instead of using Caddy's global/default-configured storage.
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
Expand Down Expand Up @@ -243,19 +247,32 @@
}
}

keyType := ap.KeyType
if keyType != "" {
var err error
keyType, err = caddy.NewReplacer().ReplaceOrErr(ap.KeyType, true, true)
var keySource certmagic.KeyGenerator

if ap.KeyFile != "" {
keyFilePath, err := caddy.NewReplacer().ReplaceOrErr(ap.KeyFile, true, true)
if err != nil {
return fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
return fmt.Errorf("invalid key file path %s: %v", ap.KeyFile, err)
}
if _, ok := supportedCertKeyTypes[keyType]; !ok {
return fmt.Errorf("unrecognized key type: %s", keyType)

keySource = certmagic.FileKeyGenerator{

Check failure on line 258 in modules/caddytls/automation.go

View workflow job for this annotation

GitHub Actions / govulncheck

undefined: certmagic.FileKeyGenerator

Check failure on line 258 in modules/caddytls/automation.go

View workflow job for this annotation

GitHub Actions / lint (mac)

undefined: certmagic.FileKeyGenerator (typecheck)
KeyFilename: keyFilePath,
}
} else {
keyType := ap.KeyType
if keyType != "" {
var err error
keyType, err = caddy.NewReplacer().ReplaceOrErr(ap.KeyType, true, true)
if err != nil {
return fmt.Errorf("invalid key type %s: %s", ap.KeyType, err)
}
if _, ok := supportedCertKeyTypes[keyType]; !ok {
return fmt.Errorf("unrecognized key type: %s", keyType)
}
}
keySource = certmagic.StandardKeyGenerator{
KeyType: supportedCertKeyTypes[keyType],
}
}
keySource := certmagic.StandardKeyGenerator{
KeyType: supportedCertKeyTypes[keyType],
}

storage := ap.storage
Expand Down
Loading