Repository: jetstack/cert-manager
Pull request #4168 (2021-07-01 08:37:23)

Bumps base image versions
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. If this is your first time, read our contributor guidelines https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
3. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
4. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What this PR does / why we need it**:

Bumps base images.

I wonder if we should have some automation for this.



**Release note**:
<!--  Steps to write your release note:
1. Use the release-note-* labels to set the release note state (if you have access)
2. Enter your extended release note in the below block; leaving it blank means using the PR title as the release note. If no release note is required, just write `NONE`.
-->
```release-note
NONE
```

/kind cleanup

Signed-off-by: irbekrm <irbekrm@gmail.com>



Patch:
diff --git a/build/images.bzl b/build/images.bzl
index a0341d451..cfd55c3c5 100644
--- a/build/images.bzl
+++ b/build/images.bzl
@@ -23,7 +23,7 @@ def define_base_images():
         name = "static_base",
         registry = "gcr.io",
         repository = "distroless/static",
-        digest = "sha256:a7752b29b18bb106938caefd8dcce8a94199022cbd06ea42268b968f35e837a8",
+        digest = "sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be",
     )
     # Use 'dynamic' distroless image for modified cert-manager deployments that
     # are dynamically linked. (This is not the default and you probably don't
@@ -35,5 +35,5 @@ def define_base_images():
         name = "dynamic_base",
         registry = "gcr.io",
         repository = "distroless/base",
-        digest = "sha256:75f63d4edd703030d4312dc7528a349ca34d48bec7bd754652b2d47e5a0b7873",
+        digest = "sha256:7ee881c16507dafc507113b50728adc2bc0a232e7b7052301622660c99cf5702",
     )
diff --git a/pkg/api/util/conditions.go b/pkg/api/util/conditions.go
index 985175e61..30df531d2 100644
--- a/pkg/api/util/conditions.go
+++ b/pkg/api/util/conditions.go
@@ -113,25 +113,6 @@ func CertificateHasCondition(crt *cmapi.Certificate, c cmapi.CertificateConditio
 	return false
 }
 
-// CertificateHasConditionWithObservedGeneration will return true if the given Certificate has a
-// condition matching the provided CertificateCondition with a ObservedGeneration
-// that is bigger or equal to the ObservedGeneration of the provided CertificateCondition.
-// Only the Type, Status and ObservedGeneration field will be used in the comparison,
-// meaning that this function will return 'true' even if the Reason, Message and
-// LastTransitionTime fields do not match.
-func CertificateHasConditionWithObservedGeneration(crt *cmapi.Certificate, c cmapi.CertificateCondition) bool {
-	if crt == nil {
-		return false
-	}
-	existingConditions := crt.Status.Conditions
-	for _, cond := range existingConditions {
-		if c.Type == cond.Type && c.Status == cond.Status && c.ObservedGeneration <= cond.ObservedGeneration {
-			return true
-		}
-	}
-	return false
-}
-
 func GetCertificateCondition(crt *cmapi.Certificate, conditionType cmapi.CertificateConditionType) *cmapi.CertificateCondition {
 	for _, cond := range crt.Status.Conditions {
 		if cond.Type == conditionType {
diff --git a/pkg/apis/experimental/v1alpha1/types.go b/pkg/apis/experimental/v1alpha1/types.go
index 59b8aff0e..625fbea4a 100644
--- a/pkg/apis/experimental/v1alpha1/types.go
+++ b/pkg/apis/experimental/v1alpha1/types.go
@@ -33,4 +33,8 @@ const (
 	// This annotation *may* not be present, and is used by the 'self signing'
 	// issuer type to self-sign certificates.
 	CertificateSigningRequestPrivateKeyAnnotationKey = "experimental.cert-manager.io/private-key-secret-name"
+
+	// CertificateSigningRequestCAAnnotationKey is the annotation key which will
+	// contain the base 64 encoded resulting CA certificate which signed the CSR.
+	CertificateSigningRequestCAAnnotationKey = "experimental.cert-manager.io/ca"
 )
diff --git a/pkg/controller/certificatesigningrequests/ca/BUILD.bazel b/pkg/controller/certificatesigningrequests/ca/BUILD.bazel
index beb7cd401..7b2d35867 100644
--- a/pkg/controller/certificatesigningrequests/ca/BUILD.bazel
+++ b/pkg/controller/certificatesigningrequests/ca/BUILD.bazel
@@ -8,6 +8,7 @@ go_library(
     deps = [
         "//pkg/api/util:go_default_library",
         "//pkg/apis/certmanager/v1:go_default_library",
+        "//pkg/apis/experimental/v1alpha1:go_default_library",
         "//pkg/controller:go_default_library",
         "//pkg/controller/certificatesigningrequests:go_default_library",
         "//pkg/controller/certificatesigningrequests/util:go_default_library",
diff --git a/pkg/controller/certificatesigningrequests/ca/ca.go b/pkg/controller/certificatesigningrequests/ca/ca.go
index c9ef0a691..7b4ebbc80 100644
--- a/pkg/controller/certificatesigningrequests/ca/ca.go
+++ b/pkg/controller/certificatesigningrequests/ca/ca.go
@@ -20,6 +20,7 @@ import (
 	"context"
 	"crypto"
 	"crypto/x509"
+	"encoding/base64"
 	"fmt"
 
 	certificatesv1 "k8s.io/api/certificates/v1"
@@ -32,6 +33,7 @@ import (
 
 	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
 	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
+	experimentalapi "github.com/jetstack/cert-manager/pkg/apis/experimental/v1alpha1"
 	controllerpkg "github.com/jetstack/cert-manager/pkg/controller"
 	"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests"
 	"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/util"
@@ -136,6 +138,8 @@ func (c *CA) Sign(ctx context.Context, csr *certificatesv1.CertificateSigningReq
 		return err
 	}
 
+	// Update the status.certificate first so that the sync from updating will
+	// not cause another issuance before setting the CA.
 	csr.Status.Certificate = bundle.ChainPEM
 	csr, err = c.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
 	if err != nil {
@@ -144,6 +148,17 @@ func (c *CA) Sign(ctx context.Context, csr *certificatesv1.CertificateSigningReq
 		return err
 	}
 
+	if csr.Annotations == nil {
+		csr.Annotations = make(map[string]string)
+	}
+	csr.Annotations[experimentalapi.CertificateSigningRequestCAAnnotationKey] = base64.StdEncoding.EncodeToString(bundle.CAPEM)
+	_, err = c.certClient.Update(ctx, csr, metav1.UpdateOptions{})
+	if err != nil {
+		message := fmt.Sprintf("Error setting %q", experimentalapi.CertificateSigningRequestCAAnnotationKey)
+		c.recorder.Eventf(csr, corev1.EventTypeWarning, "SigningError", "%s: %s", message, err)
+		return err
+	}
+
 	log.V(logf.DebugLevel).Info("certificate issued")
 	c.recorder.Event(csr, corev1.EventTypeNormal, "CertificateIssued", "Certificate fetched from issuer successfully")
 
diff --git a/pkg/controller/certificatesigningrequests/selfsigned/selfsigned.go b/pkg/controller/certificatesigningrequests/selfsigned/selfsigned.go
index a4963b846..841234806 100644
--- a/pkg/controller/certificatesigningrequests/selfsigned/selfsigned.go
+++ b/pkg/controller/certificatesigningrequests/selfsigned/selfsigned.go
@@ -20,6 +20,7 @@ import (
 	"context"
 	"crypto"
 	"crypto/x509"
+	"encoding/base64"
 	"errors"
 	"fmt"
 
@@ -180,6 +181,8 @@ func (s *SelfSigned) Sign(ctx context.Context, csr *certificatesv1.CertificateSi
 		return err
 	}
 
+	// Update the status.certificate first so that the sync from updating will
+	// not cause another issuance before setting the CA.
 	csr.Status.Certificate = certPEM
 	csr, err = s.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
 	if err != nil {
@@ -188,6 +191,14 @@ func (s *SelfSigned) Sign(ctx context.Context, csr *certificatesv1.CertificateSi
 		return err
 	}
 
+	csr.GetAnnotations()[experimentalapi.CertificateSigningRequestCAAnnotationKey] = base64.StdEncoding.EncodeToString(certPEM)
+	_, err = s.certClient.Update(ctx, csr, metav1.UpdateOptions{})
+	if err != nil {
+		message := fmt.Sprintf("Error setting %q", experimentalapi.CertificateSigningRequestCAAnnotationKey)
+		s.recorder.Eventf(csr, corev1.EventTypeWarning, "ErrorCAUpdate", "%s: %s", message, err)
+		return err
+	}
+
 	log.V(logf.DebugLevel).Info("self signed certificate issued")
 	s.recorder.Event(csr, corev1.EventTypeNormal, "CertificateIssued", "Certificate self signed successfully")
 


Test patch:
diff --git a/pkg/controller/certificatesigningrequests/ca/ca_test.go b/pkg/controller/certificatesigningrequests/ca/ca_test.go
index c72bb3cbc..2ab480ee7 100644
--- a/pkg/controller/certificatesigningrequests/ca/ca_test.go
+++ b/pkg/controller/certificatesigningrequests/ca/ca_test.go
@@ -517,6 +517,14 @@ func TestSign(t *testing.T) {
 							gen.SetCertificateSigningRequestCertificate(certBundle.ChainPEM),
 						),
 					)),
+					testpkg.NewAction(coretesting.NewUpdateAction(
+						certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
+						"",
+						gen.CertificateSigningRequestFrom(baseCSR,
+							gen.SetCertificateSigningRequestCertificate(certBundle.ChainPEM),
+							gen.SetCertificateSigningRequestCA(certBundle.CAPEM),
+						),
+					)),
 				},
 			},
 		},
diff --git a/pkg/controller/certificatesigningrequests/selfsigned/selfsigned_test.go b/pkg/controller/certificatesigningrequests/selfsigned/selfsigned_test.go
index caefc52f9..b39024a93 100644
--- a/pkg/controller/certificatesigningrequests/selfsigned/selfsigned_test.go
+++ b/pkg/controller/certificatesigningrequests/selfsigned/selfsigned_test.go
@@ -622,6 +622,22 @@ func TestProcessItem(t *testing.T) {
 							gen.SetCertificateSigningRequestCertificate([]byte("signed-cert")),
 						),
 					)),
+					testpkg.NewAction(coretesting.NewUpdateAction(
+						certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
+						"",
+						gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
+							gen.AddCertificateSigningRequestAnnotations(map[string]string{
+								"experimental.cert-manager.io/private-key-secret-name": "test-secret",
+							}),
+							gen.SetCertificateSigningRequestRequest(csrBundle.csrPEM),
+							gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
+								Type:   certificatesv1.CertificateApproved,
+								Status: corev1.ConditionTrue,
+							}),
+							gen.SetCertificateSigningRequestCertificate([]byte("signed-cert")),
+							gen.SetCertificateSigningRequestCA([]byte("signed-cert")),
+						),
+					)),
 				},
 			},
 		},
diff --git a/test/e2e/framework/helper/BUILD.bazel b/test/e2e/framework/helper/BUILD.bazel
index 7c3d71db5..1d4e165ed 100644
--- a/test/e2e/framework/helper/BUILD.bazel
+++ b/test/e2e/framework/helper/BUILD.bazel
@@ -18,6 +18,7 @@ go_library(
     deps = [
         "//pkg/api/util:go_default_library",
         "//pkg/apis/certmanager/v1:go_default_library",
+        "//pkg/apis/experimental/v1alpha1:go_default_library",
         "//pkg/apis/meta/v1:go_default_library",
         "//pkg/client/clientset/versioned:go_default_library",
         "//pkg/util:go_default_library",
@@ -27,7 +28,6 @@ go_library(
         "//test/e2e/framework/helper/validation/certificates:go_default_library",
         "//test/e2e/framework/helper/validation/certificatesigningrequests:go_default_library",
         "//test/e2e/framework/log:go_default_library",
-        "//test/e2e/util:go_default_library",
         "@com_github_onsi_ginkgo//:go_default_library",
         "@io_k8s_api//certificates/v1:go_default_library",
         "@io_k8s_api//core/v1:go_default_library",
diff --git a/test/e2e/framework/helper/certificates.go b/test/e2e/framework/helper/certificates.go
index 29da2e426..6bd3e2a70 100644
--- a/test/e2e/framework/helper/certificates.go
+++ b/test/e2e/framework/helper/certificates.go
@@ -29,6 +29,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/wait"
 
 	apiutil "github.com/jetstack/cert-manager/pkg/api/util"
 	cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
@@ -36,50 +37,62 @@ import (
 	"github.com/jetstack/cert-manager/pkg/util"
 	"github.com/jetstack/cert-manager/pkg/util/pki"
 	"github.com/jetstack/cert-manager/test/e2e/framework/log"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 )
 
-func (h *Helper) handleResult(ns, name string, cert *cmapi.Certificate, err error) (*cmapi.Certificate, error) {
-	if err != nil {
-		log.Logf("Error waiting for Certificate to become Ready: %v", err)
-		h.Kubectl(ns).DescribeResource("certificate", name)
-		h.Kubectl(ns).Describe("order", "challenge")
-		h.describeCertificateRequestFromCertificate(ns, cert)
-	}
-	return cert, err
-}
-
-// WaitForCertificateReady waits for the certificate resource to enter a Ready state.
+// WaitForCertificateReady waits for the certificate resource to enter a Ready
+// state.
 func (h *Helper) WaitForCertificateReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
-	result, err := e2eutil.WaitForCertificateCondition(h.CMClient.CertmanagerV1().Certificates(ns), name, cmapi.CertificateCondition{
-		Type:   cmapi.CertificateConditionReady,
-		Status: cmmeta.ConditionTrue,
-	}, timeout)
-	return h.handleResult(ns, name, result, err)
-}
-
-// WaitForCertificateReadyUpdate waits for the certificate resource to enter a
-// Ready state. If the provided cert was in a Ready state already, the function
-// waits for a state transition to have happened.
-func (h *Helper) WaitForCertificateReadyUpdate(cert *cmapi.Certificate, timeout time.Duration) (*cmapi.Certificate, error) {
-	result, err := e2eutil.WaitForCertificateConditionWithObservedGeneration(h.CMClient.CertmanagerV1().Certificates(cert.Namespace), cert.Name, cmapi.CertificateCondition{
-		Type:               cmapi.CertificateConditionReady,
-		Status:             cmmeta.ConditionTrue,
-		ObservedGeneration: cert.Generation,
-	}, timeout)
-	return h.handleResult(cert.Namespace, cert.Name, result, err)
+	var certificate *cmapi.Certificate
+	err := wait.PollImmediate(time.Second, timeout,
+		func() (bool, error) {
+			var err error
+			log.Logf("Waiting for Certificate %v to be ready", name)
+			certificate, err = h.CMClient.CertmanagerV1().Certificates(ns).Get(context.TODO(), name, metav1.GetOptions{})
+			if err != nil {
+				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
+			}
+			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
+				Type:   cmapi.CertificateConditionReady,
+				Status: cmmeta.ConditionTrue,
+			})
+			if !isReady {
+				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
+				return false, nil
+			}
+			return true, nil
+		},
+	)
+
+	// return certificate even when error to use for debugging
+	return certificate, err
 }
 
-// WaitForCertificateReadyUpdate waits for the certificate resource to enter a
-// Ready=False state. If the provided cert was in a Ready=False state already,
-// the function waits for a state transition to have happened.
-func (h *Helper) WaitForCertificateNotReadyUpdate(cert *cmapi.Certificate, timeout time.Duration) (*cmapi.Certificate, error) {
-	result, err := e2eutil.WaitForCertificateConditionWithObservedGeneration(h.CMClient.CertmanagerV1().Certificates(cert.Namespace), cert.Name, cmapi.CertificateCondition{
-		Type:               cmapi.CertificateConditionReady,
-		Status:             cmmeta.ConditionFalse,
-		ObservedGeneration: cert.Generation,
-	}, timeout)
-	return h.handleResult(cert.Namespace, cert.Name, result, err)
+// WaitForCertificateNotReady waits for the certificate resource to enter a
+// non-Ready state.
+func (h *Helper) WaitForCertificateNotReady(ns, name string, timeout time.Duration) (*cmapi.Certificate, error) {
+	var certificate *cmapi.Certificate
+	err := wait.PollImmediate(time.Second, timeout,
+		func() (bool, error) {
+			var err error
+			log.Logf("Waiting for Certificate %v to be ready", name)
+			certificate, err = h.CMClient.CertmanagerV1().Certificates(ns).Get(context.TODO(), name, metav1.GetOptions{})
+			if err != nil {
+				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
+			}
+			isReady := apiutil.CertificateHasCondition(certificate, cmapi.CertificateCondition{
+				Type:   cmapi.CertificateConditionReady,
+				Status: cmmeta.ConditionFalse,
+			})
+			if !isReady {
+				log.Logf("Expected Certificate to have Ready condition 'true' but it has: %v", certificate.Status.Conditions)
+				return false, nil
+			}
+			return true, nil
+		},
+	)
+
+	// return certificate even when error to use for debugging
+	return certificate, err
 }
 
 // ValidateIssuedCertificate will ensure that the given Certificate has a
@@ -267,6 +280,17 @@ func (h *Helper) deduplicateExtKeyUsages(us []x509.ExtKeyUsage) []x509.ExtKeyUsa
 	return us
 }
 
+func (h *Helper) WaitCertificateIssued(ns, name string, timeout time.Duration) error {
+	certificate, err := h.WaitForCertificateReady(ns, name, timeout)
+	if err != nil {
+		log.Logf("Error waiting for Certificate to become Ready: %v", err)
+		h.Kubectl(ns).DescribeResource("certificate", name)
+		h.Kubectl(ns).Describe("order", "challenge")
+		h.describeCertificateRequestFromCertificate(ns, certificate)
+	}
+	return err
+}
+
 func (h *Helper) defaultKeyUsagesToAdd(ns string, issuerRef *cmmeta.ObjectReference) (x509.KeyUsage, []x509.ExtKeyUsage, error) {
 	var issuerSpec *cmapi.IssuerSpec
 	switch issuerRef.Kind {
diff --git a/test/e2e/framework/helper/certificatesigningrequests.go b/test/e2e/framework/helper/certificatesigningrequests.go
index c4785ec2b..cd48154cb 100644
--- a/test/e2e/framework/helper/certificatesigningrequests.go
+++ b/test/e2e/framework/helper/certificatesigningrequests.go
@@ -25,6 +25,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/wait"
 
+	experimentalapi "github.com/jetstack/cert-manager/pkg/apis/experimental/v1alpha1"
 	"github.com/jetstack/cert-manager/test/e2e/framework/log"
 )
 
@@ -43,6 +44,9 @@ func (h *Helper) WaitForCertificateSigningRequestSigned(name string, timeout tim
 			if len(csr.Status.Certificate) == 0 {
 				return false, nil
 			}
+			if _, ok := csr.Annotations[experimentalapi.CertificateSigningRequestCAAnnotationKey]; !ok {
+				return false, nil
+			}
 			return true, nil
 		},
 	)
diff --git a/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go b/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go
index 045f38722..743a96ae8 100644
--- a/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go
+++ b/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go
@@ -17,11 +17,13 @@ limitations under the License.
 package certificatesigningrequests
 
 import (
+	"bytes"
 	"crypto"
 	"crypto/ecdsa"
 	"crypto/ed25519"
 	"crypto/rsa"
 	"crypto/x509"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"time"
@@ -309,6 +311,69 @@ func ExpectEmailsToMatch(csr *certificatesv1.CertificateSigningRequest, _ crypto
 	return nil
 }
 
+// ExpectCorrectTrustChain checks if the cert is signed by the root CA if one is provided
+func ExpectCorrectTrustChain(csr *certificatesv1.CertificateSigningRequest, _ crypto.Signer) error {
+	cert, err := pki.DecodeX509CertificateBytes(csr.Status.Certificate)
+	if err != nil {
+		return err
+	}
+	req, err := pki.DecodeX509CertificateRequestBytes(csr.Spec.Request)
+	if err != nil {
+		return err
+	}
+
+	var dnsName string
+	if len(req.DNSNames) > 0 {
+		dnsName = req.DNSNames[0]
+	}
+
+	caPEM, err := base64.StdEncoding.DecodeString(csr.Annotations[experimentalapi.CertificateSigningRequestCAAnnotationKey])
+	if err != nil {
+		return fmt.Errorf("failed to base 64 decode CA certificate annotation %q: %w",
+			experimentalapi.CertificateSigningRequestCAAnnotationKey, err)
+	}
+
+	rootCertPool := x509.NewCertPool()
+	rootCertPool.AppendCertsFromPEM(caPEM)
+	intermediateCertPool := x509.NewCertPool()
+	intermediateCertPool.AppendCertsFromPEM(csr.Status.Certificate)
+	opts := x509.VerifyOptions{
+		DNSName:       dnsName,
+		Intermediates: intermediateCertPool,
+		Roots:         rootCertPool,
+	}
+
+	if _, err := cert.Verify(opts); err != nil {
+		return fmt.Errorf(
+			"verify error. CERT:\n%s\nROOTS\n%s\nERROR\n%s\n",
+			csr.Status.Certificate,
+			caPEM,
+			err,
+		)
+	}
+
+	return nil
+}
+
+// ExpectCARootCertificate checks if the CA cert is root CA if one is provided
+func ExpectCARootCertificate(csr *certificatesv1.CertificateSigningRequest, _ crypto.Signer) error {
+	caPEM, err := base64.StdEncoding.DecodeString(csr.Annotations[experimentalapi.CertificateSigningRequestCAAnnotationKey])
+	if err != nil {
+		return fmt.Errorf("failed to base 64 decode CA certificate annotation %q: %w",
+			experimentalapi.CertificateSigningRequestCAAnnotationKey, err)
+	}
+	caCert, err := pki.DecodeX509CertificateBytes(caPEM)
+	if err != nil {
+		return err
+	}
+
+	if !bytes.Equal(caCert.RawSubject, caCert.RawIssuer) {
+		return fmt.Errorf("expected CA certificate to be root CA; want Issuer %v, but got %v", caCert.Subject, caCert.Issuer)
+	}
+
+	return nil
+}
+
 // ExpectIsCA checks the certificate is a CA if requested
 func ExpectIsCA(csr *certificatesv1.CertificateSigningRequest, _ crypto.Signer) error {
 	cert, err := pki.DecodeX509CertificateBytes(csr.Status.Certificate)
diff --git a/test/e2e/framework/helper/validation/validation.go b/test/e2e/framework/helper/validation/validation.go
index c67d8cc21..e384a0407 100644
--- a/test/e2e/framework/helper/validation/validation.go
+++ b/test/e2e/framework/helper/validation/validation.go
@@ -52,6 +52,8 @@ func DefaultCertificateSigningRequestSet() []certificatesigningrequests.Validati
 		certificatesigningrequests.ExpectValidDuration,
 		certificatesigningrequests.ExpectKeyUsageUsageDigitalSignature,
 		certificatesigningrequests.ExpectEmailsToMatch,
+		certificatesigningrequests.ExpectCorrectTrustChain,
+		certificatesigningrequests.ExpectCARootCertificate,
 		certificatesigningrequests.ExpectIsCA,
 		certificatesigningrequests.ExpectConditionApproved,
 		certificatesigningrequests.ExpectConditiotNotDenied,
diff --git a/test/e2e/framework/util/BUILD.bazel b/test/e2e/framework/util/BUILD.bazel
index db6b651ab..906735392 100644
--- a/test/e2e/framework/util/BUILD.bazel
+++ b/test/e2e/framework/util/BUILD.bazel
@@ -2,11 +2,15 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
 
 go_library(
     name = "go_default_library",
-    srcs = ["config.go"],
+    srcs = [
+        "config.go",
+        "domains.go",
+    ],
     importpath = "github.com/jetstack/cert-manager/test/e2e/framework/util",
     tags = ["manual"],
     visibility = ["//visibility:public"],
     deps = [
+        "//pkg/util:go_default_library",
         "@io_k8s_client_go//rest:go_default_library",
         "@io_k8s_client_go//tools/clientcmd:go_default_library",
         "@io_k8s_client_go//tools/clientcmd/api:go_default_library",
diff --git a/test/e2e/util/domains.go b/test/e2e/framework/util/domains.go
similarity index 57%
rename from test/e2e/util/domains.go
rename to test/e2e/framework/util/domains.go
index 867e0e727..e4e1304c5 100644
--- a/test/e2e/util/domains.go
+++ b/test/e2e/framework/util/domains.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The cert-manager Authors.
+Copyright 2020 The cert-manager Authors.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -22,15 +22,6 @@ import (
 	cmutil "github.com/jetstack/cert-manager/pkg/util"
 )
 
-// RandomSubdomain returns a new subdomain domain of the domain suffix.
-// e.g. abcd.example.com.
 func RandomSubdomain(domain string) string {
-	return RandomSubdomainLength(domain, 5)
-}
-
-// RandomSubdomainLength returns a new subdomain domain of the domain suffix, where the
-// subdomain has `length` number of characters.
-// e.g. abcdefghij.example.com.
-func RandomSubdomainLength(domain string, length int) string {
-	return fmt.Sprintf("%s.%s", cmutil.RandStringRunes(length), domain)
+	return fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), domain)
 }
diff --git a/test/e2e/suite/approval/BUILD.bazel b/test/e2e/suite/approval/BUILD.bazel
index 4606f27b5..1c31f3d1b 100644
--- a/test/e2e/suite/approval/BUILD.bazel
+++ b/test/e2e/suite/approval/BUILD.bazel
@@ -16,7 +16,6 @@ go_library(
         "//pkg/util:go_default_library",
         "//test/e2e/framework:go_default_library",
         "//test/e2e/framework/util:go_default_library",
-        "//test/e2e/util:go_default_library",
         "//test/unit/gen:go_default_library",
         "@com_github_onsi_ginkgo//:go_default_library",
         "@com_github_onsi_gomega//:go_default_library",
diff --git a/test/e2e/suite/approval/approval.go b/test/e2e/suite/approval/approval.go
index ed2e92fb0..2ca84c34a 100644
--- a/test/e2e/suite/approval/approval.go
+++ b/test/e2e/suite/approval/approval.go
@@ -37,7 +37,6 @@ import (
 	clientset "github.com/jetstack/cert-manager/pkg/client/clientset/versioned"
 	"github.com/jetstack/cert-manager/test/e2e/framework"
 	testutil "github.com/jetstack/cert-manager/test/e2e/framework/util"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 	"github.com/jetstack/cert-manager/test/unit/gen"
 )
 
@@ -60,7 +59,7 @@ var _ = framework.CertManagerDescribe("Approval CertificateRequests", func() {
 		var err error
 		crdclient, err = crdclientset.NewForConfig(f.KubeClientConfig)
 		Expect(err).NotTo(HaveOccurred())
-		group = e2eutil.RandomSubdomain("example.io")
+		group = testutil.RandomSubdomain("example.io")
 
 		sa, err = f.KubeClientSet.CoreV1().ServiceAccounts(f.Namespace.Name).Create(context.TODO(), &corev1.ServiceAccount{
 			ObjectMeta: metav1.ObjectMeta{
diff --git a/test/e2e/suite/conformance/certificates/acme/acme.go b/test/e2e/suite/conformance/certificates/acme/acme.go
index 8c6762df8..43a48b4ba 100644
--- a/test/e2e/suite/conformance/certificates/acme/acme.go
+++ b/test/e2e/suite/conformance/certificates/acme/acme.go
@@ -47,6 +47,7 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
 	// unsupportedHTTP01Features is a list of features that are not supported by the ACME
 	// issuer type using HTTP01
 	var unsupportedHTTP01Features = featureset.NewFeatureSet(
+		featureset.IPAddressFeature,
 		featureset.DurationFeature,
 		featureset.WildcardsFeature,
 		featureset.URISANsFeature,
@@ -78,7 +79,6 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
 
 	(&certificates.Suite{
 		Name:                "ACME HTTP01 Issuer",
-		UseIngressIPAddress: true,
 		CreateIssuerFunc:    provisionerHTTP01.createHTTP01Issuer,
 		DeleteIssuerFunc:    provisionerHTTP01.delete,
 		UnsupportedFeatures: unsupportedHTTP01Features,
@@ -94,7 +94,6 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) {
 
 	(&certificates.Suite{
 		Name:                "ACME HTTP01 ClusterIssuer",
-		UseIngressIPAddress: true,
 		CreateIssuerFunc:    provisionerHTTP01.createHTTP01ClusterIssuer,
 		DeleteIssuerFunc:    provisionerHTTP01.delete,
 		UnsupportedFeatures: unsupportedHTTP01Features,
diff --git a/test/e2e/suite/conformance/certificates/suite.go b/test/e2e/suite/conformance/certificates/suite.go
index c4e51a745..7f8ae9601 100644
--- a/test/e2e/suite/conformance/certificates/suite.go
+++ b/test/e2e/suite/conformance/certificates/suite.go
@@ -18,10 +18,12 @@ package certificates
 
 import (
 	"fmt"
+	"strings"
 
 	. "github.com/onsi/ginkgo"
 
 	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
+	"github.com/jetstack/cert-manager/pkg/util"
 	"github.com/jetstack/cert-manager/test/e2e/framework"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
 )
@@ -54,12 +56,6 @@ type Suite struct {
 	// nginx-ingress addon.
 	DomainSuffix string
 
-	// UseIngressIPAddress indicates that the IPAddress used
-	// for generating certificates should be the IngressIP.
-	// The ACME tests need this, so the challenges against the
-	// IPAddress will complete successfully.
-	UseIngressIPAddress bool
-
 	// UnsupportedFeatures is a list of features that are not supported by this
 	// invocation of the test suite.
 	// This is useful if a particular issuers explicitly does not support
@@ -72,13 +68,9 @@ type Suite struct {
 
 // complete will validate configuration and set default values.
 func (s *Suite) complete(f *framework.Framework) {
-	if s.Name == "" {
-		Fail("Name must be set")
-	}
-
-	if s.CreateIssuerFunc == nil {
-		Fail("CreateIssuerFunc must be set")
-	}
+	// TODO: work out how to fail an entire 'Describe' block so we can validate these are correctly set
+	//Expect(s.Name).NotTo(Equal(""), "Name must be set")
+	//Expect(s.CreateIssuerFunc).NotTo(BeNil(), "CreateIssuerFunc must be set")
 
 	if s.DomainSuffix == "" {
 		s.DomainSuffix = f.Config.Addons.IngressController.Domain
@@ -127,3 +119,22 @@ func (s *Suite) checkFeatures(fs ...featureset.Feature) bool {
 	}
 	return false
 }
+
+// newDomain will generate a new random subdomain of the DomainSuffix
+func (s *Suite) newDomain() string {
+	return s.newDomainDepth(1)
+}
+
+// newDomainDepth return a new domain name with the given number of subdomains
+// beneath the domain suffix.
+// If depth is zero, the domain suffix will be returned,
+// If depth is one, a random subdomain will be returned e.g. abcd.example.com,
+// If depth is two, a random sub-subdomain will be returned e.g. abcd.efgh.example.com,
+// and so on
+func (s *Suite) newDomainDepth(depth int) string {
+	subdomains := make([]string, depth)
+	for i := 0; i < depth; i++ {
+		subdomains[i] = util.RandStringRunes(4)
+	}
+	return strings.Join(append(subdomains, s.DomainSuffix), ".")
+}
diff --git a/test/e2e/suite/conformance/certificates/tests.go b/test/e2e/suite/conformance/certificates/tests.go
index b0fa975a0..db0ac27d3 100644
--- a/test/e2e/suite/conformance/certificates/tests.go
+++ b/test/e2e/suite/conformance/certificates/tests.go
@@ -44,22 +44,13 @@ func (s *Suite) Define() {
 		ctx := context.Background()
 		f := framework.NewDefaultFramework("certificates")
 
-		sharedIPAddress := "127.0.0.1"
-
-		// Wrap this in a BeforeEach else flags will not have been parsed and
-		// f.Config will not be populated at the time that this code is run.
+		// wrap this in a BeforeEach else flags will not have been parsed at
+		// the time that the `complete` function is called.
 		BeforeEach(func() {
-			if s.completed {
-				return
-			}
-
-			s.complete(f)
-
-			if s.UseIngressIPAddress {
-				sharedIPAddress = f.Config.Addons.ACMEServer.IngressIP
+			if !s.completed {
+				s.complete(f)
 			}
 		})
-
 		By("Running test suite with the following unsupported features: " + s.UnsupportedFeatures.String())
 
 		s.it(f, "should issue a basic, defaulted certificate for a single distinct DNS Name", func(issuerRef cmmeta.ObjectReference) {
@@ -71,7 +62,7 @@ func (s *Suite) Define() {
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
 					IssuerRef:  issuerRef,
-					DNSNames:   []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{s.newDomain()},
 				},
 			}
 			By("Creating a Certificate")
@@ -79,7 +70,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -98,7 +89,7 @@ func (s *Suite) Define() {
 					PrivateKey: &cmapi.CertificatePrivateKey{
 						Algorithm: cmapi.ECDSAKeyAlgorithm,
 					},
-					DNSNames:  []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:  []string{s.newDomain()},
 					IssuerRef: issuerRef,
 				},
 			}
@@ -107,7 +98,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -136,7 +127,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -168,7 +159,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -200,7 +191,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -221,7 +212,7 @@ func (s *Suite) Define() {
 				Spec: cmapi.CertificateSpec{
 					SecretName:  "testcert-tls",
 					CommonName:  cn,
-					IPAddresses: []string{sharedIPAddress},
+					IPAddresses: []string{"127.0.0.1"},
 					IssuerRef:   issuerRef,
 				},
 			}
@@ -230,7 +221,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -255,7 +246,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -285,7 +276,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -301,12 +292,12 @@ func (s *Suite) Define() {
 				},
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
-					CommonName: e2eutil.RandomSubdomain(s.DomainSuffix),
+					CommonName: s.newDomain(),
 					IssuerRef:  issuerRef,
 				},
 			}
 			testCertificate.Spec.DNSNames = []string{
-				testCertificate.Spec.CommonName, e2eutil.RandomSubdomain(s.DomainSuffix),
+				testCertificate.Spec.CommonName, s.newDomain(),
 			}
 
 			By("Creating a Certificate")
@@ -314,7 +305,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -330,9 +321,9 @@ func (s *Suite) Define() {
 				},
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
-					CommonName: e2eutil.RandomSubdomain(s.DomainSuffix),
+					CommonName: s.newDomain(),
 					IssuerRef:  issuerRef,
-					DNSNames:   []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{s.newDomain()},
 				},
 			}
 
@@ -341,7 +332,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -358,7 +349,7 @@ func (s *Suite) Define() {
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
 					IssuerRef:  issuerRef,
-					DNSNames:   []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{s.newDomain()},
 					Duration: &metav1.Duration{
 						Duration: time.Hour * 896,
 					},
@@ -369,7 +360,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -393,7 +384,7 @@ func (s *Suite) Define() {
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
 					IssuerRef:  issuerRef,
-					DNSNames:   []string{"foo." + e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{"foo." + s.newDomain()},
 				},
 			}
 			By("Creating a Certificate")
@@ -401,7 +392,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -428,7 +419,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -444,7 +435,7 @@ func (s *Suite) Define() {
 				},
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
-					DNSNames:   []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{s.newDomain()},
 					IssuerRef:  issuerRef,
 					Usages: []cmapi.KeyUsage{
 						cmapi.UsageSigning,
@@ -459,7 +450,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -484,7 +475,7 @@ func (s *Suite) Define() {
 				},
 				Spec: cmapi.CertificateSpec{
 					SecretName: "testcert-tls",
-					DNSNames:   []string{e2eutil.RandomSubdomain(s.DomainSuffix)},
+					DNSNames:   []string{s.newDomain()},
 					IssuerRef:  issuerRef,
 				},
 			}
@@ -493,7 +484,7 @@ func (s *Suite) Define() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, "testcert", time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, "testcert", time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -543,7 +534,7 @@ func (s *Suite) Define() {
 				"cert-manager.io/issuer":       issuerRef.Name,
 				"cert-manager.io/issuer-kind":  issuerRef.Kind,
 				"cert-manager.io/issuer-group": issuerRef.Group,
-			}, e2eutil.RandomSubdomain(s.DomainSuffix)), metav1.CreateOptions{})
+			}, s.newDomain()), metav1.CreateOptions{})
 			Expect(err).NotTo(HaveOccurred())
 
 			certName := ingress.Spec.TLS[0].SecretName
@@ -554,7 +545,7 @@ func (s *Suite) Define() {
 			)).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -567,7 +558,7 @@ func (s *Suite) Define() {
 
 			name := "testcert-ingress"
 			secretName := "testcert-ingress-tls"
-			domain := e2eutil.RandomSubdomain(s.DomainSuffix)
+			domain := s.newDomain()
 			duration := time.Hour * 999
 			renewBefore := time.Hour * 111
 
@@ -590,7 +581,7 @@ func (s *Suite) Define() {
 			)).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			// Verify that the ingres-shim has translated all the supplied
diff --git a/test/e2e/suite/conformance/certificatesigningrequests/BUILD.bazel b/test/e2e/suite/conformance/certificatesigningrequests/BUILD.bazel
index affeea486..99b949ed3 100644
--- a/test/e2e/suite/conformance/certificatesigningrequests/BUILD.bazel
+++ b/test/e2e/suite/conformance/certificatesigningrequests/BUILD.bazel
@@ -16,7 +16,6 @@ go_library(
         "//test/e2e/framework/helper/featureset:go_default_library",
         "//test/e2e/framework/helper/validation:go_default_library",
         "//test/e2e/framework/helper/validation/certificatesigningrequests:go_default_library",
-        "//test/e2e/util:go_default_library",
         "//test/unit/gen:go_default_library",
         "@com_github_onsi_ginkgo//:go_default_library",
         "@com_github_onsi_gomega//:go_default_library",
diff --git a/test/e2e/suite/conformance/certificatesigningrequests/suite.go b/test/e2e/suite/conformance/certificatesigningrequests/suite.go
index 7eed0d9b7..47b468998 100644
--- a/test/e2e/suite/conformance/certificatesigningrequests/suite.go
+++ b/test/e2e/suite/conformance/certificatesigningrequests/suite.go
@@ -85,22 +85,10 @@ type Suite struct {
 
 // complete will validate configuration and set default values.
 func (s *Suite) complete(f *framework.Framework) {
-	if s.Name == "" {
-		Fail("Name must be set")
-	}
-
-	if s.CreateIssuerFunc == nil {
-		Fail("CreateIssuerFunc must be set")
-	}
-
 	if s.DomainSuffix == "" {
 		s.DomainSuffix = f.Config.Addons.IngressController.Domain
 	}
 
-	if s.UnsupportedFeatures == nil {
-		s.UnsupportedFeatures = make(featureset.FeatureSet)
-	}
-
 	s.completed = true
 }
 
@@ -146,3 +134,22 @@ func (s *Suite) checkFeatures(fs ...featureset.Feature) bool {
 	}
 	return false
 }
+
+// newDomain will generate a new random subdomain of the DomainSuffix
+func (s *Suite) newDomain() string {
+	return s.newDomainDepth(1)
+}
+
+// newDomainDepth return a new domain name with the given number of subdomains
+// beneath the domain suffix.
+// If depth is zero, the domain suffix will be returned,
+// If depth is one, a random subdomain will be returned e.g. abcd.example.com,
+// If depth is two, a random sub-subdomain will be returned e.g. abcd.efgh.example.com,
+// and so on
+func (s *Suite) newDomainDepth(depth int) string {
+	subdomains := make([]string, depth)
+	for i := 0; i < depth; i++ {
+		subdomains[i] = util.RandStringRunes(4)
+	}
+	return strings.Join(append(subdomains, s.DomainSuffix), ".")
+}
diff --git a/test/e2e/suite/conformance/certificatesigningrequests/tests.go b/test/e2e/suite/conformance/certificatesigningrequests/tests.go
index 09deeab63..b961d6aa0 100644
--- a/test/e2e/suite/conformance/certificatesigningrequests/tests.go
+++ b/test/e2e/suite/conformance/certificatesigningrequests/tests.go
@@ -35,7 +35,6 @@ import (
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/validation"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/validation/certificatesigningrequests"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 	"github.com/jetstack/cert-manager/test/unit/gen"
 )
 
@@ -51,7 +50,14 @@ func (s *Suite) Define() {
 		ctx := context.Background()
 		f := framework.NewDefaultFramework("certificatesigningrequests")
 
-		sharedCommonName := "<SHOULD_GET_REPLACED>"
+		// wrap this in a BeforeEach else flags will not have been parsed at
+		// the time that the `complete` function is called.
+		BeforeEach(func() {
+			if !s.completed {
+				s.complete(f)
+			}
+		})
+
 		sharedURI, err := url.Parse("spiffe://cluster.local/ns/sandbox/sa/foo")
 		if err != nil {
 			// This should never happen, and is a bug. Panic to prevent garbage test
@@ -59,17 +65,7 @@ func (s *Suite) Define() {
 			panic(err)
 		}
 
-		// Wrap this in a BeforeEach else flags will not have been parsed and
-		// f.Config will not be populated at the time that this code is run.
-		BeforeEach(func() {
-			if s.completed {
-				return
-			}
-
-			s.complete(f)
-
-			sharedCommonName = e2eutil.RandomSubdomain(s.DomainSuffix)
-		})
+		sharedCommonName := s.newDomain()
 
 		type testCase struct {
 			keyAlgo            x509.PublicKeyAlgorithm
@@ -87,7 +83,7 @@ func (s *Suite) Define() {
 		tests := map[string]testCase{
 			"should issue an RSA certificate for a single distinct DNS Name": {
 				keyAlgo:      x509.RSA,
-				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))},
+				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(s.newDomain())},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
 					certificatesv1.UsageKeyEncipherment,
@@ -97,7 +93,7 @@ func (s *Suite) Define() {
 
 			"should issue an ECDSA certificate for a single distinct DNS Name": {
 				keyAlgo:      x509.ECDSA,
-				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))},
+				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(s.newDomain())},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
 					certificatesv1.UsageKeyEncipherment,
@@ -107,7 +103,7 @@ func (s *Suite) Define() {
 
 			"should issue an Ed25519 certificate for a single distinct DNS Name": {
 				keyAlgo:      x509.Ed25519,
-				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))},
+				csrModifiers: []gen.CSRModifier{gen.SetCSRDNSNames(s.newDomain())},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
 					certificatesv1.UsageKeyEncipherment,
@@ -187,7 +183,7 @@ func (s *Suite) Define() {
 				keyAlgo: x509.RSA,
 				csrModifiers: []gen.CSRModifier{
 					gen.SetCSRCommonName(sharedCommonName),
-					gen.SetCSRDNSNames(sharedCommonName, e2eutil.RandomSubdomain(s.DomainSuffix)),
+					gen.SetCSRDNSNames(sharedCommonName, s.newDomain()),
 				},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
@@ -199,8 +195,8 @@ func (s *Suite) Define() {
 			"should issue a certificate that defines a distinct DNS Name and another distinct Common Name": {
 				keyAlgo: x509.RSA,
 				csrModifiers: []gen.CSRModifier{
-					gen.SetCSRCommonName(e2eutil.RandomSubdomain(s.DomainSuffix)),
-					gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)),
+					gen.SetCSRCommonName(s.newDomain()),
+					gen.SetCSRDNSNames(s.newDomain()),
 				},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
@@ -228,7 +224,7 @@ func (s *Suite) Define() {
 			"should issue a certificate that defines a DNS Name and sets a duration": {
 				keyAlgo: x509.RSA,
 				csrModifiers: []gen.CSRModifier{
-					gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)),
+					gen.SetCSRDNSNames(s.newDomain()),
 				},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
@@ -243,7 +239,7 @@ func (s *Suite) Define() {
 			"should issue a certificate which has a wildcard DNS name defined": {
 				keyAlgo: x509.RSA,
 				csrModifiers: []gen.CSRModifier{
-					gen.SetCSRDNSNames("*." + e2eutil.RandomSubdomain(s.DomainSuffix)),
+					gen.SetCSRDNSNames("*." + s.newDomain()),
 				},
 				kubeCSRUsages: []certificatesv1.KeyUsage{
 					certificatesv1.UsageDigitalSignature,
diff --git a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel
index 6e5f0a36b..fbd0f4e05 100644
--- a/test/e2e/suite/issuers/acme/certificate/BUILD.bazel
+++ b/test/e2e/suite/issuers/acme/certificate/BUILD.bazel
@@ -16,6 +16,7 @@ go_library(
         "//pkg/apis/certmanager/v1:go_default_library",
         "//pkg/apis/meta/v1:go_default_library",
         "//pkg/client/clientset/versioned:go_default_library",
+        "//pkg/util:go_default_library",
         "//pkg/util/pki:go_default_library",
         "//test/e2e/framework:go_default_library",
         "//test/e2e/framework/addon:go_default_library",
@@ -23,6 +24,7 @@ go_library(
         "//test/e2e/framework/helper/validation:go_default_library",
         "//test/e2e/framework/log:go_default_library",
         "//test/e2e/framework/matcher:go_default_library",
+        "//test/e2e/framework/util:go_default_library",
         "//test/e2e/suite/issuers/acme/dnsproviders:go_default_library",
         "//test/e2e/util:go_default_library",
         "//test/unit/gen:go_default_library",
diff --git a/test/e2e/suite/issuers/acme/certificate/dns01.go b/test/e2e/suite/issuers/acme/certificate/dns01.go
index 0cd238ff1..5add0f561 100644
--- a/test/e2e/suite/issuers/acme/certificate/dns01.go
+++ b/test/e2e/suite/issuers/acme/certificate/dns01.go
@@ -67,15 +67,15 @@ func testRFC2136DNSProvider() bool {
 
 		BeforeEach(func() {
 			By("Creating an Issuer")
-			dnsDomain = util.RandomSubdomain(p.Details().BaseDomain)
+			dnsDomain = p.Details().NewTestDomain()
 			issuer := gen.Issuer(issuerName,
 				gen.SetIssuerACME(cmacme.ACMEIssuer{
 					SkipTLSVerify: true,
 					Server:        f.Config.Addons.ACMEServer.URL,
-					Email:         f.Config.Addons.ACMEServer.TestingACMEEmail,
+					Email:         testingACMEEmail,
 					PrivateKey: cmmeta.SecretKeySelector{
 						LocalObjectReference: cmmeta.LocalObjectReference{
-							Name: f.Config.Addons.ACMEServer.TestingACMEPrivateKey,
+							Name: testingACMEPrivateKey,
 						},
 					},
 					Solvers: []cmacme.ACMEChallengeSolver{
@@ -106,7 +106,7 @@ func testRFC2136DNSProvider() bool {
 				})
 			Expect(err).NotTo(HaveOccurred())
 			By("Verifying ACME account private key exists")
-			secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.GetOptions{})
+			secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{})
 			Expect(err).NotTo(HaveOccurred())
 			if len(secret.Data) != 1 {
 				Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
@@ -116,7 +116,7 @@ func testRFC2136DNSProvider() bool {
 		AfterEach(func() {
 			By("Cleaning up")
 			f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{})
-			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.DeleteOptions{})
+			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{})
 			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), certificateSecretName, metav1.DeleteOptions{})
 		})
 
@@ -136,7 +136,7 @@ func testRFC2136DNSProvider() bool {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -158,7 +158,7 @@ func testRFC2136DNSProvider() bool {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -180,7 +180,7 @@ func testRFC2136DNSProvider() bool {
 			Expect(err).NotTo(HaveOccurred())
 			// use a longer timeout for this, as it requires performing 2 dns validations in serial
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*10)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*10)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/acme/certificate/http01.go b/test/e2e/suite/issuers/acme/certificate/http01.go
index 554342017..78121d172 100644
--- a/test/e2e/suite/issuers/acme/certificate/http01.go
+++ b/test/e2e/suite/issuers/acme/certificate/http01.go
@@ -35,20 +35,24 @@ import (
 	cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
 	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
 	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
+	cmutil "github.com/jetstack/cert-manager/pkg/util"
 	"github.com/jetstack/cert-manager/test/e2e/framework"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/validation"
 	"github.com/jetstack/cert-manager/test/e2e/framework/log"
 	. "github.com/jetstack/cert-manager/test/e2e/framework/matcher"
+	frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util"
 	"github.com/jetstack/cert-manager/test/e2e/util"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 	"github.com/jetstack/cert-manager/test/unit/gen"
 )
 
+const testingACMEEmail = "e2e@cert-manager.io"
+const testingACMEPrivateKey = "test-acme-private-key"
 const foreverTestTimeout = time.Second * 60
 
 var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 	f := framework.NewDefaultFramework("create-acme-certificate-http01")
+	h := f.Helper()
 
 	var acmeIngressDomain string
 	issuerName := "test-acme-issuer"
@@ -88,9 +92,9 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		}
 		acmeIssuer := gen.Issuer(issuerName,
 			gen.SetIssuerNamespace(f.Namespace.Name),
-			gen.SetIssuerACMEEmail(f.Config.Addons.ACMEServer.TestingACMEEmail),
+			gen.SetIssuerACMEEmail(testingACMEEmail),
 			gen.SetIssuerACMEURL(f.Config.Addons.ACMEServer.URL),
-			gen.SetIssuerACMEPrivKeyRef(f.Config.Addons.ACMEServer.TestingACMEPrivateKey),
+			gen.SetIssuerACMEPrivKeyRef(testingACMEPrivateKey),
 			gen.SetIssuerACMESkipTLSVerify(true),
 			gen.SetIssuerACMESolvers(solvers))
 		By("Creating an Issuer")
@@ -115,7 +119,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 			})
 		Expect(err).NotTo(HaveOccurred())
 		By("Verifying ACME account private key exists")
-		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.GetOptions{})
+		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{})
 		Expect(err).NotTo(HaveOccurred())
 		if len(secret.Data) != 1 {
 			Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
@@ -123,13 +127,13 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 	})
 
 	JustBeforeEach(func() {
-		acmeIngressDomain = e2eutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
+		acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
 	})
 
 	AfterEach(func() {
 		By("Cleaning up")
 		f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{})
-		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.DeleteOptions{})
+		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{})
 	})
 
 	It("should obtain a signed certificate with a single CN from the ACME server", func() {
@@ -147,7 +151,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -172,7 +176,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -191,7 +195,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		cert := gen.Certificate(certificateName,
 			gen.SetCertificateSecretName(certificateSecretName),
 			gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
-			gen.SetCertificateDNSNames(acmeIngressDomain, e2eutil.RandomSubdomainLength(acmeIngressDomain, maxLengthOfDomainSegment)),
+			gen.SetCertificateDNSNames(acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)),
 		)
 		cert.Namespace = f.Namespace.Name
 
@@ -199,7 +203,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -214,7 +218,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		cert := gen.Certificate(certificateName,
 			gen.SetCertificateSecretName(certificateSecretName),
 			gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
-			gen.SetCertificateDNSNames(e2eutil.RandomSubdomain(acmeIngressDomain)),
+			gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)),
 		)
 		cert.Namespace = f.Namespace.Name
 
@@ -223,7 +227,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		By("Verifying the Certificate is valid")
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -238,7 +242,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		cert := gen.Certificate(certificateName,
 			gen.SetCertificateSecretName(certificateSecretName),
 			gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
-			gen.SetCertificateDNSNames(e2eutil.RandomSubdomain(acmeIngressDomain)),
+			gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)),
 		)
 		cert.Namespace = f.Namespace.Name
 
@@ -248,7 +252,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		By("Verifying the Certificate is valid")
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -260,17 +264,21 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Adding an additional dnsName to the Certificate")
-		newDNSName := e2eutil.RandomSubdomain(acmeIngressDomain)
+		newDNSName := fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)
 		cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName)
 
 		By("Updating the Certificate in the apiserver")
 		cert, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
-		// We are waiting for a ready condition where the observed generation is
-		// the same or a later generation than the latest spec that we just updated.
-		By("Waiting for the Certificate Ready condition to be updated")
-		_, err = f.Helper().WaitForCertificateReadyUpdate(cert, time.Minute*5)
+		By("Waiting for the Certificate to be not ready")
+		_, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, time.Minute*5)
+		Expect(err).NotTo(HaveOccurred())
+
+		By("Waiting for the Certificate to become ready & valid")
+
+		By("Waiting for the Certificate to be issued...")
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -315,7 +323,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be not ready")
-		_, err = f.Helper().WaitForCertificateNotReadyUpdate(cert, 30*time.Second)
+		_, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, 30*time.Second)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Getting the latest version of the Certificate")
@@ -323,12 +331,12 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Replacing dnsNames with a valid dns name")
-		cert.Spec.DNSNames = []string{e2eutil.RandomSubdomain(acmeIngressDomain)}
+		cert.Spec.DNSNames = []string{fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)}
 		_, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to have the Ready=True condition")
-		_, err = f.Helper().WaitForCertificateReadyUpdate(cert, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Sanity checking the issued Certificate")
@@ -383,7 +391,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -392,6 +400,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 	})
 
 	It("should obtain a signed certificate with a single CN from the ACME server when redirected", func() {
+
 		certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name)
 
 		// force-ssl-redirect should make every request turn into a redirect,
@@ -421,7 +430,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, dummycert, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, dummycert, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -486,7 +495,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -540,7 +549,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		// were to ask us for the challenge after the pod was killed, but because
 		// we kill it so early, we should always be in the self-check phase
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -563,7 +572,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -578,7 +587,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		cert := gen.Certificate(certificateName,
 			gen.SetCertificateSecretName(certificateSecretName),
 			gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
-			gen.SetCertificateDNSNames(e2eutil.RandomSubdomainLength(acmeIngressDomain, 2)),
+			gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(2), acmeIngressDomain)),
 			gen.SetCertificateIPs(f.Config.Addons.ACMEServer.IngressIP),
 		)
 		cert.Namespace = f.Namespace.Name
@@ -587,7 +596,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -602,7 +611,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		cert := gen.Certificate(certificateName,
 			gen.SetCertificateSecretName(certificateSecretName),
 			gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName}),
-			gen.SetCertificateDNSNames(e2eutil.RandomSubdomain(acmeIngressDomain)),
+			gen.SetCertificateDNSNames(fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)),
 		)
 		cert.Namespace = f.Namespace.Name
 
@@ -610,7 +619,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -622,15 +631,19 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01)", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Adding an additional dnsName to the Certificate")
-		newDNSName := e2eutil.RandomSubdomain(acmeIngressDomain)
+		newDNSName := fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)
 		cert.Spec.DNSNames = append(cert.Spec.DNSNames, newDNSName)
 
 		By("Updating the Certificate in the apiserver")
 		cert, err = certClient.Update(context.TODO(), cert, metav1.UpdateOptions{})
 		Expect(err).NotTo(HaveOccurred())
 
-		By("Waiting for the Certificate Ready condition to be updated")
-		_, err = f.Helper().WaitForCertificateReadyUpdate(cert, time.Minute*5)
+		By("Waiting for the Certificate to be not ready")
+		_, err = h.WaitForCertificateNotReady(f.Namespace.Name, certificateName, time.Minute*5)
+		Expect(err).NotTo(HaveOccurred())
+
+		By("Waiting for the Certificate to be issued...")
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/acme/certificate/notafter.go b/test/e2e/suite/issuers/acme/certificate/notafter.go
index 89ae4e15a..46633cec5 100644
--- a/test/e2e/suite/issuers/acme/certificate/notafter.go
+++ b/test/e2e/suite/issuers/acme/certificate/notafter.go
@@ -34,8 +34,8 @@ import (
 	"github.com/jetstack/cert-manager/test/e2e/framework"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
 	"github.com/jetstack/cert-manager/test/e2e/framework/helper/validation"
+	frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util"
 	"github.com/jetstack/cert-manager/test/e2e/util"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 	"github.com/jetstack/cert-manager/test/unit/gen"
 )
 
@@ -80,9 +80,9 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01 + Not After)", f
 		}
 		acmeIssuer := gen.Issuer(issuerName,
 			gen.SetIssuerNamespace(f.Namespace.Name),
-			gen.SetIssuerACMEEmail(f.Config.Addons.ACMEServer.TestingACMEEmail),
+			gen.SetIssuerACMEEmail(testingACMEEmail),
 			gen.SetIssuerACMEURL(f.Config.Addons.ACMEServer.URL),
-			gen.SetIssuerACMEPrivKeyRef(f.Config.Addons.ACMEServer.TestingACMEPrivateKey),
+			gen.SetIssuerACMEPrivKeyRef(testingACMEPrivateKey),
 			gen.SetIssuerACMESkipTLSVerify(true),
 			// Enable Duration feature to set NotAfter
 			gen.SetIssuerACMEDuration(true),
@@ -109,7 +109,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01 + Not After)", f
 			})
 		Expect(err).NotTo(HaveOccurred())
 		By("Verifying ACME account private key exists")
-		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.GetOptions{})
+		secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{})
 		Expect(err).NotTo(HaveOccurred())
 		if len(secret.Data) != 1 {
 			Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
@@ -117,13 +117,13 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01 + Not After)", f
 	})
 
 	JustBeforeEach(func() {
-		acmeIngressDomain = e2eutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
+		acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
 	})
 
 	AfterEach(func() {
 		By("Cleaning up")
 		f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{})
-		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.DeleteOptions{})
+		f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{})
 	})
 
 	It("should obtain a signed certificate with a single CN from the ACME server with 1 hour validity", func() {
@@ -143,7 +143,7 @@ var _ = framework.CertManagerDescribe("ACME Certificate (HTTP01 + Not After)", f
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/acme/certificate/webhook.go b/test/e2e/suite/issuers/acme/certificate/webhook.go
index c2f0cf790..6160591c6 100644
--- a/test/e2e/suite/issuers/acme/certificate/webhook.go
+++ b/test/e2e/suite/issuers/acme/certificate/webhook.go
@@ -54,10 +54,10 @@ var _ = framework.CertManagerDescribe("ACME webhook DNS provider", func() {
 				gen.SetIssuerACME(cmacme.ACMEIssuer{
 					SkipTLSVerify: true,
 					Server:        f.Config.Addons.ACMEServer.URL,
-					Email:         f.Config.Addons.ACMEServer.TestingACMEEmail,
+					Email:         testingACMEEmail,
 					PrivateKey: cmmeta.SecretKeySelector{
 						LocalObjectReference: cmmeta.LocalObjectReference{
-							Name: f.Config.Addons.ACMEServer.TestingACMEPrivateKey,
+							Name: testingACMEPrivateKey,
 						},
 					},
 					Solvers: []cmacme.ACMEChallengeSolver{
@@ -96,7 +96,7 @@ var _ = framework.CertManagerDescribe("ACME webhook DNS provider", func() {
 				})
 			Expect(err).NotTo(HaveOccurred())
 			By("Verifying ACME account private key exists")
-			secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.GetOptions{})
+			secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(context.TODO(), testingACMEPrivateKey, metav1.GetOptions{})
 			Expect(err).NotTo(HaveOccurred())
 			if len(secret.Data) != 1 {
 				Fail("Expected 1 key in ACME account private key secret, but there was %d", len(secret.Data))
@@ -106,7 +106,7 @@ var _ = framework.CertManagerDescribe("ACME webhook DNS provider", func() {
 		AfterEach(func() {
 			By("Cleaning up")
 			f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Delete(context.TODO(), issuerName, metav1.DeleteOptions{})
-			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), f.Config.Addons.ACMEServer.TestingACMEPrivateKey, metav1.DeleteOptions{})
+			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), testingACMEPrivateKey, metav1.DeleteOptions{})
 			f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Delete(context.TODO(), certificateSecretName, metav1.DeleteOptions{})
 		})
 
diff --git a/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel b/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel
index eb4e37ef9..240797a5e 100644
--- a/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel
+++ b/test/e2e/suite/issuers/acme/certificaterequest/BUILD.bazel
@@ -12,10 +12,12 @@ go_library(
         "//pkg/apis/acme/v1:go_default_library",
         "//pkg/apis/certmanager/v1:go_default_library",
         "//pkg/apis/meta/v1:go_default_library",
+        "//pkg/util:go_default_library",
         "//test/e2e/framework:go_default_library",
         "//test/e2e/framework/addon:go_default_library",
         "//test/e2e/framework/log:go_default_library",
         "//test/e2e/framework/matcher:go_default_library",
+        "//test/e2e/framework/util:go_default_library",
         "//test/e2e/suite/issuers/acme/dnsproviders:go_default_library",
         "//test/e2e/util:go_default_library",
         "//test/unit/gen:go_default_library",
diff --git a/test/e2e/suite/issuers/acme/certificaterequest/dns01.go b/test/e2e/suite/issuers/acme/certificaterequest/dns01.go
index e3ed9c870..0233dda19 100644
--- a/test/e2e/suite/issuers/acme/certificaterequest/dns01.go
+++ b/test/e2e/suite/issuers/acme/certificaterequest/dns01.go
@@ -63,7 +63,7 @@ func testRFC2136DNSProvider() bool {
 
 		BeforeEach(func() {
 			By("Creating an Issuer")
-			dnsDomain = util.RandomSubdomain(p.Details().BaseDomain)
+			dnsDomain = p.Details().NewTestDomain()
 			issuer := gen.Issuer(issuerName,
 				gen.SetIssuerACME(cmacme.ACMEIssuer{
 					SkipTLSVerify: true,
diff --git a/test/e2e/suite/issuers/acme/certificaterequest/http01.go b/test/e2e/suite/issuers/acme/certificaterequest/http01.go
index 5624c79ad..d7047ca16 100644
--- a/test/e2e/suite/issuers/acme/certificaterequest/http01.go
+++ b/test/e2e/suite/issuers/acme/certificaterequest/http01.go
@@ -19,6 +19,7 @@ package certificate
 import (
 	"context"
 	"crypto/x509"
+	"fmt"
 	"strings"
 	"time"
 
@@ -31,11 +32,12 @@ import (
 	cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
 	v1 "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
 	cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
+	cmutil "github.com/jetstack/cert-manager/pkg/util"
 	"github.com/jetstack/cert-manager/test/e2e/framework"
 	"github.com/jetstack/cert-manager/test/e2e/framework/log"
 	. "github.com/jetstack/cert-manager/test/e2e/framework/matcher"
+	frameworkutil "github.com/jetstack/cert-manager/test/e2e/framework/util"
 	"github.com/jetstack/cert-manager/test/e2e/util"
-	e2eutil "github.com/jetstack/cert-manager/test/e2e/util"
 	"github.com/jetstack/cert-manager/test/unit/gen"
 )
 
@@ -110,7 +112,7 @@ var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01)", func()
 	})
 
 	JustBeforeEach(func() {
-		acmeIngressDomain = e2eutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
+		acmeIngressDomain = frameworkutil.RandomSubdomain(f.Config.Addons.IngressController.Domain)
 	})
 
 	AfterEach(func() {
@@ -157,10 +159,7 @@ var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01)", func()
 		const maxLengthOfDomainSegment = 63
 		By("Creating a CertificateRequest")
 		cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
-			[]string{
-				acmeIngressDomain,
-				e2eutil.RandomSubdomainLength(acmeIngressDomain, maxLengthOfDomainSegment),
-			},
+			[]string{acmeIngressDomain, fmt.Sprintf("%s.%s", cmutil.RandStringRunes(maxLengthOfDomainSegment), acmeIngressDomain)},
 			nil, nil, x509.RSA)
 		Expect(err).NotTo(HaveOccurred())
 
@@ -175,7 +174,7 @@ var _ = framework.CertManagerDescribe("ACME CertificateRequest (HTTP01)", func()
 
 		By("Creating a CertificateRequest")
 		cr, key, err := util.NewCertManagerBasicCertificateRequest(certificateRequestName, issuerName, v1.IssuerKind, nil,
-			[]string{e2eutil.RandomSubdomain(acmeIngressDomain)},
+			[]string{fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), acmeIngressDomain)},
 			nil, nil, x509.RSA)
 		Expect(err).NotTo(HaveOccurred())
 
diff --git a/test/e2e/suite/issuers/acme/dnsproviders/BUILD.bazel b/test/e2e/suite/issuers/acme/dnsproviders/BUILD.bazel
index b942a527e..4f3232b82 100644
--- a/test/e2e/suite/issuers/acme/dnsproviders/BUILD.bazel
+++ b/test/e2e/suite/issuers/acme/dnsproviders/BUILD.bazel
@@ -13,6 +13,7 @@ go_library(
     deps = [
         "//pkg/apis/acme/v1:go_default_library",
         "//pkg/apis/meta/v1:go_default_library",
+        "//pkg/util:go_default_library",
         "//test/e2e/framework/addon/base:go_default_library",
         "//test/e2e/framework/config:go_default_library",
         "//test/e2e/framework/util/errors:go_default_library",
diff --git a/test/e2e/suite/issuers/acme/dnsproviders/dnsproviders.go b/test/e2e/suite/issuers/acme/dnsproviders/dnsproviders.go
index 124bb106b..0bdd284d0 100644
--- a/test/e2e/suite/issuers/acme/dnsproviders/dnsproviders.go
+++ b/test/e2e/suite/issuers/acme/dnsproviders/dnsproviders.go
@@ -24,6 +24,7 @@ import (
 	"fmt"
 
 	cmacme "github.com/jetstack/cert-manager/pkg/apis/acme/v1"
+	cmutil "github.com/jetstack/cert-manager/pkg/util"
 )
 
 var (
@@ -37,3 +38,7 @@ type Details struct {
 	// ProviderConfig is the issuer config needed to use these newly created credentials
 	ProviderConfig cmacme.ACMEChallengeSolverDNS01
 }
+
+func (d *Details) NewTestDomain() string {
+	return fmt.Sprintf("%s.%s", cmutil.RandStringRunes(5), d.BaseDomain)
+}
diff --git a/test/e2e/suite/issuers/ca/certificate.go b/test/e2e/suite/issuers/ca/certificate.go
index 080ab6728..bf0ca37d5 100644
--- a/test/e2e/suite/issuers/ca/certificate.go
+++ b/test/e2e/suite/issuers/ca/certificate.go
@@ -77,7 +77,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 			Expect(err).NotTo(HaveOccurred())
 			By("Verifying the Certificate is valid")
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -97,7 +97,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -116,7 +116,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -152,7 +152,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 				cert, err := certClient.Create(context.TODO(), util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1.IssuerKind, v.inputDuration, v.inputRenewBefore), metav1.CreateOptions{})
 				Expect(err).NotTo(HaveOccurred())
 				By("Waiting for the Certificate to be issued...")
-				_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+				err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 				Expect(err).NotTo(HaveOccurred())
 
 				By("Validating the issued Certificate...")
@@ -178,7 +178,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 			_, err := certClient.Create(context.TODO(), util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1.IssuerKind, nil, nil), metav1.CreateOptions{})
 			Expect(err).NotTo(HaveOccurred())
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -201,7 +201,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
 			_, err := certClient.Create(context.TODO(), gen.Certificate(certificateName, gen.SetCertificateNamespace(f.Namespace.Name), gen.SetCertificateCommonName("test.domain.com"), gen.SetCertificateSecretName(certificateSecretName), gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: issuerName, Kind: v1.IssuerKind}), gen.SetCertificateKeyUsages(v1.UsageServerAuth, v1.UsageClientAuth)), metav1.CreateOptions{})
 			Expect(err).NotTo(HaveOccurred())
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/selfsigned/certificate.go b/test/e2e/suite/issuers/selfsigned/certificate.go
index bb568be0a..82ada74b2 100644
--- a/test/e2e/suite/issuers/selfsigned/certificate.go
+++ b/test/e2e/suite/issuers/selfsigned/certificate.go
@@ -61,7 +61,7 @@ var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
 		_, err = certClient.Create(context.TODO(), util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerName, v1.IssuerKind, nil, nil), metav1.CreateOptions{})
 		Expect(err).NotTo(HaveOccurred())
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -113,7 +113,7 @@ var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
 			cert, err := certClient.Create(context.TODO(), util.NewCertManagerBasicCertificate(certificateName, certificateSecretName, issuerDurationName, v1.IssuerKind, v.inputDuration, v.inputRenewBefore), metav1.CreateOptions{})
 			Expect(err).NotTo(HaveOccurred())
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
@@ -143,7 +143,7 @@ var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/vault/certificate/approle.go b/test/e2e/suite/issuers/vault/certificate/approle.go
index fa476d62e..86f14c3da 100644
--- a/test/e2e/suite/issuers/vault/certificate/approle.go
+++ b/test/e2e/suite/issuers/vault/certificate/approle.go
@@ -180,7 +180,7 @@ func runVaultAppRoleTests(issuerKind string, testWithRoot bool, unsupportedFeatu
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
@@ -275,7 +275,7 @@ func runVaultAppRoleTests(issuerKind string, testWithRoot bool, unsupportedFeatu
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Waiting for the Certificate to be issued...")
-			_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+			err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 			Expect(err).NotTo(HaveOccurred())
 
 			By("Validating the issued Certificate...")
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 d472b02a5..29e07076c 100644
--- a/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go
+++ b/test/e2e/suite/issuers/vault/certificate/approle_custom_mount.go
@@ -178,7 +178,7 @@ func runVaultCustomAppRoleTests(issuerKind string, testWithRoot bool, unsupporte
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/issuers/venafi/tpp/certificate.go b/test/e2e/suite/issuers/venafi/tpp/certificate.go
index 55d818fa6..dddca36f8 100644
--- a/test/e2e/suite/issuers/venafi/tpp/certificate.go
+++ b/test/e2e/suite/issuers/venafi/tpp/certificate.go
@@ -83,7 +83,7 @@ var _ = TPPDescribe("Certificate with a properly configured Issuer", func() {
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Waiting for the Certificate to be issued...")
-		_, err = f.Helper().WaitForCertificateReady(f.Namespace.Name, certificateName, time.Minute*5)
+		err = f.Helper().WaitCertificateIssued(f.Namespace.Name, certificateName, time.Minute*5)
 		Expect(err).NotTo(HaveOccurred())
 
 		By("Validating the issued Certificate...")
diff --git a/test/e2e/suite/serving/cainjector.go b/test/e2e/suite/serving/cainjector.go
index 18b3c57c2..c5132c91e 100644
--- a/test/e2e/suite/serving/cainjector.go
+++ b/test/e2e/suite/serving/cainjector.go
@@ -91,7 +91,10 @@ var _ = framework.CertManagerDescribe("CA Injector", func() {
 				cert.Namespace = f.Namespace.Name
 				Expect(f.CRClient.Create(context.Background(), cert)).To(Succeed())
 
-				_, err := f.Helper().WaitForCertificateReady(f.Namespace.Name, "serving-certs", time.Second*30)
+				err := util.WaitForCertificateCondition(f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name), "serving-certs", certmanager.CertificateCondition{
+					Type:   certmanager.CertificateConditionReady,
+					Status: cmmeta.ConditionTrue,
+				}, time.Second*30)
 				Expect(err).NotTo(HaveOccurred(), "failed to wait for Certificate to become Ready")
 
 				By("grabbing the corresponding secret")
diff --git a/test/e2e/util/BUILD.bazel b/test/e2e/util/BUILD.bazel
index 2dc66d10c..c84477ba8 100644
--- a/test/e2e/util/BUILD.bazel
+++ b/test/e2e/util/BUILD.bazel
@@ -2,10 +2,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
 
 go_library(
     name = "go_default_library",
-    srcs = [
-        "domains.go",
-        "util.go",
-    ],
+    srcs = ["util.go"],
     importpath = "github.com/jetstack/cert-manager/test/e2e/util",
     visibility = ["//visibility:public"],
     deps = [
diff --git a/test/e2e/util/util.go b/test/e2e/util/util.go
index 3322fe231..ea40a8356 100644
--- a/test/e2e/util/util.go
+++ b/test/e2e/util/util.go
@@ -144,44 +144,19 @@ func wrapErrorWithClusterIssuerStatusCondition(client clientset.ClusterIssuerInt
 
 // WaitForCertificateCondition waits for the status of the named Certificate to contain
 // a condition whose type and status matches the supplied one.
-func WaitForCertificateCondition(client clientset.CertificateInterface, name string, condition v1.CertificateCondition, timeout time.Duration) (*v1.Certificate, error) {
-	var certificate *v1.Certificate = nil
+func WaitForCertificateCondition(client clientset.CertificateInterface, name string, condition v1.CertificateCondition, timeout time.Duration) error {
 	pollErr := wait.PollImmediate(500*time.Millisecond, timeout,
 		func() (bool, error) {
-			log.Logf("Waiting for Certificate %v condition %v=%v", name, condition.Type, condition.Status)
+			log.Logf("Waiting for Certificate %v condition %#v", name, condition)
 			certificate, err := client.Get(context.TODO(), name, metav1.GetOptions{})
 			if nil != err {
 				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
 			}
-			if !apiutil.CertificateHasCondition(certificate, condition) {
-				log.Logf("Expected Certificate %v condition %v=%v but it has: %v", name, condition.Type, condition.Status, condition.ObservedGeneration, certificate.Status.Conditions)
-				return false, nil
-			}
-			return true, nil
-		},
-	)
-	return certificate, wrapErrorWithCertificateStatusCondition(client, pollErr, name, condition.Type)
-}
 
-// WaitForCertificateConditionWithObservedGeneration waits for the status of the named Certificate to contain
-// a condition whose type and status matches the supplied one.
-func WaitForCertificateConditionWithObservedGeneration(client clientset.CertificateInterface, name string, condition v1.CertificateCondition, timeout time.Duration) (*v1.Certificate, error) {
-	var certificate *v1.Certificate = nil
-	pollErr := wait.PollImmediate(500*time.Millisecond, timeout,
-		func() (bool, error) {
-			log.Logf("Waiting for Certificate %v condition %v=%v", name, condition.Type, condition.Status)
-			certificate, err := client.Get(context.TODO(), name, metav1.GetOptions{})
-			if nil != err {
-				return false, fmt.Errorf("error getting Certificate %v: %v", name, err)
-			}
-			if !apiutil.CertificateHasConditionWithObservedGeneration(certificate, condition) {
-				log.Logf("Expected Certificate %v condition %v=%v (generation >= %v) but it has: %v", name, condition.Type, condition.Status, condition.ObservedGeneration, certificate.Status.Conditions)
-				return false, nil
-			}
-			return true, nil
+			return apiutil.CertificateHasCondition(certificate, condition), nil
 		},
 	)
-	return certificate, wrapErrorWithCertificateStatusCondition(client, pollErr, name, condition.Type)
+	return wrapErrorWithCertificateStatusCondition(client, pollErr, name, condition.Type)
 }
 
 // WaitForCertificateEvent waits for an event on the named Certificate to contain
diff --git a/test/unit/gen/certificatesigningrequest.go b/test/unit/gen/certificatesigningrequest.go
index 59fb5a2a9..f264cfad5 100644
--- a/test/unit/gen/certificatesigningrequest.go
+++ b/test/unit/gen/certificatesigningrequest.go
@@ -17,6 +17,7 @@ limitations under the License.
 package gen
 
 import (
+	"encoding/base64"
 	"strconv"
 
 	certificatesv1 "k8s.io/api/certificates/v1"
@@ -107,6 +108,12 @@ func SetCertificateSigningRequestCertificate(cert []byte) CertificateSigningRequ
 	}
 }
 
+func SetCertificateSigningRequestCA(ca []byte) CertificateSigningRequestModifier {
+	return AddCertificateSigningRequestAnnotations(map[string]string{
+		experimentalapi.CertificateSigningRequestCAAnnotationKey: base64.StdEncoding.EncodeToString(ca),
+	})
+}
+
 func SetCertificateSigningRequestStatusCondition(c certificatesv1.CertificateSigningRequestCondition) CertificateSigningRequestModifier {
 	return func(csr *certificatesv1.CertificateSigningRequest) {
 		if len(csr.Status.Conditions) == 0 {