From bfd8ac7eab76407f7f802a710e34413fab3b7ffb Mon Sep 17 00:00:00 2001 From: James Munnelly Date: Thu, 13 Sep 2018 17:59:07 +0100 Subject: [PATCH] Add Order and Challenge API types Signed-off-by: James Munnelly --- pkg/apis/certmanager/v1alpha1/helpers.go | 11 -- pkg/apis/certmanager/v1alpha1/register.go | 4 + .../certmanager/v1alpha1/types_certificate.go | 63 +----- .../certmanager/v1alpha1/types_challenge.go | 73 +++++++ pkg/apis/certmanager/v1alpha1/types_order.go | 184 ++++++++++++++++++ 5 files changed, 263 insertions(+), 72 deletions(-) create mode 100644 pkg/apis/certmanager/v1alpha1/types_challenge.go create mode 100644 pkg/apis/certmanager/v1alpha1/types_order.go diff --git a/pkg/apis/certmanager/v1alpha1/helpers.go b/pkg/apis/certmanager/v1alpha1/helpers.go index 33805a477..addd65a1d 100644 --- a/pkg/apis/certmanager/v1alpha1/helpers.go +++ b/pkg/apis/certmanager/v1alpha1/helpers.go @@ -59,17 +59,6 @@ func ConfigForDomain(cfgs []DomainSolverConfig, domain string) *DomainSolverConf return &DomainSolverConfig{} } -func (c *CertificateStatus) ACMEStatus() *CertificateACMEStatus { - // this is an edge case, but this will prevent panics - if c == nil { - return &CertificateACMEStatus{} - } - if c.ACME == nil { - c.ACME = &CertificateACMEStatus{} - } - return c.ACME -} - func (iss *Issuer) HasCondition(condition IssuerCondition) bool { // this is an edge case, but this will prevent panics if iss == nil { diff --git a/pkg/apis/certmanager/v1alpha1/register.go b/pkg/apis/certmanager/v1alpha1/register.go index 2af73bdee..8a7b9ae35 100644 --- a/pkg/apis/certmanager/v1alpha1/register.go +++ b/pkg/apis/certmanager/v1alpha1/register.go @@ -55,6 +55,10 @@ func addKnownTypes(scheme *runtime.Scheme) error { &IssuerList{}, &ClusterIssuer{}, &ClusterIssuerList{}, + &Order{}, + &OrderList{}, + &Challenge{}, + &ChallengeList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/certmanager/v1alpha1/types_certificate.go b/pkg/apis/certmanager/v1alpha1/types_certificate.go index 980d1e154..67e5fb057 100644 --- a/pkg/apis/certmanager/v1alpha1/types_certificate.go +++ b/pkg/apis/certmanager/v1alpha1/types_certificate.go @@ -99,29 +99,10 @@ type ACMECertificateConfig struct { Config []DomainSolverConfig `json:"config"` } -type DomainSolverConfig struct { - Domains []string `json:"domains"` - SolverConfig `json:",inline"` -} - -type SolverConfig struct { - HTTP01 *HTTP01SolverConfig `json:"http01,omitempty"` - DNS01 *DNS01SolverConfig `json:"dns01,omitempty"` -} - -type HTTP01SolverConfig struct { - Ingress string `json:"ingress"` - IngressClass *string `json:"ingressClass,omitempty"` -} - -type DNS01SolverConfig struct { - Provider string `json:"provider"` -} - // CertificateStatus defines the observed state of Certificate type CertificateStatus struct { - Conditions []CertificateCondition `json:"conditions,omitempty"` - ACME *CertificateACMEStatus `json:"acme,omitempty"` + Conditions []CertificateCondition `json:"conditions,omitempty"` + LastFailureTime *metav1.Time `json:"lastFailureTime,omitempty"` } // CertificateCondition contains condition information for an Certificate. @@ -159,43 +140,3 @@ const ( // validation was attempted. CertificateConditionValidationFailed CertificateConditionType = "ValidateFailed" ) - -// CertificateACMEStatus holds the status for an ACME issuer -type CertificateACMEStatus struct { - // Order contains details about the current in-progress ACME Order. - Order ACMEOrderStatus `json:"order,omitempty"` -} - -type ACMEOrderStatus struct { - // The URL that can be used to get information about the ACME order. - URL string `json:"url"` - Challenges []ACMEOrderChallenge `json:"challenges,omitempty"` -} - -type ACMEOrderChallenge struct { - // The URL that can be used to get information about the ACME challenge. - URL string `json:"url"` - - // The URL that can be used to get information about the ACME authorization - // associated with the challenge. - AuthzURL string `json:"authzURL"` - - // Type of ACME challenge - // Either http-01 or dns-01 - Type string `json:"type"` - - // Domain this challenge corresponds to - Domain string `json:"domain"` - - // Challenge token for this challenge - Token string `json:"token"` - - // Challenge key for this challenge - Key string `json:"key"` - - // Set to true if this challenge is for a wildcard domain - Wildcard bool `json:"wildcard"` - - // Configuration used to present this challenge - SolverConfig `json:",inline"` -} diff --git a/pkg/apis/certmanager/v1alpha1/types_challenge.go b/pkg/apis/certmanager/v1alpha1/types_challenge.go new file mode 100644 index 000000000..29e1b4fde --- /dev/null +++ b/pkg/apis/certmanager/v1alpha1/types_challenge.go @@ -0,0 +1,73 @@ +/* +Copyright 2018 The Jetstack cert-manager contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TODO: these types should be moved into their own API group once we have a loose +// coupling between ACME Issuers and their solver configurations (see: Solver proposal) + +// +genclient +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// +kubebuilder:resource:path=challenges +type Challenge struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec ChallengeSpec `json:"spec"` + Status ChallengeStatus `json:"status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ChallengeList is a list of Challenges +type ChallengeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Challenge `json:"items"` +} + +type ChallengeSpec struct { + AuthzURL string `json:"authzURL"` + Type string `json:"type"` + URL string `json:"url"` + DNSName string `json:"dnsName"` + Token string `json:"token"` + Key string `json:"key"` + Wildcard bool `json:"wildcard"` + + // Config specifies the solver configuration for this challenge. + Config SolverConfig `json:"config"` + + // IssuerRef references a properly configured ACME-type Issuer which should + // be used to create this Challenge. + // If the Issuer does not exist, processing will be retried. + // If the Issuer is not an 'ACME' Issuer, an error will be returned and the + // Challenge will be marked as failed. + IssuerRef ObjectReference `json:"issuerRef"` +} + +type ChallengeStatus struct { + Presented bool `json:"presented"` + Reason string `json:"reason"` + State State `json:"state"` +} diff --git a/pkg/apis/certmanager/v1alpha1/types_order.go b/pkg/apis/certmanager/v1alpha1/types_order.go new file mode 100644 index 000000000..8774f0a25 --- /dev/null +++ b/pkg/apis/certmanager/v1alpha1/types_order.go @@ -0,0 +1,184 @@ +/* +Copyright 2018 The Jetstack cert-manager contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TODO: these types should be moved into their own API group once we have a loose +// coupling between ACME Issuers and their solver configurations (see: Solver proposal) + +// +genclient +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// +kubebuilder:resource:path=orders +type Order struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec OrderSpec `json:"spec"` + Status OrderStatus `json:"status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// OrderList is a list of Orders +type OrderList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Order `json:"items"` +} + +type OrderSpec struct { + // Certificate signing request bytes in DER encoding. + // This will be used when finalizing the order. + // This field must be set on the order. + CSR []byte `json:"csr"` + + // IssuerRef references a properly configured ACME-type Issuer which should + // be used to create this Order. + // If the Issuer does not exist, processing will be retried. + // If the Issuer is not an 'ACME' Issuer, an error will be returned and the + // Order will be marked as failed. + IssuerRef ObjectReference `json:"issuerRef"` + + // CommonName is the common name as specified on the DER encoded CSR. + // If CommonName is not specified, the first DNSName specified will be used + // as the CommonName. + // At least on of CommonName or a DNSName must be set. + // This field must match the corresponding field on the DER encoded CSR. + CommonName string `json:"commonName,omitempty"` + + // DNSNames is a list of DNS names that should be included as part of the Order + // validation process. + // If CommonName is not specified, the first DNSName specified will be used + // as the CommonName. + // At least on of CommonName or a DNSName must be set. + // This field must match the corresponding field on the DER encoded CSR. + DNSNames []string `json:"dnsNames,omitempty"` + + // 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"` +} + +type OrderStatus struct { + // URL of the Order. + // This will initially be empty when the resource is first created. + // The Order controller will populate this field when the Order is first processed. + // This field will be immutable after it is initially set. + URL string `json:"url"` + + // FinalizeURL of the Order. + // This is used to obtain certificates for this order once it has been completed. + FinalizeURL string `json:"finalizeURL"` + + // CertificateURL is a URL that can be used to retrieve a copy of the signed + // TLS certificate for this order. + // It will be populated automatically once the order has completed successfully + // and the certificate is available for retrieval. + // +optional + CertificateURL string `json:"certificateURL,omitempty"` + + // State contains the current state of this Order resource. + // States 'success' and 'expired' are 'final' + State State `json:"state"` + + // Reason optionally provides more information about a why the order is in + // the current state. + Reason string `json:"reason"` + + // Challenges is a list of ChallengeSpecs for Challenges that must be created + // in order to complete this Order. + Challenges []ChallengeSpec `json:"challenges,omitempty"` + + // FailureTime stores the time that this order failed. + // This is used to influence garbage collection and back-off. + // The order resource will be automatically deleted after 30 minutes has + // passed since the failure time. + // +optional + FailureTime *metav1.Time `json:"failureTime,omitempty"` +} + +// State represents the state of an ACME resource, such as an Order. +// The possible options here map to the corresponding values in the +// ACME specification. +// Full details of these values can be found there. +// Clients utilising this type **must** also gracefully handle unknown +// values, as the contents of this enumeration may be added to over time. +type State string + +const ( + // Unknown is not a real state as part of the ACME spec. + // It is used to represent an unrecognised value. + Unknown State = "" + + // Valid signifies that an ACME resource is in a valid state. + // If an Order is marked 'valid', all validations on that Order + // have been completed successfully. + // This is a transient state as of ACME draft-12 + Valid State = "valid" + + // Ready signifies that an ACME resource is in a ready state. + // If an Order is marked 'Ready', the corresponding certificate + // is ready and can be obtained. + // This is a final state. + Ready State = "ready" + + // Pending signifies that an ACME resource is still pending and is not yet ready. + // If an Order is marked 'Pending', the validations for that Order are still in progress. + // This is a transient state. + Pending State = "pending" + + // Processing signifies that an ACME resource is being processed by the server. + // If an Order is marked 'Processing', the validations for that Order are currently being processed. + // This is a transient state. + Processing State = "processing" + + // Invalid signifies that an ACME resource is invalid for some reason. + // If an Order is marked 'invalid', one of its validations be have invalid for some reason. + // This is a final state. + Invalid State = "invalid" + + // Expired signifies that an ACME resource has expired. + // If an Order is marked 'Expired', one of its validations may have expired or the Order itself. + // This is a final state. + Expired State = "expired" +) + +type SolverConfig struct { + HTTP01 *HTTP01SolverConfig `json:"http01,omitempty"` + DNS01 *DNS01SolverConfig `json:"dns01,omitempty"` +} + +type HTTP01SolverConfig struct { + Ingress string `json:"ingress"` + IngressClass *string `json:"ingressClass,omitempty"` +} + +type DNS01SolverConfig struct { + Provider string `json:"provider"` +} + +type DomainSolverConfig struct { + Domains []string `json:"domains"` + SolverConfig `json:",inline"` +}