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:
Ryan Richard 2020-09-18 16:58:44 -07:00 committed by GitHub
commit 49145791cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 493 additions and 240 deletions

View File

@ -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)

View File

@ -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, err
}
if len(credentialIssuerConfigs.Items) == 0 {
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,
`No CredentialIssuerConfig was found in namespace "%s". Is Pinniped installed on this cluster in namespace "%s"?`,
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 {

View File

@ -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")
},

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
```

View File

@ -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() {

View File

@ -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}')"
#

View File

@ -26,8 +26,7 @@ import (
var (
//nolint: gochecknoglobals
scheme = runtime.NewScheme()
//nolint: gochecknoglobals
//nolint: golint
//nolint: gochecknoglobals, golint
Codecs = serializer.NewCodecFactory(scheme)
)

View File

@ -17,6 +17,7 @@ import (
type apiServiceUpdaterController struct {
namespace string
certsSecretResourceName string
aggregatorClient aggregatorclient.Interface
secretInformer corev1informers.SecretInformer
apiServiceName string
@ -24,6 +25,7 @@ type apiServiceUpdaterController struct {
func NewAPIServiceUpdaterController(
namespace string,
certsSecretResourceName string,
apiServiceName string,
aggregatorClient aggregatorclient.Interface,
secretInformer corev1informers.SecretInformer,
@ -34,6 +36,7 @@ func NewAPIServiceUpdaterController(
Name: "certs-manager-controller",
Syncer: &apiServiceUpdaterController{
namespace: namespace,
certsSecretResourceName: certsSecretResourceName,
aggregatorClient: aggregatorClient,
secretInformer: secretInformer,
apiServiceName: apiServiceName,
@ -41,7 +44,7 @@ func NewAPIServiceUpdaterController(
},
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.

View File

@ -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{

View File

@ -23,6 +23,7 @@ import (
type certsExpirerController struct {
namespace string
certsSecretResourceName string
k8sClient kubernetes.Interface
secretInformer corev1informers.SecretInformer
@ -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,
@ -46,6 +48,7 @@ func NewCertsExpirerController(
Name: "certs-expirer-controller",
Syncer: &certsExpirerController{
namespace: namespace,
certsSecretResourceName: certsSecretResourceName,
k8sClient: k8sClient,
secretInformer: secretInformer,
renewBefore: renewBefore,
@ -53,7 +56,7 @@ func NewCertsExpirerController(
},
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.

View File

@ -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,

View File

@ -21,8 +21,6 @@ import (
)
const (
//nolint: gosec
certsSecretName = "api-serving-cert"
caCertificateSecretKey = "caCertificate"
tlsPrivateKeySecretKey = "tlsPrivateKey"
tlsCertificateChainSecretKey = "tlsCertificateChain"
@ -30,6 +28,7 @@ const (
type certsManagerController struct {
namespace string
certsSecretResourceName string
k8sClient kubernetes.Interface
secretInformer corev1informers.SecretInformer
@ -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{

View File

@ -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,
},
}

View File

@ -17,12 +17,14 @@ import (
type certsObserverController struct {
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,
@ -32,13 +34,14 @@ func NewCertsObserverController(
Name: "certs-observer-controller",
Syncer: &certsObserverController{
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")

View File

@ -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{},

View File

@ -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)

View File

@ -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()

View File

@ -21,23 +21,21 @@ import (
const (
ClusterInfoNamespace = "kube-public"
ConfigName = "pinniped-config"
clusterInfoName = "cluster-info"
clusterInfoConfigMapKey = "kubeconfig"
)
type publisherController struct {
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,6 +46,7 @@ func NewPublisherController(
controllerlib.Config{
Name: "publisher-controller",
Syncer: &publisherController{
credentialIssuerConfigResourceName: credentialIssuerConfigResourceName,
namespace: namespace,
serverOverride: serverOverride,
pinnipedClient: pinnipedClient,
@ -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)

View File

@ -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(),

View File

@ -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
}

View File

@ -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{

View File

@ -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"`
}

View File

@ -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")

View File

@ -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: "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",
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",
},
{
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",
},
{
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",
},
}
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 {

View File

@ -1 +0,0 @@
---

View File

@ -1,7 +0,0 @@
---
discovery:
url: https://some.discovery/url
api:
servingCertificate:
durationSeconds: 3600
renewBeforeSeconds: 2400

View File

@ -1,5 +0,0 @@
---
api:
servingCertificate:
durationSeconds: 2400
renewBeforeSeconds: 3600

View File

@ -1,5 +0,0 @@
---
api:
servingCertificate:
durationSeconds: 2400
renewBeforeSeconds: -10

View File

@ -1,5 +0,0 @@
---
api:
servingCertificate:
durationSeconds: 2400
renewBeforeSeconds: -10

View File

@ -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)

View File

@ -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",