mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-07 05:57:02 +00:00
unify TLS Spec between supervisor and concierge
Signed-off-by: Ashish Amarnath <ashish.amarnath@broadcom.com>
This commit is contained in:
committed by
Ryan Richard
parent
080c75efe6
commit
aab1ee9edc
@@ -9,10 +9,12 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/informers/core/v1"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||
conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||
supervisorv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||
"go.pinniped.dev/internal/constable"
|
||||
"go.pinniped.dev/internal/controller/conditionsutil"
|
||||
)
|
||||
@@ -27,14 +29,66 @@ const (
|
||||
ErrNoCertificates = constable.Error("no certificates found")
|
||||
)
|
||||
|
||||
// BuildCertPoolIDP reads the tlsSpec of the IDP and returns an X509 cert pool with the CA data that is read either from
|
||||
type caBundleSource struct {
|
||||
Kind string
|
||||
Name string
|
||||
Key string
|
||||
}
|
||||
|
||||
// TLSSpec unifies the TLSSpec type that Supervisor and Concierge both individually define.
|
||||
// unifying these two definitions to allow sharing code that will read the spec and translate it into a CA bundle
|
||||
type TLSSpec struct {
|
||||
// X.509 Certificate Authority (base64-encoded PEM bundle). If omitted, a default set of system roots will be trusted.
|
||||
CertificateAuthorityData string
|
||||
// Reference to a CA bundle in a secret or a configmap.
|
||||
CertificateAuthorityDataSource *caBundleSource
|
||||
}
|
||||
|
||||
// TLSSpecForSupervisor is a helper function to convert the Supervisor's TLSSpec to the unified TLSSpec
|
||||
func TLSSpecForSupervisor(source *supervisorv1alpha1.TLSSpec) *TLSSpec {
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
dest := &TLSSpec{
|
||||
CertificateAuthorityData: source.CertificateAuthorityData,
|
||||
}
|
||||
|
||||
if source.CertificateAuthorityDataSource != nil {
|
||||
dest.CertificateAuthorityDataSource = &caBundleSource{
|
||||
Kind: source.CertificateAuthorityDataSource.Kind,
|
||||
Name: source.CertificateAuthorityDataSource.Name,
|
||||
Key: source.CertificateAuthorityDataSource.Key,
|
||||
}
|
||||
}
|
||||
|
||||
return dest
|
||||
}
|
||||
|
||||
// TlsSpecForConcierge is a helper function to convert the Concierge's TLSSpec to the unified TLSSpec
|
||||
func TlsSpecForConcierge(source *conciergev1alpha1.TLSSpec) *TLSSpec {
|
||||
if source == nil {
|
||||
return nil
|
||||
}
|
||||
dest := &TLSSpec{
|
||||
CertificateAuthorityData: source.CertificateAuthorityData,
|
||||
}
|
||||
if source.CertificateAuthorityDataSource != nil {
|
||||
dest.CertificateAuthorityDataSource = &caBundleSource{
|
||||
Kind: source.CertificateAuthorityDataSource.Kind,
|
||||
Name: source.CertificateAuthorityDataSource.Name,
|
||||
Key: source.CertificateAuthorityDataSource.Key,
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
// 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.
|
||||
// If the provided tlsSpec is nil, a nil CA bundle will be returned.
|
||||
// If the provided spec contains a CA bundle that is not properly encoded, an error will be returned.
|
||||
// TODO: should this function be exposed outside this package?
|
||||
func BuildCertPoolIDP(
|
||||
tlsSpec *v1alpha1.TLSSpec,
|
||||
func getCertPool(
|
||||
tlsSpec *TLSSpec,
|
||||
conditionPrefix string,
|
||||
namespace string,
|
||||
secretInformer v1.SecretInformer,
|
||||
@@ -55,7 +109,7 @@ func BuildCertPoolIDP(
|
||||
var err error
|
||||
caBundle := tlsSpec.CertificateAuthorityData
|
||||
field := fmt.Sprintf("%s.%s", conditionPrefix, "certificateAuthorityData")
|
||||
// currently, the ca data supplied inline in the CRDs is expected to be base64 encoded.
|
||||
// the ca data supplied inline in the CRDs is expected to be base64 encoded.
|
||||
// However, the ca data read from kubernetes secrets or config map will not be base64 encoded.
|
||||
// For kubernetes secrets, secret data read using the client-go code automatically decodes base64 encoded values.
|
||||
// So a base64 decode is required only when fetching ca bundle from the tls.certificateAuthorityData field.
|
||||
@@ -67,9 +121,7 @@ func BuildCertPoolIDP(
|
||||
field = fmt.Sprintf("%s.%s", conditionPrefix, "certificateAuthorityDataSource")
|
||||
caBundle, err = readCABundleFromSource(tlsSpec.CertificateAuthorityDataSource, namespace, secretInformer, configMapInformer)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("%s is invalid: failed to read CA bundle from source %s/%s/%s: %s",
|
||||
field, tlsSpec.CertificateAuthorityDataSource.Kind, tlsSpec.CertificateAuthorityDataSource.Name,
|
||||
tlsSpec.CertificateAuthorityDataSource.Key, err.Error())
|
||||
return nil, nil, fmt.Errorf("%s is invalid: %s", field, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +133,7 @@ func BuildCertPoolIDP(
|
||||
if decodeRequired {
|
||||
bundleBytes, err = base64.StdEncoding.DecodeString(caBundle)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("%s is invalid: %s", conditionPrefix, err.Error())
|
||||
return nil, nil, fmt.Errorf("%s is invalid: %s", field, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +156,14 @@ func BuildCertPoolIDP(
|
||||
// TODO: it should suffice that this function returns a TLSConfigurationValid condition, and perhaps we could skip
|
||||
// returning the error. This can be done once all controllers are able to use this function.
|
||||
func ValidateTLSConfig(
|
||||
tlsSpec *v1alpha1.TLSSpec,
|
||||
tlsSpec *TLSSpec,
|
||||
conditionPrefix string,
|
||||
namespace string,
|
||||
secretInformer v1.SecretInformer,
|
||||
configMapInformer v1.ConfigMapInformer,
|
||||
) (*v12.Condition, []byte, *x509.CertPool, error) {
|
||||
) (*metav1.Condition, []byte, *x509.CertPool, error) {
|
||||
// try to build a x509 cert pool using the ca data specified in the tlsSpec.
|
||||
certPool, bundle, err := BuildCertPoolIDP(tlsSpec, conditionPrefix, namespace, secretInformer, configMapInformer)
|
||||
certPool, bundle, err := getCertPool(tlsSpec, conditionPrefix, namespace, secretInformer, configMapInformer)
|
||||
if err != nil {
|
||||
// an error encountered during building a certpool using the ca data from the tlsSpec results in an invalid
|
||||
// TLS condition.
|
||||
@@ -126,14 +178,14 @@ func ValidateTLSConfig(
|
||||
return validTLSCondition(fmt.Sprintf("%s is valid: %s", conditionPrefix, loadedTLSConfigurationMessage)), bundle, certPool, err
|
||||
}
|
||||
|
||||
func readCABundleFromSource(source *v1alpha1.CABundleSource, namespace string, secretInformer v1.SecretInformer, configMapInformer v1.ConfigMapInformer) (string, error) {
|
||||
func readCABundleFromSource(source *caBundleSource, namespace string, secretInformer v1.SecretInformer, configMapInformer v1.ConfigMapInformer) (string, error) {
|
||||
switch source.Kind {
|
||||
case "Secret":
|
||||
return readCABundleFromK8sSecret(namespace, source.Name, source.Key, secretInformer)
|
||||
case "ConfigMap":
|
||||
return readCABundleFromK8sConfigMap(namespace, source.Name, source.Key, configMapInformer)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported CA bundle source: %s", source.Kind)
|
||||
return "", fmt.Errorf("unsupported CA bundle source kind: %s", source.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +194,11 @@ func readCABundleFromK8sSecret(namespace string, name string, key string, secret
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to get secret %s/%s", namespace, name)
|
||||
}
|
||||
// for kubernetes 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 %s/%s of type %s cannot be used as a certificate authority data source", namespace, name, 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 {
|
||||
return string(val), nil
|
||||
@@ -162,19 +219,19 @@ func readCABundleFromK8sConfigMap(namespace string, name string, key string, con
|
||||
return "", fmt.Errorf("key %s not found in configmap %s/%s", key, namespace, name)
|
||||
}
|
||||
|
||||
func validTLSCondition(message string) *v12.Condition {
|
||||
return &v12.Condition{
|
||||
func validTLSCondition(message string) *metav1.Condition {
|
||||
return &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: v12.ConditionTrue,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func invalidTLSCondition(message string) *v12.Condition {
|
||||
return &v12.Condition{
|
||||
func invalidTLSCondition(message string) *metav1.Condition {
|
||||
return &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: v12.ConditionFalse,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: message,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package tlsconfigutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -17,8 +16,10 @@ import (
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||
conciergev1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
|
||||
supervisorv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||
"go.pinniped.dev/internal/certauthority"
|
||||
"go.pinniped.dev/internal/controller/conditionsutil"
|
||||
)
|
||||
|
||||
func TestValidateTLSConfig(t *testing.T) {
|
||||
@@ -28,67 +29,90 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
base64EncodedBundle := base64.StdEncoding.EncodeToString(bundle)
|
||||
tests := []struct {
|
||||
name string
|
||||
tlsSpec *idpv1alpha1.TLSSpec
|
||||
tlsSpec *TLSSpec
|
||||
namespace string
|
||||
k8sObjects []runtime.Object
|
||||
expectedCondition *metav1.Condition
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "nil TLSSpec should generate a noTLSConfigurationMessage condition",
|
||||
tlsSpec: nil,
|
||||
expectedCondition: validTLSCondition(noTLSConfigurationMessage),
|
||||
expectError: false,
|
||||
name: "nil TLSSpec should generate a noTLSConfigurationMessage condition",
|
||||
tlsSpec: nil,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "tls is valid: " + noTLSConfigurationMessage,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty inline ca data should generate a loadedTLSConfigurationMessage condition",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{},
|
||||
expectedCondition: validTLSCondition(loadedTLSConfigurationMessage),
|
||||
expectError: false,
|
||||
name: "empty inline ca data should generate a loadedTLSConfigurationMessage condition",
|
||||
tlsSpec: &TLSSpec{},
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "tls is valid: " + noTLSConfigurationMessage,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid base64 encode ca data should generate a loadedTLSConfigurationMessage condition",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
},
|
||||
expectedCondition: validTLSCondition(loadedTLSConfigurationMessage),
|
||||
expectError: false,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "tls is valid: " + loadedTLSConfigurationMessage,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid base64 encoded non cert data should generate a invalidTLSCondition condition",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityData: "dGhpcyBpcyBzb21lIHRlc3QgZGF0YSB0aGF0IGlzIGJhc2U2NCBlbmNvZGVkIHRoYXQgaXMgbm90IGEgY2VydAo=",
|
||||
},
|
||||
expectedCondition: invalidTLSCondition(fmt.Sprintf("certificateAuthorityData is invalid: %s", ErrNoCertificates)),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls.certificateAuthorityData is invalid: " + ErrNoCertificates.Error(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-base64 encoded string as ca data should generate an invalidTLSCondition condition",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityData: "non base64 encoded string",
|
||||
},
|
||||
expectedCondition: invalidTLSCondition("certificateAuthorityData is invalid: illegal base64 data"),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls.certificateAuthorityData is invalid: illegal base64 data at input byte 3",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "supplying certificateAuthorityDataSource and certificateAuthorityData should generate an invalid condition",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "super-secret",
|
||||
Key: "ca-base64EncodedBundle",
|
||||
},
|
||||
},
|
||||
expectedCondition: invalidTLSCondition("tls spec config error: both tls.certificateAuthorityDataSource and tls.certificateAuthorityData provided."),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls is invalid: both tls.certificateAuthorityDataSource and tls.certificateAuthorityData provided",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return ca bundle from kubernetes secret",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
name: "should return ca bundle from kubernetes secret of type tls",
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "awesome-secret",
|
||||
Name: "awesome-secret-tls",
|
||||
Key: "ca-bundle",
|
||||
},
|
||||
},
|
||||
@@ -96,21 +120,86 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
k8sObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "awesome-secret",
|
||||
Name: "awesome-secret-tls",
|
||||
Namespace: "awesome-namespace",
|
||||
},
|
||||
Type: corev1.SecretTypeTLS,
|
||||
Data: map[string][]byte{
|
||||
"ca-bundle": []byte(bundle),
|
||||
"ca-bundle": bundle,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: validTLSCondition(fmt.Sprintf("tls is valid: %s", loadedTLSConfigurationMessage)),
|
||||
expectError: false,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "tls is valid: loaded TLS configuration",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return ca bundle from kubernetes secret of type opaque",
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "awesome-secret-opaque",
|
||||
Key: "ca-bundle",
|
||||
},
|
||||
},
|
||||
namespace: "awesome-namespace",
|
||||
k8sObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "awesome-secret-opaque",
|
||||
Namespace: "awesome-namespace",
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
Data: map[string][]byte{
|
||||
"ca-bundle": bundle,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
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{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "awesome-secret-ba",
|
||||
Key: "ca-bundle",
|
||||
},
|
||||
},
|
||||
namespace: "awesome-namespace",
|
||||
k8sObjects: []runtime.Object{
|
||||
&corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "awesome-secret-ba",
|
||||
Namespace: "awesome-namespace",
|
||||
},
|
||||
Type: corev1.SecretTypeBasicAuth,
|
||||
Data: map[string][]byte{
|
||||
"ca-bundle": bundle,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
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 ca bundle from kubernetes configMap",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "ConfigMap",
|
||||
Name: "awesome-cm",
|
||||
Key: "ca-bundle",
|
||||
@@ -128,13 +217,17 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: validTLSCondition(fmt.Sprintf("tls is valid: %s", loadedTLSConfigurationMessage)),
|
||||
expectError: false,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "tls is valid: loaded TLS configuration",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return invalid condition when failing to read ca bundle from kubernetes secret that does not exist",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "does-not-exist",
|
||||
Key: "does-not-matter",
|
||||
@@ -152,13 +245,17 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: invalidTLSCondition("tls.certificateAuthorityDataSource is invalid: failed to read from source"),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls.certificateAuthorityDataSource is invalid: failed to get secret awesome-namespace/does-not-exist: secret \"does-not-exist\" not found",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return invalid condition when failing to read ca bundle from kubernetes configMap that does not exist",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "ConfigMap",
|
||||
Name: "does-not-exist",
|
||||
Key: "does-not-matter",
|
||||
@@ -176,13 +273,17 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: invalidTLSCondition("tls.certificateAuthorityDataSource is invalid: failed to read from source"),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls.certificateAuthorityDataSource is invalid: failed to get configmap awesome-namespace/does-not-exist: configmap \"does-not-exist\" not found",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return invalid condition when using an invalid certificate authority data source",
|
||||
tlsSpec: &idpv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &idpv1alpha1.CABundleSource{
|
||||
tlsSpec: &TLSSpec{
|
||||
CertificateAuthorityDataSource: &caBundleSource{
|
||||
Kind: "SomethingElse",
|
||||
Name: "does-not-exist",
|
||||
Key: "does-not-matter",
|
||||
@@ -200,8 +301,12 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedCondition: invalidTLSCondition("tls.certificateAuthorityDataSource is invalid: unsupported CA bundle source"),
|
||||
expectError: true,
|
||||
expectedCondition: &metav1.Condition{
|
||||
Type: typeTLSConfigurationValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: ReasonInvalidTLSConfig,
|
||||
Message: "tls.certificateAuthorityDataSource is invalid: unsupported CA bundle source kind: SomethingElse",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -231,15 +336,8 @@ func TestValidateTLSConfig(t *testing.T) {
|
||||
close(stopConfigMapInformer)
|
||||
// now the objects from kubernetes should be sync'd into the informer cache.
|
||||
}
|
||||
actualCondition, _, _, err := ValidateTLSConfig(tt.tlsSpec, "tls", tt.namespace, secretsInformer, configMapInformer)
|
||||
if tt.expectError {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expectedCondition.Type, actualCondition.Type)
|
||||
require.Equal(t, tt.expectedCondition.Status, actualCondition.Status)
|
||||
require.Equal(t, tt.expectedCondition.Reason, actualCondition.Reason)
|
||||
}
|
||||
actualCondition, _, _, _ := ValidateTLSConfig(tt.tlsSpec, "tls", tt.namespace, secretsInformer, configMapInformer)
|
||||
require.Equal(t, tt.expectedCondition, actualCondition)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -430,3 +528,111 @@ func TestReadCABundleFromK8sConfigMap(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCommonTLSSpecForSupervisor(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 *supervisorv1alpha1.TLSSpec
|
||||
expected *TLSSpec
|
||||
}{
|
||||
{
|
||||
name: "should return nil spec when supervisorTLSSpec is nil",
|
||||
supervisorTLSSpec: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "should return tls spec with non-empty certificateAuthorityData",
|
||||
supervisorTLSSpec: &supervisorv1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
CertificateAuthorityDataSource: nil,
|
||||
},
|
||||
expected: &TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
CertificateAuthorityDataSource: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return tls spec with certificateAuthorityDataSource",
|
||||
supervisorTLSSpec: &supervisorv1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &supervisorv1alpha1.CABundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "awesome-secret",
|
||||
Key: "ca-bundle",
|
||||
},
|
||||
},
|
||||
expected: &TLSSpec{
|
||||
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 := TLSSpecForSupervisor(tt.supervisorTLSSpec)
|
||||
require.Equal(t, tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCommonTlsSpecForConcierge(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 *conciergev1alpha1.TLSSpec
|
||||
expected *TLSSpec
|
||||
}{
|
||||
{
|
||||
name: "should return nil spec when supervisorTLSSpec is nil",
|
||||
conciergeTLSSpec: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "should return tls spec with non-empty certificateAuthorityData",
|
||||
conciergeTLSSpec: &conciergev1alpha1.TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
CertificateAuthorityDataSource: nil,
|
||||
},
|
||||
expected: &TLSSpec{
|
||||
CertificateAuthorityData: base64EncodedBundle,
|
||||
CertificateAuthorityDataSource: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "should return tls spec with certificateAuthorityDataSource",
|
||||
conciergeTLSSpec: &conciergev1alpha1.TLSSpec{
|
||||
CertificateAuthorityDataSource: &conciergev1alpha1.CABundleSource{
|
||||
Kind: "Secret",
|
||||
Name: "awesome-secret",
|
||||
Key: "ca-bundle",
|
||||
},
|
||||
},
|
||||
expected: &TLSSpec{
|
||||
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)
|
||||
require.Equal(t, tt.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user