Add e2e test to ensure changing dnsNames on an ACME certificate triggers a re-issue
This commit is contained in:
parent
840f9de7d9
commit
5a102fb5f6
@ -92,10 +92,15 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
|
||||
})
|
||||
|
||||
It("should obtain a signed certificate with a single CN from the ACME server", func() {
|
||||
certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
|
||||
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
|
||||
|
||||
By("Creating a Certificate")
|
||||
cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain))
|
||||
_, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Verifying the Certificate is valid")
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
f.WaitCertificateIssuedValid(cert)
|
||||
})
|
||||
|
||||
It("should obtain a signed certificate for a long domain using http01 validation", func() {
|
||||
@ -108,10 +113,43 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
|
||||
})
|
||||
|
||||
It("should obtain a signed certificate with a CN and single subdomain as dns name from the ACME server", func() {
|
||||
certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
|
||||
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
|
||||
|
||||
By("Creating a Certificate")
|
||||
cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)))
|
||||
_, err := certClient.Create(util.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Verifying the Certificate is valid")
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should allow updating an existing certificate with a new dns name", 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.NewCertManagerACMECertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind, acmeIngressClass, util.ACMECertificateDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Verifying the Certificate is valid")
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Getting the latest version of the Certificate")
|
||||
cert, err = certClient.Get(certificateName, metav1.GetOptions{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Adding an additional dnsName to the Certificate")
|
||||
newDNSName := fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), util.ACMECertificateDomain)
|
||||
cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName)
|
||||
cert.Spec.ACME.Config[0].Domains = append(cert.Spec.ACME.Config[0].Domains, newDNSName)
|
||||
|
||||
By("Updating the Certificate in the apiserver")
|
||||
cert, err = certClient.Update(cert)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
f.WaitCertificateIssuedValid(cert)
|
||||
})
|
||||
|
||||
It("should fail to obtain a certificate for an invalid ACME dns name", func() {
|
||||
@ -130,4 +168,26 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
|
||||
_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
|
||||
Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
|
||||
})
|
||||
|
||||
It("should obtain a signed certificate with a single CN from the ACME server when putting an annotation on an ingress resource", func() {
|
||||
ingClient := f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.Namespace.Name)
|
||||
certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
|
||||
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
|
||||
|
||||
By("Creating an Ingress with the issuer name annotation set")
|
||||
_, err := ingClient.Create(util.NewIngress(certificateSecretName, certificateSecretName, map[string]string{
|
||||
"certmanager.k8s.io/issuer": issuerName,
|
||||
"certmanager.k8s.io/acme-challenge-provider": "http01",
|
||||
}, util.ACMECertificateDomain))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Waiting for Certificate to exist")
|
||||
err = util.WaitForCertificateToExist(certClient, certificateSecretName, foreverTestTimeout)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Verifying the Certificate is valid")
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
@ -14,6 +14,8 @@ limitations under the License.
|
||||
package certificate
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
@ -34,16 +36,9 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
|
||||
By("Creating a signing keypair fixture")
|
||||
_, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(util.NewSigningKeypairSecret(issuerSecretName))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Cleaning up")
|
||||
f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(issuerSecretName, nil)
|
||||
})
|
||||
|
||||
It("should generate a signed keypair", func() {
|
||||
By("Creating an Issuer")
|
||||
_, err := f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerCAIssuer(issuerName, issuerSecretName))
|
||||
_, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerCAIssuer(issuerName, issuerSecretName))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Waiting for Issuer to become Ready")
|
||||
err = util.WaitForIssuerCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
|
||||
@ -53,10 +48,24 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
|
||||
Status: v1alpha1.ConditionTrue,
|
||||
})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Cleaning up")
|
||||
f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(issuerSecretName, nil)
|
||||
f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Delete(issuerName, nil)
|
||||
})
|
||||
|
||||
It("should generate a signed keypair", func() {
|
||||
certClient := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name)
|
||||
secretClient := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name)
|
||||
|
||||
By("Creating a Certificate")
|
||||
cert, err := f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name).Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
|
||||
_, err := certClient.Create(util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1alpha1.IssuerKind))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Verifying the Certificate is valid")
|
||||
err = util.WaitCertificateIssuedValid(certClient, secretClient, certificateName, time.Second*30)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
f.WaitCertificateIssuedValid(cert)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@ -31,7 +31,6 @@ import (
|
||||
_ "github.com/jetstack/cert-manager/test/e2e/certificate"
|
||||
_ "github.com/jetstack/cert-manager/test/e2e/clusterissuer"
|
||||
"github.com/jetstack/cert-manager/test/e2e/framework"
|
||||
_ "github.com/jetstack/cert-manager/test/e2e/ingress"
|
||||
_ "github.com/jetstack/cert-manager/test/e2e/issuer"
|
||||
)
|
||||
|
||||
|
||||
@ -1,108 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 Jetstack Ltd.
|
||||
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 ingress
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
"github.com/jetstack/cert-manager/test/e2e/framework"
|
||||
"github.com/jetstack/cert-manager/test/util"
|
||||
)
|
||||
|
||||
const testingACMEEmail = "test@example.com"
|
||||
const testingACMEPrivateKey = "test-acme-private-key"
|
||||
const foreverTestTimeout = time.Second * 60
|
||||
|
||||
var _ = framework.CertManagerDescribe("ACME Certificate with Ingress (HTTP01)", func() {
|
||||
f := framework.NewDefaultFramework("create-acme-certificate-http01-ingress")
|
||||
|
||||
issuerName := "test-acme-issuer"
|
||||
certificateSecretName := "test-acme-certificate"
|
||||
|
||||
BeforeEach(func() {
|
||||
By("Verifying there is no existing ACME private key")
|
||||
_, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(testingACMEPrivateKey, metav1.GetOptions{})
|
||||
Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), testingACMEPrivateKey)))
|
||||
By("Verifying there is no existing TLS certificate secret")
|
||||
_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
|
||||
Expect(err).To(MatchError(apierrors.NewNotFound(corev1.Resource("secrets"), certificateSecretName)))
|
||||
By("Creating an Issuer")
|
||||
_, err = f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Create(util.NewCertManagerACMEIssuer(issuerName, framework.TestContext.ACMEURL, testingACMEEmail, testingACMEPrivateKey))
|
||||
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("Verifying the ACME account URI is set")
|
||||
err = util.WaitForIssuerStatusFunc(f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name),
|
||||
issuerName,
|
||||
func(i *v1alpha1.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(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))
|
||||
}
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Cleaning up")
|
||||
f.CertManagerClientSet.CertmanagerV1alpha1().Issuers(f.Namespace.Name).Delete(issuerName, nil)
|
||||
f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(testingACMEPrivateKey, nil)
|
||||
})
|
||||
|
||||
It("should obtain a signed certificate with a single CN from the ACME server when putting an annotation on an ingress resource", func() {
|
||||
By("Creating an Ingress with the issuer name annotation set")
|
||||
_, err := f.KubeClientSet.ExtensionsV1beta1().Ingresses(f.Namespace.Name).Create(util.NewIngress(certificateSecretName, certificateSecretName, map[string]string{
|
||||
"certmanager.k8s.io/issuer": issuerName,
|
||||
"certmanager.k8s.io/acme-challenge-provider": "http01",
|
||||
}, util.ACMECertificateDomain))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Waiting for Certificate to exist")
|
||||
err = util.WaitForCertificateToExist(f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name), certificateSecretName, foreverTestTimeout)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Waiting for Certificate to become Ready")
|
||||
err = util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1alpha1().Certificates(f.Namespace.Name),
|
||||
certificateSecretName,
|
||||
v1alpha1.CertificateCondition{
|
||||
Type: v1alpha1.CertificateConditionReady,
|
||||
Status: v1alpha1.ConditionTrue,
|
||||
}, foreverTestTimeout)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
By("Verifying TLS certificate exists")
|
||||
secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(certificateSecretName, metav1.GetOptions{})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
if len(secret.Data) != 2 {
|
||||
Fail("Expected 2 keys in ACME certificate secret, but there was %d", len(secret.Data))
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
@ -16,10 +16,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
corecs "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
|
||||
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned/typed/certmanager/v1alpha1"
|
||||
"github.com/jetstack/cert-manager/pkg/util"
|
||||
"github.com/jetstack/cert-manager/pkg/util/pki"
|
||||
)
|
||||
|
||||
var ACMECertificateDomain string
|
||||
@ -189,6 +191,55 @@ func wrapErrorWithCertificateStatusCondition(client clientset.CertificateInterfa
|
||||
return pollErr
|
||||
}
|
||||
|
||||
// WaitCertificateIssuedValid waits for the given Certificate to be
|
||||
// 'Ready' and ensures the stored certificate is valid for the specified
|
||||
// domains.
|
||||
func WaitCertificateIssuedValid(certClient clientset.CertificateInterface, secretClient corecs.SecretInterface, name string, timeout time.Duration) error {
|
||||
return wait.PollImmediate(time.Second, timeout,
|
||||
func() (bool, error) {
|
||||
glog.V(5).Infof("Waiting for Certificate %v to be ready", name)
|
||||
certificate, err := certClient.Get(name, metav1.GetOptions{})
|
||||
if nil != err {
|
||||
return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
|
||||
}
|
||||
isReady := certificate.HasCondition(v1alpha1.CertificateCondition{
|
||||
Type: v1alpha1.CertificateConditionReady,
|
||||
Status: v1alpha1.ConditionTrue,
|
||||
})
|
||||
if !isReady {
|
||||
return false, nil
|
||||
}
|
||||
glog.Infof("Getting the TLS certificate Secret resource")
|
||||
secret, err := secretClient.Get(certificate.Spec.SecretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(secret.Data) != 2 {
|
||||
glog.Infof("Expected 2 keys in certificate secret, but there was %d", len(secret.Data))
|
||||
return false, nil
|
||||
}
|
||||
certBytes, ok := secret.Data[v1.TLSCertKey]
|
||||
if !ok {
|
||||
glog.Infof("No certificate data found for Certificate %q (secret %q)", name, certificate.Spec.SecretName)
|
||||
return false, nil
|
||||
}
|
||||
// check the provided certificate is valid
|
||||
expectedCN := pki.CommonNameForCertificate(certificate)
|
||||
expectedDNSNames := pki.DNSNamesForCertificate(certificate)
|
||||
|
||||
cert, err := pki.DecodeX509CertificateBytes(certBytes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if expectedCN != cert.Subject.CommonName || !util.EqualUnsorted(cert.DNSNames, expectedDNSNames) {
|
||||
glog.Infof("Expected certificate valid for CN %q, dnsNames %v but got a certificate valid for CN %q, dnsNames %v", expectedCN, expectedDNSNames, cert.Subject.CommonName, cert.DNSNames)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// WaitForCertificateToExist waits for the named certificate to exist
|
||||
func WaitForCertificateToExist(client clientset.CertificateInterface, name string, timeout time.Duration) error {
|
||||
return wait.PollImmediate(500*time.Millisecond, timeout,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user