Beginning porting and building new venafi tests

Signed-off-by: JoshVanL <vleeuwenjoshua@gmail.com>
This commit is contained in:
JoshVanL 2019-08-05 17:50:15 +01:00
parent d96c7d2e1c
commit 28f2d071ec
5 changed files with 244 additions and 10 deletions

View File

@ -0,0 +1,75 @@
/*
Copyright 2018 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package venafi
import (
"github.com/Venafi/vcert/pkg/certificate"
"github.com/Venafi/vcert/pkg/endpoint"
"github.com/Venafi/vcert/pkg/venafi/fake"
)
type fakeConnector struct {
*fake.Connector
PingFunc func() error
ReadZoneConfigurationFunc func() (*endpoint.ZoneConfiguration, error)
RetrieveCertificateFunc func(*certificate.Request) (*certificate.PEMCollection, error)
RequestCertificateFunc func(*certificate.Request) (string, error)
RenewCertificateFunc func(*certificate.RenewalRequest) (string, error)
}
func (f fakeConnector) Default() *fakeConnector {
if f.Connector == nil {
f.Connector = fake.NewConnector(true, nil)
}
return &f
}
func (f *fakeConnector) Ping() (err error) {
if f.PingFunc != nil {
return f.PingFunc()
}
return f.Connector.Ping()
}
func (f *fakeConnector) ReadZoneConfiguration() (config *endpoint.ZoneConfiguration, err error) {
if f.ReadZoneConfigurationFunc != nil {
return f.ReadZoneConfigurationFunc()
}
return f.Connector.ReadZoneConfiguration()
}
func (f *fakeConnector) RetrieveCertificate(req *certificate.Request) (certificates *certificate.PEMCollection, err error) {
if f.RetrieveCertificateFunc != nil {
return f.RetrieveCertificateFunc(req)
}
return f.Connector.RetrieveCertificate(req)
}
func (f *fakeConnector) RequestCertificate(req *certificate.Request) (requestID string, err error) {
if f.RequestCertificateFunc != nil {
return f.RequestCertificateFunc(req)
}
return f.Connector.RequestCertificate(req)
}
func (f *fakeConnector) RenewCertificate(req *certificate.RenewalRequest) (requestID string, err error) {
if f.RenewCertificateFunc != nil {
return f.RenewCertificateFunc(req)
}
return f.Connector.RenewCertificate(req)
}

View File

@ -0,0 +1,156 @@
/*
Copyright 2018 The Jetstack cert-manager contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package venafi
import (
"crypto"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"testing"
"github.com/Venafi/vcert/pkg/venafi/fake"
//"github.com/jetstack/cert-manager/pkg/issuer"
"github.com/jetstack/cert-manager/pkg/util"
"github.com/jetstack/cert-manager/pkg/util/pki"
//"github.com/jetstack/cert-manager/test/unit/gen"
)
func checkCertificateIssued(t *testing.T, csrPEM []byte, resp []byte, err error) {
if len(resp) == 0 {
t.Errorf("expected IssueResponse to be non-nil")
t.FailNow()
return
}
if err != nil {
t.Errorf("expected no error to be returned, but got: %v", err)
return
}
csr, err := pki.DecodeX509CertificateRequestBytes(csrPEM)
if err != nil {
t.Errorf("failed to decode CSR PEM: %s", err)
return
}
crt, err := pki.DecodeX509CertificateBytes(resp)
if err != nil {
t.Errorf("unable to decode x509 certificate: %v", err)
return
}
ok, err := pki.PublicKeyMatchesCSR(crt.PublicKey, csr)
if err != nil {
t.Errorf("error checking private key: %v", err)
return
}
if !ok {
t.Errorf("private key does not match certificate")
}
// validate the common name is correct
expectedCN := csr.Subject.CommonName
if expectedCN != crt.Subject.CommonName {
t.Errorf("expected common name to be %q but it was %q", expectedCN, crt.Subject.CommonName)
}
// validate the dns names are correct
expectedDNSNames := csr.DNSNames
if !util.EqualUnsorted(crt.DNSNames, expectedDNSNames) {
t.Errorf("expected dns names to be %q but it was %q", expectedDNSNames, crt.DNSNames)
}
}
func generateCSR(t *testing.T, sk crypto.Signer, commonName string, dnsNames []string) []byte {
asn1Subj, _ := asn1.Marshal(pkix.Name{
CommonName: commonName,
}.ToRDNSequence())
template := x509.CertificateRequest{
RawSubject: asn1Subj,
SignatureAlgorithm: x509.SHA256WithRSA,
DNSNames: dnsNames,
}
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, &template, sk)
if err != nil {
t.Error(err)
t.FailNow()
}
csr := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csrBytes})
return csr
}
func TestSign(t *testing.T) {
sk, err := pki.GenerateRSAPrivateKey(2048)
if err != nil {
t.Error(err)
t.FailNow()
}
csrPEM := generateCSR(t, sk, "common-name", []string{
"foo.example.com", "bar.example.com"})
tests := map[string]testT{
"obtain a certificate with a single dnsname specified": {
csrPEM: csrPEM,
CheckFn: checkCertificateIssued,
expectedErr: false,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
runTest(t, test)
})
}
}
type testT struct {
csrPEM []byte
client connector
expectedErr bool
CheckFn func(*testing.T, []byte, []byte, error)
}
func runTest(t *testing.T, test testT) {
if test.client == nil {
test.client = fake.NewConnector(true, nil)
}
v := &Venafi{
client: test.client,
}
resp, err := v.Sign(test.csrPEM)
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")
}
if test.CheckFn != nil {
test.CheckFn(t, test.csrPEM, resp, err)
}
}

View File

@ -25,10 +25,7 @@ import (
"github.com/Venafi/vcert/pkg/endpoint"
corev1 "k8s.io/api/core/v1"
//"k8s.io/klog"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/pkg/internal/venafi"
"github.com/jetstack/cert-manager/pkg/issuer"
logf "github.com/jetstack/cert-manager/pkg/logs"
"github.com/jetstack/cert-manager/pkg/util/pki"
@ -71,30 +68,33 @@ func (v *Venafi) Issue(ctx context.Context, crt *v1alpha1.Certificate) (*issuer.
return nil, nil
}
dbg.Info("generated new private key")
v.Recorder.Event(crt, corev1.EventTypeNormal, "GenerateKey", "Generated new private key")
pk, err := pki.EncodePKCS8PrivateKey(signeeKey)
if err != nil {
return nil, err
}
dbg.Info("generated new private key")
v.Recorder.Event(crt, corev1.EventTypeNormal, "GenerateKey", "Generated new private key")
// We build a x509.Certificate as the vcert library has support for converting
// this into its own internal Certificate Request type.
dbg.Info("constructing certificate request template to submit to venafi")
csr, err := pki.GenerateCSR(crt)
if err != nil {
v.Recorder.Eventf(crt, corev1.EventTypeWarning, "GenerateCSR", "Failed to generate a CSR for the certificate: %v", err)
return nil, err
}
csrPEM, err := pki.EncodeCSR(csr, signeeKey)
if err != nil {
v.Recorder.Eventf(crt, corev1.EventTypeWarning, "EncodeCSR", "Failed to PEM encode CSR for the certificate: %v", err)
return nil, err
}
client, err := venafi.New(v.resourceNamespace, v.secretsLister, v.issuer)
client, err := v.clientBuilder(v.resourceNamespace, v.secretsLister, v.issuer)
if err != nil {
return nil, err
v.Recorder.Eventf(v.issuer, corev1.EventTypeWarning, "FailedInit", "Failed to create Venafi client: %v", err)
return nil, fmt.Errorf("error creating Venafi client: %s", err.Error())
}
cert, err := client.Sign(csrPEM)

View File

@ -25,12 +25,11 @@ import (
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/pkg/internal/venafi"
)
func (v *Venafi) Setup(ctx context.Context) error {
client, err := venafi.New(v.resourceNamespace, v.secretsLister, v.issuer)
client, err := v.clientBuilder(v.resourceNamespace, v.secretsLister, v.issuer)
if err != nil {
return err
}

View File

@ -22,6 +22,7 @@ import (
apiutil "github.com/jetstack/cert-manager/pkg/api/util"
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
"github.com/jetstack/cert-manager/pkg/controller"
"github.com/jetstack/cert-manager/pkg/internal/venafi"
"github.com/jetstack/cert-manager/pkg/issuer"
)
@ -43,6 +44,8 @@ type Venafi struct {
// For Issuers, this will be the namespace of the Issuer.
// For ClusterIssuers, this will be the cluster resource namespace.
resourceNamespace string
clientBuilder venafi.VenafiClientBuilder
}
func NewVenafi(ctx *controller.Context, issuer cmapi.GenericIssuer) (issuer.Interface, error) {
@ -50,6 +53,7 @@ func NewVenafi(ctx *controller.Context, issuer cmapi.GenericIssuer) (issuer.Inte
issuer: issuer,
secretsLister: ctx.KubeSharedInformerFactory.Core().V1().Secrets().Lister(),
resourceNamespace: ctx.IssuerOptions.ResourceNamespace(issuer),
clientBuilder: venafi.New,
}, nil
}