Merge pull request #2034 from JoshVanL/e2e-conformance-tests

Extends conformance tests
This commit is contained in:
jetstack-bot 2019-09-27 00:10:55 +01:00 committed by GitHub
commit 9cd00ce3f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 658 additions and 100 deletions

View File

@ -6,6 +6,7 @@ go_library(
"conditions.go",
"duration.go",
"issuers.go",
"names.go",
"usages.go",
],
importpath = "github.com/jetstack/cert-manager/pkg/api/util",

43
pkg/api/util/names.go Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"encoding/json"
"fmt"
"hash/fnv"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
)
func ComputeCertificateRequestName(crt *cmapi.Certificate) (string, error) {
crt = crt.DeepCopy()
specBytes, err := json.Marshal(crt.Spec)
if err != nil {
return "", err
}
hashF := fnv.New32()
_, err = hashF.Write(specBytes)
if err != nil {
return "", err
}
// shorten the cert name to 52 chars to ensure the total length of the name
// is less than or equal to 64 characters
return fmt.Sprintf("%.52s-%d", crt.Name, hashF.Sum32()), nil
}

View File

@ -39,6 +39,25 @@ go_library(
],
)
go_test(
name = "go_default_test",
srcs = ["sync_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/controller/test:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/unit/gen:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
"@io_k8s_client_go//testing:go_default_library",
"@io_k8s_utils//clock/testing:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
@ -52,21 +71,3 @@ filegroup(
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["sync_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/controller/test:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/unit/gen:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
"@io_k8s_client_go//testing:go_default_library",
"@io_k8s_utils//clock/testing:go_default_library",
],
)

View File

@ -21,10 +21,8 @@ import (
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"hash/fnv"
"reflect"
"strings"
"time"
@ -188,7 +186,7 @@ func (c *certificateRequestManager) processCertificate(ctx context.Context, crt
// The certificate request name is a product of the certificate's spec,
// which makes it unique and predictable.
// First we compute what we expect it to be.
expectedReqName, err := expectedCertificateRequestName(crt)
expectedReqName, err := apiutil.ComputeCertificateRequestName(crt)
if err != nil {
return fmt.Errorf("internal error hashing certificate spec: %v", err)
}
@ -584,24 +582,6 @@ func (c *certificateRequestManager) certificateRequiresIssuance(ctx context.Cont
return needsRenew, []string{"Certificate is expiring soon"}, nil
}
func expectedCertificateRequestName(crt *cmapi.Certificate) (string, error) {
crt = crt.DeepCopy()
specBytes, err := json.Marshal(crt.Spec)
if err != nil {
return "", err
}
hashF := fnv.New32()
_, err = hashF.Write(specBytes)
if err != nil {
return "", err
}
// shorten the cert name to 52 chars to ensure the total length of the name
// is less than or equal to 64 characters
return fmt.Sprintf("%.52s-%d", crt.Name, hashF.Sum32()), nil
}
type generateCSRFn func(*cmapi.Certificate, []byte) ([]byte, error)
func generateCSRImpl(crt *cmapi.Certificate, pk []byte) ([]byte, error) {

View File

@ -31,6 +31,7 @@ import (
coretesting "k8s.io/client-go/testing"
fakeclock "k8s.io/utils/clock/testing"
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
@ -81,7 +82,7 @@ func mustCreateCryptoBundle(t *testing.T, crt *cmapi.Certificate) cryptoBundle {
}
func createCryptoBundle(crt *cmapi.Certificate) (*cryptoBundle, error) {
reqName, err := expectedCertificateRequestName(crt)
reqName, err := apiutil.ComputeCertificateRequestName(crt)
if err != nil {
return nil, err
}

View File

@ -406,6 +406,7 @@ func (v *VaultInitializer) setupRole() error {
params := map[string]string{
"allow_any_name": "true",
"max_ttl": "2160h",
"key_type": "any",
}
url := path.Join("/v1", v.IntermediateMount, "roles", v.Role)

View File

@ -22,7 +22,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/api/core/v1"
api "k8s.io/api/core/v1"
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
@ -78,7 +77,7 @@ type Framework struct {
CRClient crclient.Client
// Namespace in which all test resources should reside
Namespace *v1.Namespace
Namespace *api.Namespace
// To make sure that this framework cleans up after itself, no matter what,
// we install a Cleanup action before each test and clear it after. If we
@ -232,7 +231,7 @@ func (f *Framework) Helper() *helper.Helper {
return f.helper
}
func (f *Framework) CertificateDurationValid(c *v1alpha2.Certificate, duration time.Duration) {
func (f *Framework) CertificateDurationValid(c *v1alpha2.Certificate, duration time.Duration, fuzz time.Duration) {
By("Verifying TLS certificate exists")
secret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Get(c.Spec.SecretName, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
@ -243,8 +242,10 @@ func (f *Framework) CertificateDurationValid(c *v1alpha2.Certificate, duration t
cert, err := pki.DecodeX509CertificateBytes(certBytes)
Expect(err).NotTo(HaveOccurred())
By("Verifying that the duration is valid")
if cert.NotAfter.Sub(cert.NotBefore) != duration {
Failf("Expected duration of %s, got %s [NotBefore: %s, NotAfter: %s]", duration, cert.NotAfter.Sub(cert.NotBefore), cert.NotBefore.Format(time.RFC3339), cert.NotAfter.Format(time.RFC3339))
certDuration := cert.NotAfter.Sub(cert.NotBefore)
if certDuration > (duration+fuzz) || certDuration < duration {
Failf("Expected duration of %s, got %s (fuzz: %s) [NotBefore: %s, NotAfter: %s]", duration, certDuration,
fuzz, cert.NotBefore.Format(time.RFC3339), cert.NotAfter.Format(time.RFC3339))
}
}

View File

@ -8,6 +8,7 @@ go_library(
"helper.go",
"kubectl.go",
"pod_start.go",
"secret.go",
],
importpath = "github.com/jetstack/cert-manager/test/e2e/framework/helper",
tags = ["manual"],

View File

@ -0,0 +1,58 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package helper
import (
"fmt"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/jetstack/cert-manager/test/e2e/framework/log"
)
// WaitForSecretCertificateData waits for the certificate data to be ready
// inside a Secret created by cert-manager.
func (h *Helper) WaitForSecretCertificateData(ns, name string, timeout time.Duration) (*corev1.Secret, error) {
var secret *corev1.Secret
err := wait.PollImmediate(time.Second, timeout,
func() (bool, error) {
var err error
log.Logf("Waiting for Secret %s:%s to contain a certificate", ns, name)
secret, err = h.KubeClient.CoreV1().Secrets(ns).Get(name, metav1.GetOptions{})
if err != nil {
return false, fmt.Errorf("error getting secret %s: %s", name, err)
}
if len(secret.Data[corev1.TLSCertKey]) > 0 {
return true, nil
}
log.Logf("Secret still does not contain certificate data %s/%s: %v",
secret.Namespace, secret.Name, secret.Data)
return false, nil
},
)
if err != nil {
return nil, err
}
return secret, nil
}

View File

@ -10,6 +10,8 @@ go_library(
"//test/e2e/suite/conformance/certificates/acme:go_default_library",
"//test/e2e/suite/conformance/certificates/ca:go_default_library",
"//test/e2e/suite/conformance/certificates/selfsigned:go_default_library",
"//test/e2e/suite/conformance/certificates/vault:go_default_library",
"//test/e2e/suite/conformance/certificates/venafi:go_default_library",
"//test/e2e/suite/conformance/rbac:go_default_library",
],
)

View File

@ -9,12 +9,15 @@ go_library(
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates",
visibility = ["//visibility:public"],
deps = [
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/util:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/e2e/framework:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
],
)
@ -33,6 +36,8 @@ filegroup(
"//test/e2e/suite/conformance/certificates/acme:all-srcs",
"//test/e2e/suite/conformance/certificates/ca:all-srcs",
"//test/e2e/suite/conformance/certificates/selfsigned:all-srcs",
"//test/e2e/suite/conformance/certificates/vault:all-srcs",
"//test/e2e/suite/conformance/certificates/venafi:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],

View File

@ -13,6 +13,7 @@ go_library(
"//test/e2e/framework/addon/pebble:go_default_library",
"//test/e2e/framework/addon/tiller:go_default_library",
"//test/e2e/suite/conformance/certificates:go_default_library",
"//test/e2e/suite/issuers/acme/dnsproviders:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package selfsigned
package acme
import (
. "github.com/onsi/ginkgo"
@ -28,76 +28,79 @@ import (
"github.com/jetstack/cert-manager/test/e2e/framework/addon/pebble"
"github.com/jetstack/cert-manager/test/e2e/framework/addon/tiller"
"github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates"
"github.com/jetstack/cert-manager/test/e2e/suite/issuers/acme/dnsproviders"
)
var _ = framework.ConformanceDescribe("Certificates", func() {
// unsupportedFeatures is a list of features that are not supported by the ACME
// unsupportedHTTP01Features is a list of features that are not supported by the ACME
// issuer type using HTTP01
var unsupportedFeatures = certificates.NewFeatureSet(
var unsupportedHTTP01Features = certificates.NewFeatureSet(
certificates.IPAddressFeature,
certificates.Wildcards,
certificates.DurationFeature,
certificates.WildcardsFeature,
)
provisioner := &acmeIssuerProvisioner{setGroupName: false}
// unsupportedDNS01Features is a list of features that are not supported by the ACME
// issuer type using DNS01
var unsupportedDNS01Features = certificates.NewFeatureSet(
certificates.IPAddressFeature,
certificates.DurationFeature,
)
provisionerHTTP01 := new(acmeIssuerProvisioner)
(&certificates.Suite{
Name: "ACME HTTP01",
CreateIssuerFunc: provisioner.create,
DeleteIssuerFunc: provisioner.delete,
UnsupportedFeatures: unsupportedFeatures,
CreateIssuerFunc: provisionerHTTP01.createHTTP01,
DeleteIssuerFunc: provisionerHTTP01.delete,
UnsupportedFeatures: unsupportedHTTP01Features,
}).Define()
// crProvisioner sets the issuerRef.group field on Certificates it creates
crProvisioner := &acmeIssuerProvisioner{setGroupName: true}
provisionerDNS01 := new(acmeIssuerProvisioner)
(&certificates.Suite{
Name: "ACME HTTP01 (CertificateRequest)",
CreateIssuerFunc: crProvisioner.create,
DeleteIssuerFunc: crProvisioner.delete,
UnsupportedFeatures: unsupportedFeatures,
Name: "ACME DNS01",
CreateIssuerFunc: provisionerDNS01.createDNS01,
DeleteIssuerFunc: provisionerDNS01.delete,
UnsupportedFeatures: unsupportedDNS01Features,
}).Define()
})
type acmeIssuerProvisioner struct {
tiller *tiller.Tiller
pebble *pebble.Pebble
// if setGroupName is true, the 'group name' field on the IssuerRef will be
// set the 'cert-manager.io'.
// Setting the group name will cause the new 'certificate requests' based
// implementation to be used, however this is not implemented for ACME yet
// See: https://github.com/jetstack/cert-manager/pull/1943
setGroupName bool
tiller *tiller.Tiller
pebble *pebble.Pebble
cloudflare *dnsproviders.Cloudflare
}
func (a *acmeIssuerProvisioner) delete(f *framework.Framework, ref cmmeta.ObjectReference) {
Expect(a.pebble.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision pebble")
if a.pebble != nil {
Expect(a.pebble.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision pebble")
}
if a.cloudflare != nil {
Expect(a.cloudflare.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision cloudflare")
}
Expect(a.tiller.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision tiller")
}
// create will deploy the required components to run an ACME issuer based test.
// createXXX will deploy the required components to run an ACME issuer based test.
// This includes:
// - tiller
// - pebble
// - a properly configured Issuer resource
func (a *acmeIssuerProvisioner) create(f *framework.Framework) cmmeta.ObjectReference {
a.tiller = &tiller.Tiller{
Name: "tiller-deploy",
ClusterPermissions: false,
Namespace: f.Namespace.Name,
}
Expect(a.tiller.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup tiller")
Expect(a.tiller.Provision()).NotTo(HaveOccurred(), "failed to provision tiller")
func (a *acmeIssuerProvisioner) createHTTP01(f *framework.Framework) cmmeta.ObjectReference {
a.deployTiller(f, "http01")
a.pebble = &pebble.Pebble{
Tiller: a.tiller,
Name: "cm-e2e-create-acme-issuer",
Name: "cm-e2e-create-acme-http01-issuer",
Namespace: f.Namespace.Name,
}
Expect(a.pebble.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup pebble")
Expect(a.pebble.Provision()).NotTo(HaveOccurred(), "failed to provision pebble")
By("Creating an ACME issuer")
By("Creating an ACME HTTP01 issuer")
issuer := &cmapi.Issuer{
ObjectMeta: metav1.ObjectMeta{
Name: "acme-issuer",
Name: "acme-issuer-http01",
},
Spec: cmapi.IssuerSpec{
IssuerConfig: cmapi.IssuerConfig{
@ -106,7 +109,7 @@ func (a *acmeIssuerProvisioner) create(f *framework.Framework) cmmeta.ObjectRefe
SkipTLSVerify: true,
PrivateKey: cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "acme-private-key",
Name: "acme-private-key-http01",
},
},
Solvers: []cmacme.ACMEChallengeSolver{
@ -123,21 +126,67 @@ func (a *acmeIssuerProvisioner) create(f *framework.Framework) cmmeta.ObjectRefe
},
},
}
issuer, err := f.CertManagerClientSet.CertmanagerV1alpha2().Issuers(f.Namespace.Name).Create(issuer)
Expect(err).NotTo(HaveOccurred(), "failed to create acme issuer")
Expect(err).NotTo(HaveOccurred(), "failed to create acme HTTP01 issuer")
return cmmeta.ObjectReference{
Group: emptyOrString(a.setGroupName, cmapi.SchemeGroupVersion.Group),
Group: cmapi.SchemeGroupVersion.Group,
Kind: cmapi.IssuerKind,
Name: issuer.Name,
}
}
// emptyOrString will return the given string 's' if 'set' is true,
// otherwise it will return the empty string.
func emptyOrString(set bool, s string) string {
if set {
return s
func (a *acmeIssuerProvisioner) createDNS01(f *framework.Framework) cmmeta.ObjectReference {
a.deployTiller(f, "dns01")
a.cloudflare = &dnsproviders.Cloudflare{
Namespace: f.Namespace.Name,
}
Expect(a.cloudflare.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup cloudflare")
Expect(a.cloudflare.Provision()).NotTo(HaveOccurred(), "failed to provision cloudflare")
By("Creating an ACME DNS01 issuer")
issuer := &cmapi.Issuer{
ObjectMeta: metav1.ObjectMeta{
Name: "acme-issuer-dns01",
},
Spec: cmapi.IssuerSpec{
IssuerConfig: cmapi.IssuerConfig{
ACME: &cmacme.ACMEIssuer{
// Hardcode this to the acme staging endpoint now due to issues with pebble dns resolution
Server: "https://acme-staging-v02.api.letsencrypt.org/directory",
SkipTLSVerify: true,
PrivateKey: cmmeta.SecretKeySelector{
LocalObjectReference: cmmeta.LocalObjectReference{
Name: "acme-private-key",
},
},
Solvers: []cmacme.ACMEChallengeSolver{
{
DNS01: &a.cloudflare.Details().ProviderConfig,
},
},
},
},
},
}
issuer, err := f.CertManagerClientSet.CertmanagerV1alpha2().Issuers(f.Namespace.Name).Create(issuer)
Expect(err).NotTo(HaveOccurred(), "failed to create acme DNS01 issuer")
return cmmeta.ObjectReference{
Group: cmapi.SchemeGroupVersion.Group,
Kind: cmapi.IssuerKind,
Name: issuer.Name,
}
return ""
}
func (a *acmeIssuerProvisioner) deployTiller(f *framework.Framework, solverType string) {
a.tiller = &tiller.Tiller{
Name: "tiller-deploy-" + solverType,
ClusterPermissions: false,
Namespace: f.Namespace.Name,
}
Expect(a.tiller.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup tiller")
Expect(a.tiller.Provision()).NotTo(HaveOccurred(), "failed to provision tiller")
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package selfsigned
package ca
import (
. "github.com/onsi/ginkgo"
@ -36,7 +36,7 @@ var _ = framework.ConformanceDescribe("Certificates", func() {
})
func createCAIssuer(f *framework.Framework) cmmeta.ObjectReference {
By("Creating a SelfSigned issuer")
By("Creating a CA issuer")
rootCertSecret, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(newSigningKeypairSecret("root-cert"))
Expect(err).NotTo(HaveOccurred(), "failed to create root signing keypair secret")

View File

@ -83,8 +83,19 @@ const (
// will never pass tests that validate the duration is as expected.
DurationFeature Feature = "Duration"
// Wildcards denotes tests that request certificates for wildcard domains.
// Some issuer's disable wildcard certificate issuance, so this feature
// allows runs of the suite to exclude those tests that utilise wildcards.
Wildcards Feature = "Wildcards"
// WildcardsFeature denotes tests that request certificates for wildcard
// domains. Some issuer's disable wildcard certificate issuance, so this
// feature allows runs of the suite to exclude those tests that utilise
// wildcards.
WildcardsFeature Feature = "Wildcards"
// ECDSAFeature denotes whether the target issuer is able to sign
// certificates with an elliptic curve private key. This is useful for some
// issuers that have trouble being configured to support this feature.
ECDSAFeature Feature = "ECDSA"
// ReusePrivateKey denotes whether the target issuer is able to sign multiple
// certificates for the same private key. This is useful for some issuers
// that have trouble being configured to support this feature.
ReusePrivateKeyFeature Feature = "ReusePrivateKey"
)

View File

@ -23,11 +23,14 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/pkg/util"
"github.com/jetstack/cert-manager/pkg/util/pki"
"github.com/jetstack/cert-manager/test/e2e/framework"
)
@ -143,6 +146,8 @@ func (s *Suite) Define() {
})
It("should issue an ECDSA, defaulted certificate for a single commonName and distinct dnsName", func() {
s.checkFeatures(ECDSAFeature)
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
@ -188,6 +193,125 @@ func (s *Suite) Define() {
err = f.Helper().WaitCertificateIssuedValid(f.Namespace.Name, "testcert", time.Minute*5)
Expect(err).NotTo(HaveOccurred())
})
It("should issue a certificate that defines a commonName and sets a duration", func() {
s.checkFeatures(DurationFeature)
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
CommonName: s.newDomain(),
IssuerRef: issuerRef,
Duration: &metav1.Duration{
Duration: time.Hour * 896,
},
},
}
By("Creating a Certificate")
err := f.CRClient.Create(ctx, testCertificate)
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssuedValid(f.Namespace.Name, "testcert", time.Minute*5)
Expect(err).NotTo(HaveOccurred())
// We set a weird time here as the duration with should never be used as
// a default by an issuer. This lets us test issuers are using our given
// duration.
// We set a 30 second buffer time here since Vault issues certificates
// with an extra 30 seconds on its duration.
f.CertificateDurationValid(testCertificate, time.Hour*896, 30*time.Second)
})
It("should issue a certificate which has a wildcard DNS name defined", func() {
s.checkFeatures(WildcardsFeature)
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
CommonName: s.newDomain(),
IssuerRef: issuerRef,
DNSNames: []string{"foo." + s.newDomain()},
},
}
By("Creating a Certificate")
err := f.CRClient.Create(ctx, testCertificate)
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssuedValid(f.Namespace.Name, "testcert", time.Minute*5)
Expect(err).NotTo(HaveOccurred())
})
It("should issue another certificate with the same private key if the existing certificate and CertificateRequest are deleted", func() {
s.checkFeatures(ReusePrivateKeyFeature)
testCertificate := &cmapi.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: "testcert",
Namespace: f.Namespace.Name,
},
Spec: cmapi.CertificateSpec{
SecretName: "testcert-tls",
CommonName: s.newDomain(),
DNSNames: []string{s.newDomain()},
IssuerRef: issuerRef,
},
}
By("Creating a Certificate")
err := f.CRClient.Create(ctx, testCertificate)
Expect(err).NotTo(HaveOccurred())
By("Waiting for the Certificate to be issued...")
err = f.Helper().WaitCertificateIssuedValid(f.Namespace.Name, "testcert", time.Minute*5)
Expect(err).NotTo(HaveOccurred())
By("Deleting existing certificate data in Secret and owned CertificateRequest")
expectedReqName, err := apiutil.ComputeCertificateRequestName(testCertificate)
Expect(err).NotTo(HaveOccurred(), "failed to generate expected name for created Certificate")
Expect(f.CertManagerClientSet.CertmanagerV1alpha2().
CertificateRequests(f.Namespace.Name).Delete(expectedReqName, &metav1.DeleteOptions{})).
NotTo(HaveOccurred(), "failed to delete owned CertificateRequest")
sec, err := f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).
Get(testCertificate.Spec.SecretName, metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred(), "failed to get secret containing signed certificate key pair data")
sec = sec.DeepCopy()
crtPEM1 := sec.Data[corev1.TLSCertKey]
crt1, err := pki.DecodeX509CertificateBytes(crtPEM1)
Expect(err).NotTo(HaveOccurred(), "failed to get decode first signed certificate data")
sec.Data[corev1.TLSCertKey] = []byte{}
_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Update(sec)
Expect(err).NotTo(HaveOccurred(), "failed to update secret by deleting the signed certificate data")
By("Waiting for the Certificate to re-issue a certificate")
sec, err = f.Helper().WaitForSecretCertificateData(f.Namespace.Name, sec.Name, time.Minute*5)
Expect(err).NotTo(HaveOccurred(), "failed to wait for secret to have a valid 2nd certificate")
crtPEM2 := sec.Data[corev1.TLSCertKey]
crt2, err := pki.DecodeX509CertificateBytes(crtPEM2)
Expect(err).NotTo(HaveOccurred(), "failed to get decode second signed certificate data")
By("Ensuing both certificates are signed by same private key")
match, err := pki.PublicKeysEqual(crt1.PublicKey, crt2.PublicKey)
Expect(err).NotTo(HaveOccurred(), "failed to check public keys of both signed certificates")
if !match {
Fail("Both signed certificates not signed by same private key")
}
})
})
}

View File

@ -0,0 +1,33 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["vault_approle.go"],
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/vault",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon/tiller:go_default_library",
"//test/e2e/framework/addon/vault:go_default_library",
"//test/e2e/suite/conformance/certificates:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,129 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package vault
import (
"path"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/addon/tiller"
vault "github.com/jetstack/cert-manager/test/e2e/framework/addon/vault"
"github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates"
)
var _ = framework.ConformanceDescribe("Certificates", func() {
provisioner := new(vaultAppRoleProvisioner)
(&certificates.Suite{
Name: "VaultAppRole",
CreateIssuerFunc: provisioner.create,
DeleteIssuerFunc: provisioner.delete,
}).Define()
})
type vaultAppRoleProvisioner struct {
tiller *tiller.Tiller
vault *vault.Vault
}
func (v *vaultAppRoleProvisioner) delete(f *framework.Framework, ref cmmeta.ObjectReference) {
Expect(v.vault.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision vault")
Expect(v.tiller.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision tiller")
}
func (v *vaultAppRoleProvisioner) create(f *framework.Framework) cmmeta.ObjectReference {
By("Creating a VaultAppRole issuer")
v.tiller = &tiller.Tiller{
Name: "tiller-deploy",
Namespace: f.Namespace.Name,
ClusterPermissions: false,
}
Expect(v.tiller.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup tiller")
Expect(v.tiller.Provision()).NotTo(HaveOccurred(), "failed to provision tiller")
v.vault = &vault.Vault{
Tiller: v.tiller,
Namespace: f.Namespace.Name,
Name: "cm-e2e-create-vault-issuer",
}
Expect(v.vault.Setup(f.Config)).NotTo(HaveOccurred(), "failed to setup vault")
Expect(v.vault.Provision()).NotTo(HaveOccurred(), "failed to provision vault")
intermediateMount := "intermediate-ca"
role := "kubernetes-vault"
vaultSecretAppRoleName := "vault-role"
vaultPath := path.Join(intermediateMount, "sign", role)
authPath := "approle"
By("Configuring the VaultAppRole server")
vaultInit := &vault.VaultInitializer{
Details: *v.vault.Details(),
RootMount: "root-ca",
IntermediateMount: intermediateMount,
Role: role,
AppRoleAuthPath: authPath,
}
Expect(vaultInit.Init()).NotTo(HaveOccurred(), "failed to init vault")
Expect(vaultInit.Setup()).NotTo(HaveOccurred(), "fauled to setup vault")
roleID, secretID, err := vaultInit.CreateAppRole()
Expect(err).NotTo(HaveOccurred(), "vault to create app role from vault")
_, err = f.KubeClientSet.CoreV1().Secrets(f.Namespace.Name).Create(vault.NewVaultAppRoleSecret(vaultSecretAppRoleName, secretID))
Expect(err).NotTo(HaveOccurred(), "vault to store app role secret from vault")
issuer, err := f.CertManagerClientSet.CertmanagerV1alpha2().Issuers(f.Namespace.Name).Create(&cmapi.Issuer{
ObjectMeta: metav1.ObjectMeta{
Name: "vault-issuer",
},
Spec: cmapi.IssuerSpec{
IssuerConfig: cmapi.IssuerConfig{
Vault: &cmapi.VaultIssuer{
Server: v.vault.Details().Host,
Path: vaultPath,
CABundle: v.vault.Details().VaultCA,
Auth: cmapi.VaultAuth{
AppRole: &cmapi.VaultAppRole{
Path: authPath,
RoleId: roleID,
SecretRef: cmmeta.SecretKeySelector{
Key: "secretkey",
LocalObjectReference: cmmeta.LocalObjectReference{
Name: vaultSecretAppRoleName,
},
},
},
},
},
},
},
})
Expect(err).NotTo(HaveOccurred(), "failed to create vault issuer")
return cmmeta.ObjectReference{
Group: cmapi.SchemeGroupVersion.Group,
Kind: cmapi.IssuerKind,
Name: issuer.Name,
}
}

View File

@ -0,0 +1,32 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["venafi.go"],
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/venafi",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/certmanager/v1alpha2:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/util/errors:go_default_library",
"//test/e2e/suite/conformance/certificates:go_default_library",
"//test/e2e/suite/issuers/venafi/addon:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,84 @@
/*
Copyright 2019 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package venafi
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/util/errors"
"github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates"
vaddon "github.com/jetstack/cert-manager/test/e2e/suite/issuers/venafi/addon"
)
var _ = framework.ConformanceDescribe("Certificates", func() {
// unsupportedFeatures is a list of features that are not supported by the
// Venafi issuer.
var unsupportedFeatures = certificates.NewFeatureSet(
certificates.DurationFeature,
// Due to the current configuration of the test environment, it does not
// support signing certificates that pair with an elliptic curve private
// key or using the same private key multiple times.
certificates.ECDSAFeature,
certificates.ReusePrivateKeyFeature,
)
provisioner := new(venafiProvisioner)
(&certificates.Suite{
Name: "Venafi",
CreateIssuerFunc: provisioner.create,
DeleteIssuerFunc: provisioner.delete,
UnsupportedFeatures: unsupportedFeatures,
}).Define()
})
type venafiProvisioner struct {
tpp *vaddon.VenafiTPP
}
func (v *venafiProvisioner) delete(f *framework.Framework, ref cmmeta.ObjectReference) {
Expect(v.tpp.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision tpp venafi")
}
func (v *venafiProvisioner) create(f *framework.Framework) cmmeta.ObjectReference {
By("Creating a Venafi issuer")
v.tpp = &vaddon.VenafiTPP{
Namespace: f.Namespace.Name,
}
err := v.tpp.Setup(f.Config)
if errors.IsSkip(err) {
framework.Skipf("Skipping test as addon could not be setup: %v", err)
}
Expect(err).NotTo(HaveOccurred(), "failed to setup tpp venafi")
Expect(v.tpp.Provision()).NotTo(HaveOccurred(), "failed to provision tpp venafi")
issuer := v.tpp.Details().BuildIssuer()
issuer, err = f.CertManagerClientSet.CertmanagerV1alpha2().Issuers(f.Namespace.Name).Create(issuer)
Expect(err).NotTo(HaveOccurred(), "failed to create issuer for venafi")
return cmmeta.ObjectReference{
Group: cmapi.SchemeGroupVersion.Group,
Kind: cmapi.IssuerKind,
Name: issuer.Name,
}
}

View File

@ -20,5 +20,7 @@ import (
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/acme"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/ca"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/selfsigned"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/vault"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificates/venafi"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/rbac"
)

View File

@ -123,7 +123,7 @@ var _ = framework.CertManagerDescribe("CA Certificate", func() {
By("Verifying the Certificate is valid")
err = h.WaitCertificateIssuedValid(f.Namespace.Name, certificateName, time.Second*30)
Expect(err).NotTo(HaveOccurred())
f.CertificateDurationValid(cert, v.expectedDuration)
f.CertificateDurationValid(cert, v.expectedDuration, 0)
})
}
})

View File

@ -102,7 +102,7 @@ var _ = framework.CertManagerDescribe("Self Signed Certificate", func() {
Expect(err).NotTo(HaveOccurred())
err = h.WaitCertificateIssuedValid(f.Namespace.Name, certificateName, time.Second*30)
Expect(err).NotTo(HaveOccurred())
f.CertificateDurationValid(cert, v.expectedDuration)
f.CertificateDurationValid(cert, v.expectedDuration, 0)
})
}

View File

@ -178,7 +178,7 @@ var _ = framework.CertManagerDescribe("Vault Certificate (AppRole)", func() {
Expect(err).NotTo(HaveOccurred())
// Vault substract 30 seconds to the NotBefore date.
f.CertificateDurationValid(cert, v.expectedDuration+(30*time.Second))
f.CertificateDurationValid(cert, v.expectedDuration, time.Second*30)
})
}
})

View File

@ -107,8 +107,7 @@ func (v *VenafiTPP) Details() *TPPDetails {
}
func (v *VenafiTPP) Deprovision() error {
v.Base.Details().KubeClient.CoreV1().Secrets(v.createdSecret.Namespace).Delete(v.createdSecret.Name, nil)
return nil
return v.Base.Details().KubeClient.CoreV1().Secrets(v.createdSecret.Namespace).Delete(v.createdSecret.Name, nil)
}
func (v *VenafiTPP) SupportsGlobal() bool {