Configure name of the supervisor default TLS cert secret via ConfigMap

Signed-off-by: Andrew Keesler <akeesler@vmware.com>
This commit is contained in:
Ryan Richard 2020-10-28 11:56:50 -07:00 committed by Andrew Keesler
parent 978ecda758
commit 29e0ce5662
8 changed files with 71 additions and 16 deletions

View File

@ -113,6 +113,7 @@ func startControllers(
WithController(
supervisorconfig.NewTLSCertObserverController(
dynamicTLSCertProvider,
cfg.NamesConfig.DefaultTLSCertificateSecret,
kubeInformers.Core().V1().Secrets(),
pinnipedInformers.Config().V1alpha1().OIDCProviderConfigs(),
controllerlib.WithInformer,

View File

@ -30,6 +30,8 @@ metadata:
data:
#@yaml/text-templated-strings
pinniped.yaml: |
names:
defaultTLSCertificateSecret: (@= defaultResourceNameWithSuffix("default-tls-certificate") @)
labels: (@= json.encode(labels()).rstrip() @)
---
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":

View File

@ -8,8 +8,11 @@ package supervisor
import (
"fmt"
"io/ioutil"
"strings"
"sigs.k8s.io/yaml"
"go.pinniped.dev/internal/constable"
)
// FromPath loads an Config from a provided local file path, inserts any
@ -30,5 +33,20 @@ func FromPath(path string) (*Config, error) {
config.Labels = make(map[string]string)
}
if err := validateNames(&config.NamesConfig); err != nil {
return nil, fmt.Errorf("validate names: %w", err)
}
return &config, nil
}
func validateNames(names *NamesConfigSpec) error {
missingNames := []string{}
if names.DefaultTLSCertificateSecret == "" {
missingNames = append(missingNames, "defaultTLSCertificateSecret")
}
if len(missingNames) > 0 {
return constable.Error("missing required names: " + strings.Join(missingNames, ", "))
}
return nil
}

View File

@ -18,6 +18,7 @@ func TestFromPath(t *testing.T) {
name string
yaml string
wantConfig *Config
wantError string
}{
{
name: "Happy",
@ -26,23 +27,40 @@ func TestFromPath(t *testing.T) {
labels:
myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2
names:
defaultTLSCertificateSecret: my-secret-name
`),
wantConfig: &Config{
Labels: map[string]string{
"myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2",
},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
},
},
{
name: "When only the required fields are present, causes other fields to be defaulted",
yaml: here.Doc(`
---
names:
defaultTLSCertificateSecret: my-secret-name
`),
wantConfig: &Config{
Labels: map[string]string{},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
},
},
{
name: "Missing defaultTLSCertificateSecret name",
yaml: here.Doc(`
---
`),
wantError: "validate names: missing required names: defaultTLSCertificateSecret",
},
}
for _, test := range tests {
test := test
@ -62,8 +80,12 @@ func TestFromPath(t *testing.T) {
// Test FromPath()
config, err := FromPath(f.Name())
if test.wantError != "" {
require.EqualError(t, err, test.wantError)
} else {
require.NoError(t, err)
require.Equal(t, test.wantConfig, config)
}
})
}
}

View File

@ -6,4 +6,10 @@ package supervisor
// Config contains knobs to setup an instance of the Pinniped Supervisor.
type Config struct {
Labels map[string]string `json:"labels"`
NamesConfig NamesConfigSpec `json:"names"`
}
// NamesConfigSpec configures the names of some Kubernetes resources for the Supervisor.
type NamesConfigSpec struct {
DefaultTLSCertificateSecret string `json:"defaultTLSCertificateSecret"`
}

View File

@ -18,10 +18,9 @@ import (
"go.pinniped.dev/internal/controllerlib"
)
const SecretNameForDefaultTLSCertificate = "default-tls-certificate" //nolint:gosec // this is not a hardcoded credential
type tlsCertObserverController struct {
issuerTLSCertSetter IssuerTLSCertSetter
defaultTLSCertificateSecretName string
oidcProviderConfigInformer v1alpha1.OIDCProviderConfigInformer
secretInformer corev1informers.SecretInformer
}
@ -33,6 +32,7 @@ type IssuerTLSCertSetter interface {
func NewTLSCertObserverController(
issuerTLSCertSetter IssuerTLSCertSetter,
defaultTLSCertificateSecretName string,
secretInformer corev1informers.SecretInformer,
oidcProviderConfigInformer v1alpha1.OIDCProviderConfigInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc,
@ -42,6 +42,7 @@ func NewTLSCertObserverController(
Name: "tls-certs-observer-controller",
Syncer: &tlsCertObserverController{
issuerTLSCertSetter: issuerTLSCertSetter,
defaultTLSCertificateSecretName: defaultTLSCertificateSecretName,
oidcProviderConfigInformer: oidcProviderConfigInformer,
secretInformer: secretInformer,
},
@ -88,7 +89,7 @@ func (c *tlsCertObserverController) Sync(ctx controllerlib.Context) error {
klog.InfoS("tlsCertObserverController Sync updated the TLS cert cache", "issuerHostCount", len(issuerHostToTLSCertMap))
c.issuerTLSCertSetter.SetIssuerHostToTLSCertMap(issuerHostToTLSCertMap)
defaultCert, err := c.certFromSecret(ns, SecretNameForDefaultTLSCertificate)
defaultCert, err := c.certFromSecret(ns, c.defaultTLSCertificateSecretName)
if err != nil {
c.issuerTLSCertSetter.SetDefaultTLSCert(nil)
} else {

View File

@ -42,6 +42,7 @@ func TestTLSCertObserverControllerInformerFilters(t *testing.T) {
oidcProviderConfigInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().OIDCProviderConfigs()
_ = NewTLSCertObserverController(
nil,
"", // don't care about the secret name for this test
secretsInformer,
oidcProviderConfigInformer,
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
@ -115,7 +116,10 @@ func (f *fakeIssuerTLSCertSetter) SetDefaultTLSCert(certificate *tls.Certificate
func TestTLSCertObserverControllerSync(t *testing.T) {
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
const installedInNamespace = "some-namespace"
const (
installedInNamespace = "some-namespace"
defaultTLSSecretName = "some-default-secret-name"
)
var (
r *require.Assertions
@ -136,6 +140,7 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
// Set this at the last second to allow for injection of server override.
subject = NewTLSCertObserverController(
issuerTLSCertSetter,
defaultTLSSecretName,
kubeInformers.Core().V1().Secrets(),
pinnipedInformers.Config().V1alpha1().OIDCProviderConfigs(),
controllerlib.WithInformer,
@ -324,7 +329,7 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
r.Equal(expectedCertificate2, *actualCertificate2)
})
when("there is also a default TLS cert secret called default-tls-certificate", func() {
when("there is also a default TLS cert secret with the configured default TLS cert secret name", func() {
var (
expectedDefaultCertificate tls.Certificate
)
@ -338,7 +343,7 @@ func TestTLSCertObserverControllerSync(t *testing.T) {
expectedDefaultCertificate, err = tls.X509KeyPair(testCrt, testKey)
r.NoError(err)
defaultTLSCertSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "default-tls-certificate", Namespace: installedInNamespace},
ObjectMeta: metav1.ObjectMeta{Name: defaultTLSSecretName, Namespace: installedInNamespace},
Data: map[string][]byte{"tls.crt": testCrt, "tls.key": testKey},
}
r.NoError(kubeInformerClient.Tracker().Add(defaultTLSCertSecret))

View File

@ -135,7 +135,7 @@ func TestSupervisorTLSTerminationWithDefaultCerts(t *testing.T) {
requireEndpointHasTLSErrorBecauseCertificatesAreNotReady(t, issuerUsingIPAddress)
// Create a Secret at the special name which represents the default TLS cert.
specialNameForDefaultTLSCertSecret := "default-tls-certificate" //nolint:gosec // this is not a hardcoded credential
specialNameForDefaultTLSCertSecret := "pinniped-supervisor-default-tls-certificate" //nolint:gosec // this is not a hardcoded credential
defaultCA := createTLSCertificateSecret(ctx, t, ns, "cert-hostname-doesnt-matter", []net.IP{ip}, specialNameForDefaultTLSCertSecret, kubeClient)
// Now that the Secret exists, we should be able to access the endpoints by IP address using the CA.