Rename many of resources that are created in Kubernetes by Pinniped
New resource naming conventions: - Do not repeat the Kind in the name, e.g. do not call it foo-cluster-role-binding, just call it foo - Names will generally start with a prefix to identify our component, so when a user lists all objects of that kind, they can tell to which component it is related, e.g. `kubectl get configmaps` would list one named "pinniped-config" - It should be possible for an operator to make the word "pinniped" mostly disappear if they choose, by specifying the app_name in values.yaml, to the extent that is practical (but not from APIService names because those are hardcoded in golang) - Each role/clusterrole and its corresponding binding have the same name - Pinniped resource names that must be known by the server golang code are passed to the code at run time via ConfigMap, rather than hardcoded in the golang code. This also allows them to be prepended with the app_name from values.yaml while creating the ConfigMap. - Since the CLI `get-kubeconfig` command cannot guess the name of the CredentialIssuerConfig resource in advance anymore, it lists all CredentialIssuerConfig in the app's namespace and returns an error if there is not exactly one found, and then uses that one regardless of its name
This commit is contained in:
parent
24f962f1b8
commit
80a520390b
@ -301,12 +301,15 @@ func startControllers(
|
|||||||
) {
|
) {
|
||||||
aVeryLongTime := time.Hour * 24 * 365 * 100
|
aVeryLongTime := time.Hour * 24 * 365 * 100
|
||||||
|
|
||||||
|
const certsSecretResourceName = "local-user-authenticator-tls-serving-certificate"
|
||||||
|
|
||||||
// Create controller manager.
|
// Create controller manager.
|
||||||
controllerManager := controllerlib.
|
controllerManager := controllerlib.
|
||||||
NewManager().
|
NewManager().
|
||||||
WithController(
|
WithController(
|
||||||
apicerts.NewCertsManagerController(
|
apicerts.NewCertsManagerController(
|
||||||
namespace,
|
namespace,
|
||||||
|
certsSecretResourceName,
|
||||||
kubeClient,
|
kubeClient,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -320,6 +323,7 @@ func startControllers(
|
|||||||
WithController(
|
WithController(
|
||||||
apicerts.NewCertsObserverController(
|
apicerts.NewCertsObserverController(
|
||||||
namespace,
|
namespace,
|
||||||
|
certsSecretResourceName,
|
||||||
dynamicCertProvider,
|
dynamicCertProvider,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -367,7 +371,7 @@ func run() error {
|
|||||||
startControllers(ctx, dynamicCertProvider, kubeClient, kubeInformers)
|
startControllers(ctx, dynamicCertProvider, kubeClient, kubeInformers)
|
||||||
klog.InfoS("controllers are ready")
|
klog.InfoS("controllers are ready")
|
||||||
|
|
||||||
//nolint: gosec
|
//nolint: gosec // Intentionally binding to all network interfaces.
|
||||||
l, err := net.Listen("tcp", ":443")
|
l, err := net.Listen("tcp", ":443")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot create listener: %w", err)
|
return fmt.Errorf("cannot create listener: %w", err)
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/vmware-tanzu/pinniped/generated/1.19/apis/crdpinniped/v1alpha1"
|
"github.com/vmware-tanzu/pinniped/generated/1.19/apis/crdpinniped/v1alpha1"
|
||||||
pinnipedclientset "github.com/vmware-tanzu/pinniped/generated/1.19/client/clientset/versioned"
|
pinnipedclientset "github.com/vmware-tanzu/pinniped/generated/1.19/client/clientset/versioned"
|
||||||
"github.com/vmware-tanzu/pinniped/internal/constable"
|
"github.com/vmware-tanzu/pinniped/internal/constable"
|
||||||
"github.com/vmware-tanzu/pinniped/internal/controller/issuerconfig"
|
|
||||||
"github.com/vmware-tanzu/pinniped/internal/here"
|
"github.com/vmware-tanzu/pinniped/internal/here"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -239,20 +237,27 @@ func fetchPinnipedCredentialIssuerConfig(clientConfig clientcmd.ClientConfig, ku
|
|||||||
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
|
|
||||||
credentialIssuerConfig, err := clientset.CrdV1alpha1().CredentialIssuerConfigs(pinnipedInstallationNamespace).Get(ctx, issuerconfig.ConfigName, metav1.GetOptions{})
|
credentialIssuerConfigs, err := clientset.CrdV1alpha1().CredentialIssuerConfigs(pinnipedInstallationNamespace).List(ctx, metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if apierrors.IsNotFound(err) {
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(credentialIssuerConfigs.Items) == 0 {
|
||||||
return nil, constable.Error(fmt.Sprintf(
|
return nil, constable.Error(fmt.Sprintf(
|
||||||
`CredentialIssuerConfig "%s" was not found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
|
`No CredentialIssuerConfig was found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
|
||||||
issuerconfig.ConfigName,
|
|
||||||
pinnipedInstallationNamespace,
|
pinnipedInstallationNamespace,
|
||||||
pinnipedInstallationNamespace,
|
pinnipedInstallationNamespace,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
return nil, err
|
|
||||||
|
if len(credentialIssuerConfigs.Items) > 1 {
|
||||||
|
return nil, constable.Error(fmt.Sprintf(
|
||||||
|
`More than one CredentialIssuerConfig was found in namespace "%s"`,
|
||||||
|
pinnipedInstallationNamespace,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
return credentialIssuerConfig, nil
|
return &credentialIssuerConfigs.Items[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClientConfig(kubeconfigPathOverride string, currentContextName string) clientcmd.ClientConfig {
|
func newClientConfig(kubeconfigPathOverride string, currentContextName string) clientcmd.ClientConfig {
|
||||||
|
@ -200,8 +200,17 @@ func TestNewGetKubeConfigCmd(t *testing.T) {
|
|||||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint: unparam
|
func expectedKubeconfigYAML(
|
||||||
func expectedKubeconfigYAML(clusterCAData, clusterServer, command, token, pinnipedEndpoint, pinnipedCABundle, namespace string) string {
|
clusterCAData,
|
||||||
|
clusterServer,
|
||||||
|
command,
|
||||||
|
// nolint: unparam // Pass in the token even if it is always the same in practice
|
||||||
|
token,
|
||||||
|
pinnipedEndpoint,
|
||||||
|
pinnipedCABundle,
|
||||||
|
// nolint: unparam // Pass in the namespace even if it is always the same in practice
|
||||||
|
namespace string,
|
||||||
|
) string {
|
||||||
return here.Docf(`
|
return here.Docf(`
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
clusters:
|
clusters:
|
||||||
@ -240,15 +249,21 @@ func expectedKubeconfigYAML(clusterCAData, clusterServer, command, token, pinnip
|
|||||||
`, clusterCAData, clusterServer, command, pinnipedEndpoint, pinnipedCABundle, namespace, token)
|
`, clusterCAData, clusterServer, command, pinnipedEndpoint, pinnipedCABundle, namespace, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCredentialIssuerConfig(server, certificateAuthorityData string) *crdpinnipedv1alpha1.CredentialIssuerConfig {
|
func newCredentialIssuerConfig(
|
||||||
|
name,
|
||||||
|
//nolint: unparam // Pass in the namespace even if it is always the same in practice
|
||||||
|
namespace,
|
||||||
|
server,
|
||||||
|
certificateAuthorityData string,
|
||||||
|
) *crdpinnipedv1alpha1.CredentialIssuerConfig {
|
||||||
return &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
return &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: "CredentialIssuerConfig",
|
Kind: "CredentialIssuerConfig",
|
||||||
APIVersion: crdpinnipedv1alpha1.SchemeGroupVersion.String(),
|
APIVersion: crdpinnipedv1alpha1.SchemeGroupVersion.String(),
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "pinniped-config",
|
Name: name,
|
||||||
Namespace: "some-namespace",
|
Namespace: namespace,
|
||||||
},
|
},
|
||||||
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
||||||
KubeConfigInfo: &crdpinnipedv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
KubeConfigInfo: &crdpinnipedv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
||||||
@ -266,6 +281,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
var warningsBuffer *bytes.Buffer
|
var warningsBuffer *bytes.Buffer
|
||||||
var fullPathToSelf string
|
var fullPathToSelf string
|
||||||
var pinnipedClient *pinnipedfake.Clientset
|
var pinnipedClient *pinnipedfake.Clientset
|
||||||
|
const installationNamespace = "some-namespace"
|
||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
r = require.New(t)
|
r = require.New(t)
|
||||||
@ -283,7 +299,12 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
when("the CredentialIssuerConfig is found on the cluster with a configuration that matches the existing kubeconfig", func() {
|
when("the CredentialIssuerConfig is found on the cluster with a configuration that matches the existing kubeconfig", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
r.NoError(pinnipedClient.Tracker().Add(
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
newCredentialIssuerConfig("https://fake-server-url-value", "fake-certificate-authority-data-value"),
|
newCredentialIssuerConfig(
|
||||||
|
"some-cic-name",
|
||||||
|
installationNamespace,
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -294,7 +315,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -313,7 +334,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"https://fake-server-url-value",
|
"https://fake-server-url-value",
|
||||||
"fake-certificate-authority-data-value",
|
"fake-certificate-authority-data-value",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
), outputBuffer.String())
|
), outputBuffer.String())
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -327,10 +348,12 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
Resource: "credentialissuerconfigs",
|
Resource: "credentialissuerconfigs",
|
||||||
},
|
},
|
||||||
newCredentialIssuerConfig(
|
newCredentialIssuerConfig(
|
||||||
|
"some-cic-name",
|
||||||
|
installationNamespace,
|
||||||
"https://some-other-fake-server-url-value",
|
"https://some-other-fake-server-url-value",
|
||||||
"some-other-fake-certificate-authority-data-value",
|
"some-other-fake-certificate-authority-data-value",
|
||||||
),
|
),
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -342,7 +365,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"some-other-context",
|
"some-other-context",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://some-other-fake-server-url-value", restConfig.Host)
|
r.Equal("https://some-other-fake-server-url-value", restConfig.Host)
|
||||||
@ -361,7 +384,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"https://some-other-fake-server-url-value",
|
"https://some-other-fake-server-url-value",
|
||||||
"some-other-fake-certificate-authority-data-value",
|
"some-other-fake-certificate-authority-data-value",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
), outputBuffer.String())
|
), outputBuffer.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -373,7 +396,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"this-context-name-does-not-exist-in-kubeconfig.yaml",
|
"this-context-name-does-not-exist-in-kubeconfig.yaml",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
)
|
)
|
||||||
r.EqualError(err, `context "this-context-name-does-not-exist-in-kubeconfig.yaml" does not exist`)
|
r.EqualError(err, `context "this-context-name-does-not-exist-in-kubeconfig.yaml" does not exist`)
|
||||||
@ -390,7 +413,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"",
|
"",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
)
|
)
|
||||||
r.EqualError(err, "--token flag value cannot be empty")
|
r.EqualError(err, "--token flag value cannot be empty")
|
||||||
@ -406,7 +429,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/this-file-does-not-exist.yaml",
|
"./testdata/this-file-does-not-exist.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||||
)
|
)
|
||||||
r.EqualError(err, "stat ./testdata/this-file-does-not-exist.yaml: no such file or directory")
|
r.EqualError(err, "stat ./testdata/this-file-does-not-exist.yaml: no such file or directory")
|
||||||
@ -434,7 +457,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -453,7 +476,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"https://fake-server-url-value",
|
"https://fake-server-url-value",
|
||||||
"fake-certificate-authority-data-value",
|
"fake-certificate-authority-data-value",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
), outputBuffer.String())
|
), outputBuffer.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -474,7 +497,39 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
return pinnipedClient, nil
|
return pinnipedClient, nil
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
r.EqualError(err, `CredentialIssuerConfig "pinniped-config" was not found in namespace "this-is-the-wrong-namespace". Is Pinniped installed on this cluster in namespace "this-is-the-wrong-namespace"?`)
|
r.EqualError(err, `No CredentialIssuerConfig was found in namespace "this-is-the-wrong-namespace". Is Pinniped installed on this cluster in namespace "this-is-the-wrong-namespace"?`)
|
||||||
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
when("there is more than one CredentialIssuerConfig is found on the cluster", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
|
newCredentialIssuerConfig(
|
||||||
|
"another-cic-name",
|
||||||
|
installationNamespace,
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns an error", func() {
|
||||||
|
kubeClientCreatorFuncWasCalled := false
|
||||||
|
err := getKubeConfig(outputBuffer,
|
||||||
|
warningsBuffer,
|
||||||
|
"some-token",
|
||||||
|
"./testdata/kubeconfig.yaml",
|
||||||
|
"",
|
||||||
|
installationNamespace,
|
||||||
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
|
kubeClientCreatorFuncWasCalled = true
|
||||||
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
|
r.Equal("fake-certificate-authority-data-value", string(restConfig.CAData))
|
||||||
|
return pinnipedClient, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
r.EqualError(err, `More than one CredentialIssuerConfig was found in namespace "some-namespace"`)
|
||||||
r.True(kubeClientCreatorFuncWasCalled)
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -484,7 +539,12 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
when("the Server doesn't match", func() {
|
when("the Server doesn't match", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
r.NoError(pinnipedClient.Tracker().Add(
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
newCredentialIssuerConfig("non-matching-pinniped-server-url", "fake-certificate-authority-data-value"),
|
newCredentialIssuerConfig(
|
||||||
|
"some-cic-name",
|
||||||
|
installationNamespace,
|
||||||
|
"non-matching-pinniped-server-url",
|
||||||
|
"fake-certificate-authority-data-value",
|
||||||
|
),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -495,7 +555,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -517,7 +577,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"https://fake-server-url-value",
|
"https://fake-server-url-value",
|
||||||
"fake-certificate-authority-data-value",
|
"fake-certificate-authority-data-value",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
), outputBuffer.String())
|
), outputBuffer.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -525,7 +585,12 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
when("the CA doesn't match", func() {
|
when("the CA doesn't match", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
r.NoError(pinnipedClient.Tracker().Add(
|
r.NoError(pinnipedClient.Tracker().Add(
|
||||||
newCredentialIssuerConfig("https://fake-server-url-value", "non-matching-certificate-authority-data-value"),
|
newCredentialIssuerConfig(
|
||||||
|
"some-cic-name",
|
||||||
|
installationNamespace,
|
||||||
|
"https://fake-server-url-value",
|
||||||
|
"non-matching-certificate-authority-data-value",
|
||||||
|
),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -536,7 +601,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -558,7 +623,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"https://fake-server-url-value",
|
"https://fake-server-url-value",
|
||||||
"fake-certificate-authority-data-value",
|
"fake-certificate-authority-data-value",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
), outputBuffer.String())
|
), outputBuffer.String())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -574,7 +639,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "pinniped-config",
|
Name: "pinniped-config",
|
||||||
Namespace: "some-namespace",
|
Namespace: installationNamespace,
|
||||||
},
|
},
|
||||||
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{},
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{},
|
||||||
},
|
},
|
||||||
@ -588,7 +653,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -611,7 +676,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
kubeClientCreatorFuncWasCalled = true
|
kubeClientCreatorFuncWasCalled = true
|
||||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||||
@ -620,7 +685,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
r.True(kubeClientCreatorFuncWasCalled)
|
r.True(kubeClientCreatorFuncWasCalled)
|
||||||
r.EqualError(err, `CredentialIssuerConfig "pinniped-config" was not found in namespace "some-namespace". Is Pinniped installed on this cluster in namespace "some-namespace"?`)
|
r.EqualError(err, `No CredentialIssuerConfig was found in namespace "some-namespace". Is Pinniped installed on this cluster in namespace "some-namespace"?`)
|
||||||
r.Empty(warningsBuffer.String())
|
r.Empty(warningsBuffer.String())
|
||||||
r.Empty(outputBuffer.String())
|
r.Empty(outputBuffer.String())
|
||||||
})
|
})
|
||||||
@ -633,7 +698,7 @@ func TestGetKubeConfig(t *testing.T) {
|
|||||||
"some-token",
|
"some-token",
|
||||||
"./testdata/kubeconfig.yaml",
|
"./testdata/kubeconfig.yaml",
|
||||||
"",
|
"",
|
||||||
"some-namespace",
|
installationNamespace,
|
||||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||||
return nil, fmt.Errorf("some error getting CredentialIssuerConfig")
|
return nil, fmt.Errorf("some error getting CredentialIssuerConfig")
|
||||||
},
|
},
|
||||||
|
@ -54,7 +54,7 @@ kubectl create secret generic ryan \
|
|||||||
Fetch the auto-generated CA bundle for the `local-user-authenticator`'s HTTP TLS endpoint.
|
Fetch the auto-generated CA bundle for the `local-user-authenticator`'s HTTP TLS endpoint.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get secret api-serving-cert --namespace local-user-authenticator \
|
kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator \
|
||||||
-o jsonpath={.data.caCertificate} \
|
-o jsonpath={.data.caCertificate} \
|
||||||
| base64 -d \
|
| base64 -d \
|
||||||
| tee /tmp/local-user-authenticator-ca
|
| tee /tmp/local-user-authenticator-ca
|
||||||
|
@ -14,7 +14,7 @@ metadata:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: local-user-authenticator-service-account
|
name: local-user-authenticator
|
||||||
namespace: local-user-authenticator
|
namespace: local-user-authenticator
|
||||||
---
|
---
|
||||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||||
@ -47,7 +47,7 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
app: local-user-authenticator
|
app: local-user-authenticator
|
||||||
spec:
|
spec:
|
||||||
serviceAccountName: local-user-authenticator-service-account
|
serviceAccountName: local-user-authenticator
|
||||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: image-pull-secret
|
- name: image-pull-secret
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: local-user-authenticator-aggregated-api-server-role
|
name: local-user-authenticator
|
||||||
namespace: local-user-authenticator
|
namespace: local-user-authenticator
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
@ -18,13 +18,13 @@ rules:
|
|||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: local-user-authenticator-aggregated-api-server-role-binding
|
name: local-user-authenticator
|
||||||
namespace: local-user-authenticator
|
namespace: local-user-authenticator
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: local-user-authenticator-service-account
|
name: local-user-authenticator
|
||||||
namespace: local-user-authenticator
|
namespace: local-user-authenticator
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: local-user-authenticator-aggregated-api-server-role
|
name: local-user-authenticator
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
@ -14,7 +14,7 @@ metadata:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@ -25,6 +25,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app: #@ data.values.app_name
|
app: #@ data.values.app_name
|
||||||
data:
|
data:
|
||||||
|
#! If names.apiService is changed in this ConfigMap, must also change name of the ClusterIP Service resource below.
|
||||||
#@yaml/text-templated-strings
|
#@yaml/text-templated-strings
|
||||||
pinniped.yaml: |
|
pinniped.yaml: |
|
||||||
discovery:
|
discovery:
|
||||||
@ -33,6 +34,10 @@ data:
|
|||||||
servingCertificate:
|
servingCertificate:
|
||||||
durationSeconds: (@= str(data.values.api_serving_certificate_duration_seconds) @)
|
durationSeconds: (@= str(data.values.api_serving_certificate_duration_seconds) @)
|
||||||
renewBeforeSeconds: (@= str(data.values.api_serving_certificate_renew_before_seconds) @)
|
renewBeforeSeconds: (@= str(data.values.api_serving_certificate_renew_before_seconds) @)
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: (@= data.values.app_name + "-api-tls-serving-certificate" @)
|
||||||
|
credentialIssuerConfig: (@= data.values.app_name + "-config" @)
|
||||||
|
apiService: (@= data.values.app_name + "-api" @)
|
||||||
---
|
---
|
||||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@ -66,7 +71,7 @@ spec:
|
|||||||
annotations:
|
annotations:
|
||||||
scheduler.alpha.kubernetes.io/critical-pod: ""
|
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||||
spec:
|
spec:
|
||||||
serviceAccountName: #@ data.values.app_name + "-service-account"
|
serviceAccountName: #@ data.values.app_name
|
||||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
- name: image-pull-secret
|
- name: image-pull-secret
|
||||||
@ -144,7 +149,8 @@ spec:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: pinniped-api #! the golang code assumes this specific name as part of the common name during cert generation
|
#! If name is changed, must also change names.apiService in the ConfigMap above
|
||||||
|
name: #@ data.values.app_name + "-api"
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
labels:
|
labels:
|
||||||
app: #@ data.values.app_name
|
app: #@ data.values.app_name
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-cluster-role"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: [namespaces]
|
resources: [namespaces]
|
||||||
@ -23,14 +23,14 @@ rules:
|
|||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-cluster-role-binding"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-cluster-role"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
#! Give permission to various objects within the app's own namespace
|
#! Give permission to various objects within the app's own namespace
|
||||||
@ -38,7 +38,7 @@ roleRef:
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-role"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
@ -54,15 +54,15 @@ rules:
|
|||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-role-binding"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: #@ data.values.app_name + "-aggregated-api-server-role"
|
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
#! Give permission to list pods and pod exec in the kube-system namespace so we can find the API server's private key
|
#! Give permission to list pods and pod exec in the kube-system namespace so we can find the API server's private key
|
||||||
@ -70,7 +70,7 @@ roleRef:
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-kube-system-pod-exec-role"
|
name: #@ data.values.app_name + "-kube-system-pod-exec"
|
||||||
namespace: kube-system
|
namespace: kube-system
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
@ -83,23 +83,23 @@ rules:
|
|||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-kube-system-pod-exec-role-binding"
|
name: #@ data.values.app_name + "-kube-system-pod-exec"
|
||||||
namespace: kube-system
|
namespace: kube-system
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: #@ data.values.app_name + "-kube-system-pod-exec-role"
|
name: #@ data.values.app_name + "-kube-system-pod-exec"
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
#! Allow both authenticated and unauthenticated CredentialRequests (i.e. allow all requests)
|
#! Allow both authenticated and unauthenticated TokenCredentialRequests (i.e. allow all requests)
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role"
|
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [pinniped.dev]
|
- apiGroups: [pinniped.dev]
|
||||||
resources: [credentialrequests]
|
resources: [credentialrequests]
|
||||||
@ -111,7 +111,7 @@ rules:
|
|||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role-binding"
|
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: system:authenticated
|
name: system:authenticated
|
||||||
@ -121,7 +121,7 @@ subjects:
|
|||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role"
|
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
|
||||||
#! Give permissions for subjectaccessreviews, tokenreview that is needed by aggregated api servers
|
#! Give permissions for subjectaccessreviews, tokenreview that is needed by aggregated api servers
|
||||||
@ -129,11 +129,11 @@ roleRef:
|
|||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-service-account-cluster-role-binding"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
@ -145,11 +145,11 @@ roleRef:
|
|||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-extension-apiserver-authentication-reader-role-binding"
|
name: #@ data.values.app_name + "-extension-apiserver-authentication-reader"
|
||||||
namespace: kube-system
|
namespace: kube-system
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
@ -161,7 +161,7 @@ roleRef:
|
|||||||
kind: Role
|
kind: Role
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher-role"
|
name: #@ data.values.app_name + "-cluster-info-lister-watcher"
|
||||||
namespace: kube-public
|
namespace: kube-public
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
@ -171,13 +171,13 @@ rules:
|
|||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
metadata:
|
metadata:
|
||||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher-role-binding"
|
name: #@ data.values.app_name + "-cluster-info-lister-watcher"
|
||||||
namespace: kube-public
|
namespace: kube-public
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: #@ data.values.app_name + "-service-account"
|
name: #@ data.values.app_name
|
||||||
namespace: #@ data.values.namespace
|
namespace: #@ data.values.namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher-role"
|
name: #@ data.values.app_name + "-cluster-info-lister-watcher"
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
1. Fetch the auto-generated CA bundle for the `local-user-authenticator`'s HTTP TLS endpoint.
|
1. Fetch the auto-generated CA bundle for the `local-user-authenticator`'s HTTP TLS endpoint.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get secret api-serving-cert --namespace local-user-authenticator \
|
kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator \
|
||||||
-o jsonpath={.data.caCertificate} \
|
-o jsonpath={.data.caCertificate} \
|
||||||
| tee /tmp/local-user-authenticator-ca-base64-encoded
|
| tee /tmp/local-user-authenticator-ca-base64-encoded
|
||||||
```
|
```
|
||||||
|
@ -177,7 +177,7 @@ kubectl create secret generic "$test_username" \
|
|||||||
app_name="pinniped"
|
app_name="pinniped"
|
||||||
namespace="integration"
|
namespace="integration"
|
||||||
webhook_url="https://local-user-authenticator.local-user-authenticator.svc/authenticate"
|
webhook_url="https://local-user-authenticator.local-user-authenticator.svc/authenticate"
|
||||||
webhook_ca_bundle="$(kubectl get secret api-serving-cert --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')"
|
webhook_ca_bundle="$(kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')"
|
||||||
discovery_url="$(TERM=dumb kubectl cluster-info | awk '/Kubernetes master/ {print $NF}')"
|
discovery_url="$(TERM=dumb kubectl cluster-info | awk '/Kubernetes master/ {print $NF}')"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -28,8 +28,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
//nolint: gochecknoglobals
|
//nolint: gochecknoglobals
|
||||||
scheme = runtime.NewScheme()
|
scheme = runtime.NewScheme()
|
||||||
//nolint: gochecknoglobals
|
//nolint: gochecknoglobals, golint
|
||||||
//nolint: golint
|
|
||||||
Codecs = serializer.NewCodecFactory(scheme)
|
Codecs = serializer.NewCodecFactory(scheme)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
type apiServiceUpdaterController struct {
|
type apiServiceUpdaterController struct {
|
||||||
namespace string
|
namespace string
|
||||||
|
certsSecretResourceName string
|
||||||
aggregatorClient aggregatorclient.Interface
|
aggregatorClient aggregatorclient.Interface
|
||||||
secretInformer corev1informers.SecretInformer
|
secretInformer corev1informers.SecretInformer
|
||||||
apiServiceName string
|
apiServiceName string
|
||||||
@ -24,6 +25,7 @@ type apiServiceUpdaterController struct {
|
|||||||
|
|
||||||
func NewAPIServiceUpdaterController(
|
func NewAPIServiceUpdaterController(
|
||||||
namespace string,
|
namespace string,
|
||||||
|
certsSecretResourceName string,
|
||||||
apiServiceName string,
|
apiServiceName string,
|
||||||
aggregatorClient aggregatorclient.Interface,
|
aggregatorClient aggregatorclient.Interface,
|
||||||
secretInformer corev1informers.SecretInformer,
|
secretInformer corev1informers.SecretInformer,
|
||||||
@ -34,6 +36,7 @@ func NewAPIServiceUpdaterController(
|
|||||||
Name: "certs-manager-controller",
|
Name: "certs-manager-controller",
|
||||||
Syncer: &apiServiceUpdaterController{
|
Syncer: &apiServiceUpdaterController{
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
certsSecretResourceName: certsSecretResourceName,
|
||||||
aggregatorClient: aggregatorClient,
|
aggregatorClient: aggregatorClient,
|
||||||
secretInformer: secretInformer,
|
secretInformer: secretInformer,
|
||||||
apiServiceName: apiServiceName,
|
apiServiceName: apiServiceName,
|
||||||
@ -41,7 +44,7 @@ func NewAPIServiceUpdaterController(
|
|||||||
},
|
},
|
||||||
withInformer(
|
withInformer(
|
||||||
secretInformer,
|
secretInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -49,10 +52,10 @@ func NewAPIServiceUpdaterController(
|
|||||||
|
|
||||||
func (c *apiServiceUpdaterController) Sync(ctx controllerlib.Context) error {
|
func (c *apiServiceUpdaterController) Sync(ctx controllerlib.Context) error {
|
||||||
// Try to get the secret from the informer cache.
|
// Try to get the secret from the informer cache.
|
||||||
certSecret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(certsSecretName)
|
certSecret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(c.certsSecretResourceName)
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, certsSecretName, err)
|
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, c.certsSecretResourceName, err)
|
||||||
}
|
}
|
||||||
if notFound {
|
if notFound {
|
||||||
// The secret does not exist yet, so nothing to do.
|
// The secret does not exist yet, so nothing to do.
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||||
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||||
@ -41,6 +42,7 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
|||||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||||
_ = NewAPIServiceUpdaterController(
|
_ = NewAPIServiceUpdaterController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
||||||
nil,
|
nil,
|
||||||
secretsInformer,
|
secretsInformer,
|
||||||
@ -55,8 +57,8 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
subject = secretsInformerFilter
|
subject = secretsInformerFilter
|
||||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||||
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
||||||
})
|
})
|
||||||
@ -102,6 +104,7 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
|||||||
func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
|
|
||||||
@ -119,6 +122,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
|||||||
// Set this at the last second to allow for injection of server override.
|
// Set this at the last second to allow for injection of server override.
|
||||||
subject = NewAPIServiceUpdaterController(
|
subject = NewAPIServiceUpdaterController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
||||||
aggregatorAPIClient,
|
aggregatorAPIClient,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
@ -131,7 +135,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
|||||||
Name: subject.Name(),
|
Name: subject.Name(),
|
||||||
Key: controllerlib.Key{
|
Key: controllerlib.Key{
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +158,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
|||||||
timeoutContextCancel()
|
timeoutContextCancel()
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is not yet an api-serving-cert Secret in the installation namespace or it was deleted", func() {
|
when("there is not yet a serving cert Secret in the installation namespace or it was deleted", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
unrelatedSecret := &corev1.Secret{
|
unrelatedSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -174,11 +178,11 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is an api-serving-cert Secret already in the installation namespace", func() {
|
when("there is a serving cert Secret already in the installation namespace", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
apiServingCertSecret := &corev1.Secret{
|
apiServingCertSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
type certsExpirerController struct {
|
type certsExpirerController struct {
|
||||||
namespace string
|
namespace string
|
||||||
|
certsSecretResourceName string
|
||||||
k8sClient kubernetes.Interface
|
k8sClient kubernetes.Interface
|
||||||
secretInformer corev1informers.SecretInformer
|
secretInformer corev1informers.SecretInformer
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ type certsExpirerController struct {
|
|||||||
// deletion forces rotation of the secret with the help of other controllers.
|
// deletion forces rotation of the secret with the help of other controllers.
|
||||||
func NewCertsExpirerController(
|
func NewCertsExpirerController(
|
||||||
namespace string,
|
namespace string,
|
||||||
|
certsSecretResourceName string,
|
||||||
k8sClient kubernetes.Interface,
|
k8sClient kubernetes.Interface,
|
||||||
secretInformer corev1informers.SecretInformer,
|
secretInformer corev1informers.SecretInformer,
|
||||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||||
@ -46,6 +48,7 @@ func NewCertsExpirerController(
|
|||||||
Name: "certs-expirer-controller",
|
Name: "certs-expirer-controller",
|
||||||
Syncer: &certsExpirerController{
|
Syncer: &certsExpirerController{
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
certsSecretResourceName: certsSecretResourceName,
|
||||||
k8sClient: k8sClient,
|
k8sClient: k8sClient,
|
||||||
secretInformer: secretInformer,
|
secretInformer: secretInformer,
|
||||||
renewBefore: renewBefore,
|
renewBefore: renewBefore,
|
||||||
@ -53,7 +56,7 @@ func NewCertsExpirerController(
|
|||||||
},
|
},
|
||||||
withInformer(
|
withInformer(
|
||||||
secretInformer,
|
secretInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -61,10 +64,10 @@ func NewCertsExpirerController(
|
|||||||
|
|
||||||
// Sync implements controller.Syncer.Sync.
|
// Sync implements controller.Syncer.Sync.
|
||||||
func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
||||||
secret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(certsSecretName)
|
secret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(c.certsSecretResourceName)
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, certsSecretName, err)
|
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, c.certsSecretResourceName, err)
|
||||||
}
|
}
|
||||||
if notFound {
|
if notFound {
|
||||||
klog.Info("certsExpirerController Sync found that the secret does not exist yet or was deleted")
|
klog.Info("certsExpirerController Sync found that the secret does not exist yet or was deleted")
|
||||||
@ -87,7 +90,7 @@ func (c *certsExpirerController) Sync(ctx controllerlib.Context) error {
|
|||||||
err := c.k8sClient.
|
err := c.k8sClient.
|
||||||
CoreV1().
|
CoreV1().
|
||||||
Secrets(c.namespace).
|
Secrets(c.namespace).
|
||||||
Delete(ctx.Context, certsSecretName, metav1.DeleteOptions{})
|
Delete(ctx.Context, c.certsSecretResourceName, metav1.DeleteOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Do return an error here so that the controller library will reschedule
|
// Do return an error here so that the controller library will reschedule
|
||||||
// us to try deleting this cert again.
|
// us to try deleting this cert again.
|
||||||
|
@ -29,6 +29,8 @@ import (
|
|||||||
func TestExpirerControllerFilters(t *testing.T) {
|
func TestExpirerControllerFilters(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
namespace string
|
namespace string
|
||||||
@ -40,7 +42,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
|||||||
namespace: "good-namespace",
|
namespace: "good-namespace",
|
||||||
secret: corev1.Secret{
|
secret: corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: "good-namespace",
|
Namespace: "good-namespace",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -62,7 +64,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
|||||||
namespace: "good-namespacee",
|
namespace: "good-namespacee",
|
||||||
secret: corev1.Secret{
|
secret: corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: "bad-namespace",
|
Namespace: "bad-namespace",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -92,6 +94,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
|||||||
withInformer := testutil.NewObservableWithInformerOption()
|
withInformer := testutil.NewObservableWithInformerOption()
|
||||||
_ = NewCertsExpirerController(
|
_ = NewCertsExpirerController(
|
||||||
test.namespace,
|
test.namespace,
|
||||||
|
certsSecretResourceName,
|
||||||
nil, // k8sClient, not needed
|
nil, // k8sClient, not needed
|
||||||
secretsInformer,
|
secretsInformer,
|
||||||
withInformer.WithInformer,
|
withInformer.WithInformer,
|
||||||
@ -111,6 +114,8 @@ func TestExpirerControllerFilters(t *testing.T) {
|
|||||||
func TestExpirerControllerSync(t *testing.T) {
|
func TestExpirerControllerSync(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
renewBefore time.Duration
|
renewBefore time.Duration
|
||||||
@ -220,7 +225,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kubeInformerClient := kubernetesfake.NewSimpleClientset()
|
kubeInformerClient := kubernetesfake.NewSimpleClientset()
|
||||||
name := "api-serving-cert" // See certs_manager.go.
|
name := certsSecretResourceName
|
||||||
namespace := "some-namespace"
|
namespace := "some-namespace"
|
||||||
if test.fillSecretData != nil {
|
if test.fillSecretData != nil {
|
||||||
secret := &corev1.Secret{
|
secret := &corev1.Secret{
|
||||||
@ -243,6 +248,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
|||||||
|
|
||||||
c := NewCertsExpirerController(
|
c := NewCertsExpirerController(
|
||||||
namespace,
|
namespace,
|
||||||
|
certsSecretResourceName,
|
||||||
kubeAPIClient,
|
kubeAPIClient,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
|
@ -21,8 +21,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//nolint: gosec
|
|
||||||
certsSecretName = "api-serving-cert"
|
|
||||||
caCertificateSecretKey = "caCertificate"
|
caCertificateSecretKey = "caCertificate"
|
||||||
tlsPrivateKeySecretKey = "tlsPrivateKey"
|
tlsPrivateKeySecretKey = "tlsPrivateKey"
|
||||||
tlsCertificateChainSecretKey = "tlsCertificateChain"
|
tlsCertificateChainSecretKey = "tlsCertificateChain"
|
||||||
@ -30,6 +28,7 @@ const (
|
|||||||
|
|
||||||
type certsManagerController struct {
|
type certsManagerController struct {
|
||||||
namespace string
|
namespace string
|
||||||
|
certsSecretResourceName string
|
||||||
k8sClient kubernetes.Interface
|
k8sClient kubernetes.Interface
|
||||||
secretInformer corev1informers.SecretInformer
|
secretInformer corev1informers.SecretInformer
|
||||||
|
|
||||||
@ -41,7 +40,9 @@ type certsManagerController struct {
|
|||||||
serviceNameForGeneratedCertCommonName string
|
serviceNameForGeneratedCertCommonName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCertsManagerController(namespace string,
|
func NewCertsManagerController(
|
||||||
|
namespace string,
|
||||||
|
certsSecretResourceName string,
|
||||||
k8sClient kubernetes.Interface,
|
k8sClient kubernetes.Interface,
|
||||||
secretInformer corev1informers.SecretInformer,
|
secretInformer corev1informers.SecretInformer,
|
||||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||||
@ -55,6 +56,7 @@ func NewCertsManagerController(namespace string,
|
|||||||
Name: "certs-manager-controller",
|
Name: "certs-manager-controller",
|
||||||
Syncer: &certsManagerController{
|
Syncer: &certsManagerController{
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
certsSecretResourceName: certsSecretResourceName,
|
||||||
k8sClient: k8sClient,
|
k8sClient: k8sClient,
|
||||||
secretInformer: secretInformer,
|
secretInformer: secretInformer,
|
||||||
certDuration: certDuration,
|
certDuration: certDuration,
|
||||||
@ -64,23 +66,23 @@ func NewCertsManagerController(namespace string,
|
|||||||
},
|
},
|
||||||
withInformer(
|
withInformer(
|
||||||
secretInformer,
|
secretInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
// Be sure to run once even if the Secret that the informer is watching doesn't exist.
|
// Be sure to run once even if the Secret that the informer is watching doesn't exist.
|
||||||
withInitialEvent(controllerlib.Key{
|
withInitialEvent(controllerlib.Key{
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: certsSecretName,
|
Name: certsSecretResourceName,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *certsManagerController) Sync(ctx controllerlib.Context) error {
|
func (c *certsManagerController) Sync(ctx controllerlib.Context) error {
|
||||||
// Try to get the secret from the informer cache.
|
// Try to get the secret from the informer cache.
|
||||||
_, err := c.secretInformer.Lister().Secrets(c.namespace).Get(certsSecretName)
|
_, err := c.secretInformer.Lister().Secrets(c.namespace).Get(c.certsSecretResourceName)
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, certsSecretName, err)
|
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, c.certsSecretResourceName, err)
|
||||||
}
|
}
|
||||||
if !notFound {
|
if !notFound {
|
||||||
// The secret already exists, so nothing to do.
|
// The secret already exists, so nothing to do.
|
||||||
@ -112,7 +114,7 @@ func (c *certsManagerController) Sync(ctx controllerlib.Context) error {
|
|||||||
secret := corev1.Secret{
|
secret := corev1.Secret{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: certsSecretName,
|
Name: c.certsSecretResourceName,
|
||||||
Namespace: c.namespace,
|
Namespace: c.namespace,
|
||||||
},
|
},
|
||||||
StringData: map[string]string{
|
StringData: map[string]string{
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
func TestManagerControllerOptions(t *testing.T) {
|
func TestManagerControllerOptions(t *testing.T) {
|
||||||
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||||
@ -38,7 +39,17 @@ func TestManagerControllerOptions(t *testing.T) {
|
|||||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||||
observableWithInitialEventOption = testutil.NewObservableWithInitialEventOption()
|
observableWithInitialEventOption = testutil.NewObservableWithInitialEventOption()
|
||||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||||
_ = NewCertsManagerController(installedInNamespace, nil, secretsInformer, observableWithInformerOption.WithInformer, observableWithInitialEventOption.WithInitialEvent, 0, "Pinniped CA", "pinniped-api")
|
_ = NewCertsManagerController(
|
||||||
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
|
nil,
|
||||||
|
secretsInformer,
|
||||||
|
observableWithInformerOption.WithInformer,
|
||||||
|
observableWithInitialEventOption.WithInitialEvent,
|
||||||
|
0,
|
||||||
|
"Pinniped CA",
|
||||||
|
"pinniped-api",
|
||||||
|
)
|
||||||
secretsInformerFilter = observableWithInformerOption.GetFilterForInformer(secretsInformer)
|
secretsInformerFilter = observableWithInformerOption.GetFilterForInformer(secretsInformer)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -48,8 +59,8 @@ func TestManagerControllerOptions(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
subject = secretsInformerFilter
|
subject = secretsInformerFilter
|
||||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||||
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
||||||
})
|
})
|
||||||
@ -94,7 +105,7 @@ func TestManagerControllerOptions(t *testing.T) {
|
|||||||
it("asks for an initial event because the Secret may not exist yet and it needs to run anyway", func() {
|
it("asks for an initial event because the Secret may not exist yet and it needs to run anyway", func() {
|
||||||
r.Equal(controllerlib.Key{
|
r.Equal(controllerlib.Key{
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
}, observableWithInitialEventOption.GetInitialEventKey())
|
}, observableWithInitialEventOption.GetInitialEventKey())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -104,6 +115,7 @@ func TestManagerControllerOptions(t *testing.T) {
|
|||||||
func TestManagerControllerSync(t *testing.T) {
|
func TestManagerControllerSync(t *testing.T) {
|
||||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
const certDuration = 12345678 * time.Second
|
const certDuration = 12345678 * time.Second
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
@ -122,6 +134,7 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
// Set this at the last second to allow for injection of server override.
|
// Set this at the last second to allow for injection of server override.
|
||||||
subject = NewCertsManagerController(
|
subject = NewCertsManagerController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
kubeAPIClient,
|
kubeAPIClient,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -137,7 +150,7 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
Name: subject.Name(),
|
Name: subject.Name(),
|
||||||
Key: controllerlib.Key{
|
Key: controllerlib.Key{
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +173,7 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
timeoutContextCancel()
|
timeoutContextCancel()
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is not yet an api-serving-cert Secret in the installation namespace or it was deleted", func() {
|
when("there is not yet a serving cert Secret in the installation namespace or it was deleted", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
unrelatedSecret := &corev1.Secret{
|
unrelatedSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -172,7 +185,7 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("creates the api-serving-cert Secret", func() {
|
it("creates the serving cert Secret", func() {
|
||||||
startInformersAndController()
|
startInformersAndController()
|
||||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
@ -183,7 +196,7 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
r.Equal(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"}, actualAction.GetResource())
|
r.Equal(schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"}, actualAction.GetResource())
|
||||||
r.Equal(installedInNamespace, actualAction.GetNamespace())
|
r.Equal(installedInNamespace, actualAction.GetNamespace())
|
||||||
actualSecret := actualAction.GetObject().(*corev1.Secret)
|
actualSecret := actualAction.GetObject().(*corev1.Secret)
|
||||||
r.Equal("api-serving-cert", actualSecret.Name)
|
r.Equal(certsSecretResourceName, actualSecret.Name)
|
||||||
r.Equal(installedInNamespace, actualSecret.Namespace)
|
r.Equal(installedInNamespace, actualSecret.Namespace)
|
||||||
actualCACert := actualSecret.StringData["caCertificate"]
|
actualCACert := actualSecret.StringData["caCertificate"]
|
||||||
actualPrivateKey := actualSecret.StringData["tlsPrivateKey"]
|
actualPrivateKey := actualSecret.StringData["tlsPrivateKey"]
|
||||||
@ -222,11 +235,11 @@ func TestManagerControllerSync(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is an api-serving-cert Secret already in the installation namespace", func() {
|
when("there is a serving cert Secret already in the installation namespace", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
apiServingCertSecret := &corev1.Secret{
|
apiServingCertSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,14 @@ import (
|
|||||||
|
|
||||||
type certsObserverController struct {
|
type certsObserverController struct {
|
||||||
namespace string
|
namespace string
|
||||||
|
certsSecretResourceName string
|
||||||
dynamicCertProvider provider.DynamicTLSServingCertProvider
|
dynamicCertProvider provider.DynamicTLSServingCertProvider
|
||||||
secretInformer corev1informers.SecretInformer
|
secretInformer corev1informers.SecretInformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCertsObserverController(
|
func NewCertsObserverController(
|
||||||
namespace string,
|
namespace string,
|
||||||
|
certsSecretResourceName string,
|
||||||
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
||||||
secretInformer corev1informers.SecretInformer,
|
secretInformer corev1informers.SecretInformer,
|
||||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||||
@ -32,13 +34,14 @@ func NewCertsObserverController(
|
|||||||
Name: "certs-observer-controller",
|
Name: "certs-observer-controller",
|
||||||
Syncer: &certsObserverController{
|
Syncer: &certsObserverController{
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
|
certsSecretResourceName: certsSecretResourceName,
|
||||||
dynamicCertProvider: dynamicCertProvider,
|
dynamicCertProvider: dynamicCertProvider,
|
||||||
secretInformer: secretInformer,
|
secretInformer: secretInformer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
withInformer(
|
withInformer(
|
||||||
secretInformer,
|
secretInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -46,10 +49,10 @@ func NewCertsObserverController(
|
|||||||
|
|
||||||
func (c *certsObserverController) Sync(_ controllerlib.Context) error {
|
func (c *certsObserverController) Sync(_ controllerlib.Context) error {
|
||||||
// Try to get the secret from the informer cache.
|
// Try to get the secret from the informer cache.
|
||||||
certSecret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(certsSecretName)
|
certSecret, err := c.secretInformer.Lister().Secrets(c.namespace).Get(c.certsSecretResourceName)
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, certsSecretName, err)
|
return fmt.Errorf("failed to get %s/%s secret: %w", c.namespace, c.certsSecretResourceName, err)
|
||||||
}
|
}
|
||||||
if notFound {
|
if notFound {
|
||||||
klog.Info("certsObserverController Sync found that the secret does not exist yet or was deleted")
|
klog.Info("certsObserverController Sync found that the secret does not exist yet or was deleted")
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
func TestObserverControllerInformerFilters(t *testing.T) {
|
func TestObserverControllerInformerFilters(t *testing.T) {
|
||||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||||
@ -35,6 +36,7 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
|||||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||||
_ = NewCertsObserverController(
|
_ = NewCertsObserverController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
nil,
|
nil,
|
||||||
secretsInformer,
|
secretsInformer,
|
||||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||||
@ -48,8 +50,8 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
|||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
subject = secretsInformerFilter
|
subject = secretsInformerFilter
|
||||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||||
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
unrelated = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}}
|
||||||
})
|
})
|
||||||
@ -95,6 +97,7 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
|||||||
func TestObserverControllerSync(t *testing.T) {
|
func TestObserverControllerSync(t *testing.T) {
|
||||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
const certsSecretResourceName = "some-resource-name"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
|
|
||||||
@ -112,6 +115,7 @@ func TestObserverControllerSync(t *testing.T) {
|
|||||||
// Set this at the last second to allow for injection of server override.
|
// Set this at the last second to allow for injection of server override.
|
||||||
subject = NewCertsObserverController(
|
subject = NewCertsObserverController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
certsSecretResourceName,
|
||||||
dynamicCertProvider,
|
dynamicCertProvider,
|
||||||
kubeInformers.Core().V1().Secrets(),
|
kubeInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -123,7 +127,7 @@ func TestObserverControllerSync(t *testing.T) {
|
|||||||
Name: subject.Name(),
|
Name: subject.Name(),
|
||||||
Key: controllerlib.Key{
|
Key: controllerlib.Key{
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +150,7 @@ func TestObserverControllerSync(t *testing.T) {
|
|||||||
timeoutContextCancel()
|
timeoutContextCancel()
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is not yet an api-serving-cert Secret in the installation namespace or it was deleted", func() {
|
when("there is not yet a serving cert Secret in the installation namespace or it was deleted", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
unrelatedSecret := &corev1.Secret{
|
unrelatedSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -171,11 +175,11 @@ func TestObserverControllerSync(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
when("there is an api-serving-cert Secret with the expected keys already in the installation namespace", func() {
|
when("there is a serving cert Secret with the expected keys already in the installation namespace", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
apiServingCertSecret := &corev1.Secret{
|
apiServingCertSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{
|
Data: map[string][]byte{
|
||||||
@ -201,11 +205,11 @@ func TestObserverControllerSync(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
when("the api-serving-cert Secret exists but is missing the expected keys", func() {
|
when("the serving cert Secret exists but is missing the expected keys", func() {
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
apiServingCertSecret := &corev1.Secret{
|
apiServingCertSecret := &corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "api-serving-cert",
|
Name: certsSecretResourceName,
|
||||||
Namespace: installedInNamespace,
|
Namespace: installedInNamespace,
|
||||||
},
|
},
|
||||||
Data: map[string][]byte{},
|
Data: map[string][]byte{},
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
func CreateOrUpdateCredentialIssuerConfig(
|
func CreateOrUpdateCredentialIssuerConfig(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
credentialIssuerConfigNamespace string,
|
credentialIssuerConfigNamespace string,
|
||||||
|
credentialIssuerConfigResourceName string,
|
||||||
pinnipedClient pinnipedclientset.Interface,
|
pinnipedClient pinnipedclientset.Interface,
|
||||||
applyUpdatesToCredentialIssuerConfigFunc func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig),
|
applyUpdatesToCredentialIssuerConfigFunc func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig),
|
||||||
) error {
|
) error {
|
||||||
@ -26,7 +27,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
|||||||
existingCredentialIssuerConfig, err := pinnipedClient.
|
existingCredentialIssuerConfig, err := pinnipedClient.
|
||||||
CrdV1alpha1().
|
CrdV1alpha1().
|
||||||
CredentialIssuerConfigs(credentialIssuerConfigNamespace).
|
CredentialIssuerConfigs(credentialIssuerConfigNamespace).
|
||||||
Get(ctx, ConfigName, metav1.GetOptions{})
|
Get(ctx, credentialIssuerConfigResourceName, metav1.GetOptions{})
|
||||||
|
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
@ -37,7 +38,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
|||||||
ctx,
|
ctx,
|
||||||
existingCredentialIssuerConfig,
|
existingCredentialIssuerConfig,
|
||||||
notFound,
|
notFound,
|
||||||
ConfigName,
|
credentialIssuerConfigResourceName,
|
||||||
credentialIssuerConfigNamespace,
|
credentialIssuerConfigNamespace,
|
||||||
pinnipedClient,
|
pinnipedClient,
|
||||||
applyUpdatesToCredentialIssuerConfigFunc)
|
applyUpdatesToCredentialIssuerConfigFunc)
|
||||||
|
@ -31,7 +31,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
var pinnipedAPIClient *pinnipedfake.Clientset
|
var pinnipedAPIClient *pinnipedfake.Clientset
|
||||||
var credentialIssuerConfigGVR schema.GroupVersionResource
|
var credentialIssuerConfigGVR schema.GroupVersionResource
|
||||||
const installationNamespace = "some-namespace"
|
const installationNamespace = "some-namespace"
|
||||||
const configName = "pinniped-config"
|
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||||
|
|
||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
r = require.New(t)
|
r = require.New(t)
|
||||||
@ -46,7 +46,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
|
|
||||||
when("the config does not exist", func() {
|
when("the config does not exist", func() {
|
||||||
it("creates a new config which includes only the updates made by the func parameter", func() {
|
it("creates a new config which includes only the updates made by the func parameter", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.KubeConfigInfo = &crdpinnipedv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
configToUpdate.Status.KubeConfigInfo = &crdpinnipedv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
||||||
CertificateAuthorityData: "some-ca-value",
|
CertificateAuthorityData: "some-ca-value",
|
||||||
@ -55,7 +55,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
)
|
)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||||
|
|
||||||
expectedCreateAction := coretesting.NewCreateAction(
|
expectedCreateAction := coretesting.NewCreateAction(
|
||||||
credentialIssuerConfigGVR,
|
credentialIssuerConfigGVR,
|
||||||
@ -63,7 +63,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
&crdpinnipedv1alpha1.CredentialIssuerConfig{
|
&crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: configName,
|
Name: credentialIssuerConfigResourceName,
|
||||||
Namespace: installationNamespace,
|
Namespace: installationNamespace,
|
||||||
},
|
},
|
||||||
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
||||||
@ -87,7 +87,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("returns an error", func() {
|
it("returns an error", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {},
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {},
|
||||||
)
|
)
|
||||||
r.EqualError(err, "could not create or update credentialissuerconfig: create failed: error on create")
|
r.EqualError(err, "could not create or update credentialissuerconfig: create failed: error on create")
|
||||||
@ -102,7 +102,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
existingConfig = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
existingConfig = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
TypeMeta: metav1.TypeMeta{},
|
TypeMeta: metav1.TypeMeta{},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: configName,
|
Name: credentialIssuerConfigResourceName,
|
||||||
Namespace: installationNamespace,
|
Namespace: installationNamespace,
|
||||||
},
|
},
|
||||||
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
||||||
@ -125,14 +125,14 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("updates the existing config to only apply the updates made by the func parameter", func() {
|
it("updates the existing config to only apply the updates made by the func parameter", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||||
|
|
||||||
// Only the edited field should be changed.
|
// Only the edited field should be changed.
|
||||||
expectedUpdatedConfig := existingConfig.DeepCopy()
|
expectedUpdatedConfig := existingConfig.DeepCopy()
|
||||||
@ -143,7 +143,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("avoids the cost of an update if the local updates made by the func parameter did not actually change anything", func() {
|
it("avoids the cost of an update if the local updates made by the func parameter did not actually change anything", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "initial-ca-value"
|
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "initial-ca-value"
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
)
|
)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||||
r.Equal([]coretesting.Action{expectedGetAction}, pinnipedAPIClient.Actions())
|
r.Equal([]coretesting.Action{expectedGetAction}, pinnipedAPIClient.Actions())
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("returns an error", func() {
|
it("returns an error", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {},
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {},
|
||||||
)
|
)
|
||||||
r.EqualError(err, "could not create or update credentialissuerconfig: get failed: error on get")
|
r.EqualError(err, "could not create or update credentialissuerconfig: get failed: error on get")
|
||||||
@ -182,7 +182,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("returns an error", func() {
|
it("returns an error", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||||
},
|
},
|
||||||
@ -216,14 +216,14 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("retries updates on conflict", func() {
|
it("retries updates on conflict", func() {
|
||||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *v1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||||
|
|
||||||
// The first attempted update only includes its own edits.
|
// The first attempted update only includes its own edits.
|
||||||
firstExpectedUpdatedConfig := existingConfig.DeepCopy()
|
firstExpectedUpdatedConfig := existingConfig.DeepCopy()
|
||||||
|
@ -21,23 +21,21 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
ClusterInfoNamespace = "kube-public"
|
ClusterInfoNamespace = "kube-public"
|
||||||
|
|
||||||
ConfigName = "pinniped-config"
|
|
||||||
|
|
||||||
clusterInfoName = "cluster-info"
|
clusterInfoName = "cluster-info"
|
||||||
clusterInfoConfigMapKey = "kubeconfig"
|
clusterInfoConfigMapKey = "kubeconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
type publisherController struct {
|
type publisherController struct {
|
||||||
namespace string
|
namespace string
|
||||||
|
credentialIssuerConfigResourceName string
|
||||||
serverOverride *string
|
serverOverride *string
|
||||||
pinnipedClient pinnipedclientset.Interface
|
pinnipedClient pinnipedclientset.Interface
|
||||||
configMapInformer corev1informers.ConfigMapInformer
|
configMapInformer corev1informers.ConfigMapInformer
|
||||||
credentialIssuerConfigInformer crdpinnipedv1alpha1informers.CredentialIssuerConfigInformer
|
credentialIssuerConfigInformer crdpinnipedv1alpha1informers.CredentialIssuerConfigInformer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPublisherController(
|
func NewPublisherController(namespace string,
|
||||||
namespace string,
|
credentialIssuerConfigResourceName string,
|
||||||
serverOverride *string,
|
serverOverride *string,
|
||||||
pinnipedClient pinnipedclientset.Interface,
|
pinnipedClient pinnipedclientset.Interface,
|
||||||
configMapInformer corev1informers.ConfigMapInformer,
|
configMapInformer corev1informers.ConfigMapInformer,
|
||||||
@ -48,6 +46,7 @@ func NewPublisherController(
|
|||||||
controllerlib.Config{
|
controllerlib.Config{
|
||||||
Name: "publisher-controller",
|
Name: "publisher-controller",
|
||||||
Syncer: &publisherController{
|
Syncer: &publisherController{
|
||||||
|
credentialIssuerConfigResourceName: credentialIssuerConfigResourceName,
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
serverOverride: serverOverride,
|
serverOverride: serverOverride,
|
||||||
pinnipedClient: pinnipedClient,
|
pinnipedClient: pinnipedClient,
|
||||||
@ -62,7 +61,7 @@ func NewPublisherController(
|
|||||||
),
|
),
|
||||||
withInformer(
|
withInformer(
|
||||||
credentialIssuerConfigInformer,
|
credentialIssuerConfigInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(ConfigName, namespace),
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(credentialIssuerConfigResourceName, namespace),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -112,7 +111,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
|||||||
existingCredentialIssuerConfigFromInformerCache, err := c.credentialIssuerConfigInformer.
|
existingCredentialIssuerConfigFromInformerCache, err := c.credentialIssuerConfigInformer.
|
||||||
Lister().
|
Lister().
|
||||||
CredentialIssuerConfigs(c.namespace).
|
CredentialIssuerConfigs(c.namespace).
|
||||||
Get(ConfigName)
|
Get(c.credentialIssuerConfigResourceName)
|
||||||
notFound = k8serrors.IsNotFound(err)
|
notFound = k8serrors.IsNotFound(err)
|
||||||
if err != nil && !notFound {
|
if err != nil && !notFound {
|
||||||
return fmt.Errorf("could not get credentialissuerconfig: %w", err)
|
return fmt.Errorf("could not get credentialissuerconfig: %w", err)
|
||||||
@ -129,7 +128,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
|||||||
ctx.Context,
|
ctx.Context,
|
||||||
existingCredentialIssuerConfigFromInformerCache,
|
existingCredentialIssuerConfigFromInformerCache,
|
||||||
notFound,
|
notFound,
|
||||||
ConfigName,
|
c.credentialIssuerConfigResourceName,
|
||||||
c.namespace,
|
c.namespace,
|
||||||
c.pinnipedClient,
|
c.pinnipedClient,
|
||||||
updateServerAndCAFunc)
|
updateServerAndCAFunc)
|
||||||
|
@ -30,6 +30,7 @@ import (
|
|||||||
|
|
||||||
func TestInformerFilters(t *testing.T) {
|
func TestInformerFilters(t *testing.T) {
|
||||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
|
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
@ -42,14 +43,7 @@ func TestInformerFilters(t *testing.T) {
|
|||||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||||
configMapInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().ConfigMaps()
|
configMapInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().ConfigMaps()
|
||||||
credentialIssuerConfigInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Crd().V1alpha1().CredentialIssuerConfigs()
|
credentialIssuerConfigInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Crd().V1alpha1().CredentialIssuerConfigs()
|
||||||
_ = NewPublisherController(
|
_ = NewPublisherController(installedInNamespace, credentialIssuerConfigResourceName, nil, nil, configMapInformer, credentialIssuerConfigInformer, observableWithInformerOption.WithInformer)
|
||||||
installedInNamespace,
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
configMapInformer,
|
|
||||||
credentialIssuerConfigInformer,
|
|
||||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
|
||||||
)
|
|
||||||
configMapInformerFilter = observableWithInformerOption.GetFilterForInformer(configMapInformer)
|
configMapInformerFilter = observableWithInformerOption.GetFilterForInformer(configMapInformer)
|
||||||
credentialIssuerConfigInformerFilter = observableWithInformerOption.GetFilterForInformer(credentialIssuerConfigInformer)
|
credentialIssuerConfigInformerFilter = observableWithInformerOption.GetFilterForInformer(credentialIssuerConfigInformer)
|
||||||
})
|
})
|
||||||
@ -109,10 +103,10 @@ func TestInformerFilters(t *testing.T) {
|
|||||||
it.Before(func() {
|
it.Before(func() {
|
||||||
subject = credentialIssuerConfigInformerFilter
|
subject = credentialIssuerConfigInformerFilter
|
||||||
target = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
target = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "pinniped-config", Namespace: installedInNamespace},
|
ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerConfigResourceName, Namespace: installedInNamespace},
|
||||||
}
|
}
|
||||||
wrongNamespace = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
wrongNamespace = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "pinniped-config", Namespace: "wrong-namespace"},
|
ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerConfigResourceName, Namespace: "wrong-namespace"},
|
||||||
}
|
}
|
||||||
wrongName = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
wrongName = &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace},
|
ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace},
|
||||||
@ -162,6 +156,7 @@ func TestInformerFilters(t *testing.T) {
|
|||||||
|
|
||||||
func TestSync(t *testing.T) {
|
func TestSync(t *testing.T) {
|
||||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||||
|
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||||
const installedInNamespace = "some-namespace"
|
const installedInNamespace = "some-namespace"
|
||||||
|
|
||||||
var r *require.Assertions
|
var r *require.Assertions
|
||||||
@ -185,7 +180,7 @@ func TestSync(t *testing.T) {
|
|||||||
}
|
}
|
||||||
expectedCredentialIssuerConfig := &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
expectedCredentialIssuerConfig := &crdpinnipedv1alpha1.CredentialIssuerConfig{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "pinniped-config",
|
Name: credentialIssuerConfigResourceName,
|
||||||
Namespace: expectedNamespace,
|
Namespace: expectedNamespace,
|
||||||
},
|
},
|
||||||
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
Status: crdpinnipedv1alpha1.CredentialIssuerConfigStatus{
|
||||||
@ -205,6 +200,7 @@ func TestSync(t *testing.T) {
|
|||||||
// Set this at the last second to allow for injection of server override.
|
// Set this at the last second to allow for injection of server override.
|
||||||
subject = NewPublisherController(
|
subject = NewPublisherController(
|
||||||
installedInNamespace,
|
installedInNamespace,
|
||||||
|
credentialIssuerConfigResourceName,
|
||||||
serverOverride,
|
serverOverride,
|
||||||
pinnipedAPIClient,
|
pinnipedAPIClient,
|
||||||
kubeInformers.Core().V1().ConfigMaps(),
|
kubeInformers.Core().V1().ConfigMaps(),
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/vmware-tanzu/pinniped/internal/controller/issuerconfig"
|
"github.com/vmware-tanzu/pinniped/internal/controller/issuerconfig"
|
||||||
"github.com/vmware-tanzu/pinniped/internal/controllerlib"
|
"github.com/vmware-tanzu/pinniped/internal/controllerlib"
|
||||||
"github.com/vmware-tanzu/pinniped/internal/provider"
|
"github.com/vmware-tanzu/pinniped/internal/provider"
|
||||||
|
"github.com/vmware-tanzu/pinniped/pkg/config/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -36,6 +37,7 @@ const (
|
|||||||
// Prepare the controllers and their informers and return a function that will start them when called.
|
// Prepare the controllers and their informers and return a function that will start them when called.
|
||||||
func PrepareControllers(
|
func PrepareControllers(
|
||||||
serverInstallationNamespace string,
|
serverInstallationNamespace string,
|
||||||
|
namesConfig api.NamesConfigSpec,
|
||||||
discoveryURLOverride *string,
|
discoveryURLOverride *string,
|
||||||
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
||||||
servingCertDuration time.Duration,
|
servingCertDuration time.Duration,
|
||||||
@ -52,15 +54,12 @@ func PrepareControllers(
|
|||||||
kubePublicNamespaceK8sInformers, installationNamespaceK8sInformers, installationNamespacePinnipedInformers :=
|
kubePublicNamespaceK8sInformers, installationNamespaceK8sInformers, installationNamespacePinnipedInformers :=
|
||||||
createInformers(serverInstallationNamespace, k8sClient, pinnipedClient)
|
createInformers(serverInstallationNamespace, k8sClient, pinnipedClient)
|
||||||
|
|
||||||
// This string must match the name of the Service declared in the deployment yaml.
|
|
||||||
const serviceName = "pinniped-api"
|
|
||||||
|
|
||||||
// Create controller manager.
|
// Create controller manager.
|
||||||
controllerManager := controllerlib.
|
controllerManager := controllerlib.
|
||||||
NewManager().
|
NewManager().
|
||||||
WithController(
|
WithController(
|
||||||
issuerconfig.NewPublisherController(
|
issuerconfig.NewPublisherController(serverInstallationNamespace,
|
||||||
serverInstallationNamespace,
|
namesConfig.CredentialIssuerConfig,
|
||||||
discoveryURLOverride,
|
discoveryURLOverride,
|
||||||
pinnipedClient,
|
pinnipedClient,
|
||||||
kubePublicNamespaceK8sInformers.Core().V1().ConfigMaps(),
|
kubePublicNamespaceK8sInformers.Core().V1().ConfigMaps(),
|
||||||
@ -72,19 +71,21 @@ func PrepareControllers(
|
|||||||
WithController(
|
WithController(
|
||||||
apicerts.NewCertsManagerController(
|
apicerts.NewCertsManagerController(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
namesConfig.ServingCertificateSecret,
|
||||||
k8sClient,
|
k8sClient,
|
||||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
controllerlib.WithInitialEvent,
|
controllerlib.WithInitialEvent,
|
||||||
servingCertDuration,
|
servingCertDuration,
|
||||||
"Pinniped CA",
|
"Pinniped CA",
|
||||||
serviceName,
|
namesConfig.APIService,
|
||||||
),
|
),
|
||||||
singletonWorker,
|
singletonWorker,
|
||||||
).
|
).
|
||||||
WithController(
|
WithController(
|
||||||
apicerts.NewAPIServiceUpdaterController(
|
apicerts.NewAPIServiceUpdaterController(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
namesConfig.ServingCertificateSecret,
|
||||||
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName,
|
||||||
aggregatorClient,
|
aggregatorClient,
|
||||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||||
@ -95,6 +96,7 @@ func PrepareControllers(
|
|||||||
WithController(
|
WithController(
|
||||||
apicerts.NewAPIServiceUpdaterController(
|
apicerts.NewAPIServiceUpdaterController(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
namesConfig.ServingCertificateSecret,
|
||||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||||
aggregatorClient,
|
aggregatorClient,
|
||||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||||
@ -105,6 +107,7 @@ func PrepareControllers(
|
|||||||
WithController(
|
WithController(
|
||||||
apicerts.NewCertsObserverController(
|
apicerts.NewCertsObserverController(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
namesConfig.ServingCertificateSecret,
|
||||||
dynamicCertProvider,
|
dynamicCertProvider,
|
||||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -114,6 +117,7 @@ func PrepareControllers(
|
|||||||
WithController(
|
WithController(
|
||||||
apicerts.NewCertsExpirerController(
|
apicerts.NewCertsExpirerController(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
namesConfig.ServingCertificateSecret,
|
||||||
k8sClient,
|
k8sClient,
|
||||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
@ -188,7 +192,7 @@ func createClients() (
|
|||||||
return nil, nil, nil, fmt.Errorf("could not initialize pinniped client: %w", err)
|
return nil, nil, nil, fmt.Errorf("could not initialize pinniped client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint: nakedret
|
//nolint: nakedret // Short function. Makes the order of return values more clear.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ func (a *App) runServer(ctx context.Context) error {
|
|||||||
serverInstallationNamespace := podInfo.Namespace
|
serverInstallationNamespace := podInfo.Namespace
|
||||||
|
|
||||||
// Load the Kubernetes cluster signing CA.
|
// Load the Kubernetes cluster signing CA.
|
||||||
k8sClusterCA, shutdownCA, err := getClusterCASigner(ctx, serverInstallationNamespace)
|
k8sClusterCA, shutdownCA, err := getClusterCASigner(ctx, serverInstallationNamespace, cfg.NamesConfig.CredentialIssuerConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -133,6 +133,7 @@ func (a *App) runServer(ctx context.Context) error {
|
|||||||
// post start hook of the aggregated API server.
|
// post start hook of the aggregated API server.
|
||||||
startControllersFunc, err := controllermanager.PrepareControllers(
|
startControllersFunc, err := controllermanager.PrepareControllers(
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
cfg.NamesConfig,
|
||||||
cfg.DiscoveryInfo.URL,
|
cfg.DiscoveryInfo.URL,
|
||||||
dynamicCertProvider,
|
dynamicCertProvider,
|
||||||
time.Duration(*cfg.APIConfig.ServingCertificateConfig.DurationSeconds)*time.Second,
|
time.Duration(*cfg.APIConfig.ServingCertificateConfig.DurationSeconds)*time.Second,
|
||||||
@ -164,7 +165,10 @@ func (a *App) runServer(ctx context.Context) error {
|
|||||||
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
|
return server.GenericAPIServer.PrepareRun().Run(ctx.Done())
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClusterCASigner(ctx context.Context, serverInstallationNamespace string) (credentialrequest.CertIssuer, kubecertauthority.ShutdownFunc, error) {
|
func getClusterCASigner(
|
||||||
|
ctx context.Context, serverInstallationNamespace string,
|
||||||
|
credentialIssuerConfigResourceName string,
|
||||||
|
) (credentialrequest.CertIssuer, kubecertauthority.ShutdownFunc, error) {
|
||||||
// Load the Kubernetes client configuration.
|
// Load the Kubernetes client configuration.
|
||||||
kubeConfig, err := restclient.InClusterConfig()
|
kubeConfig, err := restclient.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -195,6 +199,7 @@ func getClusterCASigner(ctx context.Context, serverInstallationNamespace string)
|
|||||||
err = issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
err = issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
||||||
ctx,
|
ctx,
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
credentialIssuerConfigResourceName,
|
||||||
pinnipedClient,
|
pinnipedClient,
|
||||||
func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.Strategies = []crdpinnipedv1alpha1.CredentialIssuerConfigStrategy{
|
configToUpdate.Status.Strategies = []crdpinnipedv1alpha1.CredentialIssuerConfigStrategy{
|
||||||
@ -216,6 +221,7 @@ func getClusterCASigner(ctx context.Context, serverInstallationNamespace string)
|
|||||||
if updateErr := issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
if updateErr := issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
||||||
ctx,
|
ctx,
|
||||||
serverInstallationNamespace,
|
serverInstallationNamespace,
|
||||||
|
credentialIssuerConfigResourceName,
|
||||||
pinnipedClient,
|
pinnipedClient,
|
||||||
func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig) {
|
func(configToUpdate *crdpinnipedv1alpha1.CredentialIssuerConfig) {
|
||||||
configToUpdate.Status.Strategies = []crdpinnipedv1alpha1.CredentialIssuerConfigStrategy{
|
configToUpdate.Status.Strategies = []crdpinnipedv1alpha1.CredentialIssuerConfigStrategy{
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
package api
|
package api
|
||||||
|
|
||||||
// Config contains knobs to setup an instance of pinniped.
|
// Config contains knobs to setup an instance of Pinniped.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DiscoveryInfo DiscoveryInfoSpec `json:"discovery"`
|
DiscoveryInfo DiscoveryInfoSpec `json:"discovery"`
|
||||||
APIConfig APIConfigSpec `json:"api"`
|
APIConfig APIConfigSpec `json:"api"`
|
||||||
|
NamesConfig NamesConfigSpec `json:"names"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscoveryInfoSpec contains configuration knobs specific to
|
// DiscoveryInfoSpec contains configuration knobs specific to
|
||||||
@ -18,12 +19,19 @@ type DiscoveryInfoSpec struct {
|
|||||||
URL *string `json:"url,omitempty"`
|
URL *string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIConfigSpec contains configuration knobs for the pinniped API.
|
// APIConfigSpec contains configuration knobs for the Pinniped API.
|
||||||
//nolint: golint
|
//nolint: golint
|
||||||
type APIConfigSpec struct {
|
type APIConfigSpec struct {
|
||||||
ServingCertificateConfig ServingCertificateConfigSpec `json:"servingCertificate"`
|
ServingCertificateConfig ServingCertificateConfigSpec `json:"servingCertificate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NamesConfigSpec configures the names of some Kubernetes resources for Pinniped.
|
||||||
|
type NamesConfigSpec struct {
|
||||||
|
ServingCertificateSecret string `json:"servingCertificateSecret"`
|
||||||
|
CredentialIssuerConfig string `json:"credentialIssuerConfig"`
|
||||||
|
APIService string `json:"apiService"`
|
||||||
|
}
|
||||||
|
|
||||||
// ServingCertificateConfigSpec contains the configuration knobs for the API's
|
// ServingCertificateConfigSpec contains the configuration knobs for the API's
|
||||||
// serving certificate, i.e., the x509 certificate that it uses for the server
|
// serving certificate, i.e., the x509 certificate that it uses for the server
|
||||||
// certificate in inbound TLS connections.
|
// certificate in inbound TLS connections.
|
||||||
@ -34,10 +42,10 @@ type ServingCertificateConfigSpec struct {
|
|||||||
// CA certificate.
|
// CA certificate.
|
||||||
DurationSeconds *int64 `json:"durationSeconds,omitempty"`
|
DurationSeconds *int64 `json:"durationSeconds,omitempty"`
|
||||||
|
|
||||||
// RenewBeforeSeconds is the period of time, in seconds, that pinniped will
|
// RenewBeforeSeconds is the period of time, in seconds, that Pinniped will
|
||||||
// wait before rotating the serving certificate. This period of time starts
|
// wait before rotating the serving certificate. This period of time starts
|
||||||
// upon issuance of the serving certificate. This must be less than
|
// upon issuance of the serving certificate. This must be less than
|
||||||
// DurationSeconds. By default, pinniped begins rotation after 23328000
|
// DurationSeconds. By default, Pinniped begins rotation after 23328000
|
||||||
// seconds (about 9 months).
|
// seconds (about 9 months).
|
||||||
RenewBeforeSeconds *int64 `json:"renewBeforeSeconds,omitempty"`
|
RenewBeforeSeconds *int64 `json:"renewBeforeSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package config
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
|
|
||||||
@ -44,6 +45,10 @@ func FromPath(path string) (*api.Config, error) {
|
|||||||
return nil, fmt.Errorf("validate api: %w", err)
|
return nil, fmt.Errorf("validate api: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := validateNames(&config.NamesConfig); err != nil {
|
||||||
|
return nil, fmt.Errorf("validate names: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &config, nil
|
return &config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +62,27 @@ func maybeSetAPIDefaults(apiConfig *api.APIConfigSpec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateNames(names *api.NamesConfigSpec) error {
|
||||||
|
missingNames := []string{}
|
||||||
|
if names == nil {
|
||||||
|
missingNames = append(missingNames, "servingCertificateSecret", "credentialIssuerConfig", "apiService")
|
||||||
|
} else {
|
||||||
|
if names.ServingCertificateSecret == "" {
|
||||||
|
missingNames = append(missingNames, "servingCertificateSecret")
|
||||||
|
}
|
||||||
|
if names.CredentialIssuerConfig == "" {
|
||||||
|
missingNames = append(missingNames, "credentialIssuerConfig")
|
||||||
|
}
|
||||||
|
if names.APIService == "" {
|
||||||
|
missingNames = append(missingNames, "apiService")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missingNames) > 0 {
|
||||||
|
return constable.Error("missing required names: " + strings.Join(missingNames, ", "))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func validateAPI(apiConfig *api.APIConfigSpec) error {
|
func validateAPI(apiConfig *api.APIConfigSpec) error {
|
||||||
if *apiConfig.ServingCertificateConfig.DurationSeconds < *apiConfig.ServingCertificateConfig.RenewBeforeSeconds {
|
if *apiConfig.ServingCertificateConfig.DurationSeconds < *apiConfig.ServingCertificateConfig.RenewBeforeSeconds {
|
||||||
return constable.Error("durationSeconds cannot be smaller than renewBeforeSeconds")
|
return constable.Error("durationSeconds cannot be smaller than renewBeforeSeconds")
|
||||||
|
@ -4,23 +4,38 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/vmware-tanzu/pinniped/internal/here"
|
||||||
"github.com/vmware-tanzu/pinniped/pkg/config/api"
|
"github.com/vmware-tanzu/pinniped/pkg/config/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFromPath(t *testing.T) {
|
func TestFromPath(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
path string
|
yaml string
|
||||||
wantConfig *api.Config
|
wantConfig *api.Config
|
||||||
wantError string
|
wantError string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Happy",
|
name: "Happy",
|
||||||
path: "testdata/happy.yaml",
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
discovery:
|
||||||
|
url: https://some.discovery/url
|
||||||
|
api:
|
||||||
|
servingCertificate:
|
||||||
|
durationSeconds: 3600
|
||||||
|
renewBeforeSeconds: 2400
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
wantConfig: &api.Config{
|
wantConfig: &api.Config{
|
||||||
DiscoveryInfo: api.DiscoveryInfoSpec{
|
DiscoveryInfo: api.DiscoveryInfoSpec{
|
||||||
URL: stringPtr("https://some.discovery/url"),
|
URL: stringPtr("https://some.discovery/url"),
|
||||||
@ -31,11 +46,22 @@ func TestFromPath(t *testing.T) {
|
|||||||
RenewBeforeSeconds: int64Ptr(2400),
|
RenewBeforeSeconds: int64Ptr(2400),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
NamesConfig: api.NamesConfigSpec{
|
||||||
|
ServingCertificateSecret: "pinniped-api-tls-serving-certificate",
|
||||||
|
CredentialIssuerConfig: "pinniped-config",
|
||||||
|
APIService: "pinniped-api",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Default",
|
name: "When only the required fields are present, causes other fields to be defaulted",
|
||||||
path: "testdata/default.yaml",
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
wantConfig: &api.Config{
|
wantConfig: &api.Config{
|
||||||
DiscoveryInfo: api.DiscoveryInfoSpec{
|
DiscoveryInfo: api.DiscoveryInfoSpec{
|
||||||
URL: nil,
|
URL: nil,
|
||||||
@ -46,28 +72,112 @@ func TestFromPath(t *testing.T) {
|
|||||||
RenewBeforeSeconds: int64Ptr(60 * 60 * 24 * 30 * 9), // about 9 months
|
RenewBeforeSeconds: int64Ptr(60 * 60 * 24 * 30 * 9), // about 9 months
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
NamesConfig: api.NamesConfigSpec{
|
||||||
|
ServingCertificateSecret: "pinniped-api-tls-serving-certificate",
|
||||||
|
CredentialIssuerConfig: "pinniped-config",
|
||||||
|
APIService: "pinniped-api",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Empty",
|
||||||
|
yaml: here.Doc(``),
|
||||||
|
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuerConfig, apiService",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing apiService name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: apiService",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing credentialIssuerConfig name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: credentialIssuerConfig",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Missing servingCertificateSecret name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: servingCertificateSecret",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "InvalidDurationRenewBefore",
|
name: "InvalidDurationRenewBefore",
|
||||||
path: "testdata/invalid-duration-renew-before.yaml",
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
api:
|
||||||
|
servingCertificate:
|
||||||
|
durationSeconds: 2400
|
||||||
|
renewBeforeSeconds: 3600
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
wantError: "validate api: durationSeconds cannot be smaller than renewBeforeSeconds",
|
wantError: "validate api: durationSeconds cannot be smaller than renewBeforeSeconds",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "NegativeRenewBefore",
|
name: "NegativeRenewBefore",
|
||||||
path: "testdata/negative-renew-before.yaml",
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
api:
|
||||||
|
servingCertificate:
|
||||||
|
durationSeconds: 2400
|
||||||
|
renewBeforeSeconds: -10
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
wantError: "validate api: renewBefore must be positive",
|
wantError: "validate api: renewBefore must be positive",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ZeroRenewBefore",
|
name: "ZeroRenewBefore",
|
||||||
path: "testdata/zero-renew-before.yaml",
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
api:
|
||||||
|
servingCertificate:
|
||||||
|
durationSeconds: 2400
|
||||||
|
renewBeforeSeconds: -10
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||||
|
credentialIssuerConfig: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
`),
|
||||||
wantError: "validate api: renewBefore must be positive",
|
wantError: "validate api: renewBefore must be positive",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
test := test
|
test := test
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
config, err := FromPath(test.path)
|
// Write yaml to temp file
|
||||||
|
f, err := ioutil.TempFile("", "pinniped-test-config-yaml-*")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
err := os.Remove(f.Name())
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
_, err = f.WriteString(test.yaml)
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = f.Close()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Test FromPath()
|
||||||
|
config, err := FromPath(f.Name())
|
||||||
|
|
||||||
if test.wantError != "" {
|
if test.wantError != "" {
|
||||||
require.EqualError(t, err, test.wantError)
|
require.EqualError(t, err, test.wantError)
|
||||||
} else {
|
} else {
|
||||||
|
1
pkg/config/testdata/default.yaml
vendored
1
pkg/config/testdata/default.yaml
vendored
@ -1 +0,0 @@
|
|||||||
---
|
|
7
pkg/config/testdata/happy.yaml
vendored
7
pkg/config/testdata/happy.yaml
vendored
@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
discovery:
|
|
||||||
url: https://some.discovery/url
|
|
||||||
api:
|
|
||||||
servingCertificate:
|
|
||||||
durationSeconds: 3600
|
|
||||||
renewBeforeSeconds: 2400
|
|
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
api:
|
|
||||||
servingCertificate:
|
|
||||||
durationSeconds: 2400
|
|
||||||
renewBeforeSeconds: 3600
|
|
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
api:
|
|
||||||
servingCertificate:
|
|
||||||
durationSeconds: 2400
|
|
||||||
renewBeforeSeconds: -10
|
|
5
pkg/config/testdata/zero-renew-before.yaml
vendored
5
pkg/config/testdata/zero-renew-before.yaml
vendored
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
api:
|
|
||||||
servingCertificate:
|
|
||||||
durationSeconds: 2400
|
|
||||||
renewBeforeSeconds: -10
|
|
@ -21,6 +21,8 @@ import (
|
|||||||
func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
||||||
library.SkipUnlessIntegration(t)
|
library.SkipUnlessIntegration(t)
|
||||||
|
|
||||||
|
const defaultServingCertResourceName = "pinniped-api-tls-serving-certificate"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
forceRotation func(context.Context, kubernetes.Interface, string) error
|
forceRotation func(context.Context, kubernetes.Interface, string) error
|
||||||
@ -36,7 +38,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
|||||||
return kubeClient.
|
return kubeClient.
|
||||||
CoreV1().
|
CoreV1().
|
||||||
Secrets(namespace).
|
Secrets(namespace).
|
||||||
Delete(ctx, "api-serving-cert", metav1.DeleteOptions{})
|
Delete(ctx, defaultServingCertResourceName, metav1.DeleteOptions{})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -51,7 +53,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
|||||||
secret, err := kubeClient.
|
secret, err := kubeClient.
|
||||||
CoreV1().
|
CoreV1().
|
||||||
Secrets(namespace).
|
Secrets(namespace).
|
||||||
Get(ctx, "api-serving-cert", metav1.GetOptions{})
|
Get(ctx, defaultServingCertResourceName, metav1.GetOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
|||||||
const apiServiceName = "v1alpha1.pinniped.dev"
|
const apiServiceName = "v1alpha1.pinniped.dev"
|
||||||
|
|
||||||
// Get the initial auto-generated version of the Secret.
|
// Get the initial auto-generated version of the Secret.
|
||||||
secret, err := kubeClient.CoreV1().Secrets(namespaceName).Get(ctx, "api-serving-cert", metav1.GetOptions{})
|
secret, err := kubeClient.CoreV1().Secrets(namespaceName).Get(ctx, defaultServingCertResourceName, metav1.GetOptions{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
initialCACert := secret.Data["caCertificate"]
|
initialCACert := secret.Data["caCertificate"]
|
||||||
initialPrivateKey := secret.Data["tlsPrivateKey"]
|
initialPrivateKey := secret.Data["tlsPrivateKey"]
|
||||||
@ -102,7 +104,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
|||||||
|
|
||||||
// Expect that the Secret comes back right away with newly minted certs.
|
// Expect that the Secret comes back right away with newly minted certs.
|
||||||
secretIsRegenerated := func() bool {
|
secretIsRegenerated := func() bool {
|
||||||
secret, err = kubeClient.CoreV1().Secrets(namespaceName).Get(ctx, "api-serving-cert", metav1.GetOptions{})
|
secret, err = kubeClient.CoreV1().Secrets(namespaceName).Get(ctx, defaultServingCertResourceName, metav1.GetOptions{})
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
assert.Eventually(t, secretIsRegenerated, 10*time.Second, 250*time.Millisecond)
|
assert.Eventually(t, secretIsRegenerated, 10*time.Second, 250*time.Millisecond)
|
||||||
|
@ -130,7 +130,7 @@ func runKubectlCLI(t *testing.T, kubeConfig, namespaceName, username string) str
|
|||||||
err = f.Close()
|
err = f.Close()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
//nolint: gosec
|
//nolint: gosec // It's okay that we are passing f.Name() to an exec command here. It was created above.
|
||||||
output, err := exec.Command(
|
output, err := exec.Command(
|
||||||
"kubectl",
|
"kubectl",
|
||||||
"get",
|
"get",
|
||||||
|
Loading…
Reference in New Issue
Block a user