mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-09 09:36:15 +00:00
Restrict which packages are aware of the keys used in Pinniped-generated certificate secrets
This commit is contained in:
committed by
Joshua Casey
parent
2e996aaecd
commit
e6a0f94f8f
@@ -164,6 +164,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
apicerts.NewAPIServiceUpdaterController(
|
||||
c.ServerInstallationInfo.Namespace,
|
||||
c.NamesConfig.ServingCertificateSecret,
|
||||
apicerts.RetrieveCAFromSecret,
|
||||
loginConciergeGroupData.APIServiceName(),
|
||||
client.Aggregation,
|
||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||
@@ -175,6 +176,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
apicerts.NewAPIServiceUpdaterController(
|
||||
c.ServerInstallationInfo.Namespace,
|
||||
c.NamesConfig.ServingCertificateSecret,
|
||||
apicerts.RetrieveCAFromSecret,
|
||||
identityConciergeGroupData.APIServiceName(),
|
||||
client.Aggregation,
|
||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||
@@ -186,6 +188,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
apicerts.NewCertsObserverController(
|
||||
c.ServerInstallationInfo.Namespace,
|
||||
c.NamesConfig.ServingCertificateSecret,
|
||||
apicerts.RetrieveCertificateFromSecret,
|
||||
c.DynamicServingCertProvider,
|
||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@@ -200,7 +203,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
c.ServingCertRenewBefore,
|
||||
apicerts.TLSCertificateChainSecretKey,
|
||||
apicerts.RetrieveCertificateFromSecret,
|
||||
plog.New(),
|
||||
),
|
||||
singletonWorker,
|
||||
@@ -293,6 +296,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
clock.RealClock{},
|
||||
impersonator.New,
|
||||
c.NamesConfig.ImpersonationSignerSecret,
|
||||
apicerts.RetrieveCAFromSecret,
|
||||
c.ImpersonationSigningCertProvider,
|
||||
plog.New(),
|
||||
c.ImpersonationProxyTokenCache,
|
||||
@@ -322,7 +326,7 @@ func PrepareControllers(c *Config) (controllerinit.RunnerBuilder, error) { //nol
|
||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
365*24*time.Hour-time.Hour, // 1 year minus 1 hour hard coded value (i.e. wait until the last moment to break the signer)
|
||||
apicerts.CACertificateSecretKey,
|
||||
apicerts.RetrieveCAFromSecret,
|
||||
plog.New(),
|
||||
),
|
||||
singletonWorker,
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
type apiServiceUpdaterController struct {
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
certificateRetriever RetrieveFromSecretFunc
|
||||
aggregatorClient aggregatorclient.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
apiServiceName string
|
||||
@@ -26,6 +27,7 @@ type apiServiceUpdaterController struct {
|
||||
func NewAPIServiceUpdaterController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
certificateRetriever RetrieveFromSecretFunc,
|
||||
apiServiceName string,
|
||||
aggregatorClient aggregatorclient.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
@@ -37,6 +39,7 @@ func NewAPIServiceUpdaterController(
|
||||
Syncer: &apiServiceUpdaterController{
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
certificateRetriever: certificateRetriever,
|
||||
aggregatorClient: aggregatorClient,
|
||||
secretInformer: secretInformer,
|
||||
apiServiceName: apiServiceName,
|
||||
@@ -63,13 +66,15 @@ func (c *apiServiceUpdaterController) Sync(ctx controllerlib.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
caCertPEM, _ := c.certificateRetriever(certSecret)
|
||||
|
||||
// Update the APIService to give it the new CA bundle.
|
||||
if err := UpdateAPIService(
|
||||
ctx.Context,
|
||||
c.aggregatorClient,
|
||||
c.apiServiceName,
|
||||
c.namespace,
|
||||
certSecret.Data[CACertificateSecretKey],
|
||||
caCertPEM,
|
||||
); err != nil {
|
||||
return fmt.Errorf("could not update the API service: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
@@ -42,6 +42,9 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||
_ = NewAPIServiceUpdaterController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
func(secret *corev1.Secret) ([]byte, []byte) {
|
||||
return secret.Data["some-key-for-ca-certificate"], []byte("this value does not matter")
|
||||
},
|
||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||
nil,
|
||||
secretsInformer,
|
||||
@@ -122,6 +125,9 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
subject = NewAPIServiceUpdaterController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
func(secret *corev1.Secret) ([]byte, []byte) {
|
||||
return secret.Data["some-key-for-ca-certificate"], []byte("this value does not matter")
|
||||
},
|
||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||
aggregatorAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
@@ -185,9 +191,9 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"caCertificate": []byte("fake CA cert"),
|
||||
"tlsPrivateKey": []byte("fake private key"),
|
||||
"tlsCertificateChain": []byte("fake cert chain"),
|
||||
"some-key-for-ca-certificate": []byte("fake CA cert"),
|
||||
"serving-cert-key-EXTRA": []byte("fake cert chain"),
|
||||
"private-key-EXTRA": []byte("fake private key"),
|
||||
},
|
||||
}
|
||||
err := kubeInformerClient.Tracker().Add(apiServingCertSecret)
|
||||
|
||||
@@ -19,11 +19,17 @@ import (
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
// The following key names are unexported, to prevent a leaky abstraction.
|
||||
// Even the string literals should only be used in a very limited set of places:
|
||||
// - The unit tests for this file
|
||||
// - The unit tests for retrieve_from_secret.go
|
||||
// - Integration tests
|
||||
// Comment must end in a period, so here's a period: .
|
||||
const (
|
||||
CACertificateSecretKey = "caCertificate"
|
||||
CACertificatePrivateKeySecretKey = "caCertificatePrivateKey"
|
||||
caCertificateSecretKey = "caCertificate"
|
||||
caCertificatePrivateKeySecretKey = "caCertificatePrivateKey"
|
||||
tlsCertificateChainSecretKey = "tlsCertificateChain"
|
||||
tlsPrivateKeySecretKey = "tlsPrivateKey"
|
||||
TLSCertificateChainSecretKey = "tlsCertificateChain"
|
||||
)
|
||||
|
||||
type certsCreatorController struct {
|
||||
@@ -111,8 +117,8 @@ func (c *certsCreatorController) Sync(ctx controllerlib.Context) error {
|
||||
Labels: c.certsSecretLabels,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
CACertificateSecretKey: ca.Bundle(),
|
||||
CACertificatePrivateKeySecretKey: caPrivateKeyPEM,
|
||||
caCertificateSecretKey: ca.Bundle(),
|
||||
caCertificatePrivateKeySecretKey: caPrivateKeyPEM,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -132,7 +138,7 @@ func (c *certsCreatorController) Sync(ctx controllerlib.Context) error {
|
||||
}
|
||||
|
||||
secret.Data[tlsPrivateKeySecretKey] = tlsPrivateKeyPEM
|
||||
secret.Data[TLSCertificateChainSecretKey] = tlsCertChainPEM
|
||||
secret.Data[tlsCertificateChainSecretKey] = tlsCertChainPEM
|
||||
}
|
||||
|
||||
_, err = c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx.Context, &secret, metav1.CreateOptions{})
|
||||
|
||||
@@ -31,7 +31,7 @@ type certsExpirerController struct {
|
||||
// this controller will start to try to rotate it.
|
||||
renewBefore time.Duration
|
||||
|
||||
secretKey string
|
||||
certificateRetriever RetrieveFromSecretFunc
|
||||
|
||||
logger plog.Logger
|
||||
}
|
||||
@@ -46,7 +46,7 @@ func NewCertsExpirerController(
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
renewBefore time.Duration,
|
||||
secretKey string,
|
||||
certificateRetriever RetrieveFromSecretFunc,
|
||||
logger plog.Logger,
|
||||
) controllerlib.Controller {
|
||||
const name = "certs-expirer-controller"
|
||||
@@ -59,7 +59,7 @@ func NewCertsExpirerController(
|
||||
k8sClient: k8sClient,
|
||||
secretInformer: secretInformer,
|
||||
renewBefore: renewBefore,
|
||||
secretKey: secretKey,
|
||||
certificateRetriever: certificateRetriever,
|
||||
logger: logger.WithName(name),
|
||||
},
|
||||
},
|
||||
@@ -83,7 +83,6 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
||||
"controller", ctx.Name,
|
||||
"namespace", c.namespace,
|
||||
"name", c.certsSecretResourceName,
|
||||
"key", c.secretKey,
|
||||
"renewBefore", c.renewBefore.String(),
|
||||
)
|
||||
return nil
|
||||
@@ -91,7 +90,7 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
||||
|
||||
notBefore, notAfter, err := c.getCertBounds(secret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get cert bounds for secret %q with key %q: %w", secret.Name, c.secretKey, err)
|
||||
return fmt.Errorf("failed to get cert bounds for secret %q: %w", secret.Name, err)
|
||||
}
|
||||
|
||||
certAge := time.Since(notBefore)
|
||||
@@ -100,7 +99,6 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
||||
"controller", ctx.Name,
|
||||
"namespace", c.namespace,
|
||||
"name", c.certsSecretResourceName,
|
||||
"key", c.secretKey,
|
||||
"renewBefore", c.renewBefore.String(),
|
||||
"notBefore", notBefore.String(),
|
||||
"notAfter", notAfter.String(),
|
||||
@@ -130,7 +128,7 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
||||
// getCertBounds returns the NotBefore and NotAfter fields of the TLS
|
||||
// certificate in the provided secret, or an error.
|
||||
func (c *certsExpirerController) getCertBounds(secret *corev1.Secret) (time.Time, time.Time, error) {
|
||||
certPEM := secret.Data[c.secretKey]
|
||||
certPEM, _ := c.certificateRetriever(secret)
|
||||
if certPEM == nil {
|
||||
return time.Time{}, time.Time{}, constable.Error("failed to find certificate")
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
nil, // k8sClient, not needed
|
||||
secretsInformer,
|
||||
withInformer.WithInformer,
|
||||
0, // renewBefore, not needed
|
||||
"", // not needed
|
||||
0, // renewBefore, not needed
|
||||
nil, // not needed
|
||||
logger,
|
||||
)
|
||||
|
||||
@@ -134,14 +134,14 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "secret does not exist",
|
||||
wantLog: `{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"certs-expirer-controller","caller":"apicerts/certs_expirer.go:<line>$apicerts.(*certsExpirerController).Sync","message":"secret does not exist yet or was deleted","controller":"","namespace":"some-namespace","name":"some-resource-name","key":"some-awesome-key","renewBefore":"0s"}`,
|
||||
wantLog: `{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"certs-expirer-controller","caller":"apicerts/certs_expirer.go:<line>$apicerts.(*certsExpirerController).Sync","message":"secret does not exist yet or was deleted","controller":"","namespace":"some-namespace","name":"some-resource-name","renewBefore":"0s"}`,
|
||||
wantDelete: false,
|
||||
},
|
||||
{
|
||||
name: "secret missing key",
|
||||
fillSecretData: func(t *testing.T, m map[string][]byte) {},
|
||||
wantDelete: false,
|
||||
wantError: `failed to get cert bounds for secret "some-resource-name" with key "some-awesome-key": failed to find certificate`,
|
||||
wantError: `failed to get cert bounds for secret "some-resource-name": failed to find certificate`,
|
||||
},
|
||||
{
|
||||
name: "lifetime below threshold",
|
||||
@@ -214,7 +214,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
},
|
||||
wantDelete: false,
|
||||
wantError: `failed to get cert bounds for secret "some-resource-name" with key "some-awesome-key": failed to decode certificate PEM`,
|
||||
wantError: `failed to get cert bounds for secret "some-resource-name": failed to decode certificate PEM`,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
@@ -265,7 +265,9 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
test.renewBefore,
|
||||
fakeTestKey,
|
||||
func(secret *corev1.Secret) ([]byte, []byte) {
|
||||
return secret.Data[fakeTestKey], nil
|
||||
},
|
||||
logger,
|
||||
)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
type certsObserverController struct {
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
certificateRetriever RetrieveFromSecretFunc
|
||||
dynamicCertProvider dynamiccert.Private
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
@@ -25,6 +26,7 @@ type certsObserverController struct {
|
||||
func NewCertsObserverController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
certificateRetriever RetrieveFromSecretFunc,
|
||||
dynamicCertProvider dynamiccert.Private,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
@@ -35,6 +37,7 @@ func NewCertsObserverController(
|
||||
Syncer: &certsObserverController{
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
certificateRetriever: certificateRetriever,
|
||||
dynamicCertProvider: dynamicCertProvider,
|
||||
secretInformer: secretInformer,
|
||||
},
|
||||
@@ -62,7 +65,7 @@ func (c *certsObserverController) Sync(_ controllerlib.Context) error {
|
||||
}
|
||||
|
||||
// Mutate the in-memory cert provider to update with the latest cert values.
|
||||
if err := c.dynamicCertProvider.SetCertKeyContent(certSecret.Data[TLSCertificateChainSecretKey], certSecret.Data[tlsPrivateKeySecretKey]); err != nil {
|
||||
if err := c.dynamicCertProvider.SetCertKeyContent(c.certificateRetriever(certSecret)); err != nil {
|
||||
return fmt.Errorf("failed to set serving cert/key content from secret %s/%s: %w", c.namespace, c.certsSecretResourceName, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ package apicerts
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -23,6 +24,9 @@ import (
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
//go:embed testdata/private_key_prefix.txt
|
||||
var privateKeyPrefix string
|
||||
|
||||
func TestObserverControllerInformerFilters(t *testing.T) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
@@ -40,6 +44,7 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
nil,
|
||||
nil,
|
||||
secretsInformer,
|
||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||
)
|
||||
@@ -119,6 +124,9 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
subject = NewCertsObserverController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
func(secret *corev1.Secret) ([]byte, []byte) {
|
||||
return secret.Data["some-key-for-certificate"], secret.Data["some-key-for-private-key"]
|
||||
},
|
||||
dynamicCertProvider,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@@ -202,7 +210,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
ca, err := certauthority.Load(string(caCrt), string(caKey))
|
||||
require.NoError(t, err)
|
||||
|
||||
pem, err := ca.IssueServerCertPEM(nil, nil, time.Hour)
|
||||
servingCert, err := ca.IssueServerCertPEM(nil, nil, time.Hour)
|
||||
require.NoError(t, err)
|
||||
|
||||
apiServingCertSecret := &corev1.Secret{
|
||||
@@ -211,9 +219,9 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"caCertificate": []byte("fake cert"),
|
||||
"tlsPrivateKey": pem.KeyPEM,
|
||||
"tlsCertificateChain": pem.CertPEM,
|
||||
"some-pretend-ca-EXTRA": []byte("fake cert"),
|
||||
"some-key-for-certificate": servingCert.CertPEM,
|
||||
"some-key-for-private-key": servingCert.KeyPEM,
|
||||
},
|
||||
}
|
||||
err = kubeInformerClient.Tracker().Add(apiServingCertSecret)
|
||||
@@ -234,7 +242,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
|
||||
actualCertChain, actualKey = dynamicCertProvider.CurrentCertKeyContent()
|
||||
r.True(strings.HasPrefix(string(actualCertChain), `-----BEGIN CERTIFICATE-----`), "not a cert:\n%s", string(actualCertChain))
|
||||
r.True(strings.HasPrefix(string(actualKey), `-----BEGIN PRIVATE KEY-----`), "not a key:\n%s", string(actualKey))
|
||||
r.True(strings.HasPrefix(string(actualKey), privateKeyPrefix), "not a key:\n%s", string(actualKey))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2024 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
type RetrieveFromSecretFunc func(secret *corev1.Secret) ([]byte, []byte)
|
||||
|
||||
func RetrieveCAFromSecret(secret *corev1.Secret) ([]byte, []byte) {
|
||||
if secret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return secret.Data[caCertificateSecretKey], secret.Data[caCertificatePrivateKeySecretKey]
|
||||
}
|
||||
|
||||
func RetrieveCertificateFromSecret(secret *corev1.Secret) ([]byte, []byte) {
|
||||
if secret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return secret.Data[tlsCertificateChainSecretKey], secret.Data[tlsPrivateKeySecretKey]
|
||||
}
|
||||
|
||||
// Ensure matching function signature at compile time.
|
||||
var _ RetrieveFromSecretFunc = RetrieveCAFromSecret
|
||||
var _ RetrieveFromSecretFunc = RetrieveCertificateFromSecret
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright 2024 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestRetrieveCAFromSecret(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
secret *corev1.Secret
|
||||
wantCertificate []byte
|
||||
wantPrivateKey []byte
|
||||
}{
|
||||
{
|
||||
name: "nil input returns empty",
|
||||
secret: nil,
|
||||
},
|
||||
{
|
||||
name: "empty secret returns empty",
|
||||
secret: &corev1.Secret{},
|
||||
},
|
||||
{
|
||||
name: "populated secret returns values",
|
||||
secret: &corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
"caCertificate": []byte("foo"),
|
||||
"caCertificatePrivateKey": []byte("bar"),
|
||||
"baz": []byte("quz"),
|
||||
},
|
||||
},
|
||||
wantCertificate: []byte("foo"),
|
||||
wantPrivateKey: []byte("bar"),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actualCert, actualKey := RetrieveCAFromSecret(test.secret)
|
||||
|
||||
require.Equal(t, test.wantCertificate, actualCert)
|
||||
require.Equal(t, test.wantPrivateKey, actualKey)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveCertificateFromSecret(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
secret *corev1.Secret
|
||||
wantCertificate []byte
|
||||
wantPrivateKey []byte
|
||||
}{
|
||||
{
|
||||
name: "nil input returns empty",
|
||||
secret: nil,
|
||||
},
|
||||
{
|
||||
name: "empty secret returns empty",
|
||||
secret: &corev1.Secret{},
|
||||
},
|
||||
{
|
||||
name: "populated secret returns values",
|
||||
secret: &corev1.Secret{
|
||||
Data: map[string][]byte{
|
||||
"tlsCertificateChain": []byte("foo"),
|
||||
"tlsPrivateKey": []byte("bar"),
|
||||
"baz": []byte("quz"),
|
||||
},
|
||||
},
|
||||
wantCertificate: []byte("foo"),
|
||||
wantPrivateKey: []byte("bar"),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actualCert, actualKey := RetrieveCertificateFromSecret(test.secret)
|
||||
|
||||
require.Equal(t, test.wantCertificate, actualCert)
|
||||
require.Equal(t, test.wantPrivateKey, actualKey)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@ type impersonatorConfigController struct {
|
||||
tlsSecretName string
|
||||
caSecretName string
|
||||
impersonationSignerSecretName string
|
||||
impersonationSignerCertRetriever apicerts.RetrieveFromSecretFunc
|
||||
|
||||
k8sClient kubernetes.Interface
|
||||
pinnipedAPIClient conciergeclientset.Interface
|
||||
@@ -107,6 +108,7 @@ func NewImpersonatorConfigController(
|
||||
clock clock.Clock,
|
||||
impersonatorFunc impersonator.FactoryFunc,
|
||||
impersonationSignerSecretName string,
|
||||
impersonationSignerCertRetriever apicerts.RetrieveFromSecretFunc,
|
||||
impersonationSigningCertProvider dynamiccert.Provider,
|
||||
log plog.Logger,
|
||||
impersonationProxyTokenCache tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
@@ -125,6 +127,7 @@ func NewImpersonatorConfigController(
|
||||
tlsSecretName: tlsSecretName,
|
||||
caSecretName: caSecretName,
|
||||
impersonationSignerSecretName: impersonationSignerSecretName,
|
||||
impersonationSignerCertRetriever: impersonationSignerCertRetriever,
|
||||
k8sClient: k8sClient,
|
||||
pinnipedAPIClient: pinnipedAPIClient,
|
||||
credIssuerInformer: credentialIssuerInformer,
|
||||
@@ -1116,8 +1119,7 @@ func (c *impersonatorConfigController) loadSignerCA() error {
|
||||
return fmt.Errorf("could not load the impersonator's credential signing secret: %w", err)
|
||||
}
|
||||
|
||||
certPEM := signingCertSecret.Data[apicerts.CACertificateSecretKey]
|
||||
keyPEM := signingCertSecret.Data[apicerts.CACertificatePrivateKeySecretKey]
|
||||
certPEM, keyPEM := c.impersonationSignerCertRetriever(signingCertSecret)
|
||||
|
||||
if err := c.impersonationSigningCertProvider.SetCertKeyContent(certPEM, keyPEM); err != nil {
|
||||
return fmt.Errorf("could not set the impersonator's credential signing secret: %w", err)
|
||||
|
||||
@@ -39,7 +39,6 @@ import (
|
||||
conciergefake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
|
||||
conciergeinformers "go.pinniped.dev/generated/latest/client/concierge/informers/externalversions"
|
||||
"go.pinniped.dev/internal/certauthority"
|
||||
"go.pinniped.dev/internal/controller/apicerts"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/dynamiccert"
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
@@ -95,6 +94,7 @@ func TestImpersonatorConfigControllerOptions(t *testing.T) {
|
||||
nil,
|
||||
caSignerName,
|
||||
nil,
|
||||
nil,
|
||||
logger,
|
||||
nil,
|
||||
)
|
||||
@@ -588,6 +588,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
clocktesting.NewFakeClock(frozenNow),
|
||||
impersonatorFunc,
|
||||
mTLSClientCertCASecretName,
|
||||
func(secret *corev1.Secret) ([]byte, []byte) {
|
||||
return secret.Data["some-key-for-ca-certificate"], secret.Data["some-key-for-ca-private-key"]
|
||||
},
|
||||
mTLSClientCertProvider,
|
||||
logger,
|
||||
fakeExpiringSingletonTokenCacheGet,
|
||||
@@ -675,8 +678,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
|
||||
var newSigningKeySecret = func(resourceName string, certPEM, keyPEM []byte) *corev1.Secret {
|
||||
return newSecretWithData(resourceName, map[string][]byte{
|
||||
apicerts.CACertificateSecretKey: certPEM,
|
||||
apicerts.CACertificatePrivateKeySecretKey: keyPEM,
|
||||
"some-key-for-ca-certificate": certPEM,
|
||||
"some-key-for-ca-private-key": keyPEM,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -4095,7 +4098,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
|
||||
when("the cert is invalid", func() {
|
||||
it.Before(func() {
|
||||
mTLSClientCertCASecret.Data[apicerts.CACertificateSecretKey] = []byte("not a valid PEM formatted cert")
|
||||
mTLSClientCertCASecret.Data["some-key-for-ca-certificate"] = []byte("not a valid PEM formatted cert")
|
||||
addSecretToTrackers(mTLSClientCertCASecret, kubeInformerClient)
|
||||
})
|
||||
|
||||
|
||||
@@ -313,6 +313,7 @@ func startControllers(
|
||||
apicerts.NewCertsObserverController(
|
||||
namespace,
|
||||
certsSecretResourceName,
|
||||
apicerts.RetrieveCertificateFromSecret,
|
||||
dynamicCertProvider,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
|
||||
@@ -367,6 +367,7 @@ func prepareControllers(
|
||||
apicerts.NewAPIServiceUpdaterController(
|
||||
podInfo.Namespace,
|
||||
certificateName,
|
||||
apicerts.RetrieveCAFromSecret,
|
||||
clientSecretSupervisorGroupData.APIServiceName(),
|
||||
aggregatorClient,
|
||||
secretInformer,
|
||||
@@ -378,6 +379,7 @@ func prepareControllers(
|
||||
apicerts.NewCertsObserverController(
|
||||
podInfo.Namespace,
|
||||
certificateName,
|
||||
apicerts.RetrieveCertificateFromSecret,
|
||||
dynamicServingCertProvider,
|
||||
secretInformer,
|
||||
controllerlib.WithInformer,
|
||||
@@ -392,7 +394,7 @@ func prepareControllers(
|
||||
secretInformer,
|
||||
controllerlib.WithInformer,
|
||||
9*30*24*time.Hour, // about 9 months
|
||||
apicerts.TLSCertificateChainSecretKey,
|
||||
apicerts.RetrieveCertificateFromSecret,
|
||||
plog.New(),
|
||||
),
|
||||
singletonWorker,
|
||||
|
||||
Reference in New Issue
Block a user