Merge pull request #2573 from meyskens/venafi-custom-fields
Add venafi.cert-manager.io/custom-fields annnotation
This commit is contained in:
commit
672f7654a7
4
go.mod
4
go.mod
@ -12,7 +12,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/adal v0.5.0
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0
|
||||
github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect
|
||||
github.com/Venafi/vcert v0.0.0-20190613103158-62139eb19b25
|
||||
github.com/Venafi/vcert v0.0.0-20200207035730-5a915d73be5d
|
||||
github.com/aws/aws-sdk-go v1.24.1
|
||||
github.com/cloudflare/cloudflare-go v0.8.5
|
||||
github.com/cpu/goacmedns v0.0.0-20180701200144-565ecf2a84df
|
||||
@ -39,7 +39,7 @@ require (
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
google.golang.org/api v0.4.0
|
||||
gopkg.in/ini.v1 v1.42.0 // indirect
|
||||
gopkg.in/ini.v1 v1.52.0 // indirect
|
||||
k8s.io/api v0.17.0
|
||||
k8s.io/apiextensions-apiserver v0.17.0
|
||||
k8s.io/apimachinery v0.17.0
|
||||
|
||||
8
go.sum
8
go.sum
@ -36,8 +36,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Venafi/vcert v0.0.0-20190613103158-62139eb19b25 h1:Vy4WHFF6SULSubt7vuyJRJ5AqwjJXzJQWdF37VcsyGo=
|
||||
github.com/Venafi/vcert v0.0.0-20190613103158-62139eb19b25/go.mod h1:3sXw16DKVded/kLVDma2veqEUQC7O37h98ims7cIvN4=
|
||||
github.com/Venafi/vcert v0.0.0-20200207035730-5a915d73be5d h1:oFQa1HzZX7Kcnjnosx9wEdVi8ADTDvs+2Tz96HIXrEU=
|
||||
github.com/Venafi/vcert v0.0.0-20200207035730-5a915d73be5d/go.mod h1:5T4bFPhcgGXbdz8nVVRuE2gXSRDlZVL+9T5CwZZ3Yk4=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
@ -645,8 +645,8 @@ gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
|
||||
gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
|
||||
@ -1647,8 +1647,8 @@ def go_repositories():
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable",
|
||||
importpath = "github.com/Venafi/vcert",
|
||||
sum = "h1:Vy4WHFF6SULSubt7vuyJRJ5AqwjJXzJQWdF37VcsyGo=",
|
||||
version = "v0.0.0-20190613103158-62139eb19b25",
|
||||
sum = "h1:oFQa1HzZX7Kcnjnosx9wEdVi8ADTDvs+2Tz96HIXrEU=",
|
||||
version = "v0.0.0-20200207035730-5a915d73be5d",
|
||||
)
|
||||
go_repository(
|
||||
name = "com_github_xiang90_probing",
|
||||
@ -1719,8 +1719,8 @@ def go_repositories():
|
||||
build_file_generation = "on",
|
||||
build_file_proto_mode = "disable",
|
||||
importpath = "gopkg.in/ini.v1",
|
||||
sum = "h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=",
|
||||
version = "v1.42.0",
|
||||
sum = "h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=",
|
||||
version = "v1.52.0",
|
||||
)
|
||||
go_repository(
|
||||
name = "in_gopkg_mgo_v2",
|
||||
|
||||
@ -98,6 +98,15 @@ const (
|
||||
AllowsInjectionFromSecretAnnotation = "cert-manager.io/allow-direct-injection"
|
||||
)
|
||||
|
||||
// Issuer specific Annotations
|
||||
const (
|
||||
// VenafiCustomFieldsAnnotationKey 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 objetcs containing the name and value keys
|
||||
// for example: `[{"name": "custom-field", "value": "custom-value"}]`
|
||||
VenafiCustomFieldsAnnotationKey = "venafi.cert-manager.io/custom-fields"
|
||||
)
|
||||
|
||||
// KeyUsage specifies valid usage contexts for keys.
|
||||
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||
|
||||
@ -98,6 +98,15 @@ const (
|
||||
AllowsInjectionFromSecretAnnotation = "cert-manager.io/allow-direct-injection"
|
||||
)
|
||||
|
||||
// Issuer specific Annotations
|
||||
const (
|
||||
// VenafiCustomFieldsAnnotationKey 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 objetcs containing the name and value keys
|
||||
// for example: `[{"name": "custom-field", "value": "custom-value"}]`
|
||||
VenafiCustomFieldsAnnotationKey = "venafi.cert-manager.io/custom-fields"
|
||||
)
|
||||
|
||||
// KeyUsage specifies valid usage contexts for keys.
|
||||
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
|
||||
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
|
||||
|
||||
@ -12,6 +12,7 @@ go_library(
|
||||
"//pkg/controller/certificaterequests:go_default_library",
|
||||
"//pkg/controller/certificaterequests/util:go_default_library",
|
||||
"//pkg/internal/venafi:go_default_library",
|
||||
"//pkg/internal/venafi/api:go_default_library",
|
||||
"//pkg/issuer:go_default_library",
|
||||
"//pkg/logs:go_default_library",
|
||||
"@com_github_venafi_vcert//pkg/endpoint:go_default_library",
|
||||
@ -46,6 +47,7 @@ go_test(
|
||||
"//pkg/controller/certificaterequests:go_default_library",
|
||||
"//pkg/controller/test:go_default_library",
|
||||
"//pkg/internal/venafi:go_default_library",
|
||||
"//pkg/internal/venafi/api:go_default_library",
|
||||
"//pkg/internal/venafi/fake:go_default_library",
|
||||
"//pkg/util/pki:go_default_library",
|
||||
"//test/unit/gen:go_default_library",
|
||||
|
||||
@ -18,6 +18,8 @@ package venafi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@ -29,6 +31,7 @@ import (
|
||||
"github.com/jetstack/cert-manager/pkg/controller/certificaterequests"
|
||||
crutil "github.com/jetstack/cert-manager/pkg/controller/certificaterequests/util"
|
||||
venafiinternal "github.com/jetstack/cert-manager/pkg/internal/venafi"
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
issuerpkg "github.com/jetstack/cert-manager/pkg/issuer"
|
||||
logf "github.com/jetstack/cert-manager/pkg/logs"
|
||||
)
|
||||
@ -88,12 +91,31 @@ func (v *Venafi) Sign(ctx context.Context, cr *cmapi.CertificateRequest, issuerO
|
||||
|
||||
duration := apiutil.DefaultCertDuration(cr.Spec.Duration)
|
||||
|
||||
certPem, err := client.Sign(cr.Spec.CSRPEM, duration)
|
||||
var customFields []internalvanafiapi.CustomField
|
||||
if annotation, exists := cr.GetAnnotations()[cmapi.VenafiCustomFieldsAnnotationKey]; exists && annotation != "" {
|
||||
err := json.Unmarshal([]byte(annotation), &customFields)
|
||||
if err != nil {
|
||||
message := fmt.Sprintf("Failed to parse %q annotation", cmapi.VenafiCustomFieldsAnnotationKey)
|
||||
|
||||
v.reporter.Failed(cr, err, "CustomFieldsError", message)
|
||||
log.Error(err, message)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
certPem, err := client.Sign(cr.Spec.CSRPEM, duration, customFields)
|
||||
|
||||
// Check some known error types
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
|
||||
case venafiinternal.ErrCustomFieldsType:
|
||||
v.reporter.Failed(cr, err, "CustomFieldsError", err.Error())
|
||||
log.Error(err, err.Error())
|
||||
|
||||
return nil, nil
|
||||
|
||||
case endpoint.ErrCertificatePending:
|
||||
message := "Venafi certificate still in a pending state, the request will be retried"
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ import (
|
||||
controllertest "github.com/jetstack/cert-manager/pkg/controller/test"
|
||||
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
|
||||
internalvenafi "github.com/jetstack/cert-manager/pkg/internal/venafi"
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
internalvenafifake "github.com/jetstack/cert-manager/pkg/internal/venafi/fake"
|
||||
"github.com/jetstack/cert-manager/pkg/util/pki"
|
||||
"github.com/jetstack/cert-manager/test/unit/gen"
|
||||
@ -146,6 +147,12 @@ func TestSign(t *testing.T) {
|
||||
}),
|
||||
)
|
||||
|
||||
tppCRWithCustomFields := gen.CertificateRequestFrom(tppCR, gen.SetCertificateRequestAnnotations(map[string]string{"venafi.cert-manager.io/custom-fields": `[{"name": "cert-manager-test", "value": "test ok"}]`}))
|
||||
|
||||
tppCRWithInvalidCustomFields := gen.CertificateRequestFrom(tppCR, gen.SetCertificateRequestAnnotations(map[string]string{"venafi.cert-manager.io/custom-fields": `[{"name": cert-manager-test}]`}))
|
||||
|
||||
tppCRWithInvalidCustomFieldType := gen.CertificateRequestFrom(tppCR, gen.SetCertificateRequestAnnotations(map[string]string{"venafi.cert-manager.io/custom-fields": `[{"name": "cert-manager-test", "value": "test ok", "type": "Bool"}]`}))
|
||||
|
||||
cloudCR := gen.CertificateRequestFrom(baseCR,
|
||||
gen.SetCertificateRequestIssuer(cmmeta.ObjectReference{
|
||||
Group: certmanager.GroupName,
|
||||
@ -177,7 +184,7 @@ func TestSign(t *testing.T) {
|
||||
}
|
||||
|
||||
clientReturnsPending := &internalvenafifake.Venafi{
|
||||
SignFn: func([]byte, time.Duration) ([]byte, error) {
|
||||
SignFn: func([]byte, time.Duration, []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return nil, endpoint.ErrCertificatePending{
|
||||
CertificateID: "test-cert-id",
|
||||
Status: "test-status-pending",
|
||||
@ -185,23 +192,38 @@ func TestSign(t *testing.T) {
|
||||
},
|
||||
}
|
||||
clientReturnsTimeout := &internalvenafifake.Venafi{
|
||||
SignFn: func([]byte, time.Duration) ([]byte, error) {
|
||||
SignFn: func([]byte, time.Duration, []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return nil, endpoint.ErrRetrieveCertificateTimeout{
|
||||
CertificateID: "test-cert-id",
|
||||
}
|
||||
},
|
||||
}
|
||||
clientReturnsGenericError := &internalvenafifake.Venafi{
|
||||
SignFn: func([]byte, time.Duration) ([]byte, error) {
|
||||
SignFn: func([]byte, time.Duration, []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return nil, errors.New("this is an error")
|
||||
},
|
||||
}
|
||||
clientReturnsCert := &internalvenafifake.Venafi{
|
||||
SignFn: func([]byte, time.Duration) ([]byte, error) {
|
||||
SignFn: func([]byte, time.Duration, []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return certPEM, nil
|
||||
},
|
||||
}
|
||||
|
||||
clientReturnsCertIfCustomField := &internalvenafifake.Venafi{
|
||||
SignFn: func(csr []byte, t time.Duration, fields []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
if len(fields) > 0 && fields[0].Name == "cert-manager-test" && fields[0].Value == "test ok" {
|
||||
return certPEM, nil
|
||||
}
|
||||
return nil, errors.New("Custom field not set")
|
||||
},
|
||||
}
|
||||
|
||||
clientReturnsInvalidCustomFieldType := &internalvenafifake.Venafi{
|
||||
SignFn: func(csr []byte, t time.Duration, fields []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return nil, internalvenafi.ErrCustomFieldsType{Type: fields[0].Type}
|
||||
},
|
||||
}
|
||||
|
||||
metaFixedClockStart := metav1.NewTime(fixedClockStart)
|
||||
tests := map[string]testT{
|
||||
"tpp: if fail to build client based on missing secret then return nil and hard fail": {
|
||||
@ -573,6 +595,96 @@ func TestSign(t *testing.T) {
|
||||
fakeSecretLister: failGetSecretLister,
|
||||
fakeClient: clientReturnsCert,
|
||||
},
|
||||
"annotations: Custom Fields": {
|
||||
certificateRequest: tppCRWithCustomFields.DeepCopy(),
|
||||
issuer: tppIssuer,
|
||||
builder: &controllertest.Builder{
|
||||
CertManagerObjects: []runtime.Object{tppCRWithCustomFields.DeepCopy(), tppIssuer.DeepCopy()},
|
||||
ExpectedEvents: []string{
|
||||
`Normal CertificateIssued Certificate fetched from issuer successfully`,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
|
||||
cmapi.SchemeGroupVersion.WithResource("certificaterequests"),
|
||||
"status",
|
||||
gen.DefaultTestNamespace,
|
||||
gen.CertificateRequestFrom(tppCRWithCustomFields,
|
||||
gen.SetCertificateRequestStatusCondition(cmapi.CertificateRequestCondition{
|
||||
Type: cmapi.CertificateRequestConditionReady,
|
||||
Status: cmmeta.ConditionTrue,
|
||||
Reason: cmapi.CertificateRequestReasonIssued,
|
||||
Message: "Certificate fetched from issuer successfully",
|
||||
LastTransitionTime: &metaFixedClockStart,
|
||||
}),
|
||||
gen.SetCertificateRequestCertificate(certPEM),
|
||||
),
|
||||
)),
|
||||
},
|
||||
},
|
||||
fakeSecretLister: failGetSecretLister,
|
||||
fakeClient: clientReturnsCertIfCustomField,
|
||||
expectedErr: false,
|
||||
},
|
||||
"annotations: Error on invalid JSON in custom fields": {
|
||||
certificateRequest: tppCRWithInvalidCustomFields.DeepCopy(),
|
||||
issuer: tppIssuer,
|
||||
builder: &controllertest.Builder{
|
||||
CertManagerObjects: []runtime.Object{tppCRWithInvalidCustomFields.DeepCopy(), tppIssuer.DeepCopy()},
|
||||
ExpectedEvents: []string{
|
||||
`Warning CustomFieldsError Failed to parse "venafi.cert-manager.io/custom-fields" annotation: invalid character 'c' looking for beginning of value`,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
|
||||
cmapi.SchemeGroupVersion.WithResource("certificaterequests"),
|
||||
"status",
|
||||
gen.DefaultTestNamespace,
|
||||
gen.CertificateRequestFrom(tppCRWithInvalidCustomFields,
|
||||
gen.SetCertificateRequestStatusCondition(cmapi.CertificateRequestCondition{
|
||||
Type: cmapi.CertificateRequestConditionReady,
|
||||
Status: cmmeta.ConditionFalse,
|
||||
Reason: cmapi.CertificateRequestReasonFailed,
|
||||
Message: "Failed to parse \"venafi.cert-manager.io/custom-fields\" annotation: invalid character 'c' looking for beginning of value",
|
||||
LastTransitionTime: &metaFixedClockStart,
|
||||
}),
|
||||
gen.SetCertificateRequestFailureTime(metaFixedClockStart),
|
||||
),
|
||||
)),
|
||||
},
|
||||
},
|
||||
fakeSecretLister: failGetSecretLister,
|
||||
fakeClient: clientReturnsPending,
|
||||
expectedErr: false,
|
||||
},
|
||||
"annotations: Error on invalid type in custom fields": {
|
||||
certificateRequest: tppCRWithInvalidCustomFieldType.DeepCopy(),
|
||||
issuer: tppIssuer,
|
||||
builder: &controllertest.Builder{
|
||||
CertManagerObjects: []runtime.Object{tppCRWithInvalidCustomFieldType.DeepCopy(), tppIssuer.DeepCopy()},
|
||||
ExpectedEvents: []string{
|
||||
`Warning CustomFieldsError certificate request contains an invalid Venafi custom fields type: "Bool": certificate request contains an invalid Venafi custom fields type: "Bool"`,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateSubresourceAction(
|
||||
cmapi.SchemeGroupVersion.WithResource("certificaterequests"),
|
||||
"status",
|
||||
gen.DefaultTestNamespace,
|
||||
gen.CertificateRequestFrom(tppCRWithInvalidCustomFieldType,
|
||||
gen.SetCertificateRequestStatusCondition(cmapi.CertificateRequestCondition{
|
||||
Type: cmapi.CertificateRequestConditionReady,
|
||||
Status: cmmeta.ConditionFalse,
|
||||
Reason: cmapi.CertificateRequestReasonFailed,
|
||||
Message: "certificate request contains an invalid Venafi custom fields type: \"Bool\": certificate request contains an invalid Venafi custom fields type: \"Bool\"",
|
||||
LastTransitionTime: &metaFixedClockStart,
|
||||
}),
|
||||
gen.SetCertificateRequestFailureTime(metaFixedClockStart),
|
||||
),
|
||||
)),
|
||||
},
|
||||
},
|
||||
fakeSecretLister: failGetSecretLister,
|
||||
fakeClient: clientReturnsInvalidCustomFieldType,
|
||||
expectedErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
|
||||
@ -10,6 +10,7 @@ go_library(
|
||||
visibility = ["//pkg:__subpackages__"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1alpha2:go_default_library",
|
||||
"//pkg/internal/venafi/api:go_default_library",
|
||||
"//pkg/util/pki:go_default_library",
|
||||
"@com_github_venafi_vcert//:go_default_library",
|
||||
"@com_github_venafi_vcert//pkg/certificate:go_default_library",
|
||||
@ -29,6 +30,7 @@ filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//pkg/internal/venafi/api:all-srcs",
|
||||
"//pkg/internal/venafi/fake:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
@ -45,6 +47,7 @@ go_test(
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1alpha2:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/internal/venafi/api:go_default_library",
|
||||
"//pkg/internal/venafi/fake:go_default_library",
|
||||
"//pkg/util:go_default_library",
|
||||
"//pkg/util/pki:go_default_library",
|
||||
|
||||
22
pkg/internal/venafi/api/BUILD.bazel
Normal file
22
pkg/internal/venafi/api/BUILD.bazel
Normal file
@ -0,0 +1,22 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["api.go"],
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/internal/venafi/api",
|
||||
visibility = ["//pkg:__subpackages__"],
|
||||
)
|
||||
30
pkg/internal/venafi/api/api.go
Normal file
30
pkg/internal/venafi/api/api.go
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2020 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 api
|
||||
|
||||
type CustomFieldType string
|
||||
|
||||
const (
|
||||
CustomFieldTypePlain CustomFieldType = "Plain"
|
||||
)
|
||||
|
||||
// CustomField defines a custom field to be passed to Venafi
|
||||
type CustomField struct {
|
||||
Type CustomFieldType `json:"type,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
@ -9,6 +9,7 @@ go_library(
|
||||
importpath = "github.com/jetstack/cert-manager/pkg/internal/venafi/fake",
|
||||
visibility = ["//pkg:__subpackages__"],
|
||||
deps = [
|
||||
"//pkg/internal/venafi/api:go_default_library",
|
||||
"@com_github_venafi_vcert//pkg/certificate:go_default_library",
|
||||
"@com_github_venafi_vcert//pkg/endpoint:go_default_library",
|
||||
"@com_github_venafi_vcert//pkg/venafi/fake:go_default_library",
|
||||
|
||||
@ -20,11 +20,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
)
|
||||
|
||||
type Venafi struct {
|
||||
PingFn func() error
|
||||
SignFn func([]byte, time.Duration) ([]byte, error)
|
||||
SignFn func([]byte, time.Duration, []internalvanafiapi.CustomField) ([]byte, error)
|
||||
ReadZoneConfigurationFn func() (*endpoint.ZoneConfiguration, error)
|
||||
}
|
||||
|
||||
@ -32,8 +34,8 @@ func (v *Venafi) Ping() error {
|
||||
return v.PingFn()
|
||||
}
|
||||
|
||||
func (v *Venafi) Sign(b []byte, t time.Duration) ([]byte, error) {
|
||||
return v.SignFn(b, t)
|
||||
func (v *Venafi) Sign(b []byte, t time.Duration, f []internalvanafiapi.CustomField) ([]byte, error) {
|
||||
return v.SignFn(b, t, f)
|
||||
}
|
||||
|
||||
func (v *Venafi) ReadZoneConfiguration() (*endpoint.ZoneConfiguration, error) {
|
||||
|
||||
@ -19,18 +19,29 @@ package venafi
|
||||
import (
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Venafi/vcert/pkg/certificate"
|
||||
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
"github.com/jetstack/cert-manager/pkg/util/pki"
|
||||
)
|
||||
|
||||
// ErrCustomFieldsType provides a common error structure for a fivalid custom field types
|
||||
type ErrCustomFieldsType struct {
|
||||
Type internalvanafiapi.CustomFieldType
|
||||
}
|
||||
|
||||
func (err ErrCustomFieldsType) Error() string {
|
||||
return fmt.Sprintf("certificate request contains an invalid Venafi custom fields type: %q", err.Type)
|
||||
}
|
||||
|
||||
// This function sends a request to Venafi to for a signed certificate.
|
||||
// The CSR will be decoded to be validated against the zone configuration policy.
|
||||
// Upon the template being successfully defaulted and validated, the CSR will be sent, as is.
|
||||
func (v *Venafi) Sign(csrPEM []byte, duration time.Duration) (cert []byte, err error) {
|
||||
func (v *Venafi) Sign(csrPEM []byte, duration time.Duration, customFields []internalvanafiapi.CustomField) (cert []byte, err error) {
|
||||
// Retrieve a copy of the Venafi zone.
|
||||
// This contains default values and policy control info that we can apply
|
||||
// and check against locally.
|
||||
@ -47,6 +58,30 @@ func (v *Venafi) Sign(csrPEM []byte, duration time.Duration) (cert []byte, err e
|
||||
// Create a vcert Request structure
|
||||
vreq := newVRequest(tmpl)
|
||||
|
||||
// Convert over custom fields from our struct type to venafi's
|
||||
if len(customFields) > 0 {
|
||||
vreq.CustomFields = []certificate.CustomField{}
|
||||
for _, field := range customFields {
|
||||
var fieldType certificate.CustomFieldType
|
||||
switch field.Type {
|
||||
case internalvanafiapi.CustomFieldTypePlain:
|
||||
fieldType = certificate.CustomFieldPlain
|
||||
break
|
||||
case "":
|
||||
fieldType = certificate.CustomFieldPlain
|
||||
break
|
||||
default:
|
||||
return nil, ErrCustomFieldsType{Type: field.Type}
|
||||
}
|
||||
|
||||
vreq.CustomFields = append(vreq.CustomFields, certificate.CustomField{
|
||||
Type: fieldType,
|
||||
Name: field.Name,
|
||||
Value: field.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Apply default values from the Venafi zone
|
||||
zoneCfg.UpdateCertificateRequest(vreq)
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import (
|
||||
"github.com/Venafi/vcert/pkg/endpoint"
|
||||
"github.com/Venafi/vcert/pkg/venafi/fake"
|
||||
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
internalfake "github.com/jetstack/cert-manager/pkg/internal/venafi/fake"
|
||||
"github.com/jetstack/cert-manager/pkg/util"
|
||||
"github.com/jetstack/cert-manager/pkg/util/pki"
|
||||
@ -173,6 +174,29 @@ func TestSign(t *testing.T) {
|
||||
checkFn: checkCertificateIssued,
|
||||
expectedErr: false,
|
||||
},
|
||||
"obtain a certificate with custom fields specified": {
|
||||
csrPEM: csrPEM,
|
||||
customFields: []internalvanafiapi.CustomField{{Name: "test", Value: "ok"}},
|
||||
client: internalfake.Connector{
|
||||
RetrieveCertificateFunc: func(r *certificate.Request) (*certificate.PEMCollection, error) {
|
||||
if len(r.CustomFields) == 0 {
|
||||
return nil, errors.New("custom fields not set")
|
||||
}
|
||||
if r.CustomFields[0].Name != "test" || r.CustomFields[0].Value != "ok" {
|
||||
return nil, errors.New("custom fields content not correct")
|
||||
}
|
||||
return internalfake.Connector{}.Default().RetrieveCertificate(r) // hack to return to normal
|
||||
},
|
||||
}.Default(),
|
||||
checkFn: checkCertificateIssued,
|
||||
expectedErr: false,
|
||||
},
|
||||
"If invalid custom field type found the error": {
|
||||
csrPEM: csrPEM,
|
||||
customFields: []internalvanafiapi.CustomField{{Name: "test", Value: "ok", Type: "Bool"}},
|
||||
checkFn: checkNoCetificateIssued,
|
||||
expectedErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
@ -188,6 +212,8 @@ type testSignT struct {
|
||||
|
||||
expectedErr bool
|
||||
|
||||
customFields []internalvanafiapi.CustomField
|
||||
|
||||
checkFn func(*testing.T, []byte, []byte)
|
||||
}
|
||||
|
||||
@ -201,7 +227,7 @@ func (s *testSignT) runTest(t *testing.T) {
|
||||
client: client,
|
||||
}
|
||||
|
||||
resp, err := v.Sign(s.csrPEM, time.Minute)
|
||||
resp, err := v.Sign(s.csrPEM, time.Minute, s.customFields)
|
||||
if err != nil && !s.expectedErr {
|
||||
t.Errorf("expected to not get an error, but got: %v", err)
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ import (
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2"
|
||||
internalvanafiapi "github.com/jetstack/cert-manager/pkg/internal/venafi/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -39,7 +40,7 @@ type VenafiClientBuilder func(namespace string, secretsLister corelisters.Secret
|
||||
issuer cmapi.GenericIssuer) (Interface, error)
|
||||
|
||||
type Interface interface {
|
||||
Sign(csrPEM []byte, duration time.Duration) (cert []byte, err error)
|
||||
Sign(csrPEM []byte, duration time.Duration, customFields []internalvanafiapi.CustomField) (cert []byte, err error)
|
||||
Ping() error
|
||||
ReadZoneConfiguration() (*endpoint.ZoneConfiguration, error)
|
||||
SetClient(endpoint.Connector)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user