Add webhookbootstrap tests
Signed-off-by: James Munnelly <james@munnelly.eu>
This commit is contained in:
parent
5c17c2e37f
commit
b476a4d5f7
@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@ -35,3 +35,19 @@ filegroup(
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["controller_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//pkg/apis/certmanager/v1alpha1:go_default_library",
|
||||
"//pkg/controller/test:go_default_library",
|
||||
"//pkg/util/pki:go_default_library",
|
||||
"//test/unit/gen:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
757
pkg/controller/webhookbootstrap/controller_test.go
Normal file
757
pkg/controller/webhookbootstrap/controller_test.go
Normal file
@ -0,0 +1,757 @@
|
||||
/*
|
||||
Copyright 2019 The Jetstack cert-manager contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package webhookbootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"github.com/jetstack/cert-manager/pkg/util/pki"
|
||||
"github.com/jetstack/cert-manager/test/unit/gen"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
|
||||
testpkg "github.com/jetstack/cert-manager/pkg/controller/test"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultWebhookNamespace = "testns"
|
||||
defaultWebhookCAName = "ca-secret"
|
||||
defaultWebhookServingName = "serving-secret"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultWebhookDNSNames = []string{"testdomain.com"}
|
||||
)
|
||||
|
||||
type testT struct {
|
||||
builder *testpkg.Builder
|
||||
generatePrivateKeyBytes generatePrivateKeyBytesFn
|
||||
signCertificate signCertificateFunc
|
||||
key string
|
||||
expectedErr bool
|
||||
}
|
||||
|
||||
func runTest(t *testing.T, test testT) {
|
||||
test.builder.T = t
|
||||
test.builder.Start()
|
||||
defer test.builder.Stop()
|
||||
|
||||
c := &controller{}
|
||||
c.Register(test.builder.Context)
|
||||
c.webhookServingSecret = defaultWebhookServingName
|
||||
c.webhookCASecret = defaultWebhookCAName
|
||||
c.webhookNamespace = defaultWebhookNamespace
|
||||
c.webhookDNSNames = defaultWebhookDNSNames
|
||||
if test.generatePrivateKeyBytes != nil {
|
||||
c.generatePrivateKeyBytes = test.generatePrivateKeyBytes
|
||||
}
|
||||
if test.signCertificate != nil {
|
||||
c.signCertificate = test.signCertificate
|
||||
}
|
||||
|
||||
test.builder.Sync()
|
||||
|
||||
err := c.ProcessItem(context.Background(), test.key)
|
||||
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)
|
||||
}
|
||||
|
||||
func TestProcessItem(t *testing.T) {
|
||||
exampleBundle := mustCreateCryptoBundle(t, gen.Certificate(defaultWebhookCAName,
|
||||
gen.SetCertificateDNSNames(defaultWebhookDNSNames...),
|
||||
gen.SetCertificateOrganization("cert-manager.system"),
|
||||
))
|
||||
exampleBadDNSNameBundle := mustCreateCryptoBundle(t, gen.Certificate(defaultWebhookCAName,
|
||||
gen.SetCertificateDNSNames("nottherightdomain.com"),
|
||||
gen.SetCertificateOrganization("cert-manager.system"),
|
||||
))
|
||||
exampleBundleCA := mustCreateCryptoBundle(t, gen.Certificate(defaultWebhookCAName,
|
||||
gen.SetCertificateCommonName("cert-manager.webhook.ca"),
|
||||
gen.SetCertificateIsCA(true),
|
||||
gen.SetCertificateOrganization("cert-manager.system"),
|
||||
))
|
||||
|
||||
caSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
}
|
||||
caSecretKey := caSecret.Namespace + "/" + caSecret.Name
|
||||
|
||||
servingSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
}
|
||||
servingSecretKey := servingSecret.Namespace + "/" + servingSecret.Name
|
||||
|
||||
tests := map[string]testT{
|
||||
"do nothing if the secret's namespace does not match the webhook namespace": {
|
||||
key: "notmyns/" + defaultWebhookCAName,
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: "notmyns",
|
||||
},
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"generate a new private key for the CA secret if none exists": {
|
||||
key: caSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
caSecret,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
caSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: nil,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: nil,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"generate a new private key for the CA secret if existing private key is garbage": {
|
||||
key: caSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: []byte("garbage"),
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
caSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: nil,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: nil,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"return an error for the serving secret if the ca secret is empty": {
|
||||
key: servingSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
caSecret,
|
||||
servingSecret,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
"return an error for the serving secret if the ca certificate data is empty": {
|
||||
key: servingSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
servingSecret,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
expectedErr: true,
|
||||
},
|
||||
"generate a new private key for the serving secret if none exists": {
|
||||
key: servingSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
servingSecret,
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: nil,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: nil,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"generate a new private key for the serving secret if existing private key is garbage": {
|
||||
key: servingSecretKey,
|
||||
generatePrivateKeyBytes: testGeneratePrivateKeyBytesFn(exampleBundle.privateKeyBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: []byte("garbage"),
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: nil,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: nil,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new CA certificate if none currently exists": {
|
||||
key: caSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundleCA.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
caSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new CA certificate if existing one is garbage": {
|
||||
key: caSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundleCA.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
corev1.TLSCertKey: []byte("garbage"),
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
caSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new serving certificate if none currently exists": {
|
||||
key: servingSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundle.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundle.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new serving certificate if existing one is garbage": {
|
||||
key: servingSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundle.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundle.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new serving certificate if existing one contains mismatching private/cert pair": {
|
||||
key: servingSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundle.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundle.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"sign a new serving certificate if existing one contains wrong dnsNames": {
|
||||
key: servingSecretKey,
|
||||
signCertificate: testSignCertificateFn(exampleBundle.certBytes),
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: caSecret.Namespace,
|
||||
Name: caSecret.Name,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBadDNSNameBundle.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBadDNSNameBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{
|
||||
testpkg.NewAction(coretesting.NewUpdateAction(
|
||||
corev1.SchemeGroupVersion.WithResource("secrets"),
|
||||
servingSecret.Namespace,
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: servingSecret.Namespace,
|
||||
Name: servingSecret.Name,
|
||||
Annotations: map[string]string{
|
||||
cmapi.AllowsInjectionFromSecretAnnotation: "true",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSCertKey: exampleBundle.certBytes,
|
||||
corev1.TLSPrivateKeyKey: exampleBadDNSNameBundle.privateKeyBytes,
|
||||
cmapi.TLSCAKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
)),
|
||||
},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"do nothing if the existing CA secret is up to date": {
|
||||
key: caSecretKey,
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
"do nothing if the existing serving secret is up to date": {
|
||||
key: servingSecretKey,
|
||||
builder: &testpkg.Builder{
|
||||
KubeObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookCAName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundleCA.privateKeyBytes,
|
||||
corev1.TLSCertKey: exampleBundleCA.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: defaultWebhookServingName,
|
||||
Namespace: defaultWebhookNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
corev1.TLSPrivateKeyKey: exampleBundle.privateKeyBytes,
|
||||
corev1.TLSCertKey: exampleBundle.certBytes,
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
},
|
||||
},
|
||||
ExpectedActions: []testpkg.Action{},
|
||||
ExpectedEvents: []string{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
runTest(t, test)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type cryptoBundle struct {
|
||||
// certificate is the Certificate resource used to create this bundle
|
||||
certificate *cmapi.Certificate
|
||||
|
||||
// privateKey is the private key used as the complement to the certificates
|
||||
// in this bundle
|
||||
privateKey crypto.Signer
|
||||
privateKeyBytes []byte
|
||||
|
||||
// cert is a signed certificate
|
||||
cert *x509.Certificate
|
||||
certBytes []byte
|
||||
}
|
||||
|
||||
func mustCreateCryptoBundle(t *testing.T, crt *cmapi.Certificate) cryptoBundle {
|
||||
c, err := createCryptoBundle(crt)
|
||||
if err != nil {
|
||||
t.Fatalf("error generating crypto bundle: %v", err)
|
||||
}
|
||||
return *c
|
||||
}
|
||||
|
||||
func createCryptoBundle(crt *cmapi.Certificate) (*cryptoBundle, error) {
|
||||
privateKey, err := pki.GeneratePrivateKeyForCertificate(crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privateKeyBytes, err := pki.EncodePrivateKey(privateKey, crt.Spec.KeyEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unsignedCert, err := pki.GenerateTemplate(crt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certBytes, cert, err := pki.SignCertificate(unsignedCert, unsignedCert, privateKey.Public(), privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cryptoBundle{
|
||||
certificate: crt,
|
||||
privateKey: privateKey,
|
||||
privateKeyBytes: privateKeyBytes,
|
||||
cert: cert,
|
||||
certBytes: certBytes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func testGeneratePrivateKeyBytesFn(b []byte) generatePrivateKeyBytesFn {
|
||||
return func(*cmapi.Certificate) ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
|
||||
func testSignCertificateFn(b []byte) signCertificateFunc {
|
||||
return func(_ *cmapi.Certificate, _, _ crypto.Signer, _ *x509.Certificate) ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user