diff --git a/deploy/crds/crd-clusterissuers.v1beta1.yaml b/deploy/crds/crd-clusterissuers.v1beta1.yaml index 783249dd7..ec086957b 100644 --- a/deploy/crds/crd-clusterissuers.v1beta1.yaml +++ b/deploy/crds/crd-clusterissuers.v1beta1.yaml @@ -75,6 +75,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -1087,6 +1090,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -2101,6 +2107,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -3115,6 +3124,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object diff --git a/deploy/crds/crd-clusterissuers.yaml b/deploy/crds/crd-clusterissuers.yaml index 9999ee666..059f2e83a 100644 --- a/deploy/crds/crd-clusterissuers.yaml +++ b/deploy/crds/crd-clusterissuers.yaml @@ -75,6 +75,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -1101,6 +1104,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -2129,6 +2135,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -3157,6 +3166,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object diff --git a/deploy/crds/crd-issuers.v1beta1.yaml b/deploy/crds/crd-issuers.v1beta1.yaml index 411a0e193..bf7a82ae1 100644 --- a/deploy/crds/crd-issuers.v1beta1.yaml +++ b/deploy/crds/crd-issuers.v1beta1.yaml @@ -75,6 +75,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -1087,6 +1090,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -2101,6 +2107,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -3115,6 +3124,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object diff --git a/deploy/crds/crd-issuers.yaml b/deploy/crds/crd-issuers.yaml index 4cd3a7e81..5a188c51f 100644 --- a/deploy/crds/crd-issuers.yaml +++ b/deploy/crds/crd-issuers.yaml @@ -75,6 +75,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -1101,6 +1104,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -2129,6 +2135,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object @@ -3157,6 +3166,9 @@ spec: email: description: Email is the email address to be associated with the ACME account. This field is optional, but it is strongly recommended to be set. It will be used to contact you in case of issues with your account or certificates, including expiry notification emails. This field may be updated after the account is initially registered. type: string + enableNotAfterDate: + description: Enables requesting a Not After date on certificates that matches the duration of the certificate. This is not supported by all ACME servers like Let's Encrypt. If set to true when the ACME server does not support it it will create an error on the Order. Defaults to false. + type: boolean externalAccountBinding: description: ExternalAccountBinding is a reference to a CA external account of the ACME server. If set, upon registration cert-manager will attempt to associate the given external account credentials with the registered ACME account. type: object diff --git a/deploy/crds/crd-orders.v1beta1.yaml b/deploy/crds/crd-orders.v1beta1.yaml index e5dbcc2af..d2a581be0 100644 --- a/deploy/crds/crd-orders.v1beta1.yaml +++ b/deploy/crds/crd-orders.v1beta1.yaml @@ -102,6 +102,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time status: type: object properties: @@ -238,6 +242,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time status: type: object properties: @@ -371,6 +379,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time request: description: Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order. type: string @@ -508,6 +520,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time request: description: Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order. type: string diff --git a/deploy/crds/crd-orders.yaml b/deploy/crds/crd-orders.yaml index ea48e7332..eb354c5be 100644 --- a/deploy/crds/crd-orders.yaml +++ b/deploy/crds/crd-orders.yaml @@ -102,6 +102,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time status: type: object properties: @@ -256,6 +260,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time status: type: object properties: @@ -407,6 +415,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time request: description: Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order. type: string @@ -562,6 +574,10 @@ spec: name: description: Name of the resource being referred to. type: string + notAfter: + description: NotAfter is the date for the requested certificate's Not Valid After date + type: string + format: date-time request: description: Certificate signing request bytes in DER encoding. This will be used when finalizing the order. This field must be set on the order. type: string diff --git a/pkg/apis/acme/v1/types_issuer.go b/pkg/apis/acme/v1/types_issuer.go index 0cadd3b73..2116f2293 100644 --- a/pkg/apis/acme/v1/types_issuer.go +++ b/pkg/apis/acme/v1/types_issuer.go @@ -93,6 +93,14 @@ type ACMEIssuer struct { // Defaults to false. // +optional DisableAccountKeyGeneration bool `json:"disableAccountKeyGeneration,omitempty"` + + // Enables requesting a Not After date on certificates that matches the + // duration of the certificate. This is not supported by all ACME servers + // like Let's Encrypt. If set to true when the ACME server does not support + // it it will create an error on the Order. + // Defaults to false. + // +optional + EnableNotAfterDate bool `json:"enableNotAfterDate,omitempty"` } // ACMEExternalAccountBinding is a reference to a CA external account of the ACME diff --git a/pkg/apis/acme/v1/types_order.go b/pkg/apis/acme/v1/types_order.go index 9650ddfd3..5df632a20 100644 --- a/pkg/apis/acme/v1/types_order.go +++ b/pkg/apis/acme/v1/types_order.go @@ -69,7 +69,7 @@ type OrderSpec struct { // DNSNames is a list of DNS names that should be included as part of the Order // validation process. // This field must match the corresponding field on the DER encoded CSR. - //+optonal + //+optional DNSNames []string `json:"dnsNames,omitempty"` // IPAddresses is a list of IP addresses that should be included as part of the Order @@ -77,6 +77,10 @@ type OrderSpec struct { // This field must match the corresponding field on the DER encoded CSR. // +optional IPAddresses []string `json:"ipAddresses,omitempty"` + + // NotAfter is the date for the requested certificate's Not Valid After date + // +optional + NotAfter *metav1.Time `json:"notAfter,omitempty"` } type OrderStatus struct { diff --git a/pkg/apis/acme/v1/zz_generated.deepcopy.go b/pkg/apis/acme/v1/zz_generated.deepcopy.go index eef202c69..e1134b76e 100644 --- a/pkg/apis/acme/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1/zz_generated.deepcopy.go @@ -789,6 +789,10 @@ func (in *OrderSpec) DeepCopyInto(out *OrderSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } return } diff --git a/pkg/apis/acme/v1alpha2/types_issuer.go b/pkg/apis/acme/v1alpha2/types_issuer.go index 4e0e4a255..ecb4a4240 100644 --- a/pkg/apis/acme/v1alpha2/types_issuer.go +++ b/pkg/apis/acme/v1alpha2/types_issuer.go @@ -93,6 +93,14 @@ type ACMEIssuer struct { // Defaults to false. // +optional DisableAccountKeyGeneration bool `json:"disableAccountKeyGeneration,omitempty"` + + // Enables requesting a Not After date on certificates that matches the + // duration of the certificate. This is not supported by all ACME servers + // like Let's Encrypt. If set to true when the ACME server does not support + // it it will create an error on the Order. + // Defaults to false. + // +optional + EnableNotAfterDate bool `json:"enableNotAfterDate,omitempty"` } // ACMEExternalAccountBinding is a reference to a CA external account of the ACME diff --git a/pkg/apis/acme/v1alpha2/types_order.go b/pkg/apis/acme/v1alpha2/types_order.go index 0df925288..c2b48d412 100644 --- a/pkg/apis/acme/v1alpha2/types_order.go +++ b/pkg/apis/acme/v1alpha2/types_order.go @@ -67,7 +67,7 @@ type OrderSpec struct { // DNSNames is a list of DNS names that should be included as part of the Order // validation process. // This field must match the corresponding field on the DER encoded CSR. - //+optonal + //+optional DNSNames []string `json:"dnsNames,omitempty"` // IPAddresses is a list of IP addresses that should be included as part of the Order @@ -75,6 +75,10 @@ type OrderSpec struct { // This field must match the corresponding field on the DER encoded CSR. // +optional IPAddresses []string `json:"ipAddresses,omitempty"` + + // NotAfter is the date for the requested certificate's Not Valid After date + // +optional + NotAfter *metav1.Time `json:"notAfter,omitempty"` } type OrderStatus struct { diff --git a/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go index 373a118ef..5f23c70da 100644 --- a/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1alpha2/zz_generated.deepcopy.go @@ -789,6 +789,10 @@ func (in *OrderSpec) DeepCopyInto(out *OrderSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } return } diff --git a/pkg/apis/acme/v1alpha3/types_issuer.go b/pkg/apis/acme/v1alpha3/types_issuer.go index 4b89f8106..d50ca2316 100644 --- a/pkg/apis/acme/v1alpha3/types_issuer.go +++ b/pkg/apis/acme/v1alpha3/types_issuer.go @@ -93,6 +93,14 @@ type ACMEIssuer struct { // Defaults to false. // +optional DisableAccountKeyGeneration bool `json:"disableAccountKeyGeneration,omitempty"` + + // Enables requesting a Not After date on certificates that matches the + // duration of the certificate. This is not supported by all ACME servers + // like Let's Encrypt. If set to true when the ACME server does not support + // it it will create an error on the Order. + // Defaults to false. + // +optional + EnableNotAfterDate bool `json:"enableNotAfterDate,omitempty"` } // ACMEExternalAccountBinding is a reference to a CA external account of the ACME diff --git a/pkg/apis/acme/v1alpha3/types_order.go b/pkg/apis/acme/v1alpha3/types_order.go index 82b7f67aa..e852effa4 100644 --- a/pkg/apis/acme/v1alpha3/types_order.go +++ b/pkg/apis/acme/v1alpha3/types_order.go @@ -67,7 +67,7 @@ type OrderSpec struct { // DNSNames is a list of DNS names that should be included as part of the Order // validation process. // This field must match the corresponding field on the DER encoded CSR. - //+optonal + //+optional DNSNames []string `json:"dnsNames,omitempty"` // IPAddresses is a list of IP addresses that should be included as part of the Order @@ -75,6 +75,10 @@ type OrderSpec struct { // This field must match the corresponding field on the DER encoded CSR. // +optional IPAddresses []string `json:"ipAddresses,omitempty"` + + // NotAfter is the date for the requested certificate's Not Valid After date + // +optional + NotAfter *metav1.Time `json:"notAfter,omitempty"` } type OrderStatus struct { diff --git a/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go b/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go index 6d2113872..909444e1f 100644 --- a/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1alpha3/zz_generated.deepcopy.go @@ -789,6 +789,10 @@ func (in *OrderSpec) DeepCopyInto(out *OrderSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } return } diff --git a/pkg/apis/acme/v1beta1/types_issuer.go b/pkg/apis/acme/v1beta1/types_issuer.go index c76f4645d..2a52009ee 100644 --- a/pkg/apis/acme/v1beta1/types_issuer.go +++ b/pkg/apis/acme/v1beta1/types_issuer.go @@ -93,6 +93,14 @@ type ACMEIssuer struct { // Defaults to false. // +optional DisableAccountKeyGeneration bool `json:"disableAccountKeyGeneration,omitempty"` + + // Enables requesting a Not After date on certificates that matches the + // duration of the certificate. This is not supported by all ACME servers + // like Let's Encrypt. If set to true when the ACME server does not support + // it it will create an error on the Order. + // Defaults to false. + // +optional + EnableNotAfterDate bool `json:"enableNotAfterDate,omitempty"` } // ACMEExternalAccountBinding is a reference to a CA external account of the ACME diff --git a/pkg/apis/acme/v1beta1/types_order.go b/pkg/apis/acme/v1beta1/types_order.go index 965a9337c..25b251b28 100644 --- a/pkg/apis/acme/v1beta1/types_order.go +++ b/pkg/apis/acme/v1beta1/types_order.go @@ -68,7 +68,7 @@ type OrderSpec struct { // DNSNames is a list of DNS names that should be included as part of the Order // validation process. // This field must match the corresponding field on the DER encoded CSR. - //+optonal + //+optional DNSNames []string `json:"dnsNames,omitempty"` // IPAddresses is a list of IP addresses that should be included as part of the Order @@ -76,6 +76,10 @@ type OrderSpec struct { // This field must match the corresponding field on the DER encoded CSR. // +optional IPAddresses []string `json:"ipAddresses,omitempty"` + + // NotAfter is the date for the requested certificate's Not Valid After date + // +optional + NotAfter *metav1.Time `json:"notAfter,omitempty"` } type OrderStatus struct { diff --git a/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go b/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go index 1ef56a911..4b766e992 100644 --- a/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/acme/v1beta1/zz_generated.deepcopy.go @@ -789,6 +789,10 @@ func (in *OrderSpec) DeepCopyInto(out *OrderSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } return } diff --git a/pkg/controller/acmeorders/sync.go b/pkg/controller/acmeorders/sync.go index ae71519f2..0333c697d 100644 --- a/pkg/controller/acmeorders/sync.go +++ b/pkg/controller/acmeorders/sync.go @@ -200,7 +200,12 @@ func (c *controller) createOrder(ctx context.Context, cl acmecl.Interface, o *cm authzIDs := acmeapi.DomainIDs(dnsIdentifierSet.List()...) authzIDs = append(authzIDs, acmeapi.IPIDs(ipIdentifierSet.List()...)...) // create a new order with the acme server - acmeOrder, err := cl.AuthorizeOrder(ctx, authzIDs) + + var options []acmeapi.OrderOption + if o.Spec.NotAfter != nil { + options = append(options, acmeapi.WithOrderNotAfter(o.Spec.NotAfter.Time)) + } + acmeOrder, err := cl.AuthorizeOrder(ctx, authzIDs, options...) if acmeErr, ok := err.(*acmeapi.Error); ok { if acmeErr.StatusCode >= 400 && acmeErr.StatusCode < 500 { log.Error(err, "failed to create Order resource due to bad request, marking Order as failed") diff --git a/pkg/controller/certificaterequests/acme/acme.go b/pkg/controller/certificaterequests/acme/acme.go index 3829706f5..773f7b596 100644 --- a/pkg/controller/certificaterequests/acme/acme.go +++ b/pkg/controller/certificaterequests/acme/acme.go @@ -20,6 +20,7 @@ import ( "context" "crypto/x509" "fmt" + "time" k8sErrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -105,7 +106,7 @@ func (a *ACME) Sign(ctx context.Context, cr *v1.CertificateRequest, issuer v1.Ge } // If we fail to build the order we have to hard fail. - expectedOrder, err := buildOrder(cr, csr) + expectedOrder, err := buildOrder(cr, csr, issuer) if err != nil { message := "Failed to build order" @@ -199,7 +200,7 @@ func (a *ACME) Sign(ctx context.Context, cr *v1.CertificateRequest, issuer v1.Ge } // Build order. If we error here it is a terminating failure. -func buildOrder(cr *v1.CertificateRequest, csr *x509.CertificateRequest) (*cmacme.Order, error) { +func buildOrder(cr *v1.CertificateRequest, csr *x509.CertificateRequest, issuer v1.GenericIssuer) (*cmacme.Order, error) { var ipAddresses []string for _, ip := range csr.IPAddresses { ipAddresses = append(ipAddresses, ip.String()) @@ -218,9 +219,15 @@ func buildOrder(cr *v1.CertificateRequest, csr *x509.CertificateRequest) (*cmacm IPAddresses: ipAddresses, } + if issuer.GetSpec().ACME.EnableNotAfterDate { + notAfterTime := metav1.NewTime(time.Now().Add(cr.Spec.Duration.Duration)) + spec.NotAfter = ¬AfterTime + } + computeNameSpec := spec.DeepCopy() - // create a deep copy of the OrderSpec so we can overwrite the Request field + // create a deep copy of the OrderSpec so we can overwrite the Request and NotAfter field computeNameSpec.Request = nil + computeNameSpec.NotAfter = nil // NotAfter is time based and will shift, confusing the controller to reconcile name, err := apiutil.ComputeName(cr.Name, computeNameSpec) if err != nil { return nil, err diff --git a/pkg/controller/certificaterequests/acme/acme_test.go b/pkg/controller/certificaterequests/acme/acme_test.go index f869dbd20..bc368ed06 100644 --- a/pkg/controller/certificaterequests/acme/acme_test.go +++ b/pkg/controller/certificaterequests/acme/acme_test.go @@ -153,7 +153,7 @@ func TestSign(t *testing.T) { t.Fatalf("failed to build order during testing: %s", err) } - baseOrder, err := buildOrder(baseCR, csr) + baseOrder, err := buildOrder(baseCR, csr, baseIssuer) if err != nil { t.Fatalf("failed to build order during testing: %s", err) } diff --git a/pkg/internal/apis/acme/types_issuer.go b/pkg/internal/apis/acme/types_issuer.go index 2610e058b..1a9959769 100644 --- a/pkg/internal/apis/acme/types_issuer.go +++ b/pkg/internal/apis/acme/types_issuer.go @@ -85,6 +85,13 @@ type ACMEIssuer struct { // Defaults to false. // +optional DisableAccountKeyGeneration bool `json:"disableAccountKeyGeneration,omitempty"` + + // Enables requesting a Not After date on certificates that matches the + // duration of the certificate. This is not supported by all ACME servers + // like Let's Encrypt. If set to true when the ACME server does not support + // it it will create an error on the Order. + // Defaults to false. + EnableNotAfterDate bool `json:"enableNotAfterDate,omitempty"` } // ACMEExternalAccountBinding is a reference to a CA external account of the ACME diff --git a/pkg/internal/apis/acme/types_order.go b/pkg/internal/apis/acme/types_order.go index bd7c3658a..d6197aa7d 100644 --- a/pkg/internal/apis/acme/types_order.go +++ b/pkg/internal/apis/acme/types_order.go @@ -70,6 +70,9 @@ type OrderSpec struct { // validation process. // This field must match the corresponding field on the DER encoded CSR. IPAddresses []string + + // NotAfter is the date for the requested certificate's Not Valid After date + NotAfter *metav1.Time `json:"notAfter"` } type OrderStatus struct { diff --git a/pkg/internal/apis/acme/v1/zz_generated.conversion.go b/pkg/internal/apis/acme/v1/zz_generated.conversion.go index 40686f1e5..1973abf4f 100644 --- a/pkg/internal/apis/acme/v1/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1/zz_generated.conversion.go @@ -694,6 +694,7 @@ func autoConvert_v1_ACMEIssuer_To_acme_ACMEIssuer(in *v1.ACMEIssuer, out *acme.A } out.Solvers = *(*[]acme.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -714,6 +715,7 @@ func autoConvert_acme_ACMEIssuer_To_v1_ACMEIssuer(in *acme.ACMEIssuer, out *v1.A } out.Solvers = *(*[]v1.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -1245,6 +1247,7 @@ func autoConvert_v1_OrderSpec_To_acme_OrderSpec(in *v1.OrderSpec, out *acme.Orde out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } @@ -1262,6 +1265,7 @@ func autoConvert_acme_OrderSpec_To_v1_OrderSpec(in *acme.OrderSpec, out *v1.Orde out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } diff --git a/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go b/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go index 724256d52..c10e0bce5 100644 --- a/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1alpha2/zz_generated.conversion.go @@ -694,6 +694,7 @@ func autoConvert_v1alpha2_ACMEIssuer_To_acme_ACMEIssuer(in *v1alpha2.ACMEIssuer, } out.Solvers = *(*[]acme.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -714,6 +715,7 @@ func autoConvert_acme_ACMEIssuer_To_v1alpha2_ACMEIssuer(in *acme.ACMEIssuer, out } out.Solvers = *(*[]v1alpha2.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -1255,6 +1257,7 @@ func autoConvert_v1alpha2_OrderSpec_To_acme_OrderSpec(in *v1alpha2.OrderSpec, ou out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } @@ -1267,6 +1270,7 @@ func autoConvert_acme_OrderSpec_To_v1alpha2_OrderSpec(in *acme.OrderSpec, out *v out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } diff --git a/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go b/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go index 41a421080..565f917b4 100644 --- a/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1alpha3/zz_generated.conversion.go @@ -694,6 +694,7 @@ func autoConvert_v1alpha3_ACMEIssuer_To_acme_ACMEIssuer(in *v1alpha3.ACMEIssuer, } out.Solvers = *(*[]acme.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -714,6 +715,7 @@ func autoConvert_acme_ACMEIssuer_To_v1alpha3_ACMEIssuer(in *acme.ACMEIssuer, out } out.Solvers = *(*[]v1alpha3.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -1255,6 +1257,7 @@ func autoConvert_v1alpha3_OrderSpec_To_acme_OrderSpec(in *v1alpha3.OrderSpec, ou out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } @@ -1267,6 +1270,7 @@ func autoConvert_acme_OrderSpec_To_v1alpha3_OrderSpec(in *acme.OrderSpec, out *v out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } diff --git a/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go b/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go index be3ea4e26..e9549d7d4 100644 --- a/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go +++ b/pkg/internal/apis/acme/v1beta1/zz_generated.conversion.go @@ -694,6 +694,7 @@ func autoConvert_v1beta1_ACMEIssuer_To_acme_ACMEIssuer(in *v1beta1.ACMEIssuer, o } out.Solvers = *(*[]acme.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -714,6 +715,7 @@ func autoConvert_acme_ACMEIssuer_To_v1beta1_ACMEIssuer(in *acme.ACMEIssuer, out } out.Solvers = *(*[]v1beta1.ACMEChallengeSolver)(unsafe.Pointer(&in.Solvers)) out.DisableAccountKeyGeneration = in.DisableAccountKeyGeneration + out.EnableNotAfterDate = in.EnableNotAfterDate return nil } @@ -1245,6 +1247,7 @@ func autoConvert_v1beta1_OrderSpec_To_acme_OrderSpec(in *v1beta1.OrderSpec, out out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } @@ -1262,6 +1265,7 @@ func autoConvert_acme_OrderSpec_To_v1beta1_OrderSpec(in *acme.OrderSpec, out *v1 out.CommonName = in.CommonName out.DNSNames = *(*[]string)(unsafe.Pointer(&in.DNSNames)) out.IPAddresses = *(*[]string)(unsafe.Pointer(&in.IPAddresses)) + out.NotAfter = (*apismetav1.Time)(unsafe.Pointer(in.NotAfter)) return nil } diff --git a/pkg/internal/apis/acme/zz_generated.deepcopy.go b/pkg/internal/apis/acme/zz_generated.deepcopy.go index c06f36bdd..ceb0b8771 100644 --- a/pkg/internal/apis/acme/zz_generated.deepcopy.go +++ b/pkg/internal/apis/acme/zz_generated.deepcopy.go @@ -789,6 +789,10 @@ func (in *OrderSpec) DeepCopyInto(out *OrderSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } return } diff --git a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel index a4c852f10..98c65948e 100644 --- a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel +++ b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel @@ -5,6 +5,7 @@ go_library( srcs = [ "dns01.go", "http01.go", + "notafter.go", "webhook.go", ], importpath = "github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/certificate", @@ -16,6 +17,7 @@ go_library( "//pkg/apis/meta/v1:go_default_library", "//pkg/client/clientset/versioned:go_default_library", "//pkg/util:go_default_library", + "//pkg/util/pki:go_default_library", "//test/e2e/framework:go_default_library", "//test/e2e/framework/addon:go_default_library", "//test/e2e/framework/log:go_default_library", diff --git a/test/e2e/suite/issuers/acme/certificate/notafter.go b/test/e2e/suite/issuers/acme/certificate/notafter.go new file mode 100644 index 000000000..9f5674df4 --- /dev/null +++ b/test/e2e/suite/issuers/acme/certificate/notafter.go @@ -0,0 +1,151 @@ +/* +Copyright 2019 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 certificate + +import ( + "context" + "fmt" + "time" + + "github.com/jetstack/cert-manager/pkg/util/pki" + corev1 "k8s.io/api/core/v1" + + cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1" + v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + "github.com/jetstack/cert-manager/test/e2e/framework" + frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util" + "github.com/jetstack/cert-manager/test/e2e/util" + "github.com/jetstack/cert-manager/test/unit/gen" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01 + Not After)", func() { + f := framework.NewDefaultFramework("create-acme-certificate-duration") + + var acmeIngressDomain string + issuerName := "test-acme-issuer" + certificateName := "test-acme-certificate" + certificateSecretName := "test-acme-certificate" + // fixedIngressName is the name of an ingress resource that is configured + // with a challenge solve. + // To utilise this solver, add the 'testing.cert-manager.io/fixed-ingress: "true"' label. + fixedIngressName := "testingress" + + BeforeEach(func() { + acmeIssuer := util.NewCertManagerACMEIssuer(issuerName, f.Config.Addons.ACMEServer.URL, testingACMEEmail, testingACMEPrivateKey) + // Enable NotAfter feature + acmeIssuer.Spec.ACME.EnableNotAfterDate = true + acmeIssuer.Spec.ACME.Solvers = []cmacme.ACMEChallengeSolver{ + { + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Ingress: &cmacme.ACMEChallengeSolverHTTP01Ingress{ + Class: &f.Config.Addons.IngressController.IngressClass, + }, + }, + }, + { + Selector: &cmacme.CertificateDNSNameSelector{ + MatchLabels: map[string]string{ + "testing.cert-manager.io/fixed-ingress": "true", + }, + }, + HTTP01: &cmacme.ACMEChallengeSolverHTTP01{ + Ingress: &cmacme.ACMEChallengeSolverHTTP01Ingress{ + Name: fixedIngressName, + }, + }, + }, + } + By("Creating an Issuer") + _, err := f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), acmeIssuer, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + By("Waiting for Issuer to become Ready") + err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + v1.IssuerCondition{ + Type: v1.IssuerConditionReady, + Status: cmmeta.ConditionTrue, + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying the ACME account URI is set") + err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name), + issuerName, + func(i *v1.Issuer) (bool, error) { + if i.GetStatus().ACMEStatus().URI == "" { + return false, nil + } + return true, nil + }) + Expect(err).NotTo(HaveOccurred()) + By("Verifying ACME account private key exists") + secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + if len(secret.Data) != 1 { + Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data)) + } + }) + + JustBeforeEach(func() { + acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.IngressController.Domain) + }) + + AfterEach(func() { + By("Cleaning up") + f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{}) + f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{}) + }) + + It("should obtain a signed certificate with a single CN from the ACME server with 1 hour validity", func() { + certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name) + + By("Creating a Certificate") + cert := gen.Certificate(certificateName, + gen.SetCertificateDuration(time.Hour), + gen.SetCertificateRenewBefore(45*time.Minute), + gen.SetCertificateSecretName(certificateSecretName), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}), + gen.SetCertificateDNSNames(acmeIngressDomain), + ) + cert.Namespace = f.Namespace.Name + + _, err := certClient.Create(context.TODO(), cert, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Waiting for the Certificate to be issued...") + err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5) + Expect(err).NotTo(HaveOccurred()) + + By("Validating the issued Certificate...") + err = f.Helper().ValidateCertificate(f.Namespace.Name, certificateName) + Expect(err).NotTo(HaveOccurred()) + + sec, err := f.Helper().WaitForSecretCertificateData(f.Namespace.Name, certificateSecretName, time.Minute*5) + Expect(err).NotTo(HaveOccurred(), "failed to wait for secret") + + crtPEM := sec.Data[corev1.TLSCertKey] + crt, err := pki.DecodeX509CertificateBytes(crtPEM) + Expect(err).NotTo(HaveOccurred(), "failed to get decode signed certificate data") + + // checking losely to tot hit too many timing issues as the date is defined in the controller + if crt.NotAfter.After(time.Now().Add(time.Hour)) { + Fail(fmt.Sprintf("Certificate has a NotAfter time after more than 1 hour (requested duration), got %s, current time %s", crt.NotAfter.String(), time.Now().String())) + } + }) +})