diff --git a/test/e2e/certificate/certificate_acme.go b/test/e2e/certificate/certificate_acme.go index e5c178ae9..88e4b6ef5 100644 --- a/test/e2e/certificate/certificate_acme.go +++ b/test/e2e/certificate/certificate_acme.go @@ -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()) + + }) }) diff --git a/test/e2e/certificate/certificate_ca.go b/test/e2e/certificate/certificate_ca.go index bd47a2913..b74c672d7 100644 --- a/test/e2e/certificate/certificate_ca.go +++ b/test/e2e/certificate/certificate_ca.go @@ -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) }) }) diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go index d2f6587b9..9ee12b2d8 100644 --- a/test/e2e/e2e.go +++ b/test/e2e/e2e.go @@ -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" ) diff --git a/test/e2e/ingress/certificate_acme.go b/test/e2e/ingress/certificate_acme.go deleted file mode 100644 index 9cd601e3f..000000000 --- a/test/e2e/ingress/certificate_acme.go +++ /dev/null @@ -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)) - } - }) - -}) diff --git a/test/util/util.go b/test/util/util.go index ab655f862..b773f1872 100644 --- a/test/util/util.go +++ b/test/util/util.go @@ -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,