cert-manager
@@ -97,6 +97,10 @@ Appears In:
DNSNames is a list of subject alt names to be used on the Certificate |
+duration Duration |
+Certificate default Duration |
+
+
isCA boolean |
IsCA will mark this Certificate as valid for signing. This implies that the 'signing' usage is set |
@@ -117,6 +121,10 @@ Appears In:
Organization is the organization to be used on the Certificate |
+renewBefore Duration |
+Certificate renew before expiration duration |
+
+
secretName string |
SecretName is the name of the secret resource to store this secret in |
@@ -1386,6 +1394,45 @@ Appears In:
+
Duration v1
+
+
+
+| Group |
+Version |
+Kind |
+
+
+
+
+meta |
+v1 |
+Duration |
+
+
+
+
Duration is a wrapper around time.Duration which supports correct marshaling to YAML and JSON. In particular, it marshals into strings, which can be used as map keys in json.
+
+
+
+
+
+| Field |
+Description |
+
+
+
+
+Duration integer |
+ |
+
+
+
HTTP01SolverConfig v1alpha1
diff --git a/docs/generated/reference/output/reference/api-docs/navData.js b/docs/generated/reference/output/reference/api-docs/navData.js
index fa8246fcb..99e94cda7 100755
--- a/docs/generated/reference/output/reference/api-docs/navData.js
+++ b/docs/generated/reference/output/reference/api-docs/navData.js
@@ -1 +1 @@
-(function(){navData = {"toc":[{"section":"-strong-field-definitions-strong-","subsections":[{"section":"vaultissuer-v1alpha1"},{"section":"vaultauth-v1alpha1"},{"section":"vaultapprole-v1alpha1"},{"section":"time-v1"},{"section":"statusdetails-v1"},{"section":"statuscause-v1"},{"section":"status-v1"},{"section":"solverconfig-v1alpha1"},{"section":"selfsignedissuer-v1alpha1"},{"section":"secretkeyselector-v1alpha1"},{"section":"ownerreference-v1"},{"section":"objectreference-v1alpha1"},{"section":"objectmeta-v1"},{"section":"listmeta-v1"},{"section":"issuercondition-v1alpha1"},{"section":"initializers-v1"},{"section":"initializer-v1"},{"section":"http01solverconfig-v1alpha1"},{"section":"domainsolverconfig-v1alpha1"},{"section":"dns01solverconfig-v1alpha1"},{"section":"certificatecondition-v1alpha1"},{"section":"caissuer-v1alpha1"},{"section":"acmeissuerhttp01config-v1alpha1"},{"section":"acmeissuerdns01providerroute53-v1alpha1"},{"section":"acmeissuerdns01providerrfc2136-v1alpha1"},{"section":"acmeissuerdns01providerdigitalocean-v1alpha1"},{"section":"acmeissuerdns01providercloudflare-v1alpha1"},{"section":"acmeissuerdns01providerclouddns-v1alpha1"},{"section":"acmeissuerdns01providerazuredns-v1alpha1"},{"section":"acmeissuerdns01providerakamai-v1alpha1"},{"section":"acmeissuerdns01provideracmedns-v1alpha1"},{"section":"acmeissuerdns01provider-v1alpha1"},{"section":"acmeissuerdns01config-v1alpha1"},{"section":"acmeissuer-v1alpha1"},{"section":"acmecertificateconfig-v1alpha1"}]},{"section":"-strong-old-api-versions-strong-","subsections":[]},{"section":"challenge-v1alpha1","subsections":[]},{"section":"order-v1alpha1","subsections":[]},{"section":"issuer-v1alpha1","subsections":[]},{"section":"clusterissuer-v1alpha1","subsections":[]},{"section":"certificate-v1alpha1","subsections":[]},{"section":"-strong-cert-manager-strong-","subsections":[]}],"flatToc":["vaultissuer-v1alpha1","vaultauth-v1alpha1","vaultapprole-v1alpha1","time-v1","statusdetails-v1","statuscause-v1","status-v1","solverconfig-v1alpha1","selfsignedissuer-v1alpha1","secretkeyselector-v1alpha1","ownerreference-v1","objectreference-v1alpha1","objectmeta-v1","listmeta-v1","issuercondition-v1alpha1","initializers-v1","initializer-v1","http01solverconfig-v1alpha1","domainsolverconfig-v1alpha1","dns01solverconfig-v1alpha1","certificatecondition-v1alpha1","caissuer-v1alpha1","acmeissuerhttp01config-v1alpha1","acmeissuerdns01providerroute53-v1alpha1","acmeissuerdns01providerrfc2136-v1alpha1","acmeissuerdns01providerdigitalocean-v1alpha1","acmeissuerdns01providercloudflare-v1alpha1","acmeissuerdns01providerclouddns-v1alpha1","acmeissuerdns01providerazuredns-v1alpha1","acmeissuerdns01providerakamai-v1alpha1","acmeissuerdns01provideracmedns-v1alpha1","acmeissuerdns01provider-v1alpha1","acmeissuerdns01config-v1alpha1","acmeissuer-v1alpha1","acmecertificateconfig-v1alpha1","-strong-field-definitions-strong-","-strong-old-api-versions-strong-","challenge-v1alpha1","order-v1alpha1","issuer-v1alpha1","clusterissuer-v1alpha1","certificate-v1alpha1","-strong-cert-manager-strong-"]};})();
\ No newline at end of file
+(function(){navData = {"toc":[{"section":"-strong-field-definitions-strong-","subsections":[{"section":"vaultissuer-v1alpha1"},{"section":"vaultauth-v1alpha1"},{"section":"vaultapprole-v1alpha1"},{"section":"time-v1"},{"section":"statusdetails-v1"},{"section":"statuscause-v1"},{"section":"status-v1"},{"section":"solverconfig-v1alpha1"},{"section":"selfsignedissuer-v1alpha1"},{"section":"secretkeyselector-v1alpha1"},{"section":"ownerreference-v1"},{"section":"objectreference-v1alpha1"},{"section":"objectmeta-v1"},{"section":"listmeta-v1"},{"section":"issuercondition-v1alpha1"},{"section":"initializers-v1"},{"section":"initializer-v1"},{"section":"http01solverconfig-v1alpha1"},{"section":"duration-v1"},{"section":"domainsolverconfig-v1alpha1"},{"section":"dns01solverconfig-v1alpha1"},{"section":"certificatecondition-v1alpha1"},{"section":"caissuer-v1alpha1"},{"section":"acmeissuerhttp01config-v1alpha1"},{"section":"acmeissuerdns01providerroute53-v1alpha1"},{"section":"acmeissuerdns01providerrfc2136-v1alpha1"},{"section":"acmeissuerdns01providerdigitalocean-v1alpha1"},{"section":"acmeissuerdns01providercloudflare-v1alpha1"},{"section":"acmeissuerdns01providerclouddns-v1alpha1"},{"section":"acmeissuerdns01providerazuredns-v1alpha1"},{"section":"acmeissuerdns01providerakamai-v1alpha1"},{"section":"acmeissuerdns01provideracmedns-v1alpha1"},{"section":"acmeissuerdns01provider-v1alpha1"},{"section":"acmeissuerdns01config-v1alpha1"},{"section":"acmeissuer-v1alpha1"},{"section":"acmecertificateconfig-v1alpha1"}]},{"section":"-strong-old-api-versions-strong-","subsections":[]},{"section":"challenge-v1alpha1","subsections":[]},{"section":"order-v1alpha1","subsections":[]},{"section":"issuer-v1alpha1","subsections":[]},{"section":"clusterissuer-v1alpha1","subsections":[]},{"section":"certificate-v1alpha1","subsections":[]},{"section":"-strong-cert-manager-strong-","subsections":[]}],"flatToc":["vaultissuer-v1alpha1","vaultauth-v1alpha1","vaultapprole-v1alpha1","time-v1","statusdetails-v1","statuscause-v1","status-v1","solverconfig-v1alpha1","selfsignedissuer-v1alpha1","secretkeyselector-v1alpha1","ownerreference-v1","objectreference-v1alpha1","objectmeta-v1","listmeta-v1","issuercondition-v1alpha1","initializers-v1","initializer-v1","http01solverconfig-v1alpha1","duration-v1","domainsolverconfig-v1alpha1","dns01solverconfig-v1alpha1","certificatecondition-v1alpha1","caissuer-v1alpha1","acmeissuerhttp01config-v1alpha1","acmeissuerdns01providerroute53-v1alpha1","acmeissuerdns01providerrfc2136-v1alpha1","acmeissuerdns01providerdigitalocean-v1alpha1","acmeissuerdns01providercloudflare-v1alpha1","acmeissuerdns01providerclouddns-v1alpha1","acmeissuerdns01providerazuredns-v1alpha1","acmeissuerdns01providerakamai-v1alpha1","acmeissuerdns01provideracmedns-v1alpha1","acmeissuerdns01provider-v1alpha1","acmeissuerdns01config-v1alpha1","acmeissuer-v1alpha1","acmecertificateconfig-v1alpha1","-strong-field-definitions-strong-","-strong-old-api-versions-strong-","challenge-v1alpha1","order-v1alpha1","issuer-v1alpha1","clusterissuer-v1alpha1","certificate-v1alpha1","-strong-cert-manager-strong-"]};})();
\ No newline at end of file
diff --git a/docs/reference/certificates.rst b/docs/reference/certificates.rst
index 777df94fc..0e5f4974f 100644
--- a/docs/reference/certificates.rst
+++ b/docs/reference/certificates.rst
@@ -35,17 +35,18 @@ A simple Certificate could be defined as:
This Certificate will tell cert-manager to attempt to use the Issuer
named ``letsencrypt-prod`` to obtain a certificate key pair for the
-``foo.example.com`` and ``bar.example.com`` domains. If successful, the resulting
-key and certificate will be stored in a secret named ``acme-crt-secret`` with
-keys of ``tls.key`` and ``tls.crt`` respectively. This secret will live in the
-same namespace as the ``Certificate`` resource.
+``foo.example.com`` and ``bar.example.com`` domains. If successful, the
+resulting key and certificate will be stored in a secret named
+``acme-crt-secret`` with keys of ``tls.key`` and ``tls.crt`` respectively.
+This secret will live in the same namespace as the ``Certificate`` resource.
The ``dnsNames`` field specifies a list of `Subject Alternative Names`_ to be
associated with the certificate. If the ``commonName`` field is omitted, the
first element in the list will be the common name.
-The referenced Issuer must exist in the same namespace as the Certificate. A
-Certificate can alternatively reference a ClusterIssuer which is non-namespaced.
+The referenced Issuer must exist in the same namespace as the Certificate.
+A Certificate can alternatively reference a ClusterIssuer which is
+non-namespaced.
.. _`Subject Alternative Names`: https://en.wikipedia.org/wiki/Subject_Alternative_Name
@@ -54,3 +55,63 @@ Certificate can alternatively reference a ClusterIssuer which is non-namespaced.
:hidden:
certificates/issuer-specific-config/acme
+
+***************************************
+Certificate Duration and Renewal Window
+***************************************
+
+cert-manager Certificate resources also support custom validity durations and
+renewal windows.
+
+**Important**: The backend service implementation can choose to generate a
+certificate with a different validity period than what is requested in the
+issuer.
+
+Although the duration and renewal periods are specified on the Certificate
+resources, the corresponding Issuer or ClusterIssuer must support this.
+
+The table below shows the support state of the different backend services used
+by issuer types:
+
+=========== ============================================================
+Issuer Description
+=========== ============================================================
+ACME Only 'renewBefore' supported
+CA Fully supported
+Vault Fully supported (although the requested duration must be lower
+ than the configured Vault role's TTL)
+Self Signed Fully supported
+=========== ============================================================
+
+The default duration for all certificates is 90 days and the default renewal
+windows is 30 days. This means that certificates are considered valid for 3
+months and renewal will be attempted within 1 month of expiration.
+
+The *duration* and *renewBefore* parameters must be given in the golang `parseDuration string format `__.
+
+Example Usage
+=============
+Here an example of an issuer specifying the duration and renewal window.
+
+The certificate from the previous section is extended with a validity period of
+24 hours and to begin trying to renew 12 hours before the certificate
+expiration.
+
+ .. code-block:: yaml
+ :linenos:
+ :emphasize-lines: 7,8
+
+ apiVersion: certmanager.k8s.io/v1alpha1
+ kind: Certificate
+ metadata:
+ name: example
+ spec:
+ secretName: example-tls
+ duration: 24h
+ renewBefore: 12h
+ dnsNames:
+ - foo.example.com
+ - bar.example.com
+ issuerRef:
+ name: my-internal-ca
+ kind: Issuer
diff --git a/pkg/apis/certmanager/v1alpha1/BUILD.bazel b/pkg/apis/certmanager/v1alpha1/BUILD.bazel
index 8985b5af9..61e697a9d 100644
--- a/pkg/apis/certmanager/v1alpha1/BUILD.bazel
+++ b/pkg/apis/certmanager/v1alpha1/BUILD.bazel
@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
+ "const.go",
"conversion.go",
"defaults.go",
"doc.go",
diff --git a/pkg/apis/certmanager/v1alpha1/const.go b/pkg/apis/certmanager/v1alpha1/const.go
new file mode 100644
index 000000000..ea295c345
--- /dev/null
+++ b/pkg/apis/certmanager/v1alpha1/const.go
@@ -0,0 +1,33 @@
+/*
+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 "time"
+
+const (
+ // minimum permitted certificate duration by cert-manager
+ MinimumCertificateDuration = time.Hour
+
+ // default certificate duration if Issuer.spec.duration is not set
+ DefaultCertificateDuration = time.Hour * 24 * 90
+
+ // minimum certificate duration before certificate expiration
+ MinimumRenewBefore = time.Minute * 5
+
+ // Default duration before certificate expiration if Issuer.spec.renewBefore is not set
+ DefaultRenewBefore = time.Hour * 24 * 30
+)
diff --git a/pkg/apis/certmanager/v1alpha1/types_certificate.go b/pkg/apis/certmanager/v1alpha1/types_certificate.go
index 67e5fb057..f096f3928 100644
--- a/pkg/apis/certmanager/v1alpha1/types_certificate.go
+++ b/pkg/apis/certmanager/v1alpha1/types_certificate.go
@@ -57,6 +57,12 @@ type CertificateSpec struct {
// Organization is the organization to be used on the Certificate
Organization []string `json:"organization,omitempty"`
+ // Certificate default Duration
+ Duration *metav1.Duration `json:"duration,omitempty"`
+
+ // Certificate renew before expiration duration
+ RenewBefore *metav1.Duration `json:"renewBefore,omitempty"`
+
// DNSNames is a list of subject alt names to be used on the Certificate
DNSNames []string `json:"dnsNames,omitempty"`
diff --git a/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go
index 4a26fc512..919af8134 100644
--- a/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/certmanager/v1alpha1/zz_generated.deepcopy.go
@@ -468,6 +468,24 @@ func (in *CertificateSpec) DeepCopyInto(out *CertificateSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
+ if in.Duration != nil {
+ in, out := &in.Duration, &out.Duration
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(v1.Duration)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ if in.RenewBefore != nil {
+ in, out := &in.RenewBefore, &out.RenewBefore
+ if *in == nil {
+ *out = nil
+ } else {
+ *out = new(v1.Duration)
+ (*in).DeepCopyInto(*out)
+ }
+ }
if in.DNSNames != nil {
in, out := &in.DNSNames, &out.DNSNames
*out = make([]string, len(*in))
diff --git a/pkg/apis/certmanager/validation/BUILD.bazel b/pkg/apis/certmanager/validation/BUILD.bazel
index 415e3ed9d..c19cde07f 100644
--- a/pkg/apis/certmanager/validation/BUILD.bazel
+++ b/pkg/apis/certmanager/validation/BUILD.bazel
@@ -32,6 +32,7 @@ go_test(
"//pkg/issuer/acme/dns/rfc2136:go_default_library",
"//test/util/generate:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
],
)
diff --git a/pkg/apis/certmanager/validation/certificate.go b/pkg/apis/certmanager/validation/certificate.go
index e2ec69b2c..eeb638d33 100644
--- a/pkg/apis/certmanager/validation/certificate.go
+++ b/pkg/apis/certmanager/validation/certificate.go
@@ -70,6 +70,10 @@ func ValidateCertificateSpec(crt *v1alpha1.CertificateSpec, fldPath *field.Path)
el = append(el, field.Invalid(fldPath.Child("keyAlgorithm"), crt.KeyAlgorithm, "must be either empty or one of rsa or ecdsa"))
}
+ if crt.Duration != nil || crt.RenewBefore != nil {
+ el = append(el, ValidateDuration(crt, fldPath)...)
+ }
+
return el
}
@@ -148,3 +152,26 @@ func ValidateHTTP01SolverConfig(a *v1alpha1.HTTP01SolverConfig, fldPath *field.P
// TODO: ensure 'ingress' is a valid resource name (i.e. DNS name)
return el
}
+
+func ValidateDuration(crt *v1alpha1.CertificateSpec, fldPath *field.Path) field.ErrorList {
+ el := field.ErrorList{}
+
+ duration := v1alpha1.DefaultCertificateDuration
+ if crt.Duration != nil {
+ duration = crt.Duration.Duration
+ }
+ renewBefore := v1alpha1.DefaultRenewBefore
+ if crt.RenewBefore != nil {
+ renewBefore = crt.RenewBefore.Duration
+ }
+ if duration < v1alpha1.MinimumCertificateDuration {
+ el = append(el, field.Invalid(fldPath.Child("duration"), duration, fmt.Sprintf("certificate duration must be greater than %s", v1alpha1.MinimumCertificateDuration)))
+ }
+ if renewBefore < v1alpha1.MinimumRenewBefore {
+ el = append(el, field.Invalid(fldPath.Child("renewBefore"), renewBefore, fmt.Sprintf("certificate renewBefore must be greater than %s", v1alpha1.MinimumRenewBefore)))
+ }
+ if duration <= renewBefore {
+ el = append(el, field.Invalid(fldPath.Child("renewBefore"), renewBefore, fmt.Sprintf("certificate duration %s must be greater than renewBefore %s", duration, renewBefore)))
+ }
+ return el
+}
diff --git a/pkg/apis/certmanager/validation/certificate_for_issuer.go b/pkg/apis/certmanager/validation/certificate_for_issuer.go
index 3d6bb48e2..098a3e806 100644
--- a/pkg/apis/certmanager/validation/certificate_for_issuer.go
+++ b/pkg/apis/certmanager/validation/certificate_for_issuer.go
@@ -59,6 +59,10 @@ func ValidateCertificateForACMEIssuer(crt *v1alpha1.CertificateSpec, issuer *v1a
el = append(el, field.Invalid(specPath.Child("organization"), crt.Organization, "ACME does not support setting the organization name"))
}
+ if crt.Duration != nil {
+ el = append(el, field.Invalid(specPath.Child("duration"), crt.Duration, "ACME does not support certificate durations"))
+ }
+
return el
}
diff --git a/pkg/apis/certmanager/validation/certificate_for_issuer_test.go b/pkg/apis/certmanager/validation/certificate_for_issuer_test.go
index dc924b483..e7cd036ac 100644
--- a/pkg/apis/certmanager/validation/certificate_for_issuer_test.go
+++ b/pkg/apis/certmanager/validation/certificate_for_issuer_test.go
@@ -19,10 +19,13 @@ package validation
import (
"reflect"
"testing"
+ "time"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/test/util/generate"
"k8s.io/apimachinery/pkg/util/validation/field"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
@@ -130,6 +133,54 @@ func TestValidateCertificateForIssuer(t *testing.T) {
field.Invalid(fldPath.Child("organization"), []string{"shouldfailorg"}, "ACME does not support setting the organization name"),
},
},
+ "acme certificate with duration set": {
+ crt: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: &metav1.Duration{Duration: time.Minute * 60},
+ IssuerRef: validIssuerRef,
+ ACME: &v1alpha1.ACMECertificateConfig{
+ Config: []v1alpha1.DomainSolverConfig{
+ {
+ Domains: []string{"example.com"},
+ SolverConfig: v1alpha1.SolverConfig{
+ HTTP01: &v1alpha1.HTTP01SolverConfig{},
+ },
+ },
+ },
+ },
+ },
+ },
+ issuer: generate.Issuer(generate.IssuerConfig{
+ Name: defaultTestIssuerName,
+ Namespace: defaultTestNamespace,
+ }),
+ errs: []*field.Error{
+ field.Invalid(fldPath.Child("duration"), &metav1.Duration{Duration: time.Minute * 60}, "ACME does not support certificate durations"),
+ },
+ },
+ "acme certificate with renewBefore set": {
+ crt: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ RenewBefore: &metav1.Duration{Duration: time.Minute * 60},
+ IssuerRef: validIssuerRef,
+ ACME: &v1alpha1.ACMECertificateConfig{
+ Config: []v1alpha1.DomainSolverConfig{
+ {
+ Domains: []string{"example.com"},
+ SolverConfig: v1alpha1.SolverConfig{
+ HTTP01: &v1alpha1.HTTP01SolverConfig{},
+ },
+ },
+ },
+ },
+ },
+ },
+ issuer: generate.Issuer(generate.IssuerConfig{
+ Name: defaultTestIssuerName,
+ Namespace: defaultTestNamespace,
+ }),
+ errs: []*field.Error{},
+ },
"certificate with unspecified issuer type": {
crt: &v1alpha1.Certificate{
Spec: v1alpha1.CertificateSpec{
diff --git a/pkg/apis/certmanager/validation/certificate_test.go b/pkg/apis/certmanager/validation/certificate_test.go
index 4c253b3c4..a033439b1 100644
--- a/pkg/apis/certmanager/validation/certificate_test.go
+++ b/pkg/apis/certmanager/validation/certificate_test.go
@@ -17,11 +17,15 @@ limitations under the License.
package validation
import (
+ "fmt"
"reflect"
"testing"
+ "time"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"k8s.io/apimachinery/pkg/util/validation/field"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var (
@@ -545,3 +549,135 @@ func TestValidateHTTP01SolverConfig(t *testing.T) {
})
}
}
+
+func TestValidateDuration(t *testing.T) {
+ usefulDurations := map[string]*metav1.Duration{
+ "one second": {Duration: time.Second},
+ "ten minutes": {Duration: time.Minute * 10},
+ "half hour": {Duration: time.Minute * 30},
+ "one hour": {Duration: time.Hour},
+ "one month": {Duration: time.Hour * 24 * 30},
+ "half year": {Duration: time.Hour * 24 * 180},
+ "one year": {Duration: time.Hour * 24 * 365},
+ "ten years": {Duration: time.Hour * 24 * 365 * 10},
+ }
+
+ fldPath := field.NewPath("spec")
+ scenarios := map[string]struct {
+ cfg *v1alpha1.Certificate
+ errs []*field.Error
+ }{
+ "default duration and renewBefore": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ },
+ "valid duration and renewBefore": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: usefulDurations["one year"],
+ RenewBefore: usefulDurations["half year"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ },
+ "unset duration, valid renewBefore for default": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ RenewBefore: usefulDurations["one month"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ },
+ "unset renewBefore, valid duration for default": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: usefulDurations["one year"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ },
+ "renewBefore is bigger than the default duration": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ RenewBefore: usefulDurations["ten years"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ errs: []*field.Error{field.Invalid(fldPath.Child("renewBefore"), usefulDurations["ten years"].Duration, fmt.Sprintf("certificate duration %s must be greater than renewBefore %s", v1alpha1.DefaultCertificateDuration, usefulDurations["ten years"].Duration))},
+ },
+ "default renewBefore is bigger than the set duration": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: usefulDurations["one hour"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ errs: []*field.Error{field.Invalid(fldPath.Child("renewBefore"), v1alpha1.DefaultRenewBefore, fmt.Sprintf("certificate duration %s must be greater than renewBefore %s", usefulDurations["one hour"].Duration, v1alpha1.DefaultRenewBefore))},
+ },
+ "renewBefore is bigger than the duration": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: usefulDurations["one month"],
+ RenewBefore: usefulDurations["one year"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ errs: []*field.Error{field.Invalid(fldPath.Child("renewBefore"), usefulDurations["one year"].Duration, fmt.Sprintf("certificate duration %s must be greater than renewBefore %s", usefulDurations["one month"].Duration, usefulDurations["one year"].Duration))},
+ },
+ "renewBefore is less than the minimum permitted value": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ RenewBefore: usefulDurations["one second"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ errs: []*field.Error{field.Invalid(fldPath.Child("renewBefore"), usefulDurations["one second"].Duration, fmt.Sprintf("certificate renewBefore must be greater than %s", v1alpha1.MinimumRenewBefore))},
+ },
+ "duration is less than the minimum permitted value": {
+ cfg: &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: usefulDurations["half hour"],
+ RenewBefore: usefulDurations["ten minutes"],
+ CommonName: "testcn",
+ SecretName: "abc",
+ IssuerRef: validIssuerRef,
+ },
+ },
+ errs: []*field.Error{field.Invalid(fldPath.Child("duration"), usefulDurations["half hour"].Duration, fmt.Sprintf("certificate duration must be greater than %s", v1alpha1.MinimumCertificateDuration))},
+ },
+ }
+ for n, s := range scenarios {
+ t.Run(n, func(t *testing.T) {
+ errs := ValidateDuration(&s.cfg.Spec, fldPath)
+ if len(errs) != len(s.errs) {
+ t.Errorf("Expected %v but got %v", s.errs, errs)
+ return
+ }
+ for i, e := range errs {
+ expectedErr := s.errs[i]
+ if !reflect.DeepEqual(e, expectedErr) {
+ t.Errorf("Expected %v but got %v", expectedErr, e)
+ }
+ }
+ })
+ }
+}
diff --git a/pkg/apis/certmanager/validation/issuer.go b/pkg/apis/certmanager/validation/issuer.go
index 4dd85c1ae..cc1cf27b0 100644
--- a/pkg/apis/certmanager/validation/issuer.go
+++ b/pkg/apis/certmanager/validation/issuer.go
@@ -80,6 +80,7 @@ func ValidateIssuerConfig(iss *v1alpha1.IssuerConfig, fldPath *field.Path) field
if numConfigs == 0 {
el = append(el, field.Required(fldPath, "at least one issuer must be configured"))
}
+
return el
}
diff --git a/pkg/controller/BUILD.bazel b/pkg/controller/BUILD.bazel
index e5a2fb2b7..c44e27903 100644
--- a/pkg/controller/BUILD.bazel
+++ b/pkg/controller/BUILD.bazel
@@ -18,6 +18,7 @@ go_library(
"//pkg/client/listers/certmanager/v1alpha1:go_default_library",
"//pkg/issuer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//vendor/k8s.io/client-go/informers:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
diff --git a/pkg/controller/certificates/BUILD.bazel b/pkg/controller/certificates/BUILD.bazel
index 6b0eda134..acb486f3b 100644
--- a/pkg/controller/certificates/BUILD.bazel
+++ b/pkg/controller/certificates/BUILD.bazel
@@ -1,4 +1,4 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
@@ -48,3 +48,13 @@ filegroup(
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
+
+go_test(
+ name = "go_default_test",
+ srcs = ["sync_test.go"],
+ embed = [":go_default_library"],
+ deps = [
+ "//pkg/apis/certmanager/v1alpha1:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
+ ],
+)
diff --git a/pkg/controller/certificates/sync.go b/pkg/controller/certificates/sync.go
index b23f86694..26857aca9 100644
--- a/pkg/controller/certificates/sync.go
+++ b/pkg/controller/certificates/sync.go
@@ -18,6 +18,7 @@ package certificates
import (
"context"
+ "crypto/x509"
"fmt"
"reflect"
"strings"
@@ -69,6 +70,9 @@ var (
certificateGvk = v1alpha1.SchemeGroupVersion.WithKind("Certificate")
)
+// to help testing
+var now = time.Now
+
func (c *Controller) Sync(ctx context.Context, crt *v1alpha1.Certificate) (requeue bool, err error) {
crtCopy := crt.DeepCopy()
defer func() {
@@ -180,7 +184,7 @@ func (c *Controller) Sync(ctx context.Context, crt *v1alpha1.Certificate) (reque
}
// check if the certificate needs renewal
- needsRenew := c.Context.IssuerOptions.CertificateNeedsRenew(cert)
+ needsRenew := c.Context.IssuerOptions.CertificateNeedsRenew(cert, crt.Spec.RenewBefore)
if needsRenew {
return c.issue(ctx, i, crtCopy)
}
@@ -226,12 +230,11 @@ func (c *Controller) scheduleRenewal(crt *v1alpha1.Certificate) {
return
}
- durationUntilExpiry := cert.NotAfter.Sub(time.Now())
- renewIn := durationUntilExpiry - c.Context.IssuerOptions.RenewBeforeExpiryDuration
+ renewIn := c.calculateDurationUntilRenew(cert, crt)
c.scheduledWorkQueue.Add(key, renewIn)
- glog.Infof("Certificate %s/%s scheduled for renewal in %d hours", crt.Namespace, crt.Name, renewIn/time.Hour)
+ glog.Infof("Certificate %s/%s scheduled for renewal in %s", crt.Namespace, crt.Name, renewIn.String())
}
// issuerKind returns the kind of issuer for a certificate
@@ -341,3 +344,43 @@ func (c *Controller) updateCertificateStatus(old, new *v1alpha1.Certificate) (*v
// for CRDs (https://github.com/kubernetes/kubernetes/issues/38113)
return c.CMClient.CertmanagerV1alpha1().Certificates(new.Namespace).Update(new)
}
+
+// calculateDurationUntilRenew calculates how long cert-manager should wait to
+// until attempting to renew this certificate resource.
+func (c *Controller) calculateDurationUntilRenew(cert *x509.Certificate, crt *v1alpha1.Certificate) time.Duration {
+ messageCertificateDuration := "Certificate received from server has a validity duration of %s. The requested certificate validity duration was %s"
+ messageScheduleModified := "Certificate renewal duration was changed to fit inside the received certificate validity duration from issuer."
+
+ // validate if the certificate received was with the issuer configured
+ // duration. If not we generate an event to warn the user of that fact.
+ certDuration := cert.NotAfter.Sub(cert.NotBefore)
+ if crt.Spec.Duration != nil && certDuration < crt.Spec.Duration.Duration {
+ s := fmt.Sprintf(messageCertificateDuration, certDuration, crt.Spec.Duration.Duration)
+ glog.Info(s)
+ // TODO Use the message as the reason in a 'renewal status' condition
+ }
+
+ // renew is the duration before the certificate expiration that cert-manager
+ // will start to try renewing the certificate.
+ renewBefore := v1alpha1.DefaultRenewBefore
+ if crt.Spec.RenewBefore != nil {
+ renewBefore = crt.Spec.RenewBefore.Duration
+ }
+
+ // Verify that the renewBefore duration is inside the certificate validity duration.
+ // If not we notify with an event that we will renew the certificate
+ // before (certificate duration / 3) of its expiration duration.
+ if renewBefore > certDuration {
+ glog.Info(messageScheduleModified)
+ // TODO Use the message as the reason in a 'renewal status' condition
+ // We will renew 1/3 before the expiration date.
+ renewBefore = certDuration / 3
+ }
+
+ // calculate the amount of time until expiry
+ durationUntilExpiry := cert.NotAfter.Sub(now())
+ // calculate how long until we should start attempting to renew the certificate
+ renewIn := durationUntilExpiry - renewBefore
+
+ return renewIn
+}
diff --git a/pkg/controller/certificates/sync_test.go b/pkg/controller/certificates/sync_test.go
new file mode 100644
index 000000000..f1102f404
--- /dev/null
+++ b/pkg/controller/certificates/sync_test.go
@@ -0,0 +1,103 @@
+/*
+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 certificates
+
+import (
+ "crypto/x509"
+ "testing"
+ "time"
+
+ "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func TestCalculateDurationUntilRenew(t *testing.T) {
+ c := &Controller{}
+ currentTime := time.Now()
+ now = func() time.Time { return currentTime }
+ defer func() { now = time.Now }()
+ tests := []struct {
+ desc string
+ notBefore time.Time
+ notAfter time.Time
+ duration *metav1.Duration
+ renewBefore *metav1.Duration
+ expectedExpiry time.Duration
+ }{
+ {
+ desc: "generate an event if certificate duration is lower than requested duration",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour * 24 * 90),
+ duration: &metav1.Duration{time.Hour * 24 * 120},
+ renewBefore: nil,
+ expectedExpiry: time.Hour * 24 * 60,
+ },
+ {
+ desc: "default expiry to 30 days",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour * 24 * 120),
+ duration: nil,
+ renewBefore: nil,
+ expectedExpiry: (time.Hour * 24 * 120) - (time.Hour * 24 * 30),
+ },
+ {
+ desc: "default expiry to 2/3 of total duration if duration < 30 days",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour * 24 * 20),
+ duration: nil,
+ renewBefore: nil,
+ expectedExpiry: time.Hour * 24 * 20 * 2 / 3,
+ },
+ {
+ desc: "expiry of 2/3 of certificate duration when duration < 30 minutes",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour),
+ duration: &metav1.Duration{time.Hour},
+ renewBefore: &metav1.Duration{time.Hour / 3},
+ expectedExpiry: time.Hour * 2 / 3,
+ },
+ {
+ desc: "expiry of 60 days of certificate duration",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour * 24 * 365),
+ duration: &metav1.Duration{time.Hour * 24 * 365},
+ renewBefore: &metav1.Duration{time.Hour * 24 * 60},
+ expectedExpiry: (time.Hour * 24 * 365) - (time.Hour * 24 * 60),
+ },
+ {
+ desc: "expiry of 2/3 of certificate duration when renewBefore greater than certificate duration",
+ notBefore: now(),
+ notAfter: now().Add(time.Hour * 24 * 35),
+ duration: &metav1.Duration{time.Hour * 24 * 35},
+ renewBefore: &metav1.Duration{time.Hour * 24 * 40},
+ expectedExpiry: time.Hour * 24 * 35 * 2 / 3,
+ },
+ }
+ for k, v := range tests {
+ cert := &v1alpha1.Certificate{
+ Spec: v1alpha1.CertificateSpec{
+ Duration: v.duration,
+ RenewBefore: v.renewBefore,
+ },
+ }
+ x509Cert := &x509.Certificate{NotBefore: v.notBefore, NotAfter: v.notAfter}
+ duration := c.calculateDurationUntilRenew(x509Cert, cert)
+ if duration != v.expectedExpiry {
+ t.Errorf("test # %d - %s: got %v, expected %v", k, v.desc, duration, v.expectedExpiry)
+ }
+ }
+}
diff --git a/pkg/controller/helper.go b/pkg/controller/helper.go
index 4fc9a6198..cf30d8188 100644
--- a/pkg/controller/helper.go
+++ b/pkg/controller/helper.go
@@ -23,6 +23,7 @@ import (
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
cmlisters "github.com/jetstack/cert-manager/pkg/client/listers/certmanager/v1alpha1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type Helper interface {
@@ -90,12 +91,17 @@ func (o IssuerOptions) CanUseAmbientCredentials(iss cmapi.GenericIssuer) bool {
return false
}
-func (o IssuerOptions) CertificateNeedsRenew(cert *x509.Certificate) bool {
+func (o IssuerOptions) CertificateNeedsRenew(cert *x509.Certificate, renewBefore *metav1.Duration) bool {
+ renewBeforeDuration := o.RenewBeforeExpiryDuration
+ if renewBefore != nil {
+ renewBeforeDuration = renewBefore.Duration
+ }
+
// calculate the amount of time until expiry
durationUntilExpiry := cert.NotAfter.Sub(time.Now())
// calculate how long until we should start attempting to renew the
// certificate
- renewIn := durationUntilExpiry - o.RenewBeforeExpiryDuration
+ renewIn := durationUntilExpiry - renewBeforeDuration
// if we should being attempting to renew now, then trigger a renewal
if renewIn <= 0 {
return true
diff --git a/pkg/issuer/acme/issue.go b/pkg/issuer/acme/issue.go
index dd2c25a6f..34c2cf390 100644
--- a/pkg/issuer/acme/issue.go
+++ b/pkg/issuer/acme/issue.go
@@ -182,7 +182,7 @@ func (a *Acme) Issue(ctx context.Context, crt *v1alpha1.Certificate) (issuer.Iss
return a.retryOrder(crt, existingOrder)
}
- if a.Context.IssuerOptions.CertificateNeedsRenew(x509Cert) {
+ if a.Context.IssuerOptions.CertificateNeedsRenew(x509Cert, crt.Spec.RenewBefore) {
// existing order's certificate is near expiry
return a.retryOrder(crt, existingOrder)
}
diff --git a/pkg/issuer/vault/issue.go b/pkg/issuer/vault/issue.go
index f15c2352e..df41536ff 100644
--- a/pkg/issuer/vault/issue.go
+++ b/pkg/issuer/vault/issue.go
@@ -47,8 +47,6 @@ const (
messageErrorIssueCert = "Error issuing TLS certificate: "
messageCertIssued = "Certificate issued successfully"
-
- defaultCertificateDuration = time.Hour * 24 * 90
)
func (v *Vault) Issue(ctx context.Context, crt *v1alpha1.Certificate) (issuer.IssueResponse, error) {
@@ -98,7 +96,13 @@ func (v *Vault) obtainCertificate(ctx context.Context, crt *v1alpha1.Certificate
return nil, nil, nil, fmt.Errorf("error encoding certificate request: %s", err.Error())
}
- crtBytes, caBytes, err := v.requestVaultCert(template.Subject.CommonName, template.DNSNames, pemRequestBuf.Bytes())
+ certDuration := v1alpha1.DefaultCertificateDuration
+ if crt.Spec.Duration != nil {
+ certDuration = crt.Spec.Duration.Duration
+ }
+
+ crtBytes, caBytes, err := v.requestVaultCert(template.Subject.CommonName, certDuration, template.DNSNames, pemRequestBuf.Bytes())
+
if err != nil {
return nil, nil, nil, err
}
@@ -212,7 +216,7 @@ func (v *Vault) requestTokenWithAppRoleRef(client *vault.Client, appRole *v1alph
return token, nil
}
-func (v *Vault) requestVaultCert(commonName string, altNames []string, csr []byte) ([]byte, []byte, error) {
+func (v *Vault) requestVaultCert(commonName string, certDuration time.Duration, altNames []string, csr []byte) ([]byte, []byte, error) {
client, err := v.initVaultClient()
if err != nil {
return nil, nil, err
@@ -223,7 +227,7 @@ func (v *Vault) requestVaultCert(commonName string, altNames []string, csr []byt
parameters := map[string]string{
"common_name": commonName,
"alt_names": strings.Join(altNames, ","),
- "ttl": defaultCertificateDuration.String(),
+ "ttl": certDuration.String(),
"csr": string(csr),
"exclude_cn_from_sans": "true",
}
diff --git a/pkg/util/pki/csr.go b/pkg/util/pki/csr.go
index 0c059df5b..063a15e4e 100644
--- a/pkg/util/pki/csr.go
+++ b/pkg/util/pki/csr.go
@@ -86,9 +86,6 @@ func OrganizationForCertificate(crt *v1alpha1.Certificate) []string {
var serialNumberLimit = new(big.Int).Lsh(big.NewInt(1), 128)
-// default certification duration is 1 year
-const defaultNotAfter = time.Hour * 24 * 365
-
// GenerateCSR will generate a new *x509.CertificateRequest template to be used
// by issuers that utilise CSRs to obtain Certificates.
// The CSR will not be signed, and should be passed to either EncodeCSR or
@@ -139,7 +136,13 @@ func GenerateTemplate(issuer v1alpha1.GenericIssuer, crt *v1alpha1.Certificate)
return nil, fmt.Errorf("failed to generate serial number: %s", err.Error())
}
+ certDuration := v1alpha1.DefaultCertificateDuration
+ if crt.Spec.Duration != nil {
+ certDuration = crt.Spec.Duration.Duration
+ }
+
pubKeyAlgo, _, err := SignatureAlgorithm(crt)
+
if err != nil {
return nil, err
}
@@ -160,7 +163,7 @@ func GenerateTemplate(issuer v1alpha1.GenericIssuer, crt *v1alpha1.Certificate)
CommonName: commonName,
},
NotBefore: time.Now(),
- NotAfter: time.Now().Add(defaultNotAfter),
+ NotAfter: time.Now().Add(certDuration),
// see http://golang.org/pkg/crypto/x509/#KeyUsage
KeyUsage: keyUsages,
DNSNames: dnsNames,
diff --git a/pkg/util/pki/generate_test.go b/pkg/util/pki/generate_test.go
index 17b71889d..edc659b1e 100644
--- a/pkg/util/pki/generate_test.go
+++ b/pkg/util/pki/generate_test.go
@@ -240,7 +240,7 @@ func signTestCert(key crypto.Signer) *x509.Certificate {
CommonName: commonName,
},
NotBefore: time.Now(),
- NotAfter: time.Now().Add(defaultNotAfter),
+ NotAfter: time.Now().Add(v1alpha1.DefaultCertificateDuration),
// see http://golang.org/pkg/crypto/x509/#KeyUsage
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
}
diff --git a/test/e2e/framework/BUILD.bazel b/test/e2e/framework/BUILD.bazel
index 9f59e2da6..5a5cba75e 100644
--- a/test/e2e/framework/BUILD.bazel
+++ b/test/e2e/framework/BUILD.bazel
@@ -12,7 +12,9 @@ go_library(
tags = ["manual"],
visibility = ["//visibility:public"],
deps = [
+ "//pkg/apis/certmanager/v1alpha1:go_default_library",
"//pkg/client/clientset/versioned:go_default_library",
+ "//pkg/util/pki:go_default_library",
"//test/e2e/framework/addon:go_default_library",
"//test/e2e/framework/config:go_default_library",
"//test/e2e/framework/helper:go_default_library",
diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go
index 8fcc70ce5..54df96817 100644
--- a/test/e2e/framework/framework.go
+++ b/test/e2e/framework/framework.go
@@ -17,15 +17,23 @@ limitations under the License.
package framework
import (
+ "time"
+
"github.com/jetstack/cert-manager/test/e2e/framework/helper"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+
+ "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
+ "github.com/jetstack/cert-manager/pkg/util/pki"
"k8s.io/api/core/v1"
+ api "k8s.io/api/core/v1"
apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
+
"github.com/jetstack/cert-manager/test/e2e/framework/addon"
"github.com/jetstack/cert-manager/test/e2e/framework/config"
"github.com/jetstack/cert-manager/test/e2e/framework/util"
@@ -168,6 +176,22 @@ func (f *Framework) Helper() *helper.Helper {
}
}
+func (f *Framework) CertificateDurationValid(c *v1alpha1.Certificate, duration time.Duration) {
+ By("Verifying TLS certificate exists")
+ secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(c.Spec.SecretName, metav1.GetOptions{})
+ Expect(err).NotTo(HaveOccurred())
+ certBytes, ok := secret.Data[api.TLSCertKey]
+ if !ok {
+ Failf("No certificate data found for Certificate %q", c.Name)
+ }
+ cert, err := pki.DecodeX509CertificateBytes(certBytes)
+ Expect(err).NotTo(HaveOccurred())
+ By("Verifying that the duration is valid")
+ if cert.NotAfter.Sub(cert.NotBefore) != duration {
+ Failf("Expected duration of %s, got %s [NotBefore: %s, NotAfter: %s]", duration, cert.NotAfter.Sub(cert.NotBefore), cert.NotBefore.Format(time.RFC3339), cert.NotAfter.Format(time.RFC3339))
+ }
+}
+
// CertManagerDescribe is a wrapper function for ginkgo describe. Adds namespacing.
func CertManagerDescribe(text string, body func()) bool {
return Describe("[cert-manager] "+text, body)
diff --git a/test/e2e/suite/issuers/acme/certificate/http01.go b/test/e2e/suite/issuers/acme/certificate/http01.go
index f842bd938..4705494c0 100644
--- a/test/e2e/suite/issuers/acme/certificate/http01.go
+++ b/test/e2e/suite/issuers/acme/certificate/http01.go
@@ -116,7 +116,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
By("Creating a Certificate")
- _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, acmeIngressDomain))
+ _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil, acmeIngressClass, acmeIngressDomain))
Expect(err).NotTo(HaveOccurred())
By("Verifying the Certificate is valid")
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
@@ -130,7 +130,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
// the maximum length of a single segment of the domain being requested
const maxLengthOfDomainSegment = 63
By("Creating a Certificate")
- _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)))
+ _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil, acmeIngressClass, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)))
Expect(err).NotTo(HaveOccurred())
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
Expect(err).NotTo(HaveOccurred())
@@ -141,7 +141,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
By("Creating a Certificate")
- _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)))
+ _, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil, acmeIngressClass, acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)))
Expect(err).NotTo(HaveOccurred())
By("Verifying the Certificate is valid")
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
@@ -153,7 +153,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
By("Creating a Certificate")
- cert, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)))
+ cert, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil, acmeIngressClass, acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)))
Expect(err).NotTo(HaveOccurred())
By("Verifying the Certificate is valid")
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
@@ -180,7 +180,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
Skip("Poorly designed test skipped until it can be rewritten")
By("Creating a Certificate")
- _, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, "google.com"))
+ _, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil, acmeIngressClass, "google.com"))
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to not have a ready condition")
err = util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name),
diff --git a/test/e2e/suite/issuers/ca/BUILD.bazel b/test/e2e/suite/issuers/ca/BUILD.bazel
index 19a5fa3dd..2e7a0cead 100644
--- a/test/e2e/suite/issuers/ca/BUILD.bazel
+++ b/test/e2e/suite/issuers/ca/BUILD.bazel
@@ -18,6 +18,7 @@ go_library(
"//test/util:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
diff --git a/test/e2e/suite/issuers/ca/certificate.go b/test/e2e/suite/issuers/ca/certificate.go
index 70c61921b..57e5a78c6 100644
--- a/test/e2e/suite/issuers/ca/certificate.go
+++ b/test/e2e/suite/issuers/ca/certificate.go
@@ -25,6 +25,7 @@ import (
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/util"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var _ = framework.CertManagerDescribe("CA Certificate", func() {
@@ -64,7 +65,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
By("Creating a Certificate")
- _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
+ _, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil))
Expect(err).NotTo(HaveOccurred())
By("Verifying the Certificate is valid")
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
@@ -75,7 +76,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
- crt := util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind)
+ crt := util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil)
crt.Spec.KeyAlgorithm = v1alpha1.ECDSAKeyAlgorithm
crt.Spec.KeySize = 521
@@ -88,4 +89,39 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
Expect(err).NotTo(HaveOccurred())
})
+ cases := []struct {
+ inputDuration *metav1.Duration
+ inputRenewBefore *metav1.Duration
+ expectedDuration time.Duration
+ label string
+ }{
+ {
+ inputDuration: &metav1.Duration{time.Hour * 24 * 35},
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 35,
+ label: "35 days",
+ },
+ {
+ inputDuration: nil,
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 90,
+ label: "the default duration (90 days)",
+ },
+ }
+ for _, v := range cases {
+ v := v
+ It("should generate a signed keypair valid for "+v.label, func() {
+ certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
+ secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
+
+ By("Creating a Certificate")
+ cert, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, v.inputDuration, v.inputRenewBefore))
+ Expect(err).NotTo(HaveOccurred())
+ By("Verifying the Certificate is valid")
+ err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
+ f.CertificateDurationValid(cert, v.expectedDuration)
+ Expect(err).NotTo(HaveOccurred())
+ })
+ }
+
})
diff --git a/test/e2e/suite/issuers/selfsigned/BUILD.bazel b/test/e2e/suite/issuers/selfsigned/BUILD.bazel
index 9d2e593b8..c6262c0c0 100644
--- a/test/e2e/suite/issuers/selfsigned/BUILD.bazel
+++ b/test/e2e/suite/issuers/selfsigned/BUILD.bazel
@@ -12,6 +12,7 @@ go_library(
"//test/util:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
diff --git a/test/e2e/suite/issuers/selfsigned/certificate.go b/test/e2e/suite/issuers/selfsigned/certificate.go
index 1da5091e8..bb1c3ce10 100644
--- a/test/e2e/suite/issuers/selfsigned/certificate.go
+++ b/test/e2e/suite/issuers/selfsigned/certificate.go
@@ -17,6 +17,7 @@ limitations under the License.
package certificate
import (
+ "fmt"
"time"
. "github.com/onsi/ginkgo"
@@ -25,6 +26,7 @@ import (
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/util"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
@@ -51,9 +53,56 @@ var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
})
Expect(err).NotTo(HaveOccurred())
By("Creating a Certificate")
- _, err = certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
+ _, err = certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil))
Expect(err).NotTo(HaveOccurred())
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
Expect(err).NotTo(HaveOccurred())
})
+
+ cases := []struct {
+ inputDuration *metav1.Duration
+ inputRenewBefore *metav1.Duration
+ expectedDuration time.Duration
+ label string
+ }{
+ {
+ inputDuration: &metav1.Duration{time.Hour * 24 * 35},
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 35,
+ label: "35 days",
+ },
+ {
+ inputDuration: nil,
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 90,
+ label: "the default duration (90 days)",
+ },
+ }
+ for _, v := range cases {
+ v := v
+ It("should generate a signed keypair valid for "+v.label, func() {
+ certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
+ secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
+
+ By("Creating an Issuer")
+ issuerDurationName := fmt.Sprintf("%s-%d", issuerName, v.expectedDuration)
+ _, err := f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerSelfSignedIssuer(issuerDurationName))
+ Expect(err).NotTo(HaveOccurred())
+ By("Waiting for Issuer to become Ready")
+ err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
+ issuerDurationName,
+ v1alpha1.IssuerCondition{
+ Type: v1alpha1.IssuerConditionReady,
+ Status: v1alpha1.ConditionTrue,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating a Certificate")
+ cert, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerDurationName, v1alpha1.IssuerKind, v.inputDuration, v.inputRenewBefore))
+ Expect(err).NotTo(HaveOccurred())
+ err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
+ f.CertificateDurationValid(cert, v.expectedDuration)
+ Expect(err).NotTo(HaveOccurred())
+ })
+ }
})
diff --git a/test/e2e/suite/issuers/vault/certificate/BUILD.bazel b/test/e2e/suite/issuers/vault/certificate/BUILD.bazel
index 46dc126ee..d8648691d 100644
--- a/test/e2e/suite/issuers/vault/certificate/BUILD.bazel
+++ b/test/e2e/suite/issuers/vault/certificate/BUILD.bazel
@@ -17,6 +17,7 @@ go_library(
"//test/util:go_default_library",
"//vendor/github.com/onsi/ginkgo:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
+ "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
diff --git a/test/e2e/suite/issuers/vault/certificate/approle.go b/test/e2e/suite/issuers/vault/certificate/approle.go
index 7ace4d11f..20562eec9 100644
--- a/test/e2e/suite/issuers/vault/certificate/approle.go
+++ b/test/e2e/suite/issuers/vault/certificate/approle.go
@@ -28,6 +28,7 @@ import (
"github.com/jetstack/cert-manager/test/e2e/framework/addon/tiller"
vaultaddon "github.com/jetstack/cert-manager/test/e2e/framework/addon/vault"
"github.com/jetstack/cert-manager/test/util"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var _ = framework.CertManagerDescribe("Vault Certificate (AppRole)", func() {
@@ -98,6 +99,7 @@ var _ = framework.CertManagerDescribe("Vault Certificate (AppRole)", func() {
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
_, err := f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerVaultIssuerAppRole(issuerName, vaultURL, vaultPath, roleId, vaultSecretAppRoleName, authPath, vault.Details().VaultCA))
+
Expect(err).NotTo(HaveOccurred())
By("Waiting for Issuer to become Ready")
@@ -110,11 +112,75 @@ var _ = framework.CertManagerDescribe("Vault Certificate (AppRole)", func() {
Expect(err).NotTo(HaveOccurred())
By("Creating a Certificate")
- _, err = certClient.Create(util.NewCertManagerVaultCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
+ _, err = certClient.Create(util.NewCertManagerVaultCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil))
Expect(err).NotTo(HaveOccurred())
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
Expect(err).NotTo(HaveOccurred())
})
+
+ cases := []struct {
+ inputDuration *metav1.Duration
+ inputRenewBefore *metav1.Duration
+ expectedDuration time.Duration
+ label string
+ event string
+ }{
+ {
+ inputDuration: &metav1.Duration{time.Hour * 24 * 35},
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 35,
+ label: "valid for 35 days",
+ },
+ {
+ inputDuration: nil,
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 90,
+ label: "valid for the default value (90 days)",
+ },
+ {
+ inputDuration: &metav1.Duration{time.Hour * 24 * 365},
+ inputRenewBefore: nil,
+ expectedDuration: time.Hour * 24 * 90,
+ label: "with Vault configured maximum TTL duration (90 days) when requested duration is greater than TTL",
+ },
+ {
+ inputDuration: &metav1.Duration{time.Hour * 24 * 240},
+ inputRenewBefore: &metav1.Duration{time.Hour * 24 * 120},
+ expectedDuration: time.Hour * 24 * 90,
+ label: "with a warning event when renewBefore is bigger than the duration",
+ },
+ }
+
+ for _, v := range cases {
+ v := v
+ It("should generate a new certificate "+v.label, func() {
+ By("Creating an Issuer")
+ certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
+ secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
+
+ _, err := f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerVaultIssuerAppRole(issuerName, vault.Details().Host, vaultPath, roleId, vaultSecretAppRoleName, authPath, vault.Details().VaultCA))
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Waiting for Issuer to become Ready")
+ err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
+ issuerName,
+ v1alpha1.IssuerCondition{
+ Type: v1alpha1.IssuerConditionReady,
+ Status: v1alpha1.ConditionTrue,
+ })
+ Expect(err).NotTo(HaveOccurred())
+
+ By("Creating a Certificate")
+ cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerVaultCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, v.inputDuration, v.inputRenewBefore))
+ Expect(err).NotTo(HaveOccurred())
+
+ err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
+
+ // Vault substract 30 seconds to the NotBefore date.
+ f.CertificateDurationValid(cert, v.expectedDuration+(30*time.Second))
+ Expect(err).NotTo(HaveOccurred())
+ })
+ }
})
diff --git a/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go b/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go
index 1625550c3..d9474525c 100644
--- a/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go
+++ b/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go
@@ -111,7 +111,7 @@ var _ = framework.CertManagerDescribe("Vault Certificate (AppRole with a custom
Expect(err).NotTo(HaveOccurred())
By("Creating a Certificate")
- _, err = certClient.Create(util.NewCertManagerVaultCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
+ _, err = certClient.Create(util.NewCertManagerVaultCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, nil, nil))
Expect(err).NotTo(HaveOccurred())
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Minute*5)
diff --git a/test/e2e/suite/issuers/vault/issuer.go b/test/e2e/suite/issuers/vault/issuer.go
index c12e1ba0f..daecf1805 100644
--- a/test/e2e/suite/issuers/vault/issuer.go
+++ b/test/e2e/suite/issuers/vault/issuer.go
@@ -94,7 +94,6 @@ var _ = framework.CertManagerDescribe("Vault Issuer", func() {
_, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(vaultaddon.NewVaultAppRoleSecret(vaultSecretAppRoleName, secretId))
Expect(err).NotTo(HaveOccurred())
- By("Creating an Issuer")
_, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerVaultIssuerAppRole(issuerName, vault.Details().Host, vaultPath, roleId, vaultSecretAppRoleName, authPath, vault.Details().VaultCA))
Expect(err).NotTo(HaveOccurred())
diff --git a/test/util/generate/certificate.go b/test/util/generate/certificate.go
index f901c181c..85a053100 100644
--- a/test/util/generate/certificate.go
+++ b/test/util/generate/certificate.go
@@ -31,6 +31,8 @@ type CertificateConfig struct {
SecretName string
CommonName string
DNSNames []string
+ Duration *metav1.Duration
+ RenewBefore *metav1.Duration
// ACME parameters
SolverConfig v1alpha1.SolverConfig
@@ -43,7 +45,9 @@ func Certificate(cfg CertificateConfig) *v1alpha1.Certificate {
Namespace: cfg.Namespace,
},
Spec: v1alpha1.CertificateSpec{
- SecretName: cfg.SecretName,
+ Duration: cfg.Duration,
+ RenewBefore: cfg.RenewBefore,
+ SecretName: cfg.SecretName,
IssuerRef: v1alpha1.ObjectReference{
Name: cfg.IssuerName,
Kind: cfg.IssuerKind,
diff --git a/test/util/util.go b/test/util/util.go
index e70b9857c..acfb5d950 100644
--- a/test/util/util.go
+++ b/test/util/util.go
@@ -350,7 +350,7 @@ func NewCertManagerCAClusterIssuer(name, secretName string) *v1alpha1.ClusterIss
}
}
-func NewCertManagerBasicCertificate(name, secretName, issuerName string, issuerKind string) *v1alpha1.Certificate {
+func NewCertManagerBasicCertificate(name, secretName, issuerName string, issuerKind string, duration, renewBefore *metav1.Duration) *v1alpha1.Certificate {
return &v1alpha1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: name,
@@ -359,6 +359,8 @@ func NewCertManagerBasicCertificate(name, secretName, issuerName string, issuerK
CommonName: "test.domain.com",
Organization: []string{"test-org"},
SecretName: secretName,
+ Duration: duration,
+ RenewBefore: renewBefore,
IssuerRef: v1alpha1.ObjectReference{
Name: issuerName,
Kind: issuerKind,
@@ -367,15 +369,17 @@ func NewCertManagerBasicCertificate(name, secretName, issuerName string, issuerK
}
}
-func NewCertManagerACMECertificate(name, secretName, issuerName string, issuerKind string, ingressClass string, cn string, dnsNames ...string) *v1alpha1.Certificate {
+func NewCertManagerACMECertificate(name, secretName, issuerName string, issuerKind string, duration, renewBefore *metav1.Duration, ingressClass string, cn string, dnsNames ...string) *v1alpha1.Certificate {
return &v1alpha1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1alpha1.CertificateSpec{
- CommonName: cn,
- DNSNames: dnsNames,
- SecretName: secretName,
+ CommonName: cn,
+ DNSNames: dnsNames,
+ SecretName: secretName,
+ Duration: duration,
+ RenewBefore: renewBefore,
IssuerRef: v1alpha1.ObjectReference{
Name: issuerName,
Kind: issuerKind,
@@ -396,14 +400,16 @@ func NewCertManagerACMECertificate(name, secretName, issuerName string, issuerKi
}
}
-func NewCertManagerVaultCertificate(name, secretName, issuerName string, issuerKind string) *v1alpha1.Certificate {
+func NewCertManagerVaultCertificate(name, secretName, issuerName string, issuerKind string, duration, renewBefore *metav1.Duration) *v1alpha1.Certificate {
return &v1alpha1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1alpha1.CertificateSpec{
- CommonName: "test.domain.com",
- SecretName: secretName,
+ CommonName: "test.domain.com",
+ SecretName: secretName,
+ Duration: duration,
+ RenewBefore: renewBefore,
IssuerRef: v1alpha1.ObjectReference{
Name: issuerName,
Kind: issuerKind,