diff --git a/pkg/apis/certmanager/v1alpha1/types_challenge.go b/pkg/apis/certmanager/v1alpha1/types_challenge.go index 7d15961d3..0b10dc75a 100644 --- a/pkg/apis/certmanager/v1alpha1/types_challenge.go +++ b/pkg/apis/certmanager/v1alpha1/types_challenge.go @@ -79,7 +79,18 @@ type ChallengeSpec struct { Wildcard bool `json:"wildcard"` // Config specifies the solver configuration for this challenge. - Config SolverConfig `json:"config"` + // Only **one** of 'config' or 'solver' may be specified, and if both are + // specified then no action will be performed on the Challenge resource. + // DEPRECATED: the 'solver' field should be specified instead + // +optional + Config *SolverConfig `json:"config,omitempty"` + + // Solver contains the domain solving configuration that should be used to + // solve this challenge resource. + // Only **one** of 'config' or 'solver' may be specified, and if both are + // specified then no action will be performed on the Challenge resource. + // +optional + Solver *ACMEChallengeSolver `json:"solver,omitempty"` // IssuerRef references a properly configured ACME-type Issuer which should // be used to create this Challenge. diff --git a/pkg/apis/certmanager/v1alpha1/types_issuer.go b/pkg/apis/certmanager/v1alpha1/types_issuer.go index d47d6ca00..ed98968e8 100644 --- a/pkg/apis/certmanager/v1alpha1/types_issuer.go +++ b/pkg/apis/certmanager/v1alpha1/types_issuer.go @@ -204,15 +204,121 @@ type ACMEIssuer struct { // user account. PrivateKey SecretKeySelector `json:"privateKeySecretRef"` - // HTTP-01 config + // Solvers is a list of challenge solvers that will be used to solve + // ACME challenges for the matching domains. + // +optional + Solvers []ACMEChallengeSolver `json:"solvers,omitempty"` + + // DEPRECATED: HTTP-01 config // +optional HTTP01 *ACMEIssuerHTTP01Config `json:"http01,omitempty"` - // DNS-01 config + // DEPRECATED: DNS-01 config // +optional DNS01 *ACMEIssuerDNS01Config `json:"dns01,omitempty"` } +type ACMEChallengeSolver struct { + // Selector selects a set of DNSNames on the Certificate resource that + // should be solved using this challenge solver. + Selector *CertificateDNSNameSelector `json:"selector,omitempty"` + + // +optional + HTTP01 *ACMEChallengeSolverHTTP01 `json:"http01,omitempty"` + + // +optional + DNS01 *ACMEChallengeSolverDNS01 `json:"dns01,omitempty"` +} + +// CertificateDomainSelector selects certificates using a label selector, and +// can optionally select individual DNS names within those certificates. +// If both MatchLabels and DNSNames are empty, this selector will match all +// certificates and DNS names within them. +type CertificateDNSNameSelector struct { + // A label selector that is used to refine the set of certificate's that + // this challenge solver will apply to. + // TODO: use kubernetes standard types for matchLabels + // +optional + MatchLabels map[string]string `json:"matchLabels,omitempty"` + + // List of DNSNames that can be used to further refine the domains that + // this solver applies to. + // +optional + DNSNames []string `json:"dnsNames,omitempty"` +} + +// ACMEChallengeSolverHTTP01 contains configuration detailing how to solve +// HTTP01 challenges within a Kubernetes cluster. +// Typically this is accomplished through creating 'routes' of some description +// that configure ingress controllers to direct traffic to 'solver pods', which +// are responsible for responding to the ACME server's HTTP requests. +type ACMEChallengeSolverHTTP01 struct { + // The ingress based HTTP01 challenge solver will solve challenges by + // creating or modifying Ingress resources in order to route requests for + // '/.well-known/acme-challenge/XYZ' to 'challenge solver' pods that are + // provisioned by cert-manager for each Challenge to be completed. + // +optional + Ingress *ACMEChallengeSolverHTTP01Ingress `json:"ingress"` +} + +type ACMEChallengeSolverHTTP01Ingress struct { + // Optional service type for Kubernetes solver service + // +optional + ServiceType corev1.ServiceType `json:"serviceType,omitempty"` + + // The ingress class to use when creating Ingress resources to solve ACME + // challenges that use this challenge solver. + // Only one of 'class' or 'name' may be specified. + // +optional + Class *string `json:"class,omitempty"` + + // The name of the ingress resource that should have ACME challenge solving + // routes inserted into it in order to solve HTTP01 challenges. + // This is typically used in conjunction with ingress controllers like + // ingress-gce, which maintains a 1:1 mapping between external IPs and + // ingress resources. + // +optional + Name string `json:"name,omitempty"` +} + +type ACMEChallengeSolverDNS01 struct { + // CNAMEStrategy configures how the DNS01 provider should handle CNAME + // records when found in DNS zones. + // +optional + // +kubebuilder:validation:Enum=None,Follow + CNAMEStrategy CNAMEStrategy `json:"cnameStrategy,omitempty"` + + // +optional + Akamai *ACMEIssuerDNS01ProviderAkamai `json:"akamai,omitempty"` + + // +optional + CloudDNS *ACMEIssuerDNS01ProviderCloudDNS `json:"clouddns,omitempty"` + + // +optional + Cloudflare *ACMEIssuerDNS01ProviderCloudflare `json:"cloudflare,omitempty"` + + // +optional + Route53 *ACMEIssuerDNS01ProviderRoute53 `json:"route53,omitempty"` + + // +optional + AzureDNS *ACMEIssuerDNS01ProviderAzureDNS `json:"azuredns,omitempty"` + + // +optional + DigitalOcean *ACMEIssuerDNS01ProviderDigitalOcean `json:"digitalocean,omitempty"` + + // +optional + AcmeDNS *ACMEIssuerDNS01ProviderAcmeDNS `json:"acmedns,omitempty"` + + // +optional + RFC2136 *ACMEIssuerDNS01ProviderRFC2136 `json:"rfc2136,omitempty"` + + // +optional + Webhook *ACMEIssuerDNS01ProviderWebhook `json:"webhook,omitempty"` +} + +/////// OLD TYPES +// TODO: REMOVE THESE IN v0.9 + // ACMEIssuerHTTP01Config is a structure containing the ACME HTTP configuration options type ACMEIssuerHTTP01Config struct { // Optional service type for Kubernetes solver service @@ -268,6 +374,8 @@ type ACMEIssuerDNS01Provider struct { Webhook *ACMEIssuerDNS01ProviderWebhook `json:"webhook,omitempty"` } +//// END OLD TYPES + // CNAMEStrategy configures how the DNS01 provider should handle CNAME records // when found in DNS zones. // By default, the None strategy will be applied (i.e. do not follow CNAMEs). diff --git a/pkg/apis/certmanager/v1alpha1/types_order.go b/pkg/apis/certmanager/v1alpha1/types_order.go index fbcf83b07..d23deae20 100644 --- a/pkg/apis/certmanager/v1alpha1/types_order.go +++ b/pkg/apis/certmanager/v1alpha1/types_order.go @@ -84,7 +84,15 @@ type OrderSpec struct { // Config specifies a mapping from DNS identifiers to how those identifiers // should be solved when performing ACME challenges. // A config entry must exist for each domain listed in DNSNames and CommonName. - Config []DomainSolverConfig `json:"config"` + // Only **one** of 'config' or 'solvers' may be specified, and if both are + // specified then no action will be performed on the Order resource. + // + // This field will be removed when support for solver config specified on + // the Certificate under certificate.spec.acme has been removed. + // DEPRECATED: this field will be removed in future. Solver configuration + // must instead be provided on ACME Issuer resources. + // +optional + Config []DomainSolverConfig `json:"config,omitempty"` } type OrderStatus struct { diff --git a/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go index b0999aba0..25aaf94f2 100644 --- a/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go @@ -49,10 +49,151 @@ func (in *ACMECertificateConfig) DeepCopy() *ACMECertificateConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolver) DeepCopyInto(out *ACMEChallengeSolver) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(CertificateDNSNameSelector) + (*in).DeepCopyInto(*out) + } + if in.HTTP01 != nil { + in, out := &in.HTTP01, &out.HTTP01 + *out = new(ACMEChallengeSolverHTTP01) + (*in).DeepCopyInto(*out) + } + if in.DNS01 != nil { + in, out := &in.DNS01, &out.DNS01 + *out = new(ACMEChallengeSolverDNS01) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolver. +func (in *ACMEChallengeSolver) DeepCopy() *ACMEChallengeSolver { + if in == nil { + return nil + } + out := new(ACMEChallengeSolver) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverDNS01) DeepCopyInto(out *ACMEChallengeSolverDNS01) { + *out = *in + if in.Akamai != nil { + in, out := &in.Akamai, &out.Akamai + *out = new(ACMEIssuerDNS01ProviderAkamai) + **out = **in + } + if in.CloudDNS != nil { + in, out := &in.CloudDNS, &out.CloudDNS + *out = new(ACMEIssuerDNS01ProviderCloudDNS) + **out = **in + } + if in.Cloudflare != nil { + in, out := &in.Cloudflare, &out.Cloudflare + *out = new(ACMEIssuerDNS01ProviderCloudflare) + **out = **in + } + if in.Route53 != nil { + in, out := &in.Route53, &out.Route53 + *out = new(ACMEIssuerDNS01ProviderRoute53) + **out = **in + } + if in.AzureDNS != nil { + in, out := &in.AzureDNS, &out.AzureDNS + *out = new(ACMEIssuerDNS01ProviderAzureDNS) + **out = **in + } + if in.DigitalOcean != nil { + in, out := &in.DigitalOcean, &out.DigitalOcean + *out = new(ACMEIssuerDNS01ProviderDigitalOcean) + **out = **in + } + if in.AcmeDNS != nil { + in, out := &in.AcmeDNS, &out.AcmeDNS + *out = new(ACMEIssuerDNS01ProviderAcmeDNS) + **out = **in + } + if in.RFC2136 != nil { + in, out := &in.RFC2136, &out.RFC2136 + *out = new(ACMEIssuerDNS01ProviderRFC2136) + **out = **in + } + if in.Webhook != nil { + in, out := &in.Webhook, &out.Webhook + *out = new(ACMEIssuerDNS01ProviderWebhook) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverDNS01. +func (in *ACMEChallengeSolverDNS01) DeepCopy() *ACMEChallengeSolverDNS01 { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverDNS01) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01) DeepCopyInto(out *ACMEChallengeSolverHTTP01) { + *out = *in + if in.Ingress != nil { + in, out := &in.Ingress, &out.Ingress + *out = new(ACMEChallengeSolverHTTP01Ingress) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01. +func (in *ACMEChallengeSolverHTTP01) DeepCopy() *ACMEChallengeSolverHTTP01 { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ACMEChallengeSolverHTTP01Ingress) DeepCopyInto(out *ACMEChallengeSolverHTTP01Ingress) { + *out = *in + if in.Class != nil { + in, out := &in.Class, &out.Class + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ACMEChallengeSolverHTTP01Ingress. +func (in *ACMEChallengeSolverHTTP01Ingress) DeepCopy() *ACMEChallengeSolverHTTP01Ingress { + if in == nil { + return nil + } + out := new(ACMEChallengeSolverHTTP01Ingress) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ACMEIssuer) DeepCopyInto(out *ACMEIssuer) { *out = *in out.PrivateKey = in.PrivateKey + if in.Solvers != nil { + in, out := &in.Solvers, &out.Solvers + *out = make([]ACMEChallengeSolver, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.HTTP01 != nil { in, out := &in.HTTP01, &out.HTTP01 *out = new(ACMEIssuerHTTP01Config) @@ -412,6 +553,34 @@ func (in *CertificateCondition) DeepCopy() *CertificateCondition { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CertificateDNSNameSelector) DeepCopyInto(out *CertificateDNSNameSelector) { + *out = *in + if in.MatchLabels != nil { + in, out := &in.MatchLabels, &out.MatchLabels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.DNSNames != nil { + in, out := &in.DNSNames, &out.DNSNames + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertificateDNSNameSelector. +func (in *CertificateDNSNameSelector) DeepCopy() *CertificateDNSNameSelector { + if in == nil { + return nil + } + out := new(CertificateDNSNameSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CertificateList) DeepCopyInto(out *CertificateList) { *out = *in @@ -587,7 +756,16 @@ func (in *ChallengeList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ChallengeSpec) DeepCopyInto(out *ChallengeSpec) { *out = *in - in.Config.DeepCopyInto(&out.Config) + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(SolverConfig) + (*in).DeepCopyInto(*out) + } + if in.Solver != nil { + in, out := &in.Solver, &out.Solver + *out = new(ACMEChallengeSolver) + (*in).DeepCopyInto(*out) + } out.IssuerRef = in.IssuerRef return }