Merge pull request #127 from vmware-tanzu/rename_stuff
Rename many of resources that are created in Kubernetes by Pinniped
This commit is contained in:
commit
49145791cc
@ -301,12 +301,15 @@ func startControllers(
|
||||
) {
|
||||
aVeryLongTime := time.Hour * 24 * 365 * 100
|
||||
|
||||
const certsSecretResourceName = "local-user-authenticator-tls-serving-certificate"
|
||||
|
||||
// Create controller manager.
|
||||
controllerManager := controllerlib.
|
||||
NewManager().
|
||||
WithController(
|
||||
apicerts.NewCertsManagerController(
|
||||
namespace,
|
||||
certsSecretResourceName,
|
||||
kubeClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -320,6 +323,7 @@ func startControllers(
|
||||
WithController(
|
||||
apicerts.NewCertsObserverController(
|
||||
namespace,
|
||||
certsSecretResourceName,
|
||||
dynamicCertProvider,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -367,7 +371,7 @@ func run() error {
|
||||
startControllers(ctx, dynamicCertProvider, kubeClient, kubeInformers)
|
||||
klog.InfoS("controllers are ready")
|
||||
|
||||
//nolint: gosec
|
||||
//nolint: gosec // Intentionally binding to all network interfaces.
|
||||
l, err := net.Listen("tcp", ":443")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create listener: %w", err)
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
@ -25,7 +24,6 @@ import (
|
||||
configv1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/1.19/client/clientset/versioned"
|
||||
"go.pinniped.dev/internal/constable"
|
||||
"go.pinniped.dev/internal/controller/issuerconfig"
|
||||
"go.pinniped.dev/internal/here"
|
||||
)
|
||||
|
||||
@ -239,20 +237,27 @@ func fetchPinnipedCredentialIssuerConfig(clientConfig clientcmd.ClientConfig, ku
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
||||
defer cancelFunc()
|
||||
|
||||
credentialIssuerConfig, err := clientset.ConfigV1alpha1().CredentialIssuerConfigs(pinnipedInstallationNamespace).Get(ctx, issuerconfig.ConfigName, metav1.GetOptions{})
|
||||
credentialIssuerConfigs, err := clientset.ConfigV1alpha1().CredentialIssuerConfigs(pinnipedInstallationNamespace).List(ctx, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, constable.Error(fmt.Sprintf(
|
||||
`CredentialIssuerConfig "%s" was not found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
|
||||
issuerconfig.ConfigName,
|
||||
pinnipedInstallationNamespace,
|
||||
pinnipedInstallationNamespace,
|
||||
))
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return credentialIssuerConfig, nil
|
||||
if len(credentialIssuerConfigs.Items) == 0 {
|
||||
return nil, constable.Error(fmt.Sprintf(
|
||||
`No CredentialIssuerConfig was found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
|
||||
pinnipedInstallationNamespace,
|
||||
pinnipedInstallationNamespace,
|
||||
))
|
||||
}
|
||||
|
||||
if len(credentialIssuerConfigs.Items) > 1 {
|
||||
return nil, constable.Error(fmt.Sprintf(
|
||||
`More than one CredentialIssuerConfig was found in namespace "%s"`,
|
||||
pinnipedInstallationNamespace,
|
||||
))
|
||||
}
|
||||
|
||||
return &credentialIssuerConfigs.Items[0], nil
|
||||
}
|
||||
|
||||
func newClientConfig(kubeconfigPathOverride string, currentContextName string) clientcmd.ClientConfig {
|
||||
|
@ -200,8 +200,17 @@ func TestNewGetKubeConfigCmd(t *testing.T) {
|
||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
||||
}
|
||||
|
||||
//nolint: unparam
|
||||
func expectedKubeconfigYAML(clusterCAData, clusterServer, command, token, pinnipedEndpoint, pinnipedCABundle, namespace string) string {
|
||||
func expectedKubeconfigYAML(
|
||||
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(`
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
@ -240,15 +249,21 @@ func expectedKubeconfigYAML(clusterCAData, clusterServer, command, token, pinnip
|
||||
`, clusterCAData, clusterServer, command, pinnipedEndpoint, pinnipedCABundle, namespace, token)
|
||||
}
|
||||
|
||||
func newCredentialIssuerConfig(server, certificateAuthorityData string) *configv1alpha1.CredentialIssuerConfig {
|
||||
func newCredentialIssuerConfig(
|
||||
name,
|
||||
//nolint: unparam // Pass in the namespace even if it is always the same in practice
|
||||
namespace,
|
||||
server,
|
||||
certificateAuthorityData string,
|
||||
) *configv1alpha1.CredentialIssuerConfig {
|
||||
return &configv1alpha1.CredentialIssuerConfig{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "CredentialIssuerConfig",
|
||||
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pinniped-config",
|
||||
Namespace: "some-namespace",
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Status: configv1alpha1.CredentialIssuerConfigStatus{
|
||||
KubeConfigInfo: &configv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
||||
@ -266,6 +281,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
var warningsBuffer *bytes.Buffer
|
||||
var fullPathToSelf string
|
||||
var pinnipedClient *pinnipedfake.Clientset
|
||||
const installationNamespace = "some-namespace"
|
||||
|
||||
it.Before(func() {
|
||||
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() {
|
||||
it.Before(func() {
|
||||
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",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -313,7 +334,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"https://fake-server-url-value",
|
||||
"fake-certificate-authority-data-value",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
), outputBuffer.String())
|
||||
})
|
||||
|
||||
@ -327,10 +348,12 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
Resource: "credentialissuerconfigs",
|
||||
},
|
||||
newCredentialIssuerConfig(
|
||||
"some-cic-name",
|
||||
installationNamespace,
|
||||
"https://some-other-fake-server-url-value",
|
||||
"some-other-fake-certificate-authority-data-value",
|
||||
),
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
))
|
||||
})
|
||||
|
||||
@ -342,7 +365,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"some-other-context",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://some-other-fake-server-url-value", restConfig.Host)
|
||||
@ -361,7 +384,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"https://some-other-fake-server-url-value",
|
||||
"some-other-fake-certificate-authority-data-value",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
), outputBuffer.String())
|
||||
})
|
||||
})
|
||||
@ -373,7 +396,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"this-context-name-does-not-exist-in-kubeconfig.yaml",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
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`)
|
||||
@ -390,7 +413,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) { return pinnipedClient, nil },
|
||||
)
|
||||
r.EqualError(err, "--token flag value cannot be empty")
|
||||
@ -406,7 +429,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/this-file-does-not-exist.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
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")
|
||||
@ -434,7 +457,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -453,7 +476,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"https://fake-server-url-value",
|
||||
"fake-certificate-authority-data-value",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
), outputBuffer.String())
|
||||
})
|
||||
})
|
||||
@ -474,7 +497,39 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
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)
|
||||
})
|
||||
})
|
||||
@ -484,7 +539,12 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
when("the Server doesn't match", func() {
|
||||
it.Before(func() {
|
||||
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",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -517,7 +577,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"https://fake-server-url-value",
|
||||
"fake-certificate-authority-data-value",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
), outputBuffer.String())
|
||||
})
|
||||
})
|
||||
@ -525,7 +585,12 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
when("the CA doesn't match", func() {
|
||||
it.Before(func() {
|
||||
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",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -558,7 +623,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"https://fake-server-url-value",
|
||||
"fake-certificate-authority-data-value",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
), outputBuffer.String())
|
||||
})
|
||||
})
|
||||
@ -574,7 +639,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pinniped-config",
|
||||
Namespace: "some-namespace",
|
||||
Namespace: installationNamespace,
|
||||
},
|
||||
Status: configv1alpha1.CredentialIssuerConfigStatus{},
|
||||
},
|
||||
@ -588,7 +653,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -611,7 +676,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
kubeClientCreatorFuncWasCalled = true
|
||||
r.Equal("https://fake-server-url-value", restConfig.Host)
|
||||
@ -620,7 +685,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
},
|
||||
)
|
||||
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(outputBuffer.String())
|
||||
})
|
||||
@ -633,7 +698,7 @@ func TestGetKubeConfig(t *testing.T) {
|
||||
"some-token",
|
||||
"./testdata/kubeconfig.yaml",
|
||||
"",
|
||||
"some-namespace",
|
||||
installationNamespace,
|
||||
func(restConfig *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
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.
|
||||
|
||||
```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} \
|
||||
| base64 -d \
|
||||
| tee /tmp/local-user-authenticator-ca
|
||||
|
@ -14,7 +14,7 @@ metadata:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: local-user-authenticator-service-account
|
||||
name: local-user-authenticator
|
||||
namespace: local-user-authenticator
|
||||
---
|
||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||
@ -47,7 +47,7 @@ spec:
|
||||
labels:
|
||||
app: local-user-authenticator
|
||||
spec:
|
||||
serviceAccountName: local-user-authenticator-service-account
|
||||
serviceAccountName: local-user-authenticator
|
||||
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
|
||||
imagePullSecrets:
|
||||
- name: image-pull-secret
|
||||
|
@ -8,7 +8,7 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: local-user-authenticator-aggregated-api-server-role
|
||||
name: local-user-authenticator
|
||||
namespace: local-user-authenticator
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
@ -18,13 +18,13 @@ rules:
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: local-user-authenticator-aggregated-api-server-role-binding
|
||||
name: local-user-authenticator
|
||||
namespace: local-user-authenticator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: local-user-authenticator-service-account
|
||||
name: local-user-authenticator
|
||||
namespace: local-user-authenticator
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: local-user-authenticator-aggregated-api-server-role
|
||||
name: local-user-authenticator
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
@ -14,7 +14,7 @@ metadata:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -25,6 +25,7 @@ metadata:
|
||||
labels:
|
||||
app: #@ data.values.app_name
|
||||
data:
|
||||
#! If names.apiService is changed in this ConfigMap, must also change name of the ClusterIP Service resource below.
|
||||
#@yaml/text-templated-strings
|
||||
pinniped.yaml: |
|
||||
discovery:
|
||||
@ -33,6 +34,10 @@ data:
|
||||
servingCertificate:
|
||||
durationSeconds: (@= str(data.values.api_serving_certificate_duration_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 != "":
|
||||
apiVersion: v1
|
||||
@ -66,7 +71,7 @@ spec:
|
||||
annotations:
|
||||
scheduler.alpha.kubernetes.io/critical-pod: ""
|
||||
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 != "":
|
||||
imagePullSecrets:
|
||||
- name: image-pull-secret
|
||||
@ -144,7 +149,8 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
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
|
||||
labels:
|
||||
app: #@ data.values.app_name
|
||||
|
@ -8,7 +8,7 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-aggregated-api-server-cluster-role"
|
||||
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: [namespaces]
|
||||
@ -23,14 +23,14 @@ rules:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-aggregated-api-server-cluster-role-binding"
|
||||
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
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
|
||||
|
||||
#! Give permission to various objects within the app's own namespace
|
||||
@ -38,7 +38,7 @@ roleRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-aggregated-api-server-role"
|
||||
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||
namespace: #@ data.values.namespace
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
@ -54,15 +54,15 @@ rules:
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-aggregated-api-server-role-binding"
|
||||
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||
namespace: #@ data.values.namespace
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: #@ data.values.app_name + "-aggregated-api-server-role"
|
||||
name: #@ data.values.app_name + "-aggregated-api-server"
|
||||
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
|
||||
@ -70,7 +70,7 @@ roleRef:
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-kube-system-pod-exec-role"
|
||||
name: #@ data.values.app_name + "-kube-system-pod-exec"
|
||||
namespace: kube-system
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
@ -83,23 +83,23 @@ rules:
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-kube-system-pod-exec-role-binding"
|
||||
name: #@ data.values.app_name + "-kube-system-pod-exec"
|
||||
namespace: kube-system
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
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
|
||||
|
||||
#! 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
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role"
|
||||
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||
rules:
|
||||
- apiGroups: [login.pinniped.dev]
|
||||
resources: [tokencredentialrequests]
|
||||
@ -108,7 +108,7 @@ rules:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role-binding"
|
||||
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated
|
||||
@ -118,7 +118,7 @@ subjects:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
name: #@ data.values.app_name + "-credentialrequests-cluster-role"
|
||||
name: #@ data.values.app_name + "-create-token-credential-requests"
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
#! Give permissions for subjectaccessreviews, tokenreview that is needed by aggregated api servers
|
||||
@ -126,11 +126,11 @@ roleRef:
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-service-account-cluster-role-binding"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
kind: ClusterRole
|
||||
@ -142,11 +142,11 @@ roleRef:
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-extension-apiserver-authentication-reader-role-binding"
|
||||
name: #@ data.values.app_name + "-extension-apiserver-authentication-reader"
|
||||
namespace: kube-system
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
kind: Role
|
||||
@ -158,7 +158,7 @@ roleRef:
|
||||
kind: Role
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher-role"
|
||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher"
|
||||
namespace: kube-public
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
@ -168,13 +168,13 @@ rules:
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher-role-binding"
|
||||
name: #@ data.values.app_name + "-cluster-info-lister-watcher"
|
||||
namespace: kube-public
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: #@ data.values.app_name + "-service-account"
|
||||
name: #@ data.values.app_name
|
||||
namespace: #@ data.values.namespace
|
||||
roleRef:
|
||||
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
|
||||
|
@ -75,7 +75,7 @@
|
||||
1. Fetch the auto-generated CA bundle for the `local-user-authenticator`'s HTTP TLS endpoint.
|
||||
|
||||
```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} \
|
||||
| tee /tmp/local-user-authenticator-ca-base64-encoded
|
||||
```
|
||||
|
@ -35,7 +35,7 @@ function unittest_cmd() {
|
||||
else
|
||||
cmd='go test'
|
||||
fi
|
||||
echo "${cmd} -count 1 -short -race ./..."
|
||||
echo "${cmd} -short -race ./..."
|
||||
}
|
||||
|
||||
function with_modules() {
|
||||
|
@ -177,7 +177,7 @@ kubectl create secret generic "$test_username" \
|
||||
app_name="pinniped"
|
||||
namespace="integration"
|
||||
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}')"
|
||||
|
||||
#
|
||||
|
@ -26,8 +26,7 @@ import (
|
||||
var (
|
||||
//nolint: gochecknoglobals
|
||||
scheme = runtime.NewScheme()
|
||||
//nolint: gochecknoglobals
|
||||
//nolint: golint
|
||||
//nolint: gochecknoglobals, golint
|
||||
Codecs = serializer.NewCodecFactory(scheme)
|
||||
)
|
||||
|
||||
|
@ -16,14 +16,16 @@ import (
|
||||
)
|
||||
|
||||
type apiServiceUpdaterController struct {
|
||||
namespace string
|
||||
aggregatorClient aggregatorclient.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
apiServiceName string
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
aggregatorClient aggregatorclient.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
apiServiceName string
|
||||
}
|
||||
|
||||
func NewAPIServiceUpdaterController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
apiServiceName string,
|
||||
aggregatorClient aggregatorclient.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
@ -33,15 +35,16 @@ func NewAPIServiceUpdaterController(
|
||||
controllerlib.Config{
|
||||
Name: "certs-manager-controller",
|
||||
Syncer: &apiServiceUpdaterController{
|
||||
namespace: namespace,
|
||||
aggregatorClient: aggregatorClient,
|
||||
secretInformer: secretInformer,
|
||||
apiServiceName: apiServiceName,
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
aggregatorClient: aggregatorClient,
|
||||
secretInformer: secretInformer,
|
||||
apiServiceName: apiServiceName,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
secretInformer,
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
@ -49,10 +52,10 @@ func NewAPIServiceUpdaterController(
|
||||
|
||||
func (c *apiServiceUpdaterController) Sync(ctx controllerlib.Context) error {
|
||||
// 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)
|
||||
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 {
|
||||
// The secret does not exist yet, so nothing to do.
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
var r *require.Assertions
|
||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
@ -41,6 +42,7 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
_ = NewAPIServiceUpdaterController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||
nil,
|
||||
secretsInformer,
|
||||
@ -55,8 +57,8 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||
|
||||
it.Before(func() {
|
||||
subject = secretsInformerFilter
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||
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) {
|
||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
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.
|
||||
subject = NewAPIServiceUpdaterController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||
aggregatorAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
@ -131,7 +135,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
Name: subject.Name(),
|
||||
Key: controllerlib.Key{
|
||||
Namespace: installedInNamespace,
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
},
|
||||
}
|
||||
|
||||
@ -154,7 +158,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
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() {
|
||||
unrelatedSecret := &corev1.Secret{
|
||||
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() {
|
||||
apiServingCertSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
|
@ -22,9 +22,10 @@ import (
|
||||
)
|
||||
|
||||
type certsExpirerController struct {
|
||||
namespace string
|
||||
k8sClient kubernetes.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
k8sClient kubernetes.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
|
||||
// renewBefore is the amount of time after the cert's issuance where
|
||||
// this controller will start to try to rotate it.
|
||||
@ -36,6 +37,7 @@ type certsExpirerController struct {
|
||||
// deletion forces rotation of the secret with the help of other controllers.
|
||||
func NewCertsExpirerController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
k8sClient kubernetes.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
@ -45,15 +47,16 @@ func NewCertsExpirerController(
|
||||
controllerlib.Config{
|
||||
Name: "certs-expirer-controller",
|
||||
Syncer: &certsExpirerController{
|
||||
namespace: namespace,
|
||||
k8sClient: k8sClient,
|
||||
secretInformer: secretInformer,
|
||||
renewBefore: renewBefore,
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
k8sClient: k8sClient,
|
||||
secretInformer: secretInformer,
|
||||
renewBefore: renewBefore,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
secretInformer,
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
@ -61,10 +64,10 @@ func NewCertsExpirerController(
|
||||
|
||||
// Sync implements controller.Syncer.Sync.
|
||||
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)
|
||||
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 {
|
||||
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.
|
||||
CoreV1().
|
||||
Secrets(c.namespace).
|
||||
Delete(ctx.Context, certsSecretName, metav1.DeleteOptions{})
|
||||
Delete(ctx.Context, c.certsSecretResourceName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
// Do return an error here so that the controller library will reschedule
|
||||
// us to try deleting this cert again.
|
||||
|
@ -29,6 +29,8 @@ import (
|
||||
func TestExpirerControllerFilters(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
namespace string
|
||||
@ -40,7 +42,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
namespace: "good-namespace",
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: "good-namespace",
|
||||
},
|
||||
},
|
||||
@ -62,7 +64,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
namespace: "good-namespacee",
|
||||
secret: corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: "bad-namespace",
|
||||
},
|
||||
},
|
||||
@ -92,6 +94,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
withInformer := testutil.NewObservableWithInformerOption()
|
||||
_ = NewCertsExpirerController(
|
||||
test.namespace,
|
||||
certsSecretResourceName,
|
||||
nil, // k8sClient, not needed
|
||||
secretsInformer,
|
||||
withInformer.WithInformer,
|
||||
@ -111,6 +114,8 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
func TestExpirerControllerSync(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
renewBefore time.Duration
|
||||
@ -220,7 +225,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
}
|
||||
|
||||
kubeInformerClient := kubernetesfake.NewSimpleClientset()
|
||||
name := "api-serving-cert" // See certs_manager.go.
|
||||
name := certsSecretResourceName
|
||||
namespace := "some-namespace"
|
||||
if test.fillSecretData != nil {
|
||||
secret := &corev1.Secret{
|
||||
@ -243,6 +248,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
|
||||
c := NewCertsExpirerController(
|
||||
namespace,
|
||||
certsSecretResourceName,
|
||||
kubeAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
|
@ -21,17 +21,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
//nolint: gosec
|
||||
certsSecretName = "api-serving-cert"
|
||||
caCertificateSecretKey = "caCertificate"
|
||||
tlsPrivateKeySecretKey = "tlsPrivateKey"
|
||||
tlsCertificateChainSecretKey = "tlsCertificateChain"
|
||||
)
|
||||
|
||||
type certsManagerController struct {
|
||||
namespace string
|
||||
k8sClient kubernetes.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
k8sClient kubernetes.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
|
||||
// certDuration is the lifetime of both the serving certificate and its CA
|
||||
// certificate that this controller will use when issuing the certificates.
|
||||
@ -41,7 +40,9 @@ type certsManagerController struct {
|
||||
serviceNameForGeneratedCertCommonName string
|
||||
}
|
||||
|
||||
func NewCertsManagerController(namespace string,
|
||||
func NewCertsManagerController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
k8sClient kubernetes.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
@ -55,6 +56,7 @@ func NewCertsManagerController(namespace string,
|
||||
Name: "certs-manager-controller",
|
||||
Syncer: &certsManagerController{
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
k8sClient: k8sClient,
|
||||
secretInformer: secretInformer,
|
||||
certDuration: certDuration,
|
||||
@ -64,23 +66,23 @@ func NewCertsManagerController(namespace string,
|
||||
},
|
||||
withInformer(
|
||||
secretInformer,
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
// Be sure to run once even if the Secret that the informer is watching doesn't exist.
|
||||
withInitialEvent(controllerlib.Key{
|
||||
Namespace: namespace,
|
||||
Name: certsSecretName,
|
||||
Name: certsSecretResourceName,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *certsManagerController) Sync(ctx controllerlib.Context) error {
|
||||
// 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)
|
||||
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 {
|
||||
// The secret already exists, so nothing to do.
|
||||
@ -112,7 +114,7 @@ func (c *certsManagerController) Sync(ctx controllerlib.Context) error {
|
||||
secret := corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: certsSecretName,
|
||||
Name: c.certsSecretResourceName,
|
||||
Namespace: c.namespace,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
func TestManagerControllerOptions(t *testing.T) {
|
||||
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
var r *require.Assertions
|
||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
@ -38,7 +39,17 @@ func TestManagerControllerOptions(t *testing.T) {
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
observableWithInitialEventOption = testutil.NewObservableWithInitialEventOption()
|
||||
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)
|
||||
})
|
||||
|
||||
@ -48,8 +59,8 @@ func TestManagerControllerOptions(t *testing.T) {
|
||||
|
||||
it.Before(func() {
|
||||
subject = secretsInformerFilter
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||
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() {
|
||||
r.Equal(controllerlib.Key{
|
||||
Namespace: installedInNamespace,
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
}, observableWithInitialEventOption.GetInitialEventKey())
|
||||
})
|
||||
})
|
||||
@ -104,6 +115,7 @@ func TestManagerControllerOptions(t *testing.T) {
|
||||
func TestManagerControllerSync(t *testing.T) {
|
||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
const certDuration = 12345678 * time.Second
|
||||
|
||||
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.
|
||||
subject = NewCertsManagerController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
kubeAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -137,7 +150,7 @@ func TestManagerControllerSync(t *testing.T) {
|
||||
Name: subject.Name(),
|
||||
Key: controllerlib.Key{
|
||||
Namespace: installedInNamespace,
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
},
|
||||
}
|
||||
|
||||
@ -160,7 +173,7 @@ func TestManagerControllerSync(t *testing.T) {
|
||||
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() {
|
||||
unrelatedSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@ -172,7 +185,7 @@ func TestManagerControllerSync(t *testing.T) {
|
||||
r.NoError(err)
|
||||
})
|
||||
|
||||
it("creates the api-serving-cert Secret", func() {
|
||||
it("creates the serving cert Secret", func() {
|
||||
startInformersAndController()
|
||||
err := controllerlib.TestSync(t, subject, *syncContext)
|
||||
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(installedInNamespace, actualAction.GetNamespace())
|
||||
actualSecret := actualAction.GetObject().(*corev1.Secret)
|
||||
r.Equal("api-serving-cert", actualSecret.Name)
|
||||
r.Equal(certsSecretResourceName, actualSecret.Name)
|
||||
r.Equal(installedInNamespace, actualSecret.Namespace)
|
||||
actualCACert := actualSecret.StringData["caCertificate"]
|
||||
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() {
|
||||
apiServingCertSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
}
|
||||
|
@ -16,13 +16,15 @@ import (
|
||||
)
|
||||
|
||||
type certsObserverController struct {
|
||||
namespace string
|
||||
dynamicCertProvider provider.DynamicTLSServingCertProvider
|
||||
secretInformer corev1informers.SecretInformer
|
||||
namespace string
|
||||
certsSecretResourceName string
|
||||
dynamicCertProvider provider.DynamicTLSServingCertProvider
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
|
||||
func NewCertsObserverController(
|
||||
namespace string,
|
||||
certsSecretResourceName string,
|
||||
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
@ -31,14 +33,15 @@ func NewCertsObserverController(
|
||||
controllerlib.Config{
|
||||
Name: "certs-observer-controller",
|
||||
Syncer: &certsObserverController{
|
||||
namespace: namespace,
|
||||
dynamicCertProvider: dynamicCertProvider,
|
||||
secretInformer: secretInformer,
|
||||
namespace: namespace,
|
||||
certsSecretResourceName: certsSecretResourceName,
|
||||
dynamicCertProvider: dynamicCertProvider,
|
||||
secretInformer: secretInformer,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
secretInformer,
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretName, namespace),
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(certsSecretResourceName, namespace),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
@ -46,10 +49,10 @@ func NewCertsObserverController(
|
||||
|
||||
func (c *certsObserverController) Sync(_ controllerlib.Context) error {
|
||||
// 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)
|
||||
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 {
|
||||
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) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
var r *require.Assertions
|
||||
var observableWithInformerOption *testutil.ObservableWithInformerOption
|
||||
@ -35,6 +36,7 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
_ = NewCertsObserverController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
nil,
|
||||
secretsInformer,
|
||||
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
|
||||
@ -48,8 +50,8 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
||||
|
||||
it.Before(func() {
|
||||
subject = secretsInformerFilter
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "api-serving-cert", Namespace: "wrong-namespace"}}
|
||||
target = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: installedInNamespace}}
|
||||
wrongNamespace = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: certsSecretResourceName, Namespace: "wrong-namespace"}}
|
||||
wrongName = &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace}}
|
||||
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) {
|
||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const installedInNamespace = "some-namespace"
|
||||
const certsSecretResourceName = "some-resource-name"
|
||||
|
||||
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.
|
||||
subject = NewCertsObserverController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
dynamicCertProvider,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -123,7 +127,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
Name: subject.Name(),
|
||||
Key: controllerlib.Key{
|
||||
Namespace: installedInNamespace,
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
},
|
||||
}
|
||||
|
||||
@ -146,7 +150,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
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() {
|
||||
unrelatedSecret := &corev1.Secret{
|
||||
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() {
|
||||
apiServingCertSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
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() {
|
||||
apiServingCertSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "api-serving-cert",
|
||||
Name: certsSecretResourceName,
|
||||
Namespace: installedInNamespace,
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
func CreateOrUpdateCredentialIssuerConfig(
|
||||
ctx context.Context,
|
||||
credentialIssuerConfigNamespace string,
|
||||
credentialIssuerConfigResourceName string,
|
||||
pinnipedClient pinnipedclientset.Interface,
|
||||
applyUpdatesToCredentialIssuerConfigFunc func(configToUpdate *configv1alpha1.CredentialIssuerConfig),
|
||||
) error {
|
||||
@ -26,7 +27,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
||||
existingCredentialIssuerConfig, err := pinnipedClient.
|
||||
ConfigV1alpha1().
|
||||
CredentialIssuerConfigs(credentialIssuerConfigNamespace).
|
||||
Get(ctx, ConfigName, metav1.GetOptions{})
|
||||
Get(ctx, credentialIssuerConfigResourceName, metav1.GetOptions{})
|
||||
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if err != nil && !notFound {
|
||||
@ -37,7 +38,7 @@ func CreateOrUpdateCredentialIssuerConfig(
|
||||
ctx,
|
||||
existingCredentialIssuerConfig,
|
||||
notFound,
|
||||
ConfigName,
|
||||
credentialIssuerConfigResourceName,
|
||||
credentialIssuerConfigNamespace,
|
||||
pinnipedClient,
|
||||
applyUpdatesToCredentialIssuerConfigFunc)
|
||||
|
@ -30,7 +30,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
var pinnipedAPIClient *pinnipedfake.Clientset
|
||||
var credentialIssuerConfigGVR schema.GroupVersionResource
|
||||
const installationNamespace = "some-namespace"
|
||||
const configName = "pinniped-config"
|
||||
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
@ -45,7 +45,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
|
||||
when("the config does not exist", 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 *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.KubeConfigInfo = &configv1alpha1.CredentialIssuerConfigKubeConfigInfo{
|
||||
CertificateAuthorityData: "some-ca-value",
|
||||
@ -54,7 +54,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
)
|
||||
r.NoError(err)
|
||||
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||
|
||||
expectedCreateAction := coretesting.NewCreateAction(
|
||||
credentialIssuerConfigGVR,
|
||||
@ -62,7 +62,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
&configv1alpha1.CredentialIssuerConfig{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
Name: credentialIssuerConfigResourceName,
|
||||
Namespace: installationNamespace,
|
||||
},
|
||||
Status: configv1alpha1.CredentialIssuerConfigStatus{
|
||||
@ -86,7 +86,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
it("returns an error", func() {
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {},
|
||||
)
|
||||
r.EqualError(err, "could not create or update credentialissuerconfig: create failed: error on create")
|
||||
@ -101,7 +101,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
existingConfig = &configv1alpha1.CredentialIssuerConfig{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: configName,
|
||||
Name: credentialIssuerConfigResourceName,
|
||||
Namespace: installationNamespace,
|
||||
},
|
||||
Status: configv1alpha1.CredentialIssuerConfigStatus{
|
||||
@ -124,14 +124,14 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
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 *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||
},
|
||||
)
|
||||
r.NoError(err)
|
||||
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||
|
||||
// Only the edited field should be changed.
|
||||
expectedUpdatedConfig := existingConfig.DeepCopy()
|
||||
@ -142,7 +142,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() {
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "initial-ca-value"
|
||||
|
||||
@ -154,7 +154,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
)
|
||||
r.NoError(err)
|
||||
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||
r.Equal([]coretesting.Action{expectedGetAction}, pinnipedAPIClient.Actions())
|
||||
})
|
||||
|
||||
@ -166,7 +166,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
it("returns an error", func() {
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {},
|
||||
)
|
||||
r.EqualError(err, "could not create or update credentialissuerconfig: get failed: error on get")
|
||||
@ -181,7 +181,7 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
it("returns an error", func() {
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||
},
|
||||
@ -215,14 +215,14 @@ func TestCreateOrUpdateCredentialIssuerConfig(t *testing.T) {
|
||||
})
|
||||
|
||||
it("retries updates on conflict", func() {
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, pinnipedAPIClient,
|
||||
err := CreateOrUpdateCredentialIssuerConfig(ctx, installationNamespace, credentialIssuerConfigResourceName, pinnipedAPIClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
||||
},
|
||||
)
|
||||
r.NoError(err)
|
||||
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, configName)
|
||||
expectedGetAction := coretesting.NewGetAction(credentialIssuerConfigGVR, installationNamespace, credentialIssuerConfigResourceName)
|
||||
|
||||
// The first attempted update only includes its own edits.
|
||||
firstExpectedUpdatedConfig := existingConfig.DeepCopy()
|
||||
|
@ -20,24 +20,22 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ClusterInfoNamespace = "kube-public"
|
||||
|
||||
ConfigName = "pinniped-config"
|
||||
|
||||
ClusterInfoNamespace = "kube-public"
|
||||
clusterInfoName = "cluster-info"
|
||||
clusterInfoConfigMapKey = "kubeconfig"
|
||||
)
|
||||
|
||||
type publisherController struct {
|
||||
namespace string
|
||||
serverOverride *string
|
||||
pinnipedClient pinnipedclientset.Interface
|
||||
configMapInformer corev1informers.ConfigMapInformer
|
||||
credentialIssuerConfigInformer configv1alpha1informers.CredentialIssuerConfigInformer
|
||||
namespace string
|
||||
credentialIssuerConfigResourceName string
|
||||
serverOverride *string
|
||||
pinnipedClient pinnipedclientset.Interface
|
||||
configMapInformer corev1informers.ConfigMapInformer
|
||||
credentialIssuerConfigInformer configv1alpha1informers.CredentialIssuerConfigInformer
|
||||
}
|
||||
|
||||
func NewPublisherController(
|
||||
namespace string,
|
||||
func NewPublisherController(namespace string,
|
||||
credentialIssuerConfigResourceName string,
|
||||
serverOverride *string,
|
||||
pinnipedClient pinnipedclientset.Interface,
|
||||
configMapInformer corev1informers.ConfigMapInformer,
|
||||
@ -48,11 +46,12 @@ func NewPublisherController(
|
||||
controllerlib.Config{
|
||||
Name: "publisher-controller",
|
||||
Syncer: &publisherController{
|
||||
namespace: namespace,
|
||||
serverOverride: serverOverride,
|
||||
pinnipedClient: pinnipedClient,
|
||||
configMapInformer: configMapInformer,
|
||||
credentialIssuerConfigInformer: credentialIssuerConfigInformer,
|
||||
credentialIssuerConfigResourceName: credentialIssuerConfigResourceName,
|
||||
namespace: namespace,
|
||||
serverOverride: serverOverride,
|
||||
pinnipedClient: pinnipedClient,
|
||||
configMapInformer: configMapInformer,
|
||||
credentialIssuerConfigInformer: credentialIssuerConfigInformer,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
@ -62,7 +61,7 @@ func NewPublisherController(
|
||||
),
|
||||
withInformer(
|
||||
credentialIssuerConfigInformer,
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(ConfigName, namespace),
|
||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(credentialIssuerConfigResourceName, namespace),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
)
|
||||
@ -112,7 +111,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
||||
existingCredentialIssuerConfigFromInformerCache, err := c.credentialIssuerConfigInformer.
|
||||
Lister().
|
||||
CredentialIssuerConfigs(c.namespace).
|
||||
Get(ConfigName)
|
||||
Get(c.credentialIssuerConfigResourceName)
|
||||
notFound = k8serrors.IsNotFound(err)
|
||||
if err != nil && !notFound {
|
||||
return fmt.Errorf("could not get credentialissuerconfig: %w", err)
|
||||
@ -129,7 +128,7 @@ func (c *publisherController) Sync(ctx controllerlib.Context) error {
|
||||
ctx.Context,
|
||||
existingCredentialIssuerConfigFromInformerCache,
|
||||
notFound,
|
||||
ConfigName,
|
||||
c.credentialIssuerConfigResourceName,
|
||||
c.namespace,
|
||||
c.pinnipedClient,
|
||||
updateServerAndCAFunc)
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
|
||||
func TestInformerFilters(t *testing.T) {
|
||||
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||
const installedInNamespace = "some-namespace"
|
||||
|
||||
var r *require.Assertions
|
||||
@ -44,6 +45,7 @@ func TestInformerFilters(t *testing.T) {
|
||||
credentialIssuerConfigInformer := pinnipedinformers.NewSharedInformerFactory(nil, 0).Config().V1alpha1().CredentialIssuerConfigs()
|
||||
_ = NewPublisherController(
|
||||
installedInNamespace,
|
||||
credentialIssuerConfigResourceName,
|
||||
nil,
|
||||
nil,
|
||||
configMapInformer,
|
||||
@ -109,10 +111,10 @@ func TestInformerFilters(t *testing.T) {
|
||||
it.Before(func() {
|
||||
subject = credentialIssuerConfigInformerFilter
|
||||
target = &configv1alpha1.CredentialIssuerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "pinniped-config", Namespace: installedInNamespace},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerConfigResourceName, Namespace: installedInNamespace},
|
||||
}
|
||||
wrongNamespace = &configv1alpha1.CredentialIssuerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "pinniped-config", Namespace: "wrong-namespace"},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: credentialIssuerConfigResourceName, Namespace: "wrong-namespace"},
|
||||
}
|
||||
wrongName = &configv1alpha1.CredentialIssuerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: installedInNamespace},
|
||||
@ -162,6 +164,7 @@ func TestInformerFilters(t *testing.T) {
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
|
||||
const credentialIssuerConfigResourceName = "some-resource-name"
|
||||
const installedInNamespace = "some-namespace"
|
||||
|
||||
var r *require.Assertions
|
||||
@ -185,7 +188,7 @@ func TestSync(t *testing.T) {
|
||||
}
|
||||
expectedCredentialIssuerConfig := &configv1alpha1.CredentialIssuerConfig{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pinniped-config",
|
||||
Name: credentialIssuerConfigResourceName,
|
||||
Namespace: expectedNamespace,
|
||||
},
|
||||
Status: configv1alpha1.CredentialIssuerConfigStatus{
|
||||
@ -205,6 +208,7 @@ func TestSync(t *testing.T) {
|
||||
// Set this at the last second to allow for injection of server override.
|
||||
subject = NewPublisherController(
|
||||
installedInNamespace,
|
||||
credentialIssuerConfigResourceName,
|
||||
serverOverride,
|
||||
pinnipedAPIClient,
|
||||
kubeInformers.Core().V1().ConfigMaps(),
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"go.pinniped.dev/internal/controller/issuerconfig"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/provider"
|
||||
"go.pinniped.dev/pkg/config/api"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,6 +36,7 @@ const (
|
||||
// Prepare the controllers and their informers and return a function that will start them when called.
|
||||
func PrepareControllers(
|
||||
serverInstallationNamespace string,
|
||||
namesConfig api.NamesConfigSpec,
|
||||
discoveryURLOverride *string,
|
||||
dynamicCertProvider provider.DynamicTLSServingCertProvider,
|
||||
servingCertDuration time.Duration,
|
||||
@ -51,15 +53,12 @@ func PrepareControllers(
|
||||
kubePublicNamespaceK8sInformers, installationNamespaceK8sInformers, installationNamespacePinnipedInformers :=
|
||||
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.
|
||||
controllerManager := controllerlib.
|
||||
NewManager().
|
||||
WithController(
|
||||
issuerconfig.NewPublisherController(
|
||||
serverInstallationNamespace,
|
||||
issuerconfig.NewPublisherController(serverInstallationNamespace,
|
||||
namesConfig.CredentialIssuerConfig,
|
||||
discoveryURLOverride,
|
||||
pinnipedClient,
|
||||
kubePublicNamespaceK8sInformers.Core().V1().ConfigMaps(),
|
||||
@ -71,19 +70,21 @@ func PrepareControllers(
|
||||
WithController(
|
||||
apicerts.NewCertsManagerController(
|
||||
serverInstallationNamespace,
|
||||
namesConfig.ServingCertificateSecret,
|
||||
k8sClient,
|
||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
controllerlib.WithInitialEvent,
|
||||
servingCertDuration,
|
||||
"Pinniped CA",
|
||||
serviceName,
|
||||
namesConfig.APIService,
|
||||
),
|
||||
singletonWorker,
|
||||
).
|
||||
WithController(
|
||||
apicerts.NewAPIServiceUpdaterController(
|
||||
serverInstallationNamespace,
|
||||
namesConfig.ServingCertificateSecret,
|
||||
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName,
|
||||
aggregatorClient,
|
||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||
@ -94,6 +95,7 @@ func PrepareControllers(
|
||||
WithController(
|
||||
apicerts.NewCertsObserverController(
|
||||
serverInstallationNamespace,
|
||||
namesConfig.ServingCertificateSecret,
|
||||
dynamicCertProvider,
|
||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -103,6 +105,7 @@ func PrepareControllers(
|
||||
WithController(
|
||||
apicerts.NewCertsExpirerController(
|
||||
serverInstallationNamespace,
|
||||
namesConfig.ServingCertificateSecret,
|
||||
k8sClient,
|
||||
installationNamespaceK8sInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
@ -177,7 +180,7 @@ func createClients() (
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
serverInstallationNamespace := podInfo.Namespace
|
||||
|
||||
// Load the Kubernetes cluster signing CA.
|
||||
k8sClusterCA, shutdownCA, err := getClusterCASigner(ctx, serverInstallationNamespace)
|
||||
k8sClusterCA, shutdownCA, err := getClusterCASigner(ctx, serverInstallationNamespace, cfg.NamesConfig.CredentialIssuerConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -133,6 +133,7 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
// post start hook of the aggregated API server.
|
||||
startControllersFunc, err := controllermanager.PrepareControllers(
|
||||
serverInstallationNamespace,
|
||||
cfg.NamesConfig,
|
||||
cfg.DiscoveryInfo.URL,
|
||||
dynamicCertProvider,
|
||||
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())
|
||||
}
|
||||
|
||||
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.
|
||||
kubeConfig, err := restclient.InClusterConfig()
|
||||
if err != nil {
|
||||
@ -195,6 +199,7 @@ func getClusterCASigner(ctx context.Context, serverInstallationNamespace string)
|
||||
err = issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
||||
ctx,
|
||||
serverInstallationNamespace,
|
||||
credentialIssuerConfigResourceName,
|
||||
pinnipedClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.Strategies = []configv1alpha1.CredentialIssuerConfigStrategy{
|
||||
@ -216,6 +221,7 @@ func getClusterCASigner(ctx context.Context, serverInstallationNamespace string)
|
||||
if updateErr := issuerconfig.CreateOrUpdateCredentialIssuerConfig(
|
||||
ctx,
|
||||
serverInstallationNamespace,
|
||||
credentialIssuerConfigResourceName,
|
||||
pinnipedClient,
|
||||
func(configToUpdate *configv1alpha1.CredentialIssuerConfig) {
|
||||
configToUpdate.Status.Strategies = []configv1alpha1.CredentialIssuerConfigStrategy{
|
||||
|
@ -3,10 +3,11 @@
|
||||
|
||||
package api
|
||||
|
||||
// Config contains knobs to setup an instance of pinniped.
|
||||
// Config contains knobs to setup an instance of Pinniped.
|
||||
type Config struct {
|
||||
DiscoveryInfo DiscoveryInfoSpec `json:"discovery"`
|
||||
APIConfig APIConfigSpec `json:"api"`
|
||||
NamesConfig NamesConfigSpec `json:"names"`
|
||||
}
|
||||
|
||||
// DiscoveryInfoSpec contains configuration knobs specific to
|
||||
@ -18,12 +19,19 @@ type DiscoveryInfoSpec struct {
|
||||
URL *string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// APIConfigSpec contains configuration knobs for the pinniped API.
|
||||
// APIConfigSpec contains configuration knobs for the Pinniped API.
|
||||
//nolint: golint
|
||||
type APIConfigSpec struct {
|
||||
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
|
||||
// serving certificate, i.e., the x509 certificate that it uses for the server
|
||||
// certificate in inbound TLS connections.
|
||||
@ -34,10 +42,10 @@ type ServingCertificateConfigSpec struct {
|
||||
// CA certificate.
|
||||
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
|
||||
// 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).
|
||||
RenewBeforeSeconds *int64 `json:"renewBeforeSeconds,omitempty"`
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
@ -44,6 +45,10 @@ func FromPath(path string) (*api.Config, error) {
|
||||
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
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
if *apiConfig.ServingCertificateConfig.DurationSeconds < *apiConfig.ServingCertificateConfig.RenewBeforeSeconds {
|
||||
return constable.Error("durationSeconds cannot be smaller than renewBeforeSeconds")
|
||||
|
@ -4,23 +4,38 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.pinniped.dev/internal/here"
|
||||
"go.pinniped.dev/pkg/config/api"
|
||||
)
|
||||
|
||||
func TestFromPath(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
yaml string
|
||||
wantConfig *api.Config
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
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{
|
||||
DiscoveryInfo: api.DiscoveryInfoSpec{
|
||||
URL: stringPtr("https://some.discovery/url"),
|
||||
@ -31,11 +46,22 @@ func TestFromPath(t *testing.T) {
|
||||
RenewBeforeSeconds: int64Ptr(2400),
|
||||
},
|
||||
},
|
||||
NamesConfig: api.NamesConfigSpec{
|
||||
ServingCertificateSecret: "pinniped-api-tls-serving-certificate",
|
||||
CredentialIssuerConfig: "pinniped-config",
|
||||
APIService: "pinniped-api",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Default",
|
||||
path: "testdata/default.yaml",
|
||||
name: "When only the required fields are present, causes other fields to be defaulted",
|
||||
yaml: here.Doc(`
|
||||
---
|
||||
names:
|
||||
servingCertificateSecret: pinniped-api-tls-serving-certificate
|
||||
credentialIssuerConfig: pinniped-config
|
||||
apiService: pinniped-api
|
||||
`),
|
||||
wantConfig: &api.Config{
|
||||
DiscoveryInfo: api.DiscoveryInfoSpec{
|
||||
URL: nil,
|
||||
@ -46,28 +72,112 @@ func TestFromPath(t *testing.T) {
|
||||
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: "InvalidDurationRenewBefore",
|
||||
path: "testdata/invalid-duration-renew-before.yaml",
|
||||
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",
|
||||
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",
|
||||
},
|
||||
{
|
||||
name: "NegativeRenewBefore",
|
||||
path: "testdata/negative-renew-before.yaml",
|
||||
name: "NegativeRenewBefore",
|
||||
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",
|
||||
},
|
||||
{
|
||||
name: "ZeroRenewBefore",
|
||||
path: "testdata/zero-renew-before.yaml",
|
||||
name: "ZeroRenewBefore",
|
||||
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",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
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 != "" {
|
||||
require.EqualError(t, err, test.wantError)
|
||||
} 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) {
|
||||
library.SkipUnlessIntegration(t)
|
||||
|
||||
const defaultServingCertResourceName = "pinniped-api-tls-serving-certificate"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
forceRotation func(context.Context, kubernetes.Interface, string) error
|
||||
@ -36,7 +38,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
||||
return kubeClient.
|
||||
CoreV1().
|
||||
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.
|
||||
CoreV1().
|
||||
Secrets(namespace).
|
||||
Get(ctx, "api-serving-cert", metav1.GetOptions{})
|
||||
Get(ctx, defaultServingCertResourceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -83,7 +85,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
|
||||
const apiServiceName = "v1alpha1.login.pinniped.dev"
|
||||
|
||||
// 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)
|
||||
initialCACert := secret.Data["caCertificate"]
|
||||
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.
|
||||
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
|
||||
}
|
||||
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()
|
||||
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(
|
||||
"kubectl",
|
||||
"get",
|
||||
|
Loading…
Reference in New Issue
Block a user