Rename existing references to "IDP" and "Identity Provider".
Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
parent
f3a83882a4
commit
34da8c7877
@ -60,11 +60,11 @@ func newExchangeCredentialCmd(args []string, stdout, stderr io.Writer) *exchange
|
||||
Requires all of the following environment variables, which are
|
||||
typically set in the kubeconfig:
|
||||
- PINNIPED_TOKEN: the token to send to Pinniped for exchange
|
||||
- PINNIPED_NAMESPACE: the namespace of the identity provider to authenticate
|
||||
- PINNIPED_NAMESPACE: the namespace of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_IDP_TYPE: the type of identity provider to authenticate
|
||||
- PINNIPED_AUTHENTICATOR_TYPE: the type of authenticator to authenticate
|
||||
against (e.g., "webhook")
|
||||
- PINNIPED_IDP_NAME: the name of the identity provider to authenticate
|
||||
- PINNIPED_AUTHENTICATOR_NAME: the name of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_CA_BUNDLE: the CA bundle to trust when calling
|
||||
Pinniped's HTTPS endpoint
|
||||
@ -87,15 +87,15 @@ type envGetter func(string) (string, bool)
|
||||
type tokenExchanger func(
|
||||
ctx context.Context,
|
||||
namespace string,
|
||||
idp corev1.TypedLocalObjectReference,
|
||||
authenticator corev1.TypedLocalObjectReference,
|
||||
token string,
|
||||
caBundle string,
|
||||
apiEndpoint string,
|
||||
) (*clientauthenticationv1beta1.ExecCredential, error)
|
||||
|
||||
const (
|
||||
ErrMissingEnvVar = constable.Error("failed to get credential: environment variable not set")
|
||||
ErrInvalidIDPType = constable.Error("invalid IDP type")
|
||||
ErrMissingEnvVar = constable.Error("failed to get credential: environment variable not set")
|
||||
ErrInvalidAuthenticatorType = constable.Error("invalid authenticator type")
|
||||
)
|
||||
|
||||
func runExchangeCredential(stdout, _ io.Writer) {
|
||||
@ -115,14 +115,14 @@ func exchangeCredential(envGetter envGetter, tokenExchanger tokenExchanger, outp
|
||||
return envVarNotSetError("PINNIPED_NAMESPACE")
|
||||
}
|
||||
|
||||
idpType, varExists := envGetter("PINNIPED_IDP_TYPE")
|
||||
authenticatorType, varExists := envGetter("PINNIPED_AUTHENTICATOR_TYPE")
|
||||
if !varExists {
|
||||
return envVarNotSetError("PINNIPED_IDP_TYPE")
|
||||
return envVarNotSetError("PINNIPED_AUTHENTICATOR_TYPE")
|
||||
}
|
||||
|
||||
idpName, varExists := envGetter("PINNIPED_IDP_NAME")
|
||||
authenticatorName, varExists := envGetter("PINNIPED_AUTHENTICATOR_NAME")
|
||||
if !varExists {
|
||||
return envVarNotSetError("PINNIPED_IDP_NAME")
|
||||
return envVarNotSetError("PINNIPED_AUTHENTICATOR_NAME")
|
||||
}
|
||||
|
||||
token, varExists := envGetter("PINNIPED_TOKEN")
|
||||
@ -140,16 +140,16 @@ func exchangeCredential(envGetter envGetter, tokenExchanger tokenExchanger, outp
|
||||
return envVarNotSetError("PINNIPED_K8S_API_ENDPOINT")
|
||||
}
|
||||
|
||||
idp := corev1.TypedLocalObjectReference{Name: idpName}
|
||||
switch strings.ToLower(idpType) {
|
||||
authenticator := corev1.TypedLocalObjectReference{Name: authenticatorName}
|
||||
switch strings.ToLower(authenticatorType) {
|
||||
case "webhook":
|
||||
idp.APIGroup = &auth1alpha1.SchemeGroupVersion.Group
|
||||
idp.Kind = "WebhookAuthenticator"
|
||||
authenticator.APIGroup = &auth1alpha1.SchemeGroupVersion.Group
|
||||
authenticator.Kind = "WebhookAuthenticator"
|
||||
default:
|
||||
return fmt.Errorf(`%w: %q, supported values are "webhook"`, ErrInvalidIDPType, idpType)
|
||||
return fmt.Errorf(`%w: %q, supported values are "webhook"`, ErrInvalidAuthenticatorType, authenticatorType)
|
||||
}
|
||||
|
||||
cred, err := tokenExchanger(ctx, namespace, idp, token, caBundle, apiEndpoint)
|
||||
cred, err := tokenExchanger(ctx, namespace, authenticator, token, caBundle, apiEndpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get credential: %w", err)
|
||||
}
|
||||
|
@ -43,11 +43,11 @@ var (
|
||||
Requires all of the following environment variables, which are
|
||||
typically set in the kubeconfig:
|
||||
- PINNIPED_TOKEN: the token to send to Pinniped for exchange
|
||||
- PINNIPED_NAMESPACE: the namespace of the identity provider to authenticate
|
||||
- PINNIPED_NAMESPACE: the namespace of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_IDP_TYPE: the type of identity provider to authenticate
|
||||
- PINNIPED_AUTHENTICATOR_TYPE: the type of authenticator to authenticate
|
||||
against (e.g., "webhook")
|
||||
- PINNIPED_IDP_NAME: the name of the identity provider to authenticate
|
||||
- PINNIPED_AUTHENTICATOR_NAME: the name of the authenticator to authenticate
|
||||
against
|
||||
- PINNIPED_CA_BUNDLE: the CA bundle to trust when calling
|
||||
Pinniped's HTTPS endpoint
|
||||
@ -142,12 +142,12 @@ func TestExchangeCredential(t *testing.T) {
|
||||
r = require.New(t)
|
||||
buffer = new(bytes.Buffer)
|
||||
fakeEnv = map[string]string{
|
||||
"PINNIPED_NAMESPACE": "namespace from env",
|
||||
"PINNIPED_IDP_TYPE": "Webhook",
|
||||
"PINNIPED_IDP_NAME": "webhook name from env",
|
||||
"PINNIPED_TOKEN": "token from env",
|
||||
"PINNIPED_CA_BUNDLE": "ca bundle from env",
|
||||
"PINNIPED_K8S_API_ENDPOINT": "k8s api from env",
|
||||
"PINNIPED_NAMESPACE": "namespace from env",
|
||||
"PINNIPED_AUTHENTICATOR_TYPE": "Webhook",
|
||||
"PINNIPED_AUTHENTICATOR_NAME": "webhook name from env",
|
||||
"PINNIPED_TOKEN": "token from env",
|
||||
"PINNIPED_CA_BUNDLE": "ca bundle from env",
|
||||
"PINNIPED_K8S_API_ENDPOINT": "k8s api from env",
|
||||
}
|
||||
})
|
||||
|
||||
@ -158,16 +158,16 @@ func TestExchangeCredential(t *testing.T) {
|
||||
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_NAMESPACE")
|
||||
})
|
||||
|
||||
it("returns an error when PINNIPED_IDP_TYPE is missing", func() {
|
||||
delete(fakeEnv, "PINNIPED_IDP_TYPE")
|
||||
it("returns an error when PINNIPED_AUTHENTICATOR_TYPE is missing", func() {
|
||||
delete(fakeEnv, "PINNIPED_AUTHENTICATOR_TYPE")
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_IDP_TYPE")
|
||||
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_AUTHENTICATOR_TYPE")
|
||||
})
|
||||
|
||||
it("returns an error when PINNIPED_IDP_NAME is missing", func() {
|
||||
delete(fakeEnv, "PINNIPED_IDP_NAME")
|
||||
it("returns an error when PINNIPED_AUTHENTICATOR_NAME is missing", func() {
|
||||
delete(fakeEnv, "PINNIPED_AUTHENTICATOR_NAME")
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_IDP_NAME")
|
||||
r.EqualError(err, "failed to get credential: environment variable not set: PINNIPED_AUTHENTICATOR_NAME")
|
||||
})
|
||||
|
||||
it("returns an error when PINNIPED_TOKEN is missing", func() {
|
||||
@ -190,16 +190,16 @@ func TestExchangeCredential(t *testing.T) {
|
||||
})
|
||||
|
||||
when("env vars are invalid", func() {
|
||||
it("returns an error when PINNIPED_IDP_TYPE is missing", func() {
|
||||
fakeEnv["PINNIPED_IDP_TYPE"] = "invalid"
|
||||
it("returns an error when PINNIPED_AUTHENTICATOR_TYPE is missing", func() {
|
||||
fakeEnv["PINNIPED_AUTHENTICATOR_TYPE"] = "invalid"
|
||||
err := exchangeCredential(envGetter, tokenExchanger, buffer, 30*time.Second)
|
||||
r.EqualError(err, `invalid IDP type: "invalid", supported values are "webhook"`)
|
||||
r.EqualError(err, `invalid authenticator type: "invalid", supported values are "webhook"`)
|
||||
})
|
||||
})
|
||||
|
||||
when("the token exchange fails", func() {
|
||||
it.Before(func() {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, idp corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
return nil, fmt.Errorf("some error")
|
||||
}
|
||||
})
|
||||
@ -212,7 +212,7 @@ func TestExchangeCredential(t *testing.T) {
|
||||
|
||||
when("the JSON encoder fails", func() {
|
||||
it.Before(func() {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, idp corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
return &clientauthenticationv1beta1.ExecCredential{
|
||||
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
||||
Token: "some token",
|
||||
@ -229,7 +229,7 @@ func TestExchangeCredential(t *testing.T) {
|
||||
|
||||
when("the token exchange times out", func() {
|
||||
it.Before(func() {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, idp corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
select {
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
return &clientauthenticationv1beta1.ExecCredential{
|
||||
@ -253,7 +253,7 @@ func TestExchangeCredential(t *testing.T) {
|
||||
var actualNamespace, actualToken, actualCaBundle, actualAPIEndpoint string
|
||||
|
||||
it.Before(func() {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, idp corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
tokenExchanger = func(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
actualNamespace, actualToken, actualCaBundle, actualAPIEndpoint = namespace, token, caBundle, apiEndpoint
|
||||
now := metav1.NewTime(time.Date(2020, 7, 29, 1, 2, 3, 0, time.UTC))
|
||||
return &clientauthenticationv1beta1.ExecCredential{
|
||||
|
@ -33,12 +33,12 @@ func init() {
|
||||
}
|
||||
|
||||
type getKubeConfigFlags struct {
|
||||
token string
|
||||
kubeconfig string
|
||||
contextOverride string
|
||||
namespace string
|
||||
idpName string
|
||||
idpType string
|
||||
token string
|
||||
kubeconfig string
|
||||
contextOverride string
|
||||
namespace string
|
||||
authenticatorName string
|
||||
authenticatorType string
|
||||
}
|
||||
|
||||
type getKubeConfigCommand struct {
|
||||
@ -88,8 +88,8 @@ func (c *getKubeConfigCommand) Command() *cobra.Command {
|
||||
cmd.Flags().StringVar(&c.flags.kubeconfig, "kubeconfig", c.flags.kubeconfig, "Path to the kubeconfig file")
|
||||
cmd.Flags().StringVar(&c.flags.contextOverride, "kubeconfig-context", c.flags.contextOverride, "Kubeconfig context override")
|
||||
cmd.Flags().StringVar(&c.flags.namespace, "pinniped-namespace", c.flags.namespace, "Namespace in which Pinniped was installed")
|
||||
cmd.Flags().StringVar(&c.flags.idpType, "idp-type", c.flags.idpType, "Identity provider type (e.g., 'webhook')")
|
||||
cmd.Flags().StringVar(&c.flags.idpName, "idp-name", c.flags.idpType, "Identity provider name")
|
||||
cmd.Flags().StringVar(&c.flags.authenticatorType, "authenticator-type", c.flags.authenticatorType, "Authenticator type (e.g., 'webhook')")
|
||||
cmd.Flags().StringVar(&c.flags.authenticatorName, "authenticator-name", c.flags.authenticatorType, "Authenticator name")
|
||||
mustMarkRequired(cmd, "token")
|
||||
return cmd
|
||||
}
|
||||
@ -116,9 +116,9 @@ func (c *getKubeConfigCommand) run(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
idpType, idpName := c.flags.idpType, c.flags.idpName
|
||||
if idpType == "" || idpName == "" {
|
||||
idpType, idpName, err = getDefaultIDP(clientset, c.flags.namespace)
|
||||
authenticatorType, authenticatorName := c.flags.authenticatorType, c.flags.authenticatorName
|
||||
if authenticatorType == "" || authenticatorName == "" {
|
||||
authenticatorType, authenticatorName, err = getDefaultAuthenticator(clientset, c.flags.namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -143,7 +143,7 @@ func (c *getKubeConfigCommand) run(cmd *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
config := newPinnipedKubeconfig(v1Cluster, fullPathToSelf, c.flags.token, c.flags.namespace, idpType, idpName)
|
||||
config := newPinnipedKubeconfig(v1Cluster, fullPathToSelf, c.flags.token, c.flags.namespace, authenticatorType, authenticatorName)
|
||||
|
||||
err = writeConfigAsYAML(cmd.OutOrStdout(), config)
|
||||
if err != nil {
|
||||
@ -168,22 +168,22 @@ func issueWarningForNonMatchingServerOrCA(v1Cluster v1.Cluster, credentialIssuer
|
||||
return nil
|
||||
}
|
||||
|
||||
type noIDPError struct{ Namespace string }
|
||||
type noAuthenticatorError struct{ Namespace string }
|
||||
|
||||
func (e noIDPError) Error() string {
|
||||
return fmt.Sprintf(`no identity providers were found in namespace %q`, e.Namespace)
|
||||
func (e noAuthenticatorError) Error() string {
|
||||
return fmt.Sprintf(`no authenticators were found in namespace %q`, e.Namespace)
|
||||
}
|
||||
|
||||
type indeterminateIDPError struct{ Namespace string }
|
||||
type indeterminateAuthenticatorError struct{ Namespace string }
|
||||
|
||||
func (e indeterminateIDPError) Error() string {
|
||||
func (e indeterminateAuthenticatorError) Error() string {
|
||||
return fmt.Sprintf(
|
||||
`multiple identity providers were found in namespace %q, so --pinniped-idp-name/--pinniped-idp-type must be specified`,
|
||||
`multiple authenticators were found in namespace %q, so --authenticator-name/--authenticator-type must be specified`,
|
||||
e.Namespace,
|
||||
)
|
||||
}
|
||||
|
||||
func getDefaultIDP(clientset pinnipedclientset.Interface, namespace string) (string, string, error) {
|
||||
func getDefaultAuthenticator(clientset pinnipedclientset.Interface, namespace string) (string, string, error) {
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
||||
defer cancelFunc()
|
||||
|
||||
@ -192,19 +192,19 @@ func getDefaultIDP(clientset pinnipedclientset.Interface, namespace string) (str
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
type ref struct{ idpType, idpName string }
|
||||
idps := make([]ref, 0, len(webhooks.Items))
|
||||
type ref struct{ authenticatorType, authenticatorName string }
|
||||
authenticators := make([]ref, 0, len(webhooks.Items))
|
||||
for _, webhook := range webhooks.Items {
|
||||
idps = append(idps, ref{idpType: "webhook", idpName: webhook.Name})
|
||||
authenticators = append(authenticators, ref{authenticatorType: "webhook", authenticatorName: webhook.Name})
|
||||
}
|
||||
|
||||
if len(idps) == 0 {
|
||||
return "", "", noIDPError{namespace}
|
||||
if len(authenticators) == 0 {
|
||||
return "", "", noAuthenticatorError{namespace}
|
||||
}
|
||||
if len(idps) > 1 {
|
||||
return "", "", indeterminateIDPError{namespace}
|
||||
if len(authenticators) > 1 {
|
||||
return "", "", indeterminateAuthenticatorError{namespace}
|
||||
}
|
||||
return idps[0].idpType, idps[0].idpName, nil
|
||||
return authenticators[0].authenticatorType, authenticators[0].authenticatorName, nil
|
||||
}
|
||||
|
||||
func fetchPinnipedCredentialIssuerConfig(clientset pinnipedclientset.Interface, pinnipedInstallationNamespace string) (*configv1alpha1.CredentialIssuerConfig, error) {
|
||||
@ -277,7 +277,7 @@ func copyCurrentClusterFromExistingKubeConfig(currentKubeConfig clientcmdapi.Con
|
||||
return v1Cluster, nil
|
||||
}
|
||||
|
||||
func newPinnipedKubeconfig(v1Cluster v1.Cluster, fullPathToSelf string, token string, namespace string, idpType string, idpName string) v1.Config {
|
||||
func newPinnipedKubeconfig(v1Cluster v1.Cluster, fullPathToSelf string, token string, namespace string, authenticatorType string, authenticatorName string) v1.Config {
|
||||
clusterName := "pinniped-cluster"
|
||||
userName := "pinniped-user"
|
||||
|
||||
@ -324,12 +324,12 @@ func newPinnipedKubeconfig(v1Cluster v1.Cluster, fullPathToSelf string, token st
|
||||
Value: token,
|
||||
},
|
||||
{
|
||||
Name: "PINNIPED_IDP_TYPE",
|
||||
Value: idpType,
|
||||
Name: "PINNIPED_AUTHENTICATOR_TYPE",
|
||||
Value: authenticatorType,
|
||||
},
|
||||
{
|
||||
Name: "PINNIPED_IDP_NAME",
|
||||
Value: idpName,
|
||||
Name: "PINNIPED_AUTHENTICATOR_NAME",
|
||||
Value: authenticatorName,
|
||||
},
|
||||
},
|
||||
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
|
||||
|
@ -30,9 +30,9 @@ var (
|
||||
get-kubeconfig [flags]
|
||||
|
||||
Flags:
|
||||
--authenticator-name string Authenticator name
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook')
|
||||
-h, --help help for get-kubeconfig
|
||||
--idp-name string Identity provider name
|
||||
--idp-type string Identity provider type (e.g., 'webhook')
|
||||
--kubeconfig string Path to the kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context override
|
||||
--pinniped-namespace string Namespace in which Pinniped was installed (default "pinniped")
|
||||
@ -61,9 +61,9 @@ var (
|
||||
get-kubeconfig [flags]
|
||||
|
||||
Flags:
|
||||
--authenticator-name string Authenticator name
|
||||
--authenticator-type string Authenticator type (e.g., 'webhook')
|
||||
-h, --help help for get-kubeconfig
|
||||
--idp-name string Identity provider name
|
||||
--idp-type string Identity provider type (e.g., 'webhook')
|
||||
--kubeconfig string Path to the kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context override
|
||||
--pinniped-namespace string Namespace in which Pinniped was installed (default "pinniped")
|
||||
@ -116,15 +116,15 @@ func TestNewGetKubeConfigCmd(t *testing.T) {
|
||||
}
|
||||
|
||||
type expectedKubeconfigYAML struct {
|
||||
clusterCAData string
|
||||
clusterServer string
|
||||
command string
|
||||
token string
|
||||
pinnipedEndpoint string
|
||||
pinnipedCABundle string
|
||||
namespace string
|
||||
idpType string
|
||||
idpName string
|
||||
clusterCAData string
|
||||
clusterServer string
|
||||
command string
|
||||
token string
|
||||
pinnipedEndpoint string
|
||||
pinnipedCABundle string
|
||||
namespace string
|
||||
authenticatorType string
|
||||
authenticatorName string
|
||||
}
|
||||
|
||||
func (e expectedKubeconfigYAML) String() string {
|
||||
@ -160,14 +160,14 @@ func (e expectedKubeconfigYAML) String() string {
|
||||
value: %s
|
||||
- name: PINNIPED_TOKEN
|
||||
value: %s
|
||||
- name: PINNIPED_IDP_TYPE
|
||||
- name: PINNIPED_AUTHENTICATOR_TYPE
|
||||
value: %s
|
||||
- name: PINNIPED_IDP_NAME
|
||||
- name: PINNIPED_AUTHENTICATOR_NAME
|
||||
value: %s
|
||||
installHint: |-
|
||||
The Pinniped CLI is required to authenticate to the current cluster.
|
||||
For more information, please visit https://pinniped.dev
|
||||
`, e.clusterCAData, e.clusterServer, e.command, e.pinnipedEndpoint, e.pinnipedCABundle, e.namespace, e.token, e.idpType, e.idpName)
|
||||
`, e.clusterCAData, e.clusterServer, e.command, e.pinnipedEndpoint, e.pinnipedCABundle, e.namespace, e.token, e.authenticatorType, e.authenticatorName)
|
||||
}
|
||||
|
||||
func newCredentialIssuerConfig(name, namespace, server, certificateAuthorityData string) *configv1alpha1.CredentialIssuerConfig {
|
||||
@ -224,36 +224,36 @@ func TestRun(t *testing.T) {
|
||||
wantError: "some error configuring clientset",
|
||||
},
|
||||
{
|
||||
name: "fail to get IDPs",
|
||||
name: "fail to get authenticators",
|
||||
mocks: func(cmd *getKubeConfigCommand) {
|
||||
cmd.flags.idpName = ""
|
||||
cmd.flags.idpType = ""
|
||||
cmd.flags.authenticatorName = ""
|
||||
cmd.flags.authenticatorType = ""
|
||||
clientset := pinnipedfake.NewSimpleClientset()
|
||||
clientset.PrependReactor("*", "*", func(_ coretesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, fmt.Errorf("some error getting IDPs")
|
||||
return true, nil, fmt.Errorf("some error getting authenticators")
|
||||
})
|
||||
cmd.kubeClientCreator = func(_ *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
return clientset, nil
|
||||
}
|
||||
},
|
||||
wantError: "some error getting IDPs",
|
||||
wantError: "some error getting authenticators",
|
||||
},
|
||||
{
|
||||
name: "zero IDPs",
|
||||
name: "zero authenticators",
|
||||
mocks: func(cmd *getKubeConfigCommand) {
|
||||
cmd.flags.idpName = ""
|
||||
cmd.flags.idpType = ""
|
||||
cmd.flags.authenticatorName = ""
|
||||
cmd.flags.authenticatorType = ""
|
||||
cmd.kubeClientCreator = func(_ *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
return pinnipedfake.NewSimpleClientset(), nil
|
||||
}
|
||||
},
|
||||
wantError: `no identity providers were found in namespace "test-namespace"`,
|
||||
wantError: `no authenticators were found in namespace "test-namespace"`,
|
||||
},
|
||||
{
|
||||
name: "multiple IDPs",
|
||||
name: "multiple authenticators",
|
||||
mocks: func(cmd *getKubeConfigCommand) {
|
||||
cmd.flags.idpName = ""
|
||||
cmd.flags.idpType = ""
|
||||
cmd.flags.authenticatorName = ""
|
||||
cmd.flags.authenticatorType = ""
|
||||
cmd.kubeClientCreator = func(_ *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
return pinnipedfake.NewSimpleClientset(
|
||||
&authv1alpha.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Namespace: "test-namespace", Name: "webhook-one"}},
|
||||
@ -261,7 +261,7 @@ func TestRun(t *testing.T) {
|
||||
), nil
|
||||
}
|
||||
},
|
||||
wantError: `multiple identity providers were found in namespace "test-namespace", so --pinniped-idp-name/--pinniped-idp-type must be specified`,
|
||||
wantError: `multiple authenticators were found in namespace "test-namespace", so --authenticator-name/--authenticator-type must be specified`,
|
||||
},
|
||||
{
|
||||
name: "fail to get CredentialIssuerConfigs",
|
||||
@ -330,41 +330,41 @@ func TestRun(t *testing.T) {
|
||||
}
|
||||
},
|
||||
wantStdout: expectedKubeconfigYAML{
|
||||
clusterCAData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
|
||||
clusterServer: "https://fake-server-url-value",
|
||||
command: "/path/to/pinniped",
|
||||
token: "test-token",
|
||||
pinnipedEndpoint: "https://fake-server-url-value",
|
||||
pinnipedCABundle: "fake-certificate-authority-data-value",
|
||||
namespace: "test-namespace",
|
||||
idpType: "test-idp-type",
|
||||
idpName: "test-idp-name",
|
||||
clusterCAData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
|
||||
clusterServer: "https://fake-server-url-value",
|
||||
command: "/path/to/pinniped",
|
||||
token: "test-token",
|
||||
pinnipedEndpoint: "https://fake-server-url-value",
|
||||
pinnipedCABundle: "fake-certificate-authority-data-value",
|
||||
namespace: "test-namespace",
|
||||
authenticatorType: "test-authenticator-type",
|
||||
authenticatorName: "test-authenticator-name",
|
||||
}.String(),
|
||||
},
|
||||
{
|
||||
name: "success using local CA data and discovered IDP",
|
||||
name: "success using local CA data and discovered authenticator",
|
||||
mocks: func(cmd *getKubeConfigCommand) {
|
||||
cmd.flags.idpName = ""
|
||||
cmd.flags.idpType = ""
|
||||
cmd.flags.authenticatorName = ""
|
||||
cmd.flags.authenticatorType = ""
|
||||
|
||||
cmd.kubeClientCreator = func(_ *rest.Config) (pinnipedclientset.Interface, error) {
|
||||
return pinnipedfake.NewSimpleClientset(
|
||||
&authv1alpha.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Namespace: "test-namespace", Name: "discovered-idp"}},
|
||||
&authv1alpha.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Namespace: "test-namespace", Name: "discovered-authenticator"}},
|
||||
newCredentialIssuerConfig("pinniped-config", "test-namespace", "https://example.com", "test-ca"),
|
||||
), nil
|
||||
}
|
||||
},
|
||||
wantStderr: `WARNING: Server and certificate authority did not match between local kubeconfig and Pinniped's CredentialIssuerConfig on the cluster. Using local kubeconfig values.`,
|
||||
wantStdout: expectedKubeconfigYAML{
|
||||
clusterCAData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
|
||||
clusterServer: "https://fake-server-url-value",
|
||||
command: "/path/to/pinniped",
|
||||
token: "test-token",
|
||||
pinnipedEndpoint: "https://fake-server-url-value",
|
||||
pinnipedCABundle: "fake-certificate-authority-data-value",
|
||||
namespace: "test-namespace",
|
||||
idpType: "webhook",
|
||||
idpName: "discovered-idp",
|
||||
clusterCAData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
|
||||
clusterServer: "https://fake-server-url-value",
|
||||
command: "/path/to/pinniped",
|
||||
token: "test-token",
|
||||
pinnipedEndpoint: "https://fake-server-url-value",
|
||||
pinnipedCABundle: "fake-certificate-authority-data-value",
|
||||
namespace: "test-namespace",
|
||||
authenticatorType: "webhook",
|
||||
authenticatorName: "discovered-authenticator",
|
||||
}.String(),
|
||||
},
|
||||
}
|
||||
@ -377,8 +377,8 @@ func TestRun(t *testing.T) {
|
||||
c := newGetKubeConfigCommand()
|
||||
c.flags.token = "test-token"
|
||||
c.flags.namespace = "test-namespace"
|
||||
c.flags.idpName = "test-idp-name"
|
||||
c.flags.idpType = "test-idp-type"
|
||||
c.flags.authenticatorName = "test-authenticator-name"
|
||||
c.flags.authenticatorType = "test-authenticator-type"
|
||||
c.getPathToSelf = func() (string, error) { return "/path/to/pinniped", nil }
|
||||
c.flags.kubeconfig = "./testdata/kubeconfig.yaml"
|
||||
tt.mocks(c)
|
||||
|
@ -143,7 +143,7 @@ as the identity provider.
|
||||
allow you to authenticate as the user that you created above.
|
||||
|
||||
```bash
|
||||
pinniped get-kubeconfig --token "pinny-the-seal:password123" --idp-type webhook --idp-name local-user-authenticator > /tmp/pinniped-kubeconfig
|
||||
pinniped get-kubeconfig --token "pinny-the-seal:password123" --authenticator-type webhook --authenticator-name local-user-authenticator > /tmp/pinniped-kubeconfig
|
||||
```
|
||||
|
||||
If you are using MacOS, you may get an error dialog that says
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
var ErrLoginFailed = errors.New("login failed")
|
||||
|
||||
// ExchangeToken exchanges an opaque token using the Pinniped TokenCredentialRequest API, returning a client-go ExecCredential valid on the target cluster.
|
||||
func ExchangeToken(ctx context.Context, namespace string, idp corev1.TypedLocalObjectReference, token string, caBundle string, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
func ExchangeToken(ctx context.Context, namespace string, authenticator corev1.TypedLocalObjectReference, token string, caBundle string, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
||||
client, err := getClient(apiEndpoint, caBundle)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get API client: %w", err)
|
||||
@ -35,7 +35,7 @@ func ExchangeToken(ctx context.Context, namespace string, idp corev1.TypedLocalO
|
||||
},
|
||||
Spec: v1alpha1.TokenCredentialRequestSpec{
|
||||
Token: token,
|
||||
Authenticator: idp,
|
||||
Authenticator: authenticator,
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
|
@ -25,7 +25,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
testIDP := corev1.TypedLocalObjectReference{
|
||||
testAuthenticator := corev1.TypedLocalObjectReference{
|
||||
APIGroup: &auth1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "WebhookAuthenticator",
|
||||
Name: "test-webhook",
|
||||
@ -33,7 +33,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
|
||||
t.Run("invalid configuration", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testIDP, "", "", "")
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testAuthenticator, "", "", "")
|
||||
require.EqualError(t, err, "could not get API client: invalid configuration: no configuration has been provided, try setting KUBERNETES_MASTER environment variable")
|
||||
require.Nil(t, got)
|
||||
})
|
||||
@ -46,7 +46,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
_, _ = w.Write([]byte("some server error"))
|
||||
})
|
||||
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testIDP, "", caBundle, endpoint)
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testAuthenticator, "", caBundle, endpoint)
|
||||
require.EqualError(t, err, `could not login: an error on the server ("some server error") has prevented the request from succeeding (post tokencredentialrequests.login.concierge.pinniped.dev)`)
|
||||
require.Nil(t, got)
|
||||
})
|
||||
@ -63,7 +63,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testIDP, "", caBundle, endpoint)
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testAuthenticator, "", caBundle, endpoint)
|
||||
require.EqualError(t, err, `login failed: some login failure`)
|
||||
require.Nil(t, got)
|
||||
})
|
||||
@ -78,7 +78,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testIDP, "", caBundle, endpoint)
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testAuthenticator, "", caBundle, endpoint)
|
||||
require.EqualError(t, err, `login failed: unknown`)
|
||||
require.Nil(t, got)
|
||||
})
|
||||
@ -129,7 +129,7 @@ func TestExchangeToken(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testIDP, "test-token", caBundle, endpoint)
|
||||
got, err := ExchangeToken(ctx, "test-namespace", testAuthenticator, "test-token", caBundle, endpoint)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &clientauthenticationv1beta1.ExecCredential{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"go.pinniped.dev/internal/certauthority/dynamiccertauthority"
|
||||
"go.pinniped.dev/internal/concierge/apiserver"
|
||||
"go.pinniped.dev/internal/config/concierge"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllermanager"
|
||||
"go.pinniped.dev/internal/downward"
|
||||
"go.pinniped.dev/internal/dynamiccert"
|
||||
@ -104,8 +104,8 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
}
|
||||
serverInstallationNamespace := podInfo.Namespace
|
||||
|
||||
// Initialize the cache of active identity providers.
|
||||
idpCache := idpcache.New()
|
||||
// Initialize the cache of active authenticators.
|
||||
authenticators := authncache.New()
|
||||
|
||||
// This cert provider will provide certs to the API server and will
|
||||
// be mutated by a controller to keep the certs up to date with what
|
||||
@ -131,7 +131,7 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
DynamicSigningCertProvider: dynamicSigningCertProvider,
|
||||
ServingCertDuration: time.Duration(*cfg.APIConfig.ServingCertificateConfig.DurationSeconds) * time.Second,
|
||||
ServingCertRenewBefore: time.Duration(*cfg.APIConfig.ServingCertificateConfig.RenewBeforeSeconds) * time.Second,
|
||||
IDPCache: idpCache,
|
||||
AuthenticatorCache: authenticators,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@ -141,7 +141,7 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
// Get the aggregated API server config.
|
||||
aggregatedAPIServerConfig, err := getAggregatedAPIServerConfig(
|
||||
dynamicServingCertProvider,
|
||||
idpCache,
|
||||
authenticators,
|
||||
dynamiccertauthority.New(dynamicSigningCertProvider),
|
||||
startControllersFunc,
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package idpcache implements a cache of active identity providers.
|
||||
package idpcache
|
||||
// Package authncache implements a cache of active authenticators.
|
||||
package authncache
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -17,12 +17,12 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoSuchIDP is returned by Cache.AuthenticateTokenCredentialRequest() when the requested IDP is not configured.
|
||||
ErrNoSuchIDP = fmt.Errorf("no such identity provider")
|
||||
// ErrNoSuchAuthenticator is returned by Cache.AuthenticateTokenCredentialRequest() when the requested authenticator is not configured.
|
||||
ErrNoSuchAuthenticator = fmt.Errorf("no such authenticator")
|
||||
)
|
||||
|
||||
// Cache implements the authenticator.Token interface by multiplexing across a dynamic set of identity providers
|
||||
// loaded from IDP resources.
|
||||
// Cache implements the authenticator.Token interface by multiplexing across a dynamic set of authenticators
|
||||
// loaded from authenticator resources.
|
||||
type Cache struct {
|
||||
cache sync.Map
|
||||
}
|
||||
@ -43,7 +43,7 @@ func New() *Cache {
|
||||
return &Cache{}
|
||||
}
|
||||
|
||||
// Get an identity provider by key.
|
||||
// Get an authenticator by key.
|
||||
func (c *Cache) Get(key Key) Value {
|
||||
res, _ := c.cache.Load(key)
|
||||
if res == nil {
|
||||
@ -52,12 +52,12 @@ func (c *Cache) Get(key Key) Value {
|
||||
return res.(Value)
|
||||
}
|
||||
|
||||
// Store an identity provider into the cache.
|
||||
// Store an authenticator into the cache.
|
||||
func (c *Cache) Store(key Key, value Value) {
|
||||
c.cache.Store(key, value)
|
||||
}
|
||||
|
||||
// Delete an identity provider from the cache.
|
||||
// Delete an authenticator from the cache.
|
||||
func (c *Cache) Delete(key Key) {
|
||||
c.cache.Delete(key)
|
||||
}
|
||||
@ -93,14 +93,14 @@ func (c *Cache) AuthenticateTokenCredentialRequest(ctx context.Context, req *log
|
||||
|
||||
val := c.Get(key)
|
||||
if val == nil {
|
||||
return nil, ErrNoSuchIDP
|
||||
return nil, ErrNoSuchAuthenticator
|
||||
}
|
||||
|
||||
// The incoming context could have an audience. Since we do not want to handle audiences right now, do not pass it
|
||||
// through directly to the authentication webhook.
|
||||
ctx = valuelessContext{ctx}
|
||||
|
||||
// Call the selected IDP.
|
||||
// Call the selected authenticator.
|
||||
resp, authenticated, err := val.AuthenticateToken(ctx, req.Spec.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package idpcache
|
||||
package authncache
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -31,13 +31,13 @@ func TestCache(t *testing.T) {
|
||||
cache := New()
|
||||
require.NotNil(t, cache)
|
||||
|
||||
key1 := Key{Namespace: "foo", Name: "idp-one"}
|
||||
key1 := Key{Namespace: "foo", Name: "authenticator-one"}
|
||||
mockToken1 := mocktokenauthenticator.NewMockToken(ctrl)
|
||||
cache.Store(key1, mockToken1)
|
||||
require.Equal(t, mockToken1, cache.Get(key1))
|
||||
require.Equal(t, 1, len(cache.Keys()))
|
||||
|
||||
key2 := Key{Namespace: "foo", Name: "idp-two"}
|
||||
key2 := Key{Namespace: "foo", Name: "authenticator-two"}
|
||||
mockToken2 := mocktokenauthenticator.NewMockToken(ctrl)
|
||||
cache.Store(key2, mockToken2)
|
||||
require.Equal(t, mockToken2, cache.Get(key2))
|
||||
@ -101,10 +101,10 @@ func TestAuthenticateTokenCredentialRequest(t *testing.T) {
|
||||
return c
|
||||
}
|
||||
|
||||
t.Run("no such IDP", func(t *testing.T) {
|
||||
t.Run("no such authenticator", func(t *testing.T) {
|
||||
c := New()
|
||||
res, err := c.AuthenticateTokenCredentialRequest(context.Background(), validRequest.DeepCopy())
|
||||
require.EqualError(t, err, "no such identity provider")
|
||||
require.EqualError(t, err, "no such authenticator")
|
||||
require.Nil(t, res)
|
||||
})
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package webhookcachecleaner implements a controller for garbage collectting webhook IDPs from an IDP cache.
|
||||
// Package webhookcachecleaner implements a controller for garbage collecting webhook authenticators from an authenticator cache.
|
||||
package webhookcachecleaner
|
||||
|
||||
import (
|
||||
@ -12,25 +12,25 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
idpinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
|
||||
// New instantiates a new controllerlib.Controller which will garbage collect webhooks from the provided Cache.
|
||||
func New(cache *idpcache.Cache, webhookIDPs idpinformers.WebhookAuthenticatorInformer, log logr.Logger) controllerlib.Controller {
|
||||
func New(cache *authncache.Cache, webhooks authinformers.WebhookAuthenticatorInformer, log logr.Logger) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "webhookcachecleaner-controller",
|
||||
Syncer: &controller{
|
||||
cache: cache,
|
||||
webhookIDPs: webhookIDPs,
|
||||
log: log.WithName("webhookcachecleaner-controller"),
|
||||
cache: cache,
|
||||
webhooks: webhooks,
|
||||
log: log.WithName("webhookcachecleaner-controller"),
|
||||
},
|
||||
},
|
||||
controllerlib.WithInformer(
|
||||
webhookIDPs,
|
||||
webhooks,
|
||||
pinnipedcontroller.MatchAnythingFilter(),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
@ -38,14 +38,14 @@ func New(cache *idpcache.Cache, webhookIDPs idpinformers.WebhookAuthenticatorInf
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
cache *idpcache.Cache
|
||||
webhookIDPs idpinformers.WebhookAuthenticatorInformer
|
||||
log logr.Logger
|
||||
cache *authncache.Cache
|
||||
webhooks authinformers.WebhookAuthenticatorInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *controller) Sync(_ controllerlib.Context) error {
|
||||
webhooks, err := c.webhookIDPs.Lister().List(labels.Everything())
|
||||
webhooks, err := c.webhooks.Lister().List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list WebhookAuthenticators: %w", err)
|
||||
}
|
||||
@ -63,7 +63,7 @@ func (c *controller) Sync(_ controllerlib.Context) error {
|
||||
continue
|
||||
}
|
||||
if _, exists := webhooksByKey[controllerlib.Key{Namespace: key.Namespace, Name: key.Name}]; !exists {
|
||||
c.log.WithValues("idp", klog.KRef(key.Namespace, key.Name)).Info("deleting webhook IDP from cache")
|
||||
c.log.WithValues("webhook", klog.KRef(key.Namespace, key.Name)).Info("deleting webhook authenticator from cache")
|
||||
c.cache.Delete(key)
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ import (
|
||||
authv1alpha "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/1.19/client/clientset/versioned/fake"
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
)
|
||||
@ -23,37 +23,37 @@ import (
|
||||
func TestController(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testKey1 := idpcache.Key{
|
||||
testKey1 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
}
|
||||
testKey2 := idpcache.Key{
|
||||
testKey2 := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-two",
|
||||
}
|
||||
testKeyNonwebhook := idpcache.Key{
|
||||
testKeyNonwebhook := authncache.Key{
|
||||
APIGroup: "authentication.concierge.pinniped.dev",
|
||||
Kind: "SomeOtherIdentityProvider",
|
||||
Kind: "SomeOtherAuthenticator",
|
||||
Namespace: "test-namespace",
|
||||
Name: "test-name-one",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
webhookIDPs []runtime.Object
|
||||
initialCache map[idpcache.Key]idpcache.Value
|
||||
webhooks []runtime.Object
|
||||
initialCache map[authncache.Key]authncache.Value
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantCacheKeys []idpcache.Key
|
||||
wantCacheKeys []authncache.Key
|
||||
}{
|
||||
{
|
||||
name: "no change",
|
||||
initialCache: map[idpcache.Key]idpcache.Value{testKey1: nil},
|
||||
webhookIDPs: []runtime.Object{
|
||||
initialCache: map[authncache.Key]authncache.Value{testKey1: nil},
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
@ -61,12 +61,12 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []idpcache.Key{testKey1},
|
||||
wantCacheKeys: []authncache.Key{testKey1},
|
||||
},
|
||||
{
|
||||
name: "IDPs not yet added",
|
||||
name: "authenticators not yet added",
|
||||
initialCache: nil,
|
||||
webhookIDPs: []runtime.Object{
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
@ -80,16 +80,16 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCacheKeys: []idpcache.Key{},
|
||||
wantCacheKeys: []authncache.Key{},
|
||||
},
|
||||
{
|
||||
name: "successful cleanup",
|
||||
initialCache: map[idpcache.Key]idpcache.Value{
|
||||
initialCache: map[authncache.Key]authncache.Value{
|
||||
testKey1: nil,
|
||||
testKey2: nil,
|
||||
testKeyNonwebhook: nil,
|
||||
},
|
||||
webhookIDPs: []runtime.Object{
|
||||
webhooks: []runtime.Object{
|
||||
&authv1alpha.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: testKey1.Namespace,
|
||||
@ -98,9 +98,9 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`webhookcachecleaner-controller "level"=0 "msg"="deleting webhook IDP from cache" "idp"={"name":"test-name-two","namespace":"test-namespace"}`,
|
||||
`webhookcachecleaner-controller "level"=0 "msg"="deleting webhook authenticator from cache" "webhook"={"name":"test-name-two","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheKeys: []idpcache.Key{testKey1, testKeyNonwebhook},
|
||||
wantCacheKeys: []authncache.Key{testKey1, testKeyNonwebhook},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -108,9 +108,9 @@ func TestController(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhookIDPs...)
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhooks...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := idpcache.New()
|
||||
cache := authncache.New()
|
||||
for k, v := range tt.initialCache {
|
||||
cache.Store(k, v)
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package webhookcachefiller implements a controller for filling an idpcache.Cache with each added/updated WebhookAuthenticator.
|
||||
// Package webhookcachefiller implements a controller for filling an authncache.Cache with each added/updated WebhookAuthenticator.
|
||||
package webhookcachefiller
|
||||
|
||||
import (
|
||||
@ -21,25 +21,25 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
idpinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/authentication/v1alpha1"
|
||||
authinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/authentication/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
)
|
||||
|
||||
// New instantiates a new controllerlib.Controller which will populate the provided idpcache.Cache.
|
||||
func New(cache *idpcache.Cache, webhookIDPs idpinformers.WebhookAuthenticatorInformer, log logr.Logger) controllerlib.Controller {
|
||||
// New instantiates a new controllerlib.Controller which will populate the provided authncache.Cache.
|
||||
func New(cache *authncache.Cache, webhooks authinformers.WebhookAuthenticatorInformer, log logr.Logger) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
Name: "webhookcachefiller-controller",
|
||||
Syncer: &controller{
|
||||
cache: cache,
|
||||
webhookIDPs: webhookIDPs,
|
||||
log: log.WithName("webhookcachefiller-controller"),
|
||||
cache: cache,
|
||||
webhooks: webhooks,
|
||||
log: log.WithName("webhookcachefiller-controller"),
|
||||
},
|
||||
},
|
||||
controllerlib.WithInformer(
|
||||
webhookIDPs,
|
||||
webhooks,
|
||||
pinnipedcontroller.MatchAnythingFilter(),
|
||||
controllerlib.InformerOption{},
|
||||
),
|
||||
@ -47,14 +47,14 @@ func New(cache *idpcache.Cache, webhookIDPs idpinformers.WebhookAuthenticatorInf
|
||||
}
|
||||
|
||||
type controller struct {
|
||||
cache *idpcache.Cache
|
||||
webhookIDPs idpinformers.WebhookAuthenticatorInformer
|
||||
log logr.Logger
|
||||
cache *authncache.Cache
|
||||
webhooks authinformers.WebhookAuthenticatorInformer
|
||||
log logr.Logger
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
func (c *controller) Sync(ctx controllerlib.Context) error {
|
||||
obj, err := c.webhookIDPs.Lister().WebhookAuthenticators(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
obj, err := c.webhooks.Lister().WebhookAuthenticators(ctx.Key.Namespace).Get(ctx.Key.Name)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
c.log.Info("Sync() found that the WebhookAuthenticator does not exist yet or was deleted")
|
||||
return nil
|
||||
@ -68,13 +68,13 @@ func (c *controller) Sync(ctx controllerlib.Context) error {
|
||||
return fmt.Errorf("failed to build webhook config: %w", err)
|
||||
}
|
||||
|
||||
c.cache.Store(idpcache.Key{
|
||||
c.cache.Store(authncache.Key{
|
||||
APIGroup: auth1alpha1.GroupName,
|
||||
Kind: "WebhookAuthenticator",
|
||||
Namespace: ctx.Key.Namespace,
|
||||
Name: ctx.Key.Name,
|
||||
}, webhookAuthenticator)
|
||||
c.log.WithValues("idp", klog.KObj(obj), "endpoint", obj.Spec.Endpoint).Info("added new webhook IDP")
|
||||
c.log.WithValues("webhook", klog.KObj(obj), "endpoint", obj.Spec.Endpoint).Info("added new webhook authenticator")
|
||||
return nil
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
auth1alpha1 "go.pinniped.dev/generated/1.19/apis/concierge/authentication/v1alpha1"
|
||||
pinnipedfake "go.pinniped.dev/generated/1.19/client/clientset/versioned/fake"
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/internal/testutil/testlogger"
|
||||
@ -34,7 +34,7 @@ func TestController(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
syncKey controllerlib.Key
|
||||
webhookIDPs []runtime.Object
|
||||
webhooks []runtime.Object
|
||||
wantErr string
|
||||
wantLogs []string
|
||||
wantCacheEntries int
|
||||
@ -49,7 +49,7 @@ func TestController(t *testing.T) {
|
||||
{
|
||||
name: "invalid webhook",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
webhookIDPs: []runtime.Object{
|
||||
webhooks: []runtime.Object{
|
||||
&auth1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
@ -65,7 +65,7 @@ func TestController(t *testing.T) {
|
||||
{
|
||||
name: "valid webhook",
|
||||
syncKey: controllerlib.Key{Namespace: "test-namespace", Name: "test-name"},
|
||||
webhookIDPs: []runtime.Object{
|
||||
webhooks: []runtime.Object{
|
||||
&auth1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "test-namespace",
|
||||
@ -78,7 +78,7 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
},
|
||||
wantLogs: []string{
|
||||
`webhookcachefiller-controller "level"=0 "msg"="added new webhook IDP" "endpoint"="https://example.com" "idp"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
`webhookcachefiller-controller "level"=0 "msg"="added new webhook authenticator" "endpoint"="https://example.com" "webhook"={"name":"test-name","namespace":"test-namespace"}`,
|
||||
},
|
||||
wantCacheEntries: 1,
|
||||
},
|
||||
@ -88,9 +88,9 @@ func TestController(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhookIDPs...)
|
||||
fakeClient := pinnipedfake.NewSimpleClientset(tt.webhooks...)
|
||||
informers := pinnipedinformers.NewSharedInformerFactory(fakeClient, 0)
|
||||
cache := idpcache.New()
|
||||
cache := authncache.New()
|
||||
testLog := testlogger.New(t)
|
||||
|
||||
controller := New(cache, informers.Authentication().V1alpha1().WebhookAuthenticators(), testLog)
|
@ -24,9 +24,9 @@ import (
|
||||
pinnipedinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions"
|
||||
"go.pinniped.dev/internal/config/concierge"
|
||||
"go.pinniped.dev/internal/controller/apicerts"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/webhookcachecleaner"
|
||||
"go.pinniped.dev/internal/controller/identityprovider/webhookcachefiller"
|
||||
"go.pinniped.dev/internal/controller/authenticator/authncache"
|
||||
"go.pinniped.dev/internal/controller/authenticator/webhookcachecleaner"
|
||||
"go.pinniped.dev/internal/controller/authenticator/webhookcachefiller"
|
||||
"go.pinniped.dev/internal/controller/issuerconfig"
|
||||
"go.pinniped.dev/internal/controller/kubecertagent"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
@ -70,8 +70,8 @@ type Config struct {
|
||||
// certificate.
|
||||
ServingCertRenewBefore time.Duration
|
||||
|
||||
// IDPCache is a cache of authenticators shared amongst various IDP-related controllers.
|
||||
IDPCache *idpcache.Cache
|
||||
// AuthenticatorCache is a cache of authenticators shared amongst various authenticated-related controllers.
|
||||
AuthenticatorCache *authncache.Cache
|
||||
|
||||
// Labels are labels that should be added to any resources created by the controllers.
|
||||
Labels map[string]string
|
||||
@ -227,11 +227,11 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
||||
singletonWorker,
|
||||
).
|
||||
|
||||
// The cache filler controllers are responsible for keep an in-memory representation of active
|
||||
// IDPs up to date.
|
||||
// The cache filler/cleaner controllers are responsible for keep an in-memory representation of active
|
||||
// authenticators up to date.
|
||||
WithController(
|
||||
webhookcachefiller.New(
|
||||
c.IDPCache,
|
||||
c.AuthenticatorCache,
|
||||
informers.installationNamespacePinniped.Authentication().V1alpha1().WebhookAuthenticators(),
|
||||
klogr.New(),
|
||||
),
|
||||
@ -239,7 +239,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
||||
).
|
||||
WithController(
|
||||
webhookcachecleaner.New(
|
||||
c.IDPCache,
|
||||
c.AuthenticatorCache,
|
||||
informers.installationNamespacePinniped.Authentication().V1alpha1().WebhookAuthenticators(),
|
||||
klogr.New(),
|
||||
),
|
||||
|
@ -38,13 +38,13 @@ func TestCLIGetKubeconfig(t *testing.T) {
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), 4*time.Minute)
|
||||
defer cancelFunc()
|
||||
|
||||
idp := library.CreateTestWebhookIDP(ctx, t)
|
||||
authenticator := library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
|
||||
// Build pinniped CLI.
|
||||
pinnipedExe := buildPinnipedCLI(t)
|
||||
|
||||
// Run pinniped CLI to get kubeconfig.
|
||||
kubeConfigYAML := runPinnipedCLIGetKubeconfig(t, pinnipedExe, env.TestUser.Token, env.ConciergeNamespace, "webhook", idp.Name)
|
||||
kubeConfigYAML := runPinnipedCLIGetKubeconfig(t, pinnipedExe, env.TestUser.Token, env.ConciergeNamespace, "webhook", authenticator.Name)
|
||||
|
||||
// In addition to the client-go based testing below, also try the kubeconfig
|
||||
// with kubectl to validate that it works.
|
||||
@ -91,7 +91,7 @@ func buildPinnipedCLI(t *testing.T) string {
|
||||
return pinnipedExe
|
||||
}
|
||||
|
||||
func runPinnipedCLIGetKubeconfig(t *testing.T, pinnipedExe, token, namespaceName, idpType, idpName string) string {
|
||||
func runPinnipedCLIGetKubeconfig(t *testing.T, pinnipedExe, token, namespaceName, authenticatorType, authenticatorName string) string {
|
||||
t.Helper()
|
||||
|
||||
output, err := exec.Command(
|
||||
@ -99,8 +99,8 @@ func runPinnipedCLIGetKubeconfig(t *testing.T, pinnipedExe, token, namespaceName
|
||||
"get-kubeconfig",
|
||||
"--token", token,
|
||||
"--pinniped-namespace", namespaceName,
|
||||
"--idp-type", idpType,
|
||||
"--idp-name", idpName,
|
||||
"--authenticator-type", authenticatorType,
|
||||
"--authenticator-name", authenticatorName,
|
||||
).CombinedOutput()
|
||||
require.NoError(t, err, string(output))
|
||||
|
||||
|
@ -60,7 +60,7 @@ func TestClient(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
idp := library.CreateTestWebhookIDP(ctx, t)
|
||||
webhook := library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
|
||||
// Use an invalid certificate/key to validate that the ServerVersion API fails like we assume.
|
||||
invalidClient := library.NewClientsetWithCertAndKey(t, testCert, testKey)
|
||||
@ -72,7 +72,7 @@ func TestClient(t *testing.T) {
|
||||
|
||||
var resp *clientauthenticationv1beta1.ExecCredential
|
||||
assert.Eventually(t, func() bool {
|
||||
resp, err = client.ExchangeToken(ctx, env.ConciergeNamespace, idp, env.TestUser.Token, string(clientConfig.CAData), clientConfig.Host)
|
||||
resp, err = client.ExchangeToken(ctx, env.ConciergeNamespace, webhook, env.TestUser.Token, string(clientConfig.CAData), clientConfig.Host)
|
||||
return err == nil
|
||||
}, 10*time.Second, 500*time.Millisecond)
|
||||
require.NoError(t, err)
|
||||
|
@ -44,7 +44,7 @@ func TestSuccessfulCredentialRequest(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
testWebhook := library.CreateTestWebhookIDP(ctx, t)
|
||||
testWebhook := library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
|
||||
var response *loginv1alpha1.TokenCredentialRequest
|
||||
successfulResponse := func() bool {
|
||||
@ -125,7 +125,7 @@ func TestCredentialRequest_OtherwiseValidRequestWithRealTokenShouldFailWhenTheCl
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
testWebhook := library.CreateTestWebhookIDP(ctx, t)
|
||||
testWebhook := library.CreateTestWebhookAuthenticator(ctx, t)
|
||||
|
||||
response, err := makeRequest(ctx, t, validCredentialRequestSpecWithRealToken(t, testWebhook))
|
||||
|
||||
@ -152,10 +152,10 @@ func makeRequest(ctx context.Context, t *testing.T, spec loginv1alpha1.TokenCred
|
||||
}, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func validCredentialRequestSpecWithRealToken(t *testing.T, idp corev1.TypedLocalObjectReference) loginv1alpha1.TokenCredentialRequestSpec {
|
||||
func validCredentialRequestSpecWithRealToken(t *testing.T, authenticator corev1.TypedLocalObjectReference) loginv1alpha1.TokenCredentialRequestSpec {
|
||||
return loginv1alpha1.TokenCredentialRequestSpec{
|
||||
Token: library.IntegrationEnv(t).TestUser.Token,
|
||||
Authenticator: idp,
|
||||
Authenticator: authenticator,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +119,10 @@ func newAnonymousClientRestConfigWithCertAndKeyAdded(t *testing.T, clientCertifi
|
||||
return config
|
||||
}
|
||||
|
||||
// CreateTestWebhookIDP creates and returns a test WebhookAuthenticator in $PINNIPED_TEST_CONCIERGE_NAMESPACE, which will be
|
||||
// CreateTestWebhookAuthenticator creates and returns a test WebhookAuthenticator in $PINNIPED_TEST_CONCIERGE_NAMESPACE, which will be
|
||||
// automatically deleted at the end of the current test's lifetime. It returns a corev1.TypedLocalObjectReference which
|
||||
// descibes the test IDP within the test namespace.
|
||||
func CreateTestWebhookIDP(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
// describes the test webhook authenticator within the test namespace.
|
||||
func CreateTestWebhookAuthenticator(ctx context.Context, t *testing.T) corev1.TypedLocalObjectReference {
|
||||
t.Helper()
|
||||
testEnv := IntegrationEnv(t)
|
||||
|
||||
@ -132,7 +132,7 @@ func CreateTestWebhookIDP(ctx context.Context, t *testing.T) corev1.TypedLocalOb
|
||||
createContext, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
idp, err := webhooks.Create(createContext, &auth1alpha1.WebhookAuthenticator{
|
||||
webhook, err := webhooks.Create(createContext, &auth1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
GenerateName: "test-webhook-",
|
||||
Labels: map[string]string{"pinniped.dev/test": ""},
|
||||
@ -141,21 +141,21 @@ func CreateTestWebhookIDP(ctx context.Context, t *testing.T) corev1.TypedLocalOb
|
||||
Spec: testEnv.TestWebhook,
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err, "could not create test WebhookAuthenticator")
|
||||
t.Logf("created test WebhookAuthenticator %s/%s", idp.Namespace, idp.Name)
|
||||
t.Logf("created test WebhookAuthenticator %s/%s", webhook.Namespace, webhook.Name)
|
||||
|
||||
t.Cleanup(func() {
|
||||
t.Helper()
|
||||
t.Logf("cleaning up test WebhookAuthenticator %s/%s", idp.Namespace, idp.Name)
|
||||
t.Logf("cleaning up test WebhookAuthenticator %s/%s", webhook.Namespace, webhook.Name)
|
||||
deleteCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
err := webhooks.Delete(deleteCtx, idp.Name, metav1.DeleteOptions{})
|
||||
require.NoErrorf(t, err, "could not cleanup test WebhookAuthenticator %s/%s", idp.Namespace, idp.Name)
|
||||
err := webhooks.Delete(deleteCtx, webhook.Name, metav1.DeleteOptions{})
|
||||
require.NoErrorf(t, err, "could not cleanup test WebhookAuthenticator %s/%s", webhook.Namespace, webhook.Name)
|
||||
})
|
||||
|
||||
return corev1.TypedLocalObjectReference{
|
||||
APIGroup: &auth1alpha1.SchemeGroupVersion.Group,
|
||||
Kind: "WebhookAuthenticator",
|
||||
Name: idp.Name,
|
||||
Name: webhook.Name,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user