diff --git a/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go b/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go index 909e79c41..7ae259488 100644 --- a/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go +++ b/test/e2e/framework/helper/validation/certificatesigningrequests/certificatesigningrequests.go @@ -331,10 +331,9 @@ func ExpectIsCA(csr *certificatesv1.CertificateSigningRequest, _ crypto.Signer) markedIsCA, cert.IsCA) } - hasCertSign := (cert.KeyUsage & x509.KeyUsageCertSign) == x509.KeyUsageCertSign - if hasCertSign != markedIsCA { - return fmt.Errorf("Expected certificate to have KeyUsageCertSign=%t, but got=%t", markedIsCA, hasCertSign) - } + // NOTE: For CertificateSigningRequests that are marked as CA, we do not automatically + // add the KeyUsageCertSign bit to the KeyUsage field. This behaviour is different + // to the behaviour of the cert-manager Certificate resource. return nil } diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 7a3f22763..05a4337dd 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -49,7 +49,7 @@ func Skipf(format string, args ...interface{}) { Skip(nowStamp() + ": " + msg) } -func RequireFeatureGate(f *Framework, featureSet featuregate.FeatureGate, gate featuregate.Feature) { +func RequireFeatureGate(featureSet featuregate.FeatureGate, gate featuregate.Feature) { if !featureSet.Enabled(gate) { Skipf("feature gate %q is not enabled, skipping test", gate) } diff --git a/test/e2e/suite/certificates/additionaloutputformats.go b/test/e2e/suite/certificates/additionaloutputformats.go index 6b0d3bb28..6659a2d19 100644 --- a/test/e2e/suite/certificates/additionaloutputformats.go +++ b/test/e2e/suite/certificates/additionaloutputformats.go @@ -54,7 +54,7 @@ var _ = framework.CertManagerDescribe("Certificate AdditionalCertificateOutputFo f := framework.NewDefaultFramework("certificates-additional-output-formats") createCertificate := func(f *framework.Framework, aof []cmapi.CertificateAdditionalOutputFormat) (string, *cmapi.Certificate) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.AdditionalCertificateOutputFormats) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.AdditionalCertificateOutputFormats) crt := &cmapi.Certificate{ ObjectMeta: metav1.ObjectMeta{ @@ -332,7 +332,7 @@ var _ = framework.CertManagerDescribe("Certificate AdditionalCertificateOutputFo It("if a third party set additional output formats, they then get added to the Certificate, when they are removed again they should persist as they are still owned by a third party", func() { // This e2e test requires that the ServerSideApply feature gate is enabled. - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ServerSideApply) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ServerSideApply) crtName, crt := createCertificate(f, nil) diff --git a/test/e2e/suite/certificates/literalsubjectrdns.go b/test/e2e/suite/certificates/literalsubjectrdns.go index 3e4fec9e3..f67df5144 100644 --- a/test/e2e/suite/certificates/literalsubjectrdns.go +++ b/test/e2e/suite/certificates/literalsubjectrdns.go @@ -49,7 +49,7 @@ var _ = framework.CertManagerDescribe("literalsubject rdn parsing", func() { f := framework.NewDefaultFramework("certificate-literalsubject-rdns") createCertificate := func(f *framework.Framework, literalSubject string) (*cmapi.Certificate, error) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.LiteralCertificateSubject) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.LiteralCertificateSubject) crt := &cmapi.Certificate{ ObjectMeta: metav1.ObjectMeta{ GenerateName: testName + "-", diff --git a/test/e2e/suite/certificates/othernamesan.go b/test/e2e/suite/certificates/othernamesan.go index 39f24b6d9..37a57c09d 100644 --- a/test/e2e/suite/certificates/othernamesan.go +++ b/test/e2e/suite/certificates/othernamesan.go @@ -74,7 +74,7 @@ var _ = framework.CertManagerDescribe("othername san processing", func() { } BeforeEach(func() { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.OtherNames) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.OtherNames) By("creating a self-signing issuer") issuer := gen.Issuer(issuerName, diff --git a/test/e2e/suite/certificatesigningrequests/selfsigned/selfsigned.go b/test/e2e/suite/certificatesigningrequests/selfsigned/selfsigned.go index 1963f8726..845802162 100644 --- a/test/e2e/suite/certificatesigningrequests/selfsigned/selfsigned.go +++ b/test/e2e/suite/certificatesigningrequests/selfsigned/selfsigned.go @@ -63,7 +63,7 @@ var _ = framework.CertManagerDescribe("CertificateSigningRequests SelfSigned Sec }) It("Issuer: the private key Secret is created after the request is created should still be signed", func() { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) var err error issuer, err = f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), &cmapi.Issuer{ @@ -125,7 +125,7 @@ var _ = framework.CertManagerDescribe("CertificateSigningRequests SelfSigned Sec }) It("Issuer: private key Secret is updated with a valid private key after the request is created should still be signed", func() { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) var err error By("creating Secret with missing private key") @@ -190,7 +190,7 @@ var _ = framework.CertManagerDescribe("CertificateSigningRequests SelfSigned Sec }) It("ClusterIssuer: the private key Secret is created after the request is created should still be signed", func() { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) var err error issuer, err = f.CertManagerClientSet.CertmanagerV1().ClusterIssuers().Create(context.TODO(), &cmapi.ClusterIssuer{ @@ -252,7 +252,7 @@ var _ = framework.CertManagerDescribe("CertificateSigningRequests SelfSigned Sec }) It("ClusterIssuer: private key Secret is updated with a valid private key after the request is created should still be signed", func() { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) var err error By("creating Secret with missing private key") diff --git a/test/e2e/suite/conformance/certificates/tests.go b/test/e2e/suite/conformance/certificates/tests.go index fa60af321..51128c4e6 100644 --- a/test/e2e/suite/conformance/certificates/tests.go +++ b/test/e2e/suite/conformance/certificates/tests.go @@ -83,7 +83,7 @@ func (s *Suite) Define() { sharedIPAddress = f.Config.Addons.ACMEServer.IngressIP case "Gateway": sharedIPAddress = f.Config.Addons.ACMEServer.GatewayIP - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalGatewayAPISupport) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalGatewayAPISupport) } }) @@ -224,7 +224,7 @@ func (s *Suite) Define() { }, featureset.CommonNameFeature) s.it(f, "should issue a certificate with a couple valid otherName SAN values set as well as an emailAddress", func(issuerRef cmmeta.ObjectReference) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.OtherNames) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.OtherNames) emailAddresses := []string{"email@domain.test"} otherNames := []cmapi.OtherName{ { @@ -305,7 +305,7 @@ cKK5t8N1YDX5CV+01X3vvxpM3ciYuCY9y+lSegrIEI+izRyD7P9KaZlwMaYmsBZq }, featureset.OtherNamesFeature) s.it(f, "should issue a basic, defaulted certificate for a single distinct DNS Name with a literal subject", func(issuerRef cmmeta.ObjectReference) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.LiteralCertificateSubject) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.LiteralCertificateSubject) // Some issuers use the CN to define the cert's "ID" // if one cert manages to be in an error state in the issuer it might throw an error // this makes the CN more unique @@ -963,7 +963,7 @@ cKK5t8N1YDX5CV+01X3vvxpM3ciYuCY9y+lSegrIEI+izRyD7P9KaZlwMaYmsBZq }) s.it(f, "Creating a Gateway with annotations for issuerRef and other Certificate fields", func(issuerRef cmmeta.ObjectReference) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalGatewayAPISupport) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalGatewayAPISupport) name := "testcert-gateway" secretName := "testcert-gateway-tls" diff --git a/test/e2e/suite/conformance/certificatesigningrequests/acme/acme.go b/test/e2e/suite/conformance/certificatesigningrequests/acme/acme.go index e9a7e0e79..29d5b19b8 100644 --- a/test/e2e/suite/conformance/certificatesigningrequests/acme/acme.go +++ b/test/e2e/suite/conformance/certificatesigningrequests/acme/acme.go @@ -46,13 +46,15 @@ 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, featureset.CommonNameFeature, featureset.KeyUsagesFeature, featureset.EmailSANsFeature, + featureset.SaveCAToSecret, + featureset.IssueCAFeature, + featureset.OtherNamesFeature, ) // unsupportedDNS01Features is a list of features that are not supported by the ACME @@ -64,6 +66,9 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) { featureset.CommonNameFeature, featureset.KeyUsagesFeature, featureset.EmailSANsFeature, + featureset.SaveCAToSecret, + featureset.IssueCAFeature, + featureset.OtherNamesFeature, ) http01 := &acme{ @@ -75,8 +80,8 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) { } (&certificatesigningrequests.Suite{ - Name: "ACME HTTP01 Issuer", - DomainSuffix: "ingress-nginx.http01.example.com", + Name: "ACME HTTP01 Issuer (Ingress)", + HTTP01TestType: "Ingress", CreateIssuerFunc: http01.createHTTP01Issuer, DeleteIssuerFunc: http01.delete, UnsupportedFeatures: unsupportedHTTP01Features, @@ -91,8 +96,8 @@ func runACMEIssuerTests(eab *cmacme.ACMEExternalAccountBinding) { }).Define() (&certificatesigningrequests.Suite{ - Name: "ACME HTTP01 ClusterIssuer", - DomainSuffix: "ingress-nginx.http01.example.com", + Name: "ACME HTTP01 ClusterIssuer (Ingress)", + HTTP01TestType: "Ingress", CreateIssuerFunc: http01.createHTTP01ClusterIssuer, DeleteIssuerFunc: http01.delete, UnsupportedFeatures: unsupportedHTTP01Features, diff --git a/test/e2e/suite/conformance/certificatesigningrequests/suite.go b/test/e2e/suite/conformance/certificatesigningrequests/suite.go index 6dec02dfa..81af69c7e 100644 --- a/test/e2e/suite/conformance/certificatesigningrequests/suite.go +++ b/test/e2e/suite/conformance/certificatesigningrequests/suite.go @@ -64,6 +64,11 @@ type Suite struct { // If not specified, this function will be skipped. DeProvisionFunc func(context.Context, *framework.Framework, *certificatesv1.CertificateSigningRequest) + // SharedIPAddress is the IP address that will be used in all certificates + // that require an IP address to be set. For HTTP-01 tests, this IP address + // will be set to the IP address of the Ingress/ Gateway controller. + SharedIPAddress string + // DomainSuffix is a suffix used on all domain requests. // This is useful when the issuer being tested requires special // configuration for a set of domains in order for certificates to be @@ -72,18 +77,55 @@ type Suite struct { // nginx-ingress addon. DomainSuffix string + // HTTP01TestType is set to "Ingress" or "Gateway" to determine which IPs + // and Domains will be used to run the ACME HTTP-01 test suites. + HTTP01TestType string + // 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 // certain features due to restrictions in their implementation. UnsupportedFeatures featureset.FeatureSet - // completed is used internally to track whether Complete() has been called - completed bool + // validated is used internally to track whether Validate has been called already. + validated bool } -// complete will validate configuration and set default values. -func (s *Suite) complete(f *framework.Framework) { +// setup will set default values for fields on the Suite struct. +func (s *Suite) setup(f *framework.Framework) { + if s.SharedIPAddress == "" { + switch s.HTTP01TestType { + case "Ingress": + s.SharedIPAddress = f.Config.Addons.ACMEServer.IngressIP + case "Gateway": + s.SharedIPAddress = f.Config.Addons.ACMEServer.GatewayIP + default: + s.SharedIPAddress = "127.0.0.1" + } + } + + if s.DomainSuffix == "" { + switch s.HTTP01TestType { + case "Ingress": + s.DomainSuffix = f.Config.Addons.IngressController.Domain + case "Gateway": + s.DomainSuffix = f.Config.Addons.Gateway.Domain + default: + s.DomainSuffix = "example.com" + } + } + + if s.UnsupportedFeatures == nil { + s.UnsupportedFeatures = make(featureset.FeatureSet) + } +} + +// validate will validate the Suite struct to ensure all required fields are set. +func (s *Suite) validate() { + if s.validated { + return + } + if s.Name == "" { Fail("Name must be set") } @@ -92,15 +134,11 @@ func (s *Suite) complete(f *framework.Framework) { Fail("CreateIssuerFunc must be set") } - if s.DomainSuffix == "" { - s.DomainSuffix = f.Config.Addons.IngressController.Domain + if s.HTTP01TestType == "Gateway" { + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalGatewayAPISupport) } - if s.UnsupportedFeatures == nil { - s.UnsupportedFeatures = make(featureset.FeatureSet) - } - - s.completed = true + s.validated = true } // it is called by the tests to in Define() to setup and run the test @@ -109,7 +147,7 @@ func (s *Suite) it(f *framework.Framework, name string, fn func(context.Context, return } It(name, func(ctx context.Context) { - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.ExperimentalCertificateSigningRequestControllers) By("Creating an issuer resource") signerName := s.CreateIssuerFunc(ctx, f) diff --git a/test/e2e/suite/conformance/certificatesigningrequests/tests.go b/test/e2e/suite/conformance/certificatesigningrequests/tests.go index f837d0ef6..086cf70b2 100644 --- a/test/e2e/suite/conformance/certificatesigningrequests/tests.go +++ b/test/e2e/suite/conformance/certificatesigningrequests/tests.go @@ -51,8 +51,8 @@ import ( func (s *Suite) Define() { Describe("CertificateSigningRequest with issuer type "+s.Name, func() { f := framework.NewDefaultFramework("certificatesigningrequests") + s.setup(f) - sharedCommonName := "" 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 @@ -63,13 +63,7 @@ func (s *Suite) Define() { // 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) + s.validate() }) type testCase struct { @@ -78,7 +72,7 @@ func (s *Suite) Define() { // csrModifers define the shape of the X.509 CSR which is used in the // test case. We use a function to allow access to variables that are // initialized at test runtime by complete(). - csrModifiers func() []gen.CSRModifier + csrModifiers []gen.CSRModifier kubeCSRUsages []certificatesv1.KeyUsage kubeCSRAnnotations map[string]string kubeCSRExpirationSeconds *int32 @@ -94,8 +88,8 @@ func (s *Suite) Define() { { name: "should issue an RSA certificate for a single distinct DNS Name", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -106,8 +100,8 @@ func (s *Suite) Define() { { name: "should issue an ECDSA certificate for a single distinct DNS Name", keyAlgo: x509.ECDSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -118,8 +112,8 @@ func (s *Suite) Define() { { name: "should issue an Ed25519 certificate for a single distinct DNS Name", keyAlgo: x509.Ed25519, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -130,8 +124,8 @@ func (s *Suite) Define() { { name: "should issue an RSA certificate for a single Common Name", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + rand.String(10))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("test-common-name-" + rand.String(10)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -142,8 +136,8 @@ func (s *Suite) Define() { { name: "should issue an ECDSA certificate for a single Common Name", keyAlgo: x509.ECDSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + rand.String(10))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("test-common-name-" + rand.String(10)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -154,8 +148,8 @@ func (s *Suite) Define() { { name: "should issue an Ed25519 certificate for a single Common Name", keyAlgo: x509.Ed25519, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + rand.String(10))} + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("test-common-name-" + rand.String(10)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -166,11 +160,9 @@ func (s *Suite) Define() { { name: "should issue a certificate that defines a Common Name and IP Address", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRCommonName("test-common-name-" + rand.String(10)), - gen.SetCSRIPAddresses(net.IPv4(127, 0, 0, 1), net.IPv4(8, 8, 8, 8)), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("test-common-name-" + rand.String(10)), + gen.SetCSRIPAddresses(net.ParseIP(s.SharedIPAddress)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -178,13 +170,51 @@ func (s *Suite) Define() { }, requiredFeatures: []featureset.Feature{featureset.CommonNameFeature, featureset.IPAddressFeature}, }, + { + name: "should issue a certificate that defines an IP Address", + keyAlgo: x509.RSA, + csrModifiers: []gen.CSRModifier{ + gen.SetCSRIPAddresses(net.ParseIP(s.SharedIPAddress)), + }, + kubeCSRUsages: []certificatesv1.KeyUsage{ + certificatesv1.UsageDigitalSignature, + certificatesv1.UsageKeyEncipherment, + }, + requiredFeatures: []featureset.Feature{featureset.IPAddressFeature}, + }, + { + name: "should issue a certificate that defines a DNS Name and IP Address", + keyAlgo: x509.RSA, + csrModifiers: []gen.CSRModifier{ + gen.SetCSRIPAddresses(net.ParseIP(s.SharedIPAddress)), + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), + }, + kubeCSRUsages: []certificatesv1.KeyUsage{ + certificatesv1.UsageDigitalSignature, + certificatesv1.UsageKeyEncipherment, + }, + requiredFeatures: []featureset.Feature{featureset.OnlySAN, featureset.IPAddressFeature}, + }, + { + name: "should issue a CA certificate with the CA basicConstraint set", + keyAlgo: x509.RSA, + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), + }, + kubeCSRAnnotations: map[string]string{ + experimentalapi.CertificateSigningRequestIsCAAnnotationKey: "true", + }, + kubeCSRUsages: []certificatesv1.KeyUsage{ + certificatesv1.UsageDigitalSignature, + certificatesv1.UsageKeyEncipherment, + }, + requiredFeatures: []featureset.Feature{featureset.IssueCAFeature}, + }, { name: "should issue a certificate that defines an Email Address", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSREmails([]string{"alice@example.com", "bob@cert-manager.io"}), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSREmails([]string{"alice@example.com", "bob@cert-manager.io"}), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -195,11 +225,9 @@ func (s *Suite) Define() { { name: "should issue a certificate that defines a Common Name and URI SAN", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRCommonName("test-common-name-" + rand.String(10)), - gen.SetCSRURIs(sharedURI), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("test-common-name-" + rand.String(10)), + gen.SetCSRURIs(sharedURI), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -208,28 +236,28 @@ func (s *Suite) Define() { requiredFeatures: []featureset.Feature{featureset.CommonNameFeature, featureset.URISANsFeature}, }, { - name: "should issue a certificate that defines a 2 distinct DNS Name with one copied to the Common Name", + name: "should issue a certificate that define 2 distinct DNS Names with one copied to the Common Name", keyAlgo: x509.RSA, csrModifiers: func() []gen.CSRModifier { + commonName := e2eutil.RandomSubdomain(s.DomainSuffix) + return []gen.CSRModifier{ - gen.SetCSRCommonName(sharedCommonName), - gen.SetCSRDNSNames(sharedCommonName, e2eutil.RandomSubdomain(s.DomainSuffix)), + gen.SetCSRCommonName(commonName), + gen.SetCSRDNSNames(commonName, e2eutil.RandomSubdomain(s.DomainSuffix)), } - }, + }(), kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, certificatesv1.UsageKeyEncipherment, }, - requiredFeatures: []featureset.Feature{}, + requiredFeatures: []featureset.Feature{featureset.CommonNameFeature}, }, { name: "should issue a certificate that defines a distinct DNS Name and another distinct Common Name", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRCommonName(e2eutil.RandomSubdomain(s.DomainSuffix)), - gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName(e2eutil.RandomSubdomain(s.DomainSuffix)), + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -241,11 +269,13 @@ func (s *Suite) Define() { name: "should issue a certificate that defines a Common Name, DNS Name, and sets a duration", keyAlgo: x509.RSA, csrModifiers: func() []gen.CSRModifier { + commonName := e2eutil.RandomSubdomain(s.DomainSuffix) + return []gen.CSRModifier{ - gen.SetCSRDNSNames(sharedCommonName), - gen.SetCSRDNSNames(sharedCommonName), + gen.SetCSRCommonName(commonName), + gen.SetCSRDNSNames(commonName), } - }, + }(), kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, certificatesv1.UsageKeyEncipherment, @@ -259,11 +289,13 @@ func (s *Suite) Define() { name: "should issue a certificate that defines a Common Name, DNS Name, and sets a duration via expiration seconds", keyAlgo: x509.RSA, csrModifiers: func() []gen.CSRModifier { + commonName := e2eutil.RandomSubdomain(s.DomainSuffix) + return []gen.CSRModifier{ - gen.SetCSRDNSNames(sharedCommonName), - gen.SetCSRDNSNames(sharedCommonName), + gen.SetCSRCommonName(commonName), + gen.SetCSRDNSNames(commonName), } - }, + }(), kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, certificatesv1.UsageKeyEncipherment, @@ -274,10 +306,8 @@ func (s *Suite) Define() { { name: "should issue a certificate that defines a DNS Name and sets a duration", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -291,10 +321,8 @@ func (s *Suite) Define() { { name: "should issue a certificate which has a wildcard DNS Name defined", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRDNSNames("*." + e2eutil.RandomSubdomain(s.DomainSuffix)), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRDNSNames("*." + e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -302,13 +330,27 @@ func (s *Suite) Define() { }, requiredFeatures: []featureset.Feature{featureset.WildcardsFeature, featureset.OnlySAN}, }, + { + name: "should issue a certificate which has a wildcard DNS Name and its apex DNS Name defined", + keyAlgo: x509.RSA, + csrModifiers: func() []gen.CSRModifier { + dnsDomain := e2eutil.RandomSubdomain(s.DomainSuffix) + + return []gen.CSRModifier{ + gen.SetCSRDNSNames("*."+dnsDomain, dnsDomain), + } + }(), + kubeCSRUsages: []certificatesv1.KeyUsage{ + certificatesv1.UsageDigitalSignature, + certificatesv1.UsageKeyEncipherment, + }, + requiredFeatures: []featureset.Feature{featureset.WildcardsFeature, featureset.OnlySAN}, + }, { name: "should issue a certificate that includes only a URISANs name", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRURIs(sharedURI), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRURIs(sharedURI), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -317,13 +359,10 @@ func (s *Suite) Define() { requiredFeatures: []featureset.Feature{featureset.URISANsFeature, featureset.OnlySAN}, }, { - name: "should issue a certificate that includes arbitrary key usages", + name: "should issue a certificate that includes arbitrary key usages with common name", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRCommonName(sharedCommonName), - gen.SetCSRDNSNames(sharedCommonName), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName(e2eutil.RandomSubdomain(s.DomainSuffix)), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageServerAuth, @@ -331,21 +370,19 @@ func (s *Suite) Define() { certificatesv1.UsageDigitalSignature, certificatesv1.UsageDataEncipherment, }, - requiredFeatures: []featureset.Feature{featureset.KeyUsagesFeature}, extraValidations: []certificatesigningrequests.ValidationFunc{ certificatesigningrequests.ExpectKeyUsageExtKeyUsageClientAuth, certificatesigningrequests.ExpectKeyUsageExtKeyUsageServerAuth, certificatesigningrequests.ExpectKeyUsageUsageDigitalSignature, certificatesigningrequests.ExpectKeyUsageUsageDataEncipherment, }, + requiredFeatures: []featureset.Feature{featureset.KeyUsagesFeature}, }, { name: "should issue a signing CA certificate that has a large duration", keyAlgo: x509.RSA, - csrModifiers: func() []gen.CSRModifier { - return []gen.CSRModifier{ - gen.SetCSRCommonName("cert-manager-ca"), - } + csrModifiers: []gen.CSRModifier{ + gen.SetCSRCommonName("cert-manager-ca"), }, kubeCSRUsages: []certificatesv1.KeyUsage{ certificatesv1.UsageDigitalSignature, @@ -358,19 +395,47 @@ func (s *Suite) Define() { }, requiredFeatures: []featureset.Feature{featureset.KeyUsagesFeature, featureset.DurationFeature, featureset.CommonNameFeature}, }, + { + name: "should issue a certificate that defines a long domain", + keyAlgo: x509.RSA, + csrModifiers: func() []gen.CSRModifier { + const maxLengthOfDomainSegment = 63 + return []gen.CSRModifier{ + gen.SetCSRDNSNames(e2eutil.RandomSubdomainLength(s.DomainSuffix, maxLengthOfDomainSegment)), + } + }(), + kubeCSRUsages: []certificatesv1.KeyUsage{ + certificatesv1.UsageDigitalSignature, + certificatesv1.UsageKeyEncipherment, + }, + requiredFeatures: []featureset.Feature{featureset.OnlySAN, featureset.LongDomainFeatureSet}, + }, + } + + addAnnotation := func(annotations map[string]string, key, value string) map[string]string { + if annotations == nil { + annotations = map[string]string{} + } + annotations[key] = value + return annotations } defineTest := func(test testCase) { s.it(f, test.name, func(ctx context.Context, signerName string) { // Generate request CSR - csr, key, err := gen.CSR(test.keyAlgo, test.csrModifiers()...) + csr, key, err := gen.CSR(test.keyAlgo, test.csrModifiers...) Expect(err).NotTo(HaveOccurred()) // Create CertificateSigningRequest + randomTestID := rand.String(10) kubeCSR := &certificatesv1.CertificateSigningRequest{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: "e2e-conformance-", - Annotations: test.kubeCSRAnnotations, + Name: "e2e-conformance-" + randomTestID, + Annotations: addAnnotation( + test.kubeCSRAnnotations, + "conformance.cert-manager.io/test-name", + s.Name+" "+test.name, + ), }, Spec: certificatesv1.CertificateSigningRequestSpec{ Request: csr, @@ -421,7 +486,8 @@ func (s *Suite) Define() { // Validate that the request was signed as expected. Add extra // validations which may be required for this test. By("Validating the issued CertificateSigningRequest...") - validations := append([]certificatesigningrequests.ValidationFunc(nil), test.extraValidations...) + validations := []certificatesigningrequests.ValidationFunc(nil) + validations = append(validations, test.extraValidations...) validations = append(validations, validation.CertificateSigningRequestSetForUnsupportedFeatureSet(s.UnsupportedFeatures)...) err = f.Helper().ValidateCertificateSigningRequest(kubeCSR.Name, key, validations...) Expect(err).NotTo(HaveOccurred()) diff --git a/test/e2e/suite/conformance/certificatesigningrequests/vault/approle.go b/test/e2e/suite/conformance/certificatesigningrequests/vault/approle.go index 256c9c992..c14514479 100644 --- a/test/e2e/suite/conformance/certificatesigningrequests/vault/approle.go +++ b/test/e2e/suite/conformance/certificatesigningrequests/vault/approle.go @@ -53,56 +53,50 @@ type secrets struct { } var _ = framework.ConformanceDescribe("CertificateSigningRequests", func() { + var unsupportedFeatures = featureset.NewFeatureSet( + featureset.KeyUsagesFeature, + featureset.Ed25519FeatureSet, + featureset.IssueCAFeature, + ) + issuer := &approle{ testWithRootCA: true, } (&certificatesigningrequests.Suite{ - Name: "Vault AppRole Issuer With Root CA", - CreateIssuerFunc: issuer.createIssuer, - DeleteIssuerFunc: issuer.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault AppRole Issuer With Root CA", + CreateIssuerFunc: issuer.createIssuer, + DeleteIssuerFunc: issuer.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() issuerNoRoot := &approle{ testWithRootCA: false, } (&certificatesigningrequests.Suite{ - Name: "Vault AppRole Issuer Without Root CA", - CreateIssuerFunc: issuerNoRoot.createIssuer, - DeleteIssuerFunc: issuerNoRoot.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault AppRole Issuer Without Root CA", + CreateIssuerFunc: issuerNoRoot.createIssuer, + DeleteIssuerFunc: issuerNoRoot.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() clusterIssuer := &approle{ testWithRootCA: true, } (&certificatesigningrequests.Suite{ - Name: "Vault AppRole ClusterIssuer With Root CA", - CreateIssuerFunc: clusterIssuer.createClusterIssuer, - DeleteIssuerFunc: clusterIssuer.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault AppRole ClusterIssuer With Root CA", + CreateIssuerFunc: clusterIssuer.createClusterIssuer, + DeleteIssuerFunc: clusterIssuer.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() clusterIssuerNoRoot := &approle{ testWithRootCA: false, } (&certificatesigningrequests.Suite{ - Name: "Vault AppRole ClusterIssuer Without Root CA", - CreateIssuerFunc: clusterIssuerNoRoot.createClusterIssuer, - DeleteIssuerFunc: clusterIssuerNoRoot.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault AppRole ClusterIssuer Without Root CA", + CreateIssuerFunc: clusterIssuerNoRoot.createClusterIssuer, + DeleteIssuerFunc: clusterIssuerNoRoot.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() }) diff --git a/test/e2e/suite/conformance/certificatesigningrequests/vault/kubernetes.go b/test/e2e/suite/conformance/certificatesigningrequests/vault/kubernetes.go index 6fd8ed86f..438bfa067 100644 --- a/test/e2e/suite/conformance/certificatesigningrequests/vault/kubernetes.go +++ b/test/e2e/suite/conformance/certificatesigningrequests/vault/kubernetes.go @@ -38,30 +38,30 @@ import ( ) var _ = framework.ConformanceDescribe("CertificateSigningRequests", func() { + var unsupportedFeatures = featureset.NewFeatureSet( + featureset.KeyUsagesFeature, + featureset.Ed25519FeatureSet, + featureset.IssueCAFeature, + ) + issuer := &kubernetes{ testWithRootCA: true, } (&certificatesigningrequests.Suite{ - Name: "Vault Kubernetes Auth Issuer With Root CA", - CreateIssuerFunc: issuer.createIssuer, - DeleteIssuerFunc: issuer.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault Kubernetes Auth Issuer With Root CA", + CreateIssuerFunc: issuer.createIssuer, + DeleteIssuerFunc: issuer.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() clusterIssuer := &kubernetes{ testWithRootCA: true, } (&certificatesigningrequests.Suite{ - Name: "Vault Kubernetes Auth ClusterIssuer With Root CA", - CreateIssuerFunc: clusterIssuer.createClusterIssuer, - DeleteIssuerFunc: clusterIssuer.delete, - UnsupportedFeatures: featureset.NewFeatureSet( - featureset.KeyUsagesFeature, - featureset.Ed25519FeatureSet, - ), + Name: "Vault Kubernetes Auth ClusterIssuer With Root CA", + CreateIssuerFunc: clusterIssuer.createClusterIssuer, + DeleteIssuerFunc: clusterIssuer.delete, + UnsupportedFeatures: unsupportedFeatures, }).Define() }) diff --git a/test/e2e/suite/issuers/ca/certificate.go b/test/e2e/suite/issuers/ca/certificate.go index 879885cda..c0c1e76c1 100644 --- a/test/e2e/suite/issuers/ca/certificate.go +++ b/test/e2e/suite/issuers/ca/certificate.go @@ -157,7 +157,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() { It("should be able to create a certificate with additional output formats", func() { // Output formats is only enabled via this feature gate being enabled. // Don't run test if the gate isn't enabled. - framework.RequireFeatureGate(f, utilfeature.DefaultFeatureGate, feature.AdditionalCertificateOutputFormats) + framework.RequireFeatureGate(utilfeature.DefaultFeatureGate, feature.AdditionalCertificateOutputFormats) certClient := f.CertManagerClientSet.CertmanagerV1().Certificates(f.Namespace.Name)