error when CA bundle from Secret or ConfigMap is empty

Co-authored-by: Joshua Casey <joshuatcasey@gmail.com>
This commit is contained in:
Ryan Richard
2024-07-19 16:18:52 -07:00
parent bf1c02d328
commit 920b519ebf
5 changed files with 238 additions and 313 deletions

View File

@@ -155,7 +155,6 @@ func TestController(t *testing.T) {
defer cancel()
informers.Start(ctx.Done())
informers.WaitForCacheSync(ctx.Done())
controllerlib.TestRunSynchronously(t, controller)
syncCtx := controllerlib.Context{

View File

@@ -306,7 +306,7 @@ func (c *jwtCacheFillerController) cacheValueAsJWTAuthenticator(value authncache
func (c *jwtCacheFillerController) validateTLSBundle(tlsSpec *authenticationv1alpha1.TLSSpec, conditions []*metav1.Condition) (*x509.CertPool, []*metav1.Condition, []byte, bool) {
condition, pemBundle, rootCAs := tlsconfigutil.ValidateTLSConfig(
tlsconfigutil.TlsSpecForConcierge(tlsSpec),
tlsconfigutil.TLSSpecForConcierge(tlsSpec),
"spec.tls",
c.namespace,
c.secretInformer,

View File

@@ -341,7 +341,7 @@ func (c *webhookCacheFillerController) validateConnection(certPool *x509.CertPoo
func (c *webhookCacheFillerController) validateTLSBundle(tlsSpec *authenticationv1alpha1.TLSSpec, conditions []*metav1.Condition) (*x509.CertPool, []byte, []*metav1.Condition, bool) {
condition, pemBytes, rootCAs := tlsconfigutil.ValidateTLSConfig(
tlsconfigutil.TlsSpecForConcierge(tlsSpec),
tlsconfigutil.TLSSpecForConcierge(tlsSpec),
"spec.tls",
c.namespace,
c.secretInformer,

View File

@@ -64,8 +64,8 @@ func TLSSpecForSupervisor(source *idpv1alpha1.TLSSpec) *TLSSpec {
return dest
}
// TlsSpecForConcierge is a helper function to convert the Concierge's TLSSpec to the unified TLSSpec.
func TlsSpecForConcierge(source *authenticationv1alpha1.TLSSpec) *TLSSpec {
// TLSSpecForConcierge is a helper function to convert the Concierge's TLSSpec to the unified TLSSpec.
func TLSSpecForConcierge(source *authenticationv1alpha1.TLSSpec) *TLSSpec {
if source == nil {
return nil
}
@@ -82,6 +82,30 @@ func TlsSpecForConcierge(source *authenticationv1alpha1.TLSSpec) *TLSSpec {
return dest
}
// ValidateTLSConfig reads ca bundle in the tlsSpec, supplied either inline using the CertificateAuthorityDate
// or as a reference to a kubernetes secret or configmap using the CertificateAuthorityDataSource, and returns
// - a condition of type TLSConfigurationValid based on the validity of the ca bundle,
// - a pem encoded ca bundle
// - a X509 cert pool with the ca bundle
// TODO: should this show the resource version of the Secret/ConfigMap to the user on all conditions?
func ValidateTLSConfig(
tlsSpec *TLSSpec,
conditionPrefix string,
namespace string,
secretInformer corev1informers.SecretInformer,
configMapInformer corev1informers.ConfigMapInformer,
) (*metav1.Condition, []byte, *x509.CertPool) {
certPool, bundle, err := getCertPool(tlsSpec, conditionPrefix, namespace, secretInformer, configMapInformer)
if err != nil {
return invalidTLSCondition(err.Error()), nil, nil
}
if bundle == nil {
// An empty or nil CA bundle results in a valid TLS condition which indicates that no CA data was supplied.
return validTLSCondition(fmt.Sprintf("%s is valid: %s", conditionPrefix, noTLSConfigurationMessage)), nil, nil
}
return validTLSCondition(fmt.Sprintf("%s is valid: %s", conditionPrefix, loadedTLSConfigurationMessage)), bundle, certPool
}
// getCertPool reads the unified tlsSpec and returns an X509 cert pool with the CA data that is read either from
// the inline tls.certificateAuthorityData or from a kubernetes secret or a config map as specified in the
// tls.certificateAuthorityDataSource.
@@ -147,30 +171,6 @@ func getCertPool(
return ca, bundleBytes, nil
}
// ValidateTLSConfig reads ca bundle in the tlsSpec, supplied either inline using the CertificateAuthorityDate
// or as a reference to a kubernetes secret or configmap using the CertificateAuthorityDataSource, and returns
// - a condition of type TLSConfigurationValid based on the validity of the ca bundle,
// - a pem encoded ca bundle
// - a X509 cert pool with the ca bundle
// TODO: should this show the resource version of the Secret/ConfigMap to the user on all conditions?
func ValidateTLSConfig(
tlsSpec *TLSSpec,
conditionPrefix string,
namespace string,
secretInformer corev1informers.SecretInformer,
configMapInformer corev1informers.ConfigMapInformer,
) (*metav1.Condition, []byte, *x509.CertPool) {
certPool, bundle, err := getCertPool(tlsSpec, conditionPrefix, namespace, secretInformer, configMapInformer)
if err != nil {
return invalidTLSCondition(err.Error()), nil, nil
}
if bundle == nil {
// An empty or nil CA bundle results in a valid TLS condition which indicates that no CA data was supplied.
return validTLSCondition(fmt.Sprintf("%s is valid: %s", conditionPrefix, noTLSConfigurationMessage)), nil, nil
}
return validTLSCondition(fmt.Sprintf("%s is valid: %s", conditionPrefix, loadedTLSConfigurationMessage)), bundle, certPool
}
func readCABundleFromSource(source *caBundleSource, namespace string, secretInformer corev1informers.SecretInformer, configMapInformer corev1informers.ConfigMapInformer) (string, error) {
switch source.Kind {
case "Secret":
@@ -189,17 +189,21 @@ func readCABundleFromK8sSecret(namespace string, name string, key string, secret
if err != nil {
return "", errors.Wrapf(err, "failed to get secret %q", namespacedName)
}
// for kubernetes secrets to be used as a certificate authority data source, the secret should be of type
// For Secrets to be used as a certificate authority data source, the secret should be of type
// kubernetes.io/tls or Opaque. It is an error to use a secret that is of any other type.
if s.Type != corev1.SecretTypeTLS && s.Type != corev1.SecretTypeOpaque {
return "", fmt.Errorf("secret %q of type %q cannot be used as a certificate authority data source", namespacedName, s.Type)
}
// ca bundle in the secret is expected to exist in a specific key, if that key does not exist, then it is an error
if val, exists := s.Data[key]; exists {
// TODO: if val is an empty string, it should be an error
return string(val), nil
val, exists := s.Data[key]
if !exists {
return "", fmt.Errorf("key %q not found in secret %q", key, namespacedName)
}
return "", fmt.Errorf("key %q not found in secret %q", key, namespacedName)
if len(val) == 0 {
return "", fmt.Errorf("key %q has empty value in secret %q", key, namespacedName)
}
return string(val), nil
}
func readCABundleFromK8sConfigMap(namespace string, name string, key string, configMapInformer corev1informers.ConfigMapInformer) (string, error) {
@@ -210,12 +214,14 @@ func readCABundleFromK8sConfigMap(namespace string, name string, key string, con
return "", errors.Wrapf(err, "failed to get configmap %q", namespacedName)
}
// ca bundle in the secret is expected to exist in a specific key, if that key does not exist, then it is an error
if val, exists := c.Data[key]; exists {
// TODO: if val is an empty string, it should be an error
return val, nil
val, exists := c.Data[key]
if !exists {
return "", fmt.Errorf("key %q not found in configmap %q", key, namespacedName)
}
return "", fmt.Errorf("key %q not found in configmap %q", key, namespacedName)
if len(val) == 0 {
return "", fmt.Errorf("key %q has empty value in configmap %q", key, namespacedName)
}
return val, nil
}
func validTLSCondition(message string) *metav1.Condition {

View File

@@ -5,6 +5,7 @@ package tlsconfigutil
import (
"context"
"crypto/x509"
"encoding/base64"
"testing"
"time"
@@ -27,12 +28,17 @@ func TestValidateTLSConfig(t *testing.T) {
testCA, err := certauthority.New("Test CA", 1*time.Hour)
require.NoError(t, err)
bundle := testCA.Bundle()
certPool := x509.NewCertPool()
require.True(t, certPool.AppendCertsFromPEM(bundle))
base64EncodedBundle := base64.StdEncoding.EncodeToString(bundle)
tests := []struct {
name string
tlsSpec *TLSSpec
namespace string
k8sObjects []runtime.Object
expectedBundle []byte
expectedCertPool *x509.CertPool
expectedCondition *metav1.Condition
}{
{
@@ -60,6 +66,8 @@ func TestValidateTLSConfig(t *testing.T) {
tlsSpec: &TLSSpec{
CertificateAuthorityData: base64EncodedBundle,
},
expectedBundle: bundle,
expectedCertPool: certPool,
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionTrue,
@@ -130,6 +138,8 @@ func TestValidateTLSConfig(t *testing.T) {
},
},
},
expectedBundle: bundle,
expectedCertPool: certPool,
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionTrue,
@@ -159,6 +169,8 @@ func TestValidateTLSConfig(t *testing.T) {
},
},
},
expectedBundle: bundle,
expectedCertPool: certPool,
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionTrue,
@@ -166,7 +178,6 @@ func TestValidateTLSConfig(t *testing.T) {
Message: "tls is valid: loaded TLS configuration",
},
},
{
name: "should return invalid condition when a secrets not of type tls or opaque are used as ca data source",
tlsSpec: &TLSSpec{
@@ -196,7 +207,120 @@ func TestValidateTLSConfig(t *testing.T) {
Message: `tls.certificateAuthorityDataSource is invalid: secret "awesome-namespace/awesome-secret-ba" of type "kubernetes.io/basic-auth" cannot be used as a certificate authority data source`,
},
},
{
name: "should return invalid condition when a secret does not have the configured key",
tlsSpec: &TLSSpec{
CertificateAuthorityDataSource: &caBundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"wrong-key": bundle,
},
},
},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
Reason: ReasonInvalidTLSConfig,
Message: `tls.certificateAuthorityDataSource is invalid: key "ca-bundle" not found in secret "awesome-namespace/awesome-secret"`,
},
},
{
name: "should return invalid condition when a secret has the configured key but its value is empty",
tlsSpec: &TLSSpec{
CertificateAuthorityDataSource: &caBundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"ca-bundle": []byte(""),
},
},
},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
Reason: ReasonInvalidTLSConfig,
Message: `tls.certificateAuthorityDataSource is invalid: key "ca-bundle" has empty value in secret "awesome-namespace/awesome-secret"`,
},
},
{
name: "should return invalid condition when a configmap does not have the configured key",
tlsSpec: &TLSSpec{
CertificateAuthorityDataSource: &caBundleSource{
Kind: "ConfigMap",
Name: "awesome-configmap",
Key: "ca-bundle",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-configmap",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"wrong-key": string(bundle),
},
},
},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
Reason: ReasonInvalidTLSConfig,
Message: `tls.certificateAuthorityDataSource is invalid: key "ca-bundle" not found in configmap "awesome-namespace/awesome-configmap"`,
},
},
{
name: "should return invalid condition when a configmap has the configured key but its value is empty",
tlsSpec: &TLSSpec{
CertificateAuthorityDataSource: &caBundleSource{
Kind: "ConfigMap",
Name: "awesome-configmap",
Key: "ca-bundle",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-configmap",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"ca-bundle": "",
},
},
},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
Reason: ReasonInvalidTLSConfig,
Message: `tls.certificateAuthorityDataSource is invalid: key "ca-bundle" has empty value in configmap "awesome-namespace/awesome-configmap"`,
},
},
{
name: "should return ca bundle from kubernetes configMap",
tlsSpec: &TLSSpec{
@@ -218,6 +342,8 @@ func TestValidateTLSConfig(t *testing.T) {
},
},
},
expectedBundle: bundle,
expectedCertPool: certPool,
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionTrue,
@@ -234,18 +360,8 @@ func TestValidateTLSConfig(t *testing.T) {
Key: "does-not-matter",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-cm",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"ca-bundle": string(bundle),
},
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
@@ -262,18 +378,8 @@ func TestValidateTLSConfig(t *testing.T) {
Key: "does-not-matter",
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-cm",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"ca-bundle": string(bundle),
},
},
},
namespace: "awesome-namespace",
k8sObjects: []runtime.Object{},
expectedCondition: &metav1.Condition{
Type: typeTLSConfigurationValid,
Status: metav1.ConditionFalse,
@@ -317,265 +423,40 @@ func TestValidateTLSConfig(t *testing.T) {
var secretsInformer corev1informers.SecretInformer
var configMapInformer corev1informers.ConfigMapInformer
if len(tt.k8sObjects) > 0 {
fakeClient := fake.NewSimpleClientset(tt.k8sObjects...)
sharedInformers := informers.NewSharedInformerFactory(fakeClient, 0)
configMapInformer = sharedInformers.Core().V1().ConfigMaps()
secretsInformer = sharedInformers.Core().V1().Secrets()
fakeClient := fake.NewSimpleClientset(tt.k8sObjects...)
sharedInformers := informers.NewSharedInformerFactory(fakeClient, 0)
configMapInformer = sharedInformers.Core().V1().ConfigMaps()
secretsInformer = sharedInformers.Core().V1().Secrets()
// calling the .Informer function registers this informer in the sharedinformer.
// doing this will ensure that this informer will be sync'd when Start is called next.
configMapInformer.Informer()
secretsInformer.Informer()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sharedInformers.Start(ctx.Done())
sharedInformers.WaitForCacheSync(ctx.Done())
}
actualCondition, _, _ := ValidateTLSConfig(tt.tlsSpec, "tls", tt.namespace, secretsInformer, configMapInformer)
require.Equal(t, tt.expectedCondition, actualCondition)
})
}
}
func TestReadCABundleFromK8sSecret(t *testing.T) {
tests := []struct {
name string
secretNamespace string
secretName string
secretKey string
k8sObjects []runtime.Object
expectedData string
expectError string
}{
{
name: "should return data from existing tls secret and existing key",
secretNamespace: "awesome-namespace",
secretName: "awesome-secret",
secretKey: "awesome",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: corev1.SecretTypeTLS,
Data: map[string][]byte{
"awesome": []byte("pinniped-is-awesome"),
},
},
},
expectedData: "pinniped-is-awesome",
expectError: "",
},
{
name: "should return data from existing opaque secret and existing key",
secretNamespace: "awesome-namespace",
secretName: "awesome-secret",
secretKey: "awesome",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"awesome": []byte("pinniped-is-awesome"),
},
},
},
expectedData: "pinniped-is-awesome",
expectError: "",
},
{
name: "should return error reading a non-existent secret",
secretNamespace: "awesome-namespace",
secretName: "does-not-exist",
secretKey: "does-not-matter",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Data: map[string][]byte{
"awesome": []byte("pinniped-is-awesome"),
},
},
},
expectedData: "",
expectError: `failed to get secret "awesome-namespace/does-not-exist": secret "does-not-exist" not found`,
},
{
name: "should return error when secret has wrong type",
secretNamespace: "awesome-namespace",
secretName: "awesome-secret",
secretKey: "awesome",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: "other-type",
Data: map[string][]byte{
"awesome": []byte("pinniped-is-awesome"),
},
},
},
expectError: `secret "awesome-namespace/awesome-secret" of type "other-type" cannot be used as a certificate authority data source`,
},
{
name: "should return error reading a non-existing key in an existing secret",
secretNamespace: "awesome-namespace",
secretName: "awesome-secret",
secretKey: "something-else",
k8sObjects: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-secret",
Namespace: "awesome-namespace",
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"awesome": []byte("pinniped-is-awesome"),
},
},
},
expectedData: "",
expectError: `key "something-else" not found in secret "awesome-namespace/awesome-secret"`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
sharedInformers := informers.NewSharedInformerFactory(fake.NewSimpleClientset(tt.k8sObjects...), 0)
secretsInformer := sharedInformers.Core().V1().Secrets()
// calling the .Informer function registers this informer in the sharedinformer.
// doing this will ensure that this informer will be sync'd when Start is called next.
// Calling the Informer() function registers this informer in the sharedinformer.
// Doing this will ensure that this informer will be sync'd when Start() is called.
// This is needed in this test because we are not using the controller library here,
// which would do these same calls for us.
configMapInformer.Informer()
secretsInformer.Informer()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sharedInformers.Start(ctx.Done())
// This is needed in this test because we are not using the controller library here,
// which would do this same call for us.
sharedInformers.WaitForCacheSync(ctx.Done())
// now the objects from kubernetes should be sync'd into the informer cache.
actualData, actualError := readCABundleFromK8sSecret(tt.secretNamespace, tt.secretName, tt.secretKey, secretsInformer)
if tt.expectError != "" {
require.ErrorContains(t, actualError, tt.expectError)
} else {
require.NoError(t, actualError)
}
require.Equal(t, tt.expectedData, actualData)
actualCondition, actualBundle, actualCertPool := ValidateTLSConfig(tt.tlsSpec, "tls", tt.namespace, secretsInformer, configMapInformer)
require.Equal(t, tt.expectedCondition, actualCondition)
require.Equal(t, tt.expectedBundle, actualBundle)
require.True(t, tt.expectedCertPool.Equal(actualCertPool), "expectedCertPool did not equal actualCertPool")
})
}
}
func TestReadCABundleFromK8sConfigMap(t *testing.T) {
tests := []struct {
name string
configMapNamespace string
configMapName string
configMapKey string
k8sObjects []runtime.Object
expectedData string
expectError string
}{
{
name: "should return expected data from an existing key in an existing configMap",
configMapNamespace: "awesome-namespace",
configMapName: "awesome-configmap",
configMapKey: "awesome",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-configmap",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"awesome": "pinniped-is-awesome",
},
},
},
expectedData: "pinniped-is-awesome",
},
{
name: "should return error reading a non-existent configMap",
configMapNamespace: "awesome-namespace",
configMapName: "does-not-exist",
configMapKey: "does-not-matter",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-configmap",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"awesome": "pinniped-is-awesome",
},
},
},
expectedData: "",
expectError: `failed to get configmap "awesome-namespace/does-not-exist": configmap "does-not-exist" not found`,
},
{
name: "should return error reading a non-existing key in an existing configMap",
configMapNamespace: "awesome-namespace",
configMapName: "awesome-configmap",
configMapKey: "does-not-exist",
k8sObjects: []runtime.Object{
&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "awesome-configmap",
Namespace: "awesome-namespace",
},
Data: map[string]string{
"awesome": "pinniped-is-awesome",
},
},
},
expectedData: "",
expectError: `key "does-not-exist" not found in configmap "awesome-namespace/awesome-configmap"`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
fakeClient := fake.NewSimpleClientset(tt.k8sObjects...)
sharedInformers := informers.NewSharedInformerFactory(fakeClient, 0)
configMapInformer := sharedInformers.Core().V1().ConfigMaps()
// calling the .Informer function registers this informer in the sharedinformer.
// doing this will ensure that this informer will be sync'd when Start is called next.
configMapInformer.Informer()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sharedInformers.Start(ctx.Done())
sharedInformers.WaitForCacheSync(ctx.Done())
actualData, actualError := readCABundleFromK8sConfigMap(tt.configMapNamespace, tt.configMapName, tt.configMapKey, configMapInformer)
if tt.expectError != "" {
require.ErrorContains(t, actualError, tt.expectError)
} else {
require.NoError(t, actualError)
}
require.Equal(t, tt.expectedData, actualData)
})
}
}
func TestNewCommonTLSSpecForSupervisor(t *testing.T) {
func TestTLSSpecForSupervisor(t *testing.T) {
testCA, err := certauthority.New("Test CA", 1*time.Hour)
require.NoError(t, err)
bundle := testCA.Bundle()
base64EncodedBundle := base64.StdEncoding.EncodeToString(bundle)
tests := []struct {
name string
supervisorTLSSpec *idpv1alpha1.TLSSpec
@@ -614,6 +495,25 @@ func TestNewCommonTLSSpecForSupervisor(t *testing.T) {
},
},
},
{
name: "should return tls spec when source has all fields filled",
supervisorTLSSpec: &idpv1alpha1.TLSSpec{
CertificateAuthorityData: base64EncodedBundle,
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
expected: &TLSSpec{
CertificateAuthorityData: base64EncodedBundle,
CertificateAuthorityDataSource: &caBundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
},
}
for _, tt := range tests {
@@ -625,18 +525,19 @@ func TestNewCommonTLSSpecForSupervisor(t *testing.T) {
}
}
func TestNewCommonTlsSpecForConcierge(t *testing.T) {
func TestTLSSpecForConcierge(t *testing.T) {
testCA, err := certauthority.New("Test CA", 1*time.Hour)
require.NoError(t, err)
bundle := testCA.Bundle()
base64EncodedBundle := base64.StdEncoding.EncodeToString(bundle)
tests := []struct {
name string
conciergeTLSSpec *authenticationv1alpha1.TLSSpec
expected *TLSSpec
}{
{
name: "should return nil spec when supervisorTLSSpec is nil",
name: "should return nil spec when TLSSpec is nil",
conciergeTLSSpec: nil,
expected: nil,
},
@@ -668,12 +569,31 @@ func TestNewCommonTlsSpecForConcierge(t *testing.T) {
},
},
},
{
name: "should return tls spec when source has all fields filled",
conciergeTLSSpec: &authenticationv1alpha1.TLSSpec{
CertificateAuthorityData: base64EncodedBundle,
CertificateAuthorityDataSource: &authenticationv1alpha1.CABundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
expected: &TLSSpec{
CertificateAuthorityData: base64EncodedBundle,
CertificateAuthorityDataSource: &caBundleSource{
Kind: "Secret",
Name: "awesome-secret",
Key: "ca-bundle",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
actual := TlsSpecForConcierge(tt.conciergeTLSSpec)
actual := TLSSpecForConcierge(tt.conciergeTLSSpec)
require.Equal(t, tt.expected, actual)
})
}