mirror of
https://github.com/caddyserver/caddy.git
synced 2026-05-13 09:06:41 +00:00
httpcaddyfile: inherit global ACME issuer settings in tls shortcuts (#7617)
This commit is contained in:
parent
fdbef2a6ef
commit
c1918ff1ad
3 changed files with 412 additions and 19 deletions
|
|
@ -550,26 +550,11 @@ func parseTLS(h Helper) ([]ConfigValue, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case acmeIssuer != nil:
|
case acmeIssuer != nil:
|
||||||
// implicit ACME issuers (from various subdirectives) - use defaults; there might be more than one
|
// implicit ACME issuers (from various subdirectives) should inherit from
|
||||||
defaultIssuers := caddytls.DefaultIssuers(acmeIssuer.Email)
|
// any globally-configured ACME issuer templates, then apply the local
|
||||||
|
// shortcut settings as overrides.
|
||||||
// if an ACME CA endpoint was set, the user expects to use that specific one,
|
defaultIssuers := implicitACMEIssuers(h, acmeIssuer)
|
||||||
// not any others that may be defaults, so replace all defaults with that ACME CA
|
|
||||||
if acmeIssuer.CA != "" {
|
|
||||||
defaultIssuers = []certmagic.Issuer{acmeIssuer}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, issuer := range defaultIssuers {
|
for _, issuer := range defaultIssuers {
|
||||||
// apply settings from the implicitly-configured ACMEIssuer to any
|
|
||||||
// default ACMEIssuers, but preserve each default issuer's CA endpoint,
|
|
||||||
// because, for example, if you configure the DNS challenge, it should
|
|
||||||
// apply to any of the default ACMEIssuers, but you don't want to trample
|
|
||||||
// out their unique CA endpoints
|
|
||||||
if iss, ok := issuer.(*caddytls.ACMEIssuer); ok && iss != nil {
|
|
||||||
acmeCopy := *acmeIssuer
|
|
||||||
acmeCopy.CA = iss.CA
|
|
||||||
issuer = &acmeCopy
|
|
||||||
}
|
|
||||||
configVals = append(configVals, ConfigValue{
|
configVals = append(configVals, ConfigValue{
|
||||||
Class: "tls.cert_issuer",
|
Class: "tls.cert_issuer",
|
||||||
Value: issuer,
|
Value: issuer,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package httpcaddyfile
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/caddyserver/caddy/v2"
|
||||||
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
||||||
"github.com/caddyserver/caddy/v2/modules/caddytls"
|
"github.com/caddyserver/caddy/v2/modules/caddytls"
|
||||||
_ "github.com/caddyserver/caddy/v2/modules/logging"
|
_ "github.com/caddyserver/caddy/v2/modules/logging"
|
||||||
|
|
@ -166,3 +168,126 @@ func TestGlobalResolversOption(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGlobalCertIssuerAppliesToImplicitACMEIssuer(t *testing.T) {
|
||||||
|
adapter := caddyfile.Adapter{
|
||||||
|
ServerType: ServerType{},
|
||||||
|
}
|
||||||
|
|
||||||
|
input := `{
|
||||||
|
cert_issuer acme {
|
||||||
|
disable_tlsalpn_challenge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
report.company.intern {
|
||||||
|
tls {
|
||||||
|
ca https://deglacme01.company.intern/acme/acme/directory
|
||||||
|
ca_root /etc/certs/company_root2.crt
|
||||||
|
}
|
||||||
|
respond "ok"
|
||||||
|
}`
|
||||||
|
|
||||||
|
out, _, err := adapter.Adapt([]byte(input), nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("adapting caddyfile: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var config struct {
|
||||||
|
Apps struct {
|
||||||
|
TLS *caddytls.TLS `json:"tls"`
|
||||||
|
} `json:"apps"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(out, &config); err != nil {
|
||||||
|
t.Fatalf("unmarshaling adapted config: %v", err)
|
||||||
|
}
|
||||||
|
if config.Apps.TLS == nil || config.Apps.TLS.Automation == nil {
|
||||||
|
t.Fatal("expected tls automation config")
|
||||||
|
}
|
||||||
|
|
||||||
|
var subjectPolicy *caddytls.AutomationPolicy
|
||||||
|
for _, ap := range config.Apps.TLS.Automation.Policies {
|
||||||
|
if len(ap.SubjectsRaw) == 1 && ap.SubjectsRaw[0] == "report.company.intern" {
|
||||||
|
subjectPolicy = ap
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if subjectPolicy == nil {
|
||||||
|
t.Fatal("expected subject-specific automation policy")
|
||||||
|
}
|
||||||
|
if len(subjectPolicy.IssuersRaw) != 1 {
|
||||||
|
t.Fatalf("expected one issuer for subject-specific policy, got %d", len(subjectPolicy.IssuersRaw))
|
||||||
|
}
|
||||||
|
|
||||||
|
var issuer caddytls.ACMEIssuer
|
||||||
|
if err := json.Unmarshal(subjectPolicy.IssuersRaw[0], &issuer); err != nil {
|
||||||
|
t.Fatalf("unmarshaling issuer: %v", err)
|
||||||
|
}
|
||||||
|
if issuer.CA != "https://deglacme01.company.intern/acme/acme/directory" {
|
||||||
|
t.Fatalf("expected custom ACME CA, got %q", issuer.CA)
|
||||||
|
}
|
||||||
|
if len(issuer.TrustedRootsPEMFiles) != 1 || issuer.TrustedRootsPEMFiles[0] != "/etc/certs/company_root2.crt" {
|
||||||
|
t.Fatalf("expected trusted roots to include site CA root, got %v", issuer.TrustedRootsPEMFiles)
|
||||||
|
}
|
||||||
|
if issuer.Challenges == nil || issuer.Challenges.TLSALPN == nil || !issuer.Challenges.TLSALPN.Disabled {
|
||||||
|
t.Fatalf("expected tls-alpn challenge to be disabled, got %#v", issuer.Challenges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMergeACMEIssuers(t *testing.T) {
|
||||||
|
base := &caddytls.ACMEIssuer{
|
||||||
|
Email: "ops@example.com",
|
||||||
|
Challenges: &caddytls.ChallengesConfig{
|
||||||
|
HTTP: &caddytls.HTTPChallengeConfig{
|
||||||
|
AlternatePort: 8080,
|
||||||
|
},
|
||||||
|
TLSALPN: &caddytls.TLSALPNChallengeConfig{
|
||||||
|
Disabled: true,
|
||||||
|
AlternatePort: 8443,
|
||||||
|
},
|
||||||
|
DNS: &caddytls.DNSChallengeConfig{
|
||||||
|
Resolvers: []string{"1.1.1.1"},
|
||||||
|
OverrideDomain: "_acme-challenge.example.net",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TrustedRootsPEMFiles: []string{"global.pem"},
|
||||||
|
}
|
||||||
|
overrides := &caddytls.ACMEIssuer{
|
||||||
|
CA: "https://deglacme01.company.intern/acme/acme/directory",
|
||||||
|
Challenges: &caddytls.ChallengesConfig{
|
||||||
|
HTTP: &caddytls.HTTPChallengeConfig{
|
||||||
|
Disabled: true,
|
||||||
|
},
|
||||||
|
DNS: &caddytls.DNSChallengeConfig{
|
||||||
|
PropagationTimeout: caddy.Duration(time.Minute),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TrustedRootsPEMFiles: []string{"site.pem"},
|
||||||
|
}
|
||||||
|
|
||||||
|
merged := mergeACMEIssuers(base, overrides)
|
||||||
|
if merged.CA != overrides.CA {
|
||||||
|
t.Fatalf("expected merged CA %q, got %q", overrides.CA, merged.CA)
|
||||||
|
}
|
||||||
|
if merged.Email != base.Email {
|
||||||
|
t.Fatalf("expected merged email %q, got %q", base.Email, merged.Email)
|
||||||
|
}
|
||||||
|
if len(merged.TrustedRootsPEMFiles) != 2 || merged.TrustedRootsPEMFiles[0] != "global.pem" || merged.TrustedRootsPEMFiles[1] != "site.pem" {
|
||||||
|
t.Fatalf("expected merged roots [global.pem site.pem], got %v", merged.TrustedRootsPEMFiles)
|
||||||
|
}
|
||||||
|
if merged.Challenges == nil || merged.Challenges.HTTP == nil || !merged.Challenges.HTTP.Disabled || merged.Challenges.HTTP.AlternatePort != 8080 {
|
||||||
|
t.Fatalf("expected merged HTTP challenge config to preserve alternate port and apply disable flag, got %#v", merged.Challenges)
|
||||||
|
}
|
||||||
|
if merged.Challenges.TLSALPN == nil || !merged.Challenges.TLSALPN.Disabled || merged.Challenges.TLSALPN.AlternatePort != 8443 {
|
||||||
|
t.Fatalf("expected merged TLS-ALPN challenge config to preserve global settings, got %#v", merged.Challenges)
|
||||||
|
}
|
||||||
|
if merged.Challenges.DNS == nil || merged.Challenges.DNS.PropagationTimeout != caddy.Duration(time.Minute) || len(merged.Challenges.DNS.Resolvers) != 1 || merged.Challenges.DNS.Resolvers[0] != "1.1.1.1" || merged.Challenges.DNS.OverrideDomain != "_acme-challenge.example.net" {
|
||||||
|
t.Fatalf("expected merged DNS challenge config to preserve global values and apply overrides, got %#v", merged.Challenges)
|
||||||
|
}
|
||||||
|
|
||||||
|
if base.CA != "" {
|
||||||
|
t.Fatalf("expected base issuer to remain unchanged, got CA %q", base.CA)
|
||||||
|
}
|
||||||
|
if len(base.TrustedRootsPEMFiles) != 1 || base.TrustedRootsPEMFiles[0] != "global.pem" {
|
||||||
|
t.Fatalf("expected base roots to remain unchanged, got %v", base.TrustedRootsPEMFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -612,6 +612,289 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]any) e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// implicitACMEIssuers returns the issuers to use for ACME-related tls
|
||||||
|
// shortcuts such as ca, ca_root, and dns. If any global cert_issuer options
|
||||||
|
// configure ACME issuers, those become the templates for the local shortcut
|
||||||
|
// configuration; otherwise, default ACME issuers are used.
|
||||||
|
func implicitACMEIssuers(h Helper, acmeIssuer *caddytls.ACMEIssuer) []certmagic.Issuer {
|
||||||
|
globalIssuers, _ := h.Option("cert_issuer").([]certmagic.Issuer)
|
||||||
|
|
||||||
|
var implicitIssuers []certmagic.Issuer
|
||||||
|
for _, issuer := range globalIssuers {
|
||||||
|
acmeWrapper, ok := issuer.(acmeCapable)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
baseIssuer := acmeWrapper.GetACMEIssuer()
|
||||||
|
if baseIssuer == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
implicitIssuers = append(implicitIssuers, mergeACMEIssuers(baseIssuer, acmeIssuer))
|
||||||
|
}
|
||||||
|
if len(implicitIssuers) > 0 {
|
||||||
|
return implicitIssuers
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an ACME CA endpoint was set locally, the user expects to use only that
|
||||||
|
// CA rather than the usual default fallback issuers.
|
||||||
|
defaultIssuers := caddytls.DefaultIssuers(acmeIssuer.Email)
|
||||||
|
if acmeIssuer.CA != "" {
|
||||||
|
defaultIssuers = []certmagic.Issuer{new(caddytls.ACMEIssuer)}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitIssuers = make([]certmagic.Issuer, 0, len(defaultIssuers))
|
||||||
|
for _, issuer := range defaultIssuers {
|
||||||
|
acmeWrapper, ok := issuer.(acmeCapable)
|
||||||
|
if !ok {
|
||||||
|
implicitIssuers = append(implicitIssuers, issuer)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
baseIssuer := acmeWrapper.GetACMEIssuer()
|
||||||
|
if baseIssuer == nil {
|
||||||
|
implicitIssuers = append(implicitIssuers, issuer)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
implicitIssuers = append(implicitIssuers, mergeACMEIssuers(baseIssuer, acmeIssuer))
|
||||||
|
}
|
||||||
|
return implicitIssuers
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeACMEIssuers(base, overrides *caddytls.ACMEIssuer) *caddytls.ACMEIssuer {
|
||||||
|
if base == nil {
|
||||||
|
return cloneACMEIssuer(overrides)
|
||||||
|
}
|
||||||
|
|
||||||
|
merged := cloneACMEIssuer(base)
|
||||||
|
if overrides == nil {
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
if overrides.CA != "" {
|
||||||
|
merged.CA = overrides.CA
|
||||||
|
}
|
||||||
|
if overrides.TestCA != "" {
|
||||||
|
merged.TestCA = overrides.TestCA
|
||||||
|
}
|
||||||
|
if overrides.Email != "" {
|
||||||
|
merged.Email = overrides.Email
|
||||||
|
}
|
||||||
|
if overrides.Profile != "" {
|
||||||
|
merged.Profile = overrides.Profile
|
||||||
|
}
|
||||||
|
if overrides.AccountKey != "" {
|
||||||
|
merged.AccountKey = overrides.AccountKey
|
||||||
|
}
|
||||||
|
if overrides.ExternalAccount != nil {
|
||||||
|
merged.ExternalAccount = cloneACMEEAB(overrides.ExternalAccount)
|
||||||
|
}
|
||||||
|
if overrides.ACMETimeout != 0 {
|
||||||
|
merged.ACMETimeout = overrides.ACMETimeout
|
||||||
|
}
|
||||||
|
if len(overrides.TrustedRootsPEMFiles) > 0 {
|
||||||
|
merged.TrustedRootsPEMFiles = appendUniqueStrings(merged.TrustedRootsPEMFiles, overrides.TrustedRootsPEMFiles...)
|
||||||
|
}
|
||||||
|
if overrides.PreferredChains != nil {
|
||||||
|
merged.PreferredChains = cloneChainPreference(overrides.PreferredChains)
|
||||||
|
}
|
||||||
|
if overrides.CertificateLifetime != 0 {
|
||||||
|
merged.CertificateLifetime = overrides.CertificateLifetime
|
||||||
|
}
|
||||||
|
if len(overrides.NetworkProxyRaw) > 0 {
|
||||||
|
merged.NetworkProxyRaw = slices.Clone(overrides.NetworkProxyRaw)
|
||||||
|
}
|
||||||
|
merged.Challenges = mergeChallengesConfig(merged.Challenges, overrides.Challenges)
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeChallengesConfig(base, overrides *caddytls.ChallengesConfig) *caddytls.ChallengesConfig {
|
||||||
|
if base == nil {
|
||||||
|
return cloneChallengesConfig(overrides)
|
||||||
|
}
|
||||||
|
merged := cloneChallengesConfig(base)
|
||||||
|
if overrides == nil {
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
merged.HTTP = mergeHTTPChallengeConfig(merged.HTTP, overrides.HTTP)
|
||||||
|
merged.TLSALPN = mergeTLSALPNChallengeConfig(merged.TLSALPN, overrides.TLSALPN)
|
||||||
|
merged.DNS = mergeDNSChallengeConfig(merged.DNS, overrides.DNS)
|
||||||
|
if overrides.BindHost != "" {
|
||||||
|
merged.BindHost = overrides.BindHost
|
||||||
|
}
|
||||||
|
if overrides.Distributed != nil {
|
||||||
|
value := *overrides.Distributed
|
||||||
|
merged.Distributed = &value
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeHTTPChallengeConfig(base, overrides *caddytls.HTTPChallengeConfig) *caddytls.HTTPChallengeConfig {
|
||||||
|
if base == nil {
|
||||||
|
return cloneHTTPChallengeConfig(overrides)
|
||||||
|
}
|
||||||
|
merged := cloneHTTPChallengeConfig(base)
|
||||||
|
if overrides == nil {
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
if overrides.Disabled {
|
||||||
|
merged.Disabled = true
|
||||||
|
}
|
||||||
|
if overrides.AlternatePort != 0 {
|
||||||
|
merged.AlternatePort = overrides.AlternatePort
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeTLSALPNChallengeConfig(base, overrides *caddytls.TLSALPNChallengeConfig) *caddytls.TLSALPNChallengeConfig {
|
||||||
|
if base == nil {
|
||||||
|
return cloneTLSALPNChallengeConfig(overrides)
|
||||||
|
}
|
||||||
|
merged := cloneTLSALPNChallengeConfig(base)
|
||||||
|
if overrides == nil {
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
if overrides.Disabled {
|
||||||
|
merged.Disabled = true
|
||||||
|
}
|
||||||
|
if overrides.AlternatePort != 0 {
|
||||||
|
merged.AlternatePort = overrides.AlternatePort
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeDNSChallengeConfig(base, overrides *caddytls.DNSChallengeConfig) *caddytls.DNSChallengeConfig {
|
||||||
|
if base == nil {
|
||||||
|
return cloneDNSChallengeConfig(overrides)
|
||||||
|
}
|
||||||
|
merged := cloneDNSChallengeConfig(base)
|
||||||
|
if overrides == nil {
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(overrides.ProviderRaw) > 0 {
|
||||||
|
merged.ProviderRaw = slices.Clone(overrides.ProviderRaw)
|
||||||
|
}
|
||||||
|
if overrides.PropagationDelay != 0 {
|
||||||
|
merged.PropagationDelay = overrides.PropagationDelay
|
||||||
|
}
|
||||||
|
if overrides.PropagationTimeout != 0 {
|
||||||
|
merged.PropagationTimeout = overrides.PropagationTimeout
|
||||||
|
}
|
||||||
|
if overrides.Resolvers != nil {
|
||||||
|
merged.Resolvers = slices.Clone(overrides.Resolvers)
|
||||||
|
}
|
||||||
|
if overrides.OverrideDomain != "" {
|
||||||
|
merged.OverrideDomain = overrides.OverrideDomain
|
||||||
|
}
|
||||||
|
if overrides.TTL != 0 {
|
||||||
|
merged.TTL = overrides.TTL
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneACMEIssuer(iss *caddytls.ACMEIssuer) *caddytls.ACMEIssuer {
|
||||||
|
if iss == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *iss
|
||||||
|
cloned.Challenges = cloneChallengesConfig(iss.Challenges)
|
||||||
|
cloned.ExternalAccount = cloneACMEEAB(iss.ExternalAccount)
|
||||||
|
cloned.TrustedRootsPEMFiles = slices.Clone(iss.TrustedRootsPEMFiles)
|
||||||
|
cloned.PreferredChains = cloneChainPreference(iss.PreferredChains)
|
||||||
|
cloned.NetworkProxyRaw = slices.Clone(iss.NetworkProxyRaw)
|
||||||
|
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneChallengesConfig(cfg *caddytls.ChallengesConfig) *caddytls.ChallengesConfig {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *cfg
|
||||||
|
cloned.HTTP = cloneHTTPChallengeConfig(cfg.HTTP)
|
||||||
|
cloned.TLSALPN = cloneTLSALPNChallengeConfig(cfg.TLSALPN)
|
||||||
|
cloned.DNS = cloneDNSChallengeConfig(cfg.DNS)
|
||||||
|
if cfg.Distributed != nil {
|
||||||
|
value := *cfg.Distributed
|
||||||
|
cloned.Distributed = &value
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneHTTPChallengeConfig(cfg *caddytls.HTTPChallengeConfig) *caddytls.HTTPChallengeConfig {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *cfg
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneTLSALPNChallengeConfig(cfg *caddytls.TLSALPNChallengeConfig) *caddytls.TLSALPNChallengeConfig {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *cfg
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneDNSChallengeConfig(cfg *caddytls.DNSChallengeConfig) *caddytls.DNSChallengeConfig {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *cfg
|
||||||
|
cloned.ProviderRaw = slices.Clone(cfg.ProviderRaw)
|
||||||
|
cloned.Resolvers = slices.Clone(cfg.Resolvers)
|
||||||
|
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneACMEEAB(eab *acme.EAB) *acme.EAB {
|
||||||
|
if eab == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *eab
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneChainPreference(pref *caddytls.ChainPreference) *caddytls.ChainPreference {
|
||||||
|
if pref == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloned := *pref
|
||||||
|
cloned.RootCommonName = slices.Clone(pref.RootCommonName)
|
||||||
|
cloned.AnyCommonName = slices.Clone(pref.AnyCommonName)
|
||||||
|
if pref.Smallest != nil {
|
||||||
|
value := *pref.Smallest
|
||||||
|
cloned.Smallest = &value
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendUniqueStrings(existing []string, additions ...string) []string {
|
||||||
|
for _, value := range additions {
|
||||||
|
if !slices.Contains(existing, value) {
|
||||||
|
existing = append(existing, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
|
||||||
// newBaseAutomationPolicy returns a new TLS automation policy that gets
|
// newBaseAutomationPolicy returns a new TLS automation policy that gets
|
||||||
// its values from the global options map. It should be used as the base
|
// its values from the global options map. It should be used as the base
|
||||||
// for any other automation policies. A nil policy (and no error) will be
|
// for any other automation policies. A nil policy (and no error) will be
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue