Merge pull request #4108 from JoshVanL/certificate-signing-request=venafi

CertificateSigningRequest Venafi controller
This commit is contained in:
jetstack-bot
2021-07-20 10:13:34 +01:00
committed by GitHub
30 changed files with 1626 additions and 58 deletions
+1
View File
@@ -27,6 +27,7 @@ go_library(
"//pkg/controller/certificatesigningrequests/ca:go_default_library",
"//pkg/controller/certificatesigningrequests/selfsigned:go_default_library",
"//pkg/controller/certificatesigningrequests/vault:go_default_library",
"//pkg/controller/certificatesigningrequests/venafi:go_default_library",
"//pkg/controller/clusterissuers:go_default_library",
"//pkg/controller/issuers:go_default_library",
"//pkg/feature:go_default_library",
+2
View File
@@ -46,6 +46,7 @@ import (
csrcacontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/ca"
csrselfsignedcontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/selfsigned"
csrvaultcontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/vault"
csrvenaficontroller "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/venafi"
clusterissuerscontroller "github.com/jetstack/cert-manager/pkg/controller/clusterissuers"
issuerscontroller "github.com/jetstack/cert-manager/pkg/controller/issuers"
"github.com/jetstack/cert-manager/pkg/feature"
@@ -195,6 +196,7 @@ var (
experimentalCertificateSigningRequestControllers = []string{
csrcacontroller.CSRControllerName,
csrselfsignedcontroller.CSRControllerName,
csrvenaficontroller.CSRControllerName,
csrvaultcontroller.CSRControllerName,
}
)
+18
View File
@@ -26,7 +26,10 @@ const (
// CertificateSigningRequestIsCAAnnotationKey is the annotation key used to
// request whether the certificate should be marked as CA.
CertificateSigningRequestIsCAAnnotationKey = "experimental.cert-manager.io/request-is-ca"
)
// SelfSigned Issuer specific Annotations
const (
// CertificateSigningRequestPrivateKeyAnnotationKey is the annotation key
// used to reference a Secret resource containing the private key used to
// sign the request.
@@ -34,3 +37,18 @@ const (
// issuer type to self-sign certificates.
CertificateSigningRequestPrivateKeyAnnotationKey = "experimental.cert-manager.io/private-key-secret-name"
)
// Venafi Issuer specific Annotations
const (
// CertificateSigningRequestVenafiCustomFieldsAnnotationKey is the annotation
// that passes on JSON encoded custom fields to the Venafi issuer.
// This will only work with Venafi TPP v19.3 and higher.
// The value is an array with objects containing the name and value keys for
// example: `[{"name": "custom-field", "value": "custom-value"}]`
CertificateSigningRequestVenafiCustomFieldsAnnotationKey = "venafi.experimental.cert-manager.io/custom-fields"
// CertificateSigningRequestVenafiPickupIDAnnotationKey is the annotation key
// used to record the Venafi Pickup ID of a certificate signing request that
// has been submitted to the Venafi API for collection later.
CertificateSigningRequestVenafiPickupIDAnnotationKey = "venafi.experimental.cert-manager.io/pickup-id"
)
@@ -74,6 +74,7 @@ filegroup(
"//pkg/controller/certificatesigningrequests/selfsigned:all-srcs",
"//pkg/controller/certificatesigningrequests/util:all-srcs",
"//pkg/controller/certificatesigningrequests/vault:all-srcs",
"//pkg/controller/certificatesigningrequests/venafi:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
@@ -38,6 +38,11 @@ func (c *Controller) Sync(ctx context.Context, csr *certificatesv1.CertificateSi
log := logf.WithResource(logf.FromContext(ctx), csr).WithValues("signerName", csr.Spec.SignerName)
dbg := log.V(logf.DebugLevel)
// Deep copy CertificateSigningRequest to prevent writing to the shared local
// cache making it invalid. Done early in the sync to avoid accidental
// invalidation by future contributions.
csr = csr.DeepCopy()
ref, ok := util.SignerIssuerRefFromSignerName(csr.Spec.SignerName)
if !ok {
dbg.Info("certificate signing request has malformed signer name,", "signerName", csr.Spec.SignerName)
@@ -0,0 +1,73 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["venafi.go"],
importpath = "github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/venafi",
visibility = ["//visibility:public"],
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",
"//pkg/issuer/venafi/client:go_default_library",
"//pkg/issuer/venafi/client/api:go_default_library",
"//pkg/logs:go_default_library",
"//pkg/util/pki:go_default_library",
"@com_github_venafi_vcert_v4//pkg/endpoint:go_default_library",
"@io_k8s_api//certificates/v1:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/api/errors:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_client_go//kubernetes/typed/certificates/v1:go_default_library",
"@io_k8s_client_go//listers/core/v1:go_default_library",
"@io_k8s_client_go//tools/record:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["venafi_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/api/util:go_default_library",
"//pkg/apis/certmanager:go_default_library",
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/controller/certificatesigningrequests:go_default_library",
"//pkg/controller/certificatesigningrequests/util:go_default_library",
"//pkg/controller/test:go_default_library",
"//pkg/issuer/venafi/client:go_default_library",
"//pkg/issuer/venafi/client/api:go_default_library",
"//pkg/issuer/venafi/client/fake:go_default_library",
"//pkg/util/pki:go_default_library",
"//test/unit/gen:go_default_library",
"@com_github_venafi_vcert_v4//pkg/endpoint:go_default_library",
"@io_k8s_api//authorization/v1:go_default_library",
"@io_k8s_api//certificates/v1:go_default_library",
"@io_k8s_api//core/v1:go_default_library",
"@io_k8s_apimachinery//pkg/api/errors:go_default_library",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
"@io_k8s_apimachinery//pkg/runtime:go_default_library",
"@io_k8s_apimachinery//pkg/runtime/schema:go_default_library",
"@io_k8s_client_go//listers/core/v1: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(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
@@ -0,0 +1,213 @@
/*
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.
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 (
"context"
"encoding/json"
"fmt"
"github.com/Venafi/vcert/v4/pkg/endpoint"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1"
corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/tools/record"
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"
venaficlient "github.com/jetstack/cert-manager/pkg/issuer/venafi/client"
venafiapi "github.com/jetstack/cert-manager/pkg/issuer/venafi/client/api"
logf "github.com/jetstack/cert-manager/pkg/logs"
"github.com/jetstack/cert-manager/pkg/util/pki"
utilpki "github.com/jetstack/cert-manager/pkg/util/pki"
)
const (
CSRControllerName = "certificatesigningrequests-issuer-venafi"
)
// Venafi is a Kubernetes CertificateSigningRequest controller, responsible for
// signing CertificateSigningRequests that reference a cert-manager Venafi
// Issuer or ClusterIssuer
type Venafi struct {
issuerOptions controllerpkg.IssuerOptions
secretsLister corelisters.SecretLister
certClient certificatesclient.CertificateSigningRequestInterface
recorder record.EventRecorder
clientBuilder venaficlient.VenafiClientBuilder
}
func init() {
controllerpkg.Register(CSRControllerName, func(ctx *controllerpkg.Context) (controllerpkg.Interface, error) {
return controllerpkg.NewBuilder(ctx, CSRControllerName).
For(certificatesigningrequests.New(apiutil.IssuerVenafi, NewVenafi(ctx))).
Complete()
})
}
func NewVenafi(ctx *controllerpkg.Context) *Venafi {
return &Venafi{
issuerOptions: ctx.IssuerOptions,
secretsLister: ctx.KubeSharedInformerFactory.Core().V1().Secrets().Lister(),
certClient: ctx.Client.CertificatesV1().CertificateSigningRequests(),
recorder: ctx.Recorder,
clientBuilder: venaficlient.New,
}
}
// Sign attempts to sign the given CertificateSigningRequest based on the
// provided Venafi Issuer or ClusterIssuer. This function will update the resource
// if signing was successful. Returns an error which, if not nil, should
// trigger a retry.
// Since this signer takes some time to sign the request, this controller will
// set a "pick ID" annotation value that is used to fetch the latest state of
// the request in subsequent re-syncs. The re-syncs are triggered by using the
// workqueue's back-off mechanism.
func (v *Venafi) Sign(ctx context.Context, csr *certificatesv1.CertificateSigningRequest, issuerObj cmapi.GenericIssuer) error {
log := logf.FromContext(ctx, "sign")
log = logf.WithRelatedResource(log, issuerObj)
resourceNamespace := v.issuerOptions.ResourceNamespace(issuerObj)
client, err := v.clientBuilder(resourceNamespace, v.secretsLister, issuerObj)
if apierrors.IsNotFound(err) {
message := "Required secret resource not found"
v.recorder.Event(csr, corev1.EventTypeWarning, "SecretNotFound", message)
log.Error(err, message)
return nil
}
if err != nil {
message := fmt.Sprintf("Failed to initialise venafi client for signing: %s", err)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorVenafiInit", message)
log.Error(err, message)
return err
}
var customFields []venafiapi.CustomField
if annotation, exists := csr.GetAnnotations()[experimentalapi.CertificateSigningRequestVenafiCustomFieldsAnnotationKey]; exists && annotation != "" {
err := json.Unmarshal([]byte(annotation), &customFields)
if err != nil {
message := fmt.Sprintf("Failed to parse %q annotation: %s", experimentalapi.CertificateSigningRequestVenafiCustomFieldsAnnotationKey, err)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorCustomFields", message)
util.CertificateSigningRequestSetFailed(csr, "ErrorCustomFields", message)
_, userr := v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
return userr
}
}
duration, err := pki.DurationFromCertificateSigningRequest(csr)
if err != nil {
message := fmt.Sprintf("Failed to parse requested duration: %s", err)
log.Error(err, message)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorParseDuration", message)
util.CertificateSigningRequestSetFailed(csr, "ErrorParseDuration", message)
_, userr := v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
return userr
}
// The signing process with Venafi is slow. The "pickupID" allows us to track
// the progress of the certificate signing. It is set as an annotation the
// first time the Certificate is reconciled.
pickupID := csr.GetAnnotations()[experimentalapi.CertificateSigningRequestVenafiPickupIDAnnotationKey]
// check if the pickup ID annotation is there, if not set it up.
if len(pickupID) == 0 {
pickupID, err := client.RequestCertificate(csr.Spec.Request, duration, customFields)
// Check some known error types
if err != nil {
switch err.(type) {
case venaficlient.ErrCustomFieldsType:
log.Error(err, "")
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorCustomFields", err.Error())
util.CertificateSigningRequestSetFailed(csr, "ErrorCustomFields", err.Error())
_, userr := v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
return userr
default:
message := fmt.Sprintf("Failed to request venafi certificate: %s", err)
log.Error(err, message)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorRequest", message)
util.CertificateSigningRequestSetFailed(csr, "ErrorRequest", message)
_, userr := v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
return userr
}
}
if csr.Annotations == nil {
csr.Annotations = make(map[string]string)
}
csr.Annotations[experimentalapi.CertificateSigningRequestVenafiPickupIDAnnotationKey] = pickupID
_, uerr := v.certClient.Update(ctx, csr, metav1.UpdateOptions{})
return uerr
}
certPem, err := client.RetrieveCertificate(pickupID, csr.Spec.Request, duration, customFields)
if err != nil {
switch err.(type) {
case endpoint.ErrCertificatePending:
message := "Venafi certificate still in a pending state, waiting"
log.V(2).Info(message, "error", err.Error())
v.recorder.Event(csr, corev1.EventTypeNormal, "IssuancePending", message)
return err
case endpoint.ErrRetrieveCertificateTimeout:
message := "Venafi retrieve certificate timeout, retrying"
log.Error(err, message)
v.recorder.Event(csr, corev1.EventTypeWarning, "RetrieveCertificateTimeout", message)
return err
default:
message := fmt.Sprintf("Failed to obtain venafi certificate: %s", err)
log.Error(err, message)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorRetrieve", message)
return err
}
}
bundle, err := utilpki.ParseSingleCertificateChainPEM(certPem)
if err != nil {
message := fmt.Sprintf("Failed to parse returned certificate bundle: %s", err)
log.Error(err, message)
v.recorder.Event(csr, corev1.EventTypeWarning, "ErrorParse", message)
util.CertificateSigningRequestSetFailed(csr, "ErrorParse", message)
_, userr := v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
return userr
}
csr.Status.Certificate = bundle.ChainPEM
csr, err = v.certClient.UpdateStatus(ctx, csr, metav1.UpdateOptions{})
if err != nil {
message := "Error updating certificate"
v.recorder.Eventf(csr, corev1.EventTypeWarning, "SigningError", "%s: %s", message, err)
return err
}
log.V(logf.DebugLevel).Info("certificate issued")
v.recorder.Event(csr, corev1.EventTypeNormal, "CertificateIssued", "Certificate fetched from venafi issuer successfully")
return nil
}
@@ -0,0 +1,905 @@
/*
Copyright 2021 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.
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 (
"context"
"crypto/x509"
"errors"
"fmt"
"testing"
"time"
"github.com/Venafi/vcert/v4/pkg/endpoint"
authzv1 "k8s.io/api/authorization/v1"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
corelisters "k8s.io/client-go/listers/core/v1"
coretesting "k8s.io/client-go/testing"
fakeclock "k8s.io/utils/clock/testing"
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
"github.com/jetstack/cert-manager/pkg/apis/certmanager"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests"
"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/util"
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
venaficlient "github.com/jetstack/cert-manager/pkg/issuer/venafi/client"
venafiapi "github.com/jetstack/cert-manager/pkg/issuer/venafi/client/api"
fakevenaficlient "github.com/jetstack/cert-manager/pkg/issuer/venafi/client/fake"
"github.com/jetstack/cert-manager/pkg/util/pki"
"github.com/jetstack/cert-manager/test/unit/gen"
)
var (
fixedClockStart = time.Now()
fixedClock = fakeclock.NewFakeClock(fixedClockStart)
)
func TestProcessItem(t *testing.T) {
metaFixedClockStart := metav1.NewTime(fixedClockStart)
util.Clock = fixedClock
rootCSRPEM, rootPK, err := gen.CSR(x509.RSA,
gen.SetCSRCommonName("root"),
)
if err != nil {
t.Fatal(err)
}
rootTmpl, err := pki.GenerateTemplateFromCSRPEM(rootCSRPEM, time.Hour, true)
if err != nil {
t.Fatal(err)
}
_, rootCert, err := pki.SignCertificate(rootTmpl, rootTmpl, rootPK.Public(), rootPK)
if err != nil {
t.Fatal(err)
}
leafCSRPEM, leafPK, err := gen.CSR(x509.RSA,
gen.SetCSRCommonName("leaf"),
)
if err != nil {
t.Fatal(err)
}
leafTmpl, err := pki.GenerateTemplateFromCSRPEM(leafCSRPEM, time.Hour, false)
if err != nil {
t.Fatal(err)
}
_, leafCert, err := pki.SignCertificate(leafTmpl, rootCert, leafPK.Public(), rootPK)
if err != nil {
t.Fatal(err)
}
certBundle, err := pki.ParseSingleCertificateChain([]*x509.Certificate{leafCert, rootCert})
if err != nil {
t.Fatal(err)
}
baseIssuer := gen.Issuer("test-issuer",
gen.SetIssuerVenafi(cmapi.VenafiIssuer{
Cloud: &cmapi.VenafiCloud{},
}),
gen.AddIssuerCondition(cmapi.IssuerCondition{
Type: cmapi.IssuerConditionReady,
Status: cmmeta.ConditionTrue,
}),
)
baseCSR := gen.CertificateSigningRequest("test-cr",
gen.SetCertificateSigningRequestRequest(leafCSRPEM),
gen.SetCertificateSigningRequestSignerName("issuers.cert-manager.io/default-unit-test-ns.test-issuer"),
gen.SetCertificateSigningRequestDuration("1440h"),
gen.SetCertificateSigningRequestUsername("user-1"),
gen.SetCertificateSigningRequestGroups([]string{"group-1", "group-2"}),
gen.SetCertificateSigningRequestUID("uid-1"),
gen.SetCertificateSigningRequestExtra(map[string]certificatesv1.ExtraValue{
"extra": []string{"1", "2"},
}),
)
tests := map[string]struct {
builder *testpkg.Builder
csr *certificatesv1.CertificateSigningRequest
clientBuilder venaficlient.VenafiClientBuilder
expectedErr bool
}{
"a CertificateSigningRequest without an approved condition should do nothing": {
csr: gen.CertificateSigningRequestFrom(baseCSR),
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
},
},
"a CertificateSigningRequest with a denied condition should do nothing": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateDenied,
Status: corev1.ConditionTrue,
}),
),
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{},
ExpectedActions: nil,
},
},
"an approved CSR where the venafi client builder returns a not found error should fire event and do nothing": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return nil, apierrors.NewNotFound(schema.GroupResource{}, "test-secret")
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning SecretNotFound Required secret resource not found",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
},
},
},
"an approved CSR where the venafi client builder returns a generic error should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return nil, errors.New("generic error")
},
expectedErr: true,
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning ErrorVenafiInit Failed to initialise venafi client for signing: generic error",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
},
},
},
"an approved CSR where the custom fields annotations contain garbage data should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": "garbage-data",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
`Warning ErrorCustomFields Failed to parse "venafi.experimental.cert-manager.io/custom-fields" annotation: invalid character 'g' looking for beginning of value`,
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": "garbage-data",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateFailed,
Status: corev1.ConditionTrue,
Reason: "ErrorCustomFields",
Message: `Failed to parse "venafi.experimental.cert-manager.io/custom-fields" annotation: invalid character 'g' looking for beginning of value`,
LastTransitionTime: metaFixedClockStart,
LastUpdateTime: metaFixedClockStart,
}),
),
)),
},
},
},
"an approved CSR where the requested duration annotations contains garbage data should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestDuration("garbage-duration"),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
`Warning ErrorParseDuration Failed to parse requested duration: failed to parse requested duration on annotation "experimental.cert-manager.io/request-duration": time: invalid duration "garbage-duration"`,
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.SetCertificateSigningRequestDuration("garbage-duration"),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateFailed,
Status: corev1.ConditionTrue,
Reason: "ErrorParseDuration",
Message: `Failed to parse requested duration: failed to parse requested duration on annotation "experimental.cert-manager.io/request-duration": time: invalid duration "garbage-duration"`,
LastTransitionTime: metaFixedClockStart,
LastUpdateTime: metaFixedClockStart,
}),
),
)),
},
},
},
"an approved CSR which does not yet have a pickup ID, but the client responds with fields type error, should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RequestCertificateFn: func(_ []byte, _ time.Duration, _ []venafiapi.CustomField) (string, error) {
return "", venaficlient.ErrCustomFieldsType{Type: "test-type"}
},
}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
`Warning ErrorCustomFields certificate request contains an invalid Venafi custom fields type: "test-type"`,
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateFailed,
Status: corev1.ConditionTrue,
Reason: "ErrorCustomFields",
Message: `certificate request contains an invalid Venafi custom fields type: "test-type"`,
LastTransitionTime: metaFixedClockStart,
LastUpdateTime: metaFixedClockStart,
}),
),
)),
},
},
},
"an approved CSR which does not yet have a pickup ID, but the client responds a generic error, should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RequestCertificateFn: func(_ []byte, _ time.Duration, _ []venafiapi.CustomField) (string, error) {
return "", errors.New("generic error")
},
}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning ErrorRequest Failed to request venafi certificate: generic error",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateFailed,
Status: corev1.ConditionTrue,
Reason: "ErrorRequest",
Message: "Failed to request venafi certificate: generic error",
LastTransitionTime: metaFixedClockStart,
LastUpdateTime: metaFixedClockStart,
}),
),
)),
},
},
},
"an approved CSR which does not yet have a pickup ID, should update the annotation with one and return": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RequestCertificateFn: func(_ []byte, _ time.Duration, _ []venafiapi.CustomField) (string, error) {
return "test-pickup-id", nil
},
}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
)),
},
},
},
"an approved CSR which has a pickup ID, retrieve certificate returns a pending error, fire event and return error": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RetrieveCertificateFn: func(_ string, _ []byte, _ time.Duration, _ []venafiapi.CustomField) ([]byte, error) {
return nil, endpoint.ErrCertificatePending{}
},
}, nil
},
expectedErr: true,
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Normal IssuancePending Venafi certificate still in a pending state, waiting",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
},
},
},
"an approved CSR which has a pickup ID, retrieve certificate returns a timeout error, fire event and return error": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RetrieveCertificateFn: func(_ string, _ []byte, _ time.Duration, _ []venafiapi.CustomField) ([]byte, error) {
return nil, endpoint.ErrRetrieveCertificateTimeout{}
},
}, nil
},
expectedErr: true,
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning RetrieveCertificateTimeout Venafi retrieve certificate timeout, retrying",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
},
},
},
"an approved CSR which has a pickup ID, retrieve certificate returns a generic error, fire event and return error": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RetrieveCertificateFn: func(_ string, _ []byte, _ time.Duration, _ []venafiapi.CustomField) ([]byte, error) {
return nil, errors.New("generic error")
},
}, nil
},
expectedErr: true,
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning ErrorRetrieve Failed to obtain venafi certificate: generic error",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
},
},
},
"an approved CSR which has a pickup ID, retrieve certificate returns garbage certificates, should mark as Failed": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RetrieveCertificateFn: func(_ string, _ []byte, _ time.Duration, _ []venafiapi.CustomField) ([]byte, error) {
return []byte("garbage"), nil
},
}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Warning ErrorParse Failed to parse returned certificate bundle: error decoding certificate PEM block",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateFailed,
Status: corev1.ConditionTrue,
Reason: "ErrorParse",
Message: "Failed to parse returned certificate bundle: error decoding certificate PEM block",
LastTransitionTime: metaFixedClockStart,
LastUpdateTime: metaFixedClockStart,
}),
),
)),
},
},
},
"an approved CSR which has a pickup ID, retrieve certificate returns a CA and certificate should update with certificate": {
csr: gen.CertificateSigningRequestFrom(baseCSR,
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
),
clientBuilder: func(_ string, _ corelisters.SecretLister, _ cmapi.GenericIssuer) (venaficlient.Interface, error) {
return &fakevenaficlient.Venafi{
RetrieveCertificateFn: func(_ string, _ []byte, _ time.Duration, _ []venafiapi.CustomField) ([]byte, error) {
return []byte(fmt.Sprintf("%s%s", certBundle.ChainPEM, certBundle.CAPEM)), nil
},
}, nil
},
builder: &testpkg.Builder{
CertManagerObjects: []runtime.Object{baseIssuer.DeepCopy()},
ExpectedEvents: []string{
"Normal CertificateIssued Certificate fetched from venafi issuer successfully",
},
ExpectedActions: []testpkg.Action{
testpkg.NewAction(coretesting.NewCreateAction(
authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews"),
"",
&authzv1.SubjectAccessReview{
Spec: authzv1.SubjectAccessReviewSpec{
User: "user-1",
Groups: []string{"group-1", "group-2"},
Extra: map[string]authzv1.ExtraValue{
"extra": []string{"1", "2"},
},
UID: "uid-1",
ResourceAttributes: &authzv1.ResourceAttributes{
Group: certmanager.GroupName,
Resource: "signers",
Verb: "reference",
Namespace: baseIssuer.Namespace,
Name: baseIssuer.Name,
Version: "*",
},
},
},
)),
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
certificatesv1.SchemeGroupVersion.WithResource("certificatesigningrequests"),
"status",
"",
gen.CertificateSigningRequestFrom(baseCSR.DeepCopy(),
gen.AddCertificateSigningRequestAnnotations(map[string]string{
"venafi.experimental.cert-manager.io/custom-fields": `[ {"name": "field-name", "value": "vield value"}]`,
"venafi.experimental.cert-manager.io/pickup-id": "test-pickup-id",
}),
gen.SetCertificateSigningRequestStatusCondition(certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
}),
gen.SetCertificateSigningRequestCertificate(certBundle.ChainPEM),
),
)),
},
},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
if test.csr != nil {
test.builder.KubeObjects = append(test.builder.KubeObjects, test.csr)
}
fixedClock.SetTime(fixedClockStart)
test.builder.Clock = fixedClock
test.builder.T = t
test.builder.Init()
// Always return true for SubjectAccessReviews in tests
test.builder.FakeKubeClient().PrependReactor("create", "*", func(action coretesting.Action) (bool, runtime.Object, error) {
if action.GetResource() != authzv1.SchemeGroupVersion.WithResource("subjectaccessreviews") {
return false, nil, nil
}
return true, &authzv1.SubjectAccessReview{
Status: authzv1.SubjectAccessReviewStatus{
Allowed: true,
},
}, nil
})
defer test.builder.Stop()
venafi := NewVenafi(test.builder.Context)
venafi.clientBuilder = test.clientBuilder
controller := certificatesigningrequests.New(apiutil.IssuerVenafi, venafi)
controller.Register(test.builder.Context)
test.builder.Start()
err := controller.ProcessItem(context.Background(), test.csr.Name)
if err != nil && !test.expectedErr {
t.Errorf("expected to not get an error, but got: %v", err)
}
if err == nil && test.expectedErr {
t.Errorf("expected to get an error but did not get one")
}
test.builder.CheckAndFinish(err)
})
}
}
+2
View File
@@ -70,6 +70,8 @@ type connector interface {
RenewCertificate(req *certificate.RenewalRequest) (requestID string, err error)
}
// New constructs a Venafi client Interface. Errors may be network errors and
// should be considered for retrying.
func New(namespace string, secretsLister corelisters.SecretLister, issuer cmapi.GenericIssuer) (Interface, error) {
cfg, err := configForIssuer(issuer, secretsLister, namespace)
if err != nil {
+1
View File
@@ -28,6 +28,7 @@ filegroup(
"//test/e2e/framework/addon/base:all-srcs",
"//test/e2e/framework/addon/chart:all-srcs",
"//test/e2e/framework/addon/vault:all-srcs",
"//test/e2e/framework/addon/venafi:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
@@ -7,7 +7,7 @@ go_library(
"doc.go",
"tpp.go",
],
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/issuers/venafi/addon",
importpath = "github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi",
tags = ["manual"],
visibility = ["//visibility:public"],
deps = [
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package addon
package venafi
import (
"context"
@@ -14,6 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// Package addon implements an addon for the Venafi platform.
// Package venafi implements an addon for the Venafi platform.
// It provides a means for e2e tests to consume credentials for Venafi TPP.
package addon
package venafi
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package addon
package venafi
import (
"context"
@@ -49,7 +49,6 @@ func DefaultCertificateSigningRequestSet() []certificatesigningrequests.Validati
certificatesigningrequests.ExpectCertificateURIsToMatch,
certificatesigningrequests.ExpectCertificateIPsToMatch,
certificatesigningrequests.ExpectValidCommonName,
certificatesigningrequests.ExpectValidDuration,
certificatesigningrequests.ExpectKeyUsageUsageDigitalSignature,
certificatesigningrequests.ExpectEmailsToMatch,
certificatesigningrequests.ExpectIsCA,
@@ -92,5 +91,11 @@ func CertificateSetForUnsupportedFeatureSet(fs featureset.FeatureSet) []certific
}
func CertificateSigningRequestSetForUnsupportedFeatureSet(fs featureset.FeatureSet) []certificatesigningrequests.ValidationFunc {
return DefaultCertificateSigningRequestSet()
validations := DefaultCertificateSigningRequestSet()
if !fs.Contains(featureset.DurationFeature) {
validations = append(validations, certificatesigningrequests.ExpectValidDuration)
}
return validations
}
+1
View File
@@ -17,6 +17,7 @@ go_library(
"//test/e2e/suite/conformance/certificatesigningrequests/ca:go_default_library",
"//test/e2e/suite/conformance/certificatesigningrequests/selfsigned:go_default_library",
"//test/e2e/suite/conformance/certificatesigningrequests/vault:go_default_library",
"//test/e2e/suite/conformance/certificatesigningrequests/venafi:go_default_library",
"//test/e2e/suite/conformance/rbac:go_default_library",
],
)
@@ -9,10 +9,10 @@ go_library(
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon/venafi:go_default_library",
"//test/e2e/framework/helper/featureset: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",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
@@ -26,10 +26,10 @@ import (
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/test/e2e/framework"
vaddon "github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
"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() {
@@ -9,10 +9,10 @@ go_library(
"//pkg/apis/certmanager/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon/venafi:go_default_library",
"//test/e2e/framework/helper/featureset: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",
"@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library",
@@ -26,10 +26,10 @@ import (
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/test/e2e/framework"
vaddon "github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
"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("[Feature:Issuers:Venafi:Cloud] Certificates", func() {
@@ -40,6 +40,7 @@ filegroup(
"//test/e2e/suite/conformance/certificatesigningrequests/ca:all-srcs",
"//test/e2e/suite/conformance/certificatesigningrequests/selfsigned:all-srcs",
"//test/e2e/suite/conformance/certificatesigningrequests/vault:all-srcs",
"//test/e2e/suite/conformance/certificatesigningrequests/venafi:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
@@ -72,8 +72,11 @@ func (s *Suite) Define() {
})
type testCase struct {
keyAlgo x509.PublicKeyAlgorithm
csrModifiers []gen.CSRModifier
keyAlgo x509.PublicKeyAlgorithm
// 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
kubeCSRUsages []certificatesv1.KeyUsage
kubeCSRAnnotations map[string]string
// The list of features that are required by the Issuer for the test to
@@ -86,8 +89,10 @@ 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))},
keyAlgo: x509.RSA,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -96,8 +101,10 @@ 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))},
keyAlgo: x509.ECDSA,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -106,8 +113,10 @@ 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))},
keyAlgo: x509.Ed25519,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -116,8 +125,10 @@ func (s *Suite) Define() {
},
"should issue an RSA certificate for a single Common Name": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))},
keyAlgo: x509.RSA,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -126,8 +137,10 @@ func (s *Suite) Define() {
},
"should issue an ECDSA certificate for a single Common Name": {
keyAlgo: x509.ECDSA,
csrModifiers: []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))},
keyAlgo: x509.ECDSA,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -136,8 +149,10 @@ func (s *Suite) Define() {
},
"should issue an Ed25519 certificate for a single Common Name": {
keyAlgo: x509.Ed25519,
csrModifiers: []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))},
keyAlgo: x509.Ed25519,
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10))}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
certificatesv1.UsageKeyEncipherment,
@@ -147,9 +162,11 @@ func (s *Suite) Define() {
"should issue a certificate that defines a Common Name and IP Address": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10)),
gen.SetCSRIPAddresses(net.IPv4(127, 0, 0, 1), net.IPv4(8, 8, 8, 8)),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10)),
gen.SetCSRIPAddresses(net.IPv4(127, 0, 0, 1), net.IPv4(8, 8, 8, 8)),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -160,8 +177,10 @@ func (s *Suite) Define() {
"should issue a certificate that defines an Email Address": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSREmails([]string{"alice@example.com", "bob@cert-manager.io"}),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSREmails([]string{"alice@example.com", "bob@cert-manager.io"}),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -172,9 +191,11 @@ func (s *Suite) Define() {
"should issue a certificate that defines a Common Name and URI SAN": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10)),
gen.SetCSRURIs(sharedURI),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName("test-common-name-" + util.RandStringRunes(10)),
gen.SetCSRURIs(sharedURI),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -185,9 +206,11 @@ func (s *Suite) Define() {
"should issue a certificate that defines a 2 distinct DNS Name with one copied to the Common Name": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRCommonName(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName, e2eutil.RandomSubdomain(s.DomainSuffix)),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName, e2eutil.RandomSubdomain(s.DomainSuffix)),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -198,9 +221,11 @@ 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)),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName(e2eutil.RandomSubdomain(s.DomainSuffix)),
gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -211,9 +236,11 @@ func (s *Suite) Define() {
"should issue a certificate that defines a Common Name, DNS Name, and sets a duration": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRDNSNames(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRDNSNames(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -227,8 +254,10 @@ 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)),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRDNSNames(e2eutil.RandomSubdomain(s.DomainSuffix)),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -242,8 +271,10 @@ 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)),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRDNSNames("*." + e2eutil.RandomSubdomain(s.DomainSuffix)),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -254,8 +285,10 @@ func (s *Suite) Define() {
"should issue a certificate that includes only a URISANs name": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRURIs(sharedURI),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRURIs(sharedURI),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -266,9 +299,11 @@ func (s *Suite) Define() {
"should issue a certificate that includes arbitrary key usages": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRCommonName(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName(sharedCommonName),
gen.SetCSRDNSNames(sharedCommonName),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageServerAuth,
@@ -287,8 +322,10 @@ func (s *Suite) Define() {
"should issue a signing CA certificate that has a large duration": {
keyAlgo: x509.RSA,
csrModifiers: []gen.CSRModifier{
gen.SetCSRCommonName("cert-manager-ca"),
csrModifiers: func() []gen.CSRModifier {
return []gen.CSRModifier{
gen.SetCSRCommonName("cert-manager-ca"),
}
},
kubeCSRUsages: []certificatesv1.KeyUsage{
certificatesv1.UsageDigitalSignature,
@@ -306,7 +343,7 @@ func (s *Suite) Define() {
defineTest := func(name string, test testCase) {
s.it(f, name, func(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
@@ -0,0 +1,37 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"cloud.go",
"tpp.go",
],
importpath = "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests/venafi",
visibility = ["//visibility:public"],
deps = [
"//pkg/controller/certificatesigningrequests/util:go_default_library",
"//pkg/util:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/framework/addon/venafi:go_default_library",
"//test/e2e/framework/helper/featureset:go_default_library",
"//test/e2e/framework/util/errors:go_default_library",
"//test/e2e/suite/conformance/certificatesigningrequests: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"],
)
@@ -0,0 +1,133 @@
/*
Copyright 2021 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.
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 (
"context"
"fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/util"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
"github.com/jetstack/cert-manager/test/e2e/framework/util/errors"
"github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests"
)
var _ = framework.ConformanceDescribe("CertificateSigningRequests", func() {
// unsupportedFeatures is a list of features that are not supported by the
// Venafi TPP issuer.
var unsupportedFeatures = featureset.NewFeatureSet(
// Venafi TPP doesn't allow setting a duration
featureset.DurationFeature,
// Due to the current configuration of the test environment, it does not
// support signing certificates that pair with an elliptic curve or
// Ed255119 private keys
featureset.ECDSAFeature,
featureset.Ed25519FeatureSet,
// Our Venafi TPP doesn't allow setting non DNS SANs
// TODO: investigate options to enable these
featureset.EmailSANsFeature,
featureset.URISANsFeature,
featureset.IPAddressFeature,
// Venafi doesn't allow certs with empty CN & DN
featureset.OnlySAN,
// Venafi doesn't setting key usages.
featureset.KeyUsagesFeature,
)
venafiIssuer := new(cloud)
(&certificatesigningrequests.Suite{
Name: "Venafi Cloud Issuer",
CreateIssuerFunc: venafiIssuer.createIssuer,
DeleteIssuerFunc: venafiIssuer.delete,
UnsupportedFeatures: unsupportedFeatures,
}).Define()
venafiClusterIssuer := new(cloud)
(&certificatesigningrequests.Suite{
Name: "Venafi Cloud Cluster Issuer",
CreateIssuerFunc: venafiClusterIssuer.createClusterIssuer,
DeleteIssuerFunc: venafiClusterIssuer.delete,
UnsupportedFeatures: unsupportedFeatures,
}).Define()
})
type cloud struct {
*venafi.VenafiCloud
}
func (c *cloud) delete(f *framework.Framework, signerName string) {
Expect(c.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision cloud venafi")
ref, _ := util.SignerIssuerRefFromSignerName(signerName)
if ref.Type == "clusterissuers" {
err := f.CertManagerClientSet.CertmanagerV1().ClusterIssuers().Delete(context.TODO(), ref.Name, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())
}
}
func (c *cloud) createIssuer(f *framework.Framework) string {
By("Creating a Venafi Cloud Issuer")
c.VenafiCloud = &venafi.VenafiCloud{
Namespace: f.Namespace.Name,
}
err := c.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 provision venafi cloud issuer")
Expect(c.Provision()).NotTo(HaveOccurred(), "failed to provision tpp venafi")
issuer := c.Details().BuildIssuer()
issuer, err = f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred(), "failed to create issuer for venafi")
return fmt.Sprintf("issuers.cert-manager.io/%s.%s", issuer.Namespace, issuer.Name)
}
// createClusterIssuer creates and returns name of a Venafi Cloud
// ClusterIssuer. The name is of the form
// "clusterissuers.cert-manager.io/issuer-ab3de1".
func (c *cloud) createClusterIssuer(f *framework.Framework) string {
By("Creating a Venafi Cloud ClusterIssuer")
c.VenafiCloud = &venafi.VenafiCloud{
Namespace: f.Config.Addons.CertManager.ClusterResourceNamespace,
}
err := c.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(c.Provision()).NotTo(HaveOccurred(), "failed to provision tpp venafi")
issuer := c.Details().BuildClusterIssuer()
issuer, err = f.CertManagerClientSet.CertmanagerV1().ClusterIssuers().Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred(), "failed to create issuer for venafi")
return fmt.Sprintf("clusterissuers.cert-manager.io/%s", issuer.Name)
}
@@ -0,0 +1,133 @@
/*
Copyright 2021 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.
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 (
"context"
"fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/jetstack/cert-manager/pkg/controller/certificatesigningrequests/util"
cmutil "github.com/jetstack/cert-manager/pkg/util"
"github.com/jetstack/cert-manager/test/e2e/framework"
"github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/framework/helper/featureset"
"github.com/jetstack/cert-manager/test/e2e/framework/util/errors"
"github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests"
)
var _ = framework.ConformanceDescribe("CertificateSigningRequests", func() {
// unsupportedFeatures is a list of features that are not supported by the
// Venafi TPP issuer.
var unsupportedFeatures = featureset.NewFeatureSet(
// Venafi TPP doesn't allow setting a duration
featureset.DurationFeature,
// Due to the current configuration of the test environment, it does not
// support signing certificates that pair with an elliptic curve or
// Ed255119 private keys
featureset.ECDSAFeature,
featureset.Ed25519FeatureSet,
// Our Venafi TPP doesn't allow setting non DNS SANs
// TODO: investigate options to enable these
featureset.EmailSANsFeature,
featureset.URISANsFeature,
featureset.IPAddressFeature,
// Venafi doesn't allow certs with empty CN & DN
featureset.OnlySAN,
// Venafi doesn't setting key usages.
featureset.KeyUsagesFeature,
)
venafiIssuer := new(tpp)
(&certificatesigningrequests.Suite{
Name: "Venafi TPP Issuer",
CreateIssuerFunc: venafiIssuer.createIssuer,
DeleteIssuerFunc: venafiIssuer.delete,
UnsupportedFeatures: unsupportedFeatures,
DomainSuffix: fmt.Sprintf("%s-venafi-e2e", cmutil.RandStringRunes(5)),
}).Define()
venafiClusterIssuer := new(tpp)
(&certificatesigningrequests.Suite{
Name: "Venafi TPP Cluster Issuer",
CreateIssuerFunc: venafiClusterIssuer.createClusterIssuer,
DeleteIssuerFunc: venafiClusterIssuer.delete,
UnsupportedFeatures: unsupportedFeatures,
DomainSuffix: fmt.Sprintf("%s-venafi-e2e", cmutil.RandStringRunes(5)),
}).Define()
})
type tpp struct {
*venafi.VenafiTPP
}
func (t *tpp) delete(f *framework.Framework, signerName string) {
Expect(t.Deprovision()).NotTo(HaveOccurred(), "failed to deprovision tpp venafi")
ref, _ := util.SignerIssuerRefFromSignerName(signerName)
if ref.Type == "clusterissuers" {
err := f.CertManagerClientSet.CertmanagerV1().ClusterIssuers().Delete(context.TODO(), ref.Name, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())
}
}
func (t *tpp) createIssuer(f *framework.Framework) string {
By("Creating a Venafi Issuer")
t.VenafiTPP = &venafi.VenafiTPP{
Namespace: f.Namespace.Name,
}
err := t.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(t.Provision()).NotTo(HaveOccurred(), "failed to provision tpp venafi")
issuer := t.Details().BuildIssuer()
issuer, err = f.CertManagerClientSet.CertmanagerV1().Issuers(f.Namespace.Name).Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred(), "failed to create issuer for venafi")
return fmt.Sprintf("issuers.cert-manager.io/%s.%s", issuer.Namespace, issuer.Name)
}
func (t *tpp) createClusterIssuer(f *framework.Framework) string {
By("Creating a Venafi ClusterIssuer")
t.VenafiTPP = &venafi.VenafiTPP{
Namespace: f.Config.Addons.CertManager.ClusterResourceNamespace,
}
err := t.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(t.Provision()).NotTo(HaveOccurred(), "failed to provision tpp venafi")
issuer := t.Details().BuildClusterIssuer()
issuer, err = f.CertManagerClientSet.CertmanagerV1().ClusterIssuers().Create(context.TODO(), issuer, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred(), "failed to create issuer for venafi")
return fmt.Sprintf("clusterissuers.cert-manager.io/%s", issuer.Name)
}
+1
View File
@@ -27,5 +27,6 @@ import (
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests/ca"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests/selfsigned"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests/vault"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/certificatesigningrequests/venafi"
_ "github.com/jetstack/cert-manager/test/e2e/suite/conformance/rbac"
)
@@ -19,7 +19,6 @@ filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//test/e2e/suite/issuers/venafi/addon:all-srcs",
"//test/e2e/suite/issuers/venafi/tpp:all-srcs",
],
tags = ["automanaged"],
@@ -15,7 +15,7 @@ go_library(
"//pkg/apis/meta/v1:go_default_library",
"//pkg/util:go_default_library",
"//test/e2e/framework:go_default_library",
"//test/e2e/suite/issuers/venafi/addon:go_default_library",
"//test/e2e/framework/addon/venafi:go_default_library",
"//test/e2e/util:go_default_library",
"@com_github_onsi_ginkgo//:go_default_library",
"@com_github_onsi_gomega//:go_default_library",
@@ -28,7 +28,7 @@ import (
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"
vaddon "github.com/jetstack/cert-manager/test/e2e/suite/issuers/venafi/addon"
vaddon "github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/util"
)
@@ -29,7 +29,7 @@ import (
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"
vaddon "github.com/jetstack/cert-manager/test/e2e/suite/issuers/venafi/addon"
vaddon "github.com/jetstack/cert-manager/test/e2e/framework/addon/venafi"
"github.com/jetstack/cert-manager/test/e2e/util"
)