Merge pull request #344 from vmware-tanzu/wire-api-group-suffix

Wire api group suffix through YTT/server components/CLI/integration tests
This commit is contained in:
Andrew Keesler 2021-01-19 18:06:12 -05:00 committed by GitHub
commit 5486427d88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 328 additions and 85 deletions

View File

@ -264,6 +264,7 @@ func run(podInfo *downward.PodInfo, cfg *supervisor.Config) error {
return fmt.Errorf("cannot create deployment ref: %w", err) return fmt.Errorf("cannot create deployment ref: %w", err)
} }
_ = *cfg.APIGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(dref) client, err := kubeclient.New(dref)
if err != nil { if err != nil {
return fmt.Errorf("cannot create k8s client: %w", err) return fmt.Errorf("cannot create k8s client: %w", err)

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package cmd package cmd
@ -70,6 +70,7 @@ func legacyGetKubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
namespace: namespace, namespace: namespace,
authenticatorName: authenticatorName, authenticatorName: authenticatorName,
authenticatorType: authenticatorType, authenticatorType: authenticatorType,
apiGroupSuffix: "pinniped.dev",
}, },
}) })
} }

View File

@ -73,6 +73,7 @@ type getKubeconfigConciergeParams struct {
namespace string namespace string
authenticatorName string authenticatorName string
authenticatorType string authenticatorType string
apiGroupSuffix string
} }
type getKubeconfigParams struct { type getKubeconfigParams struct {
@ -103,6 +104,7 @@ func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
f.StringVar(&flags.concierge.namespace, "concierge-namespace", "pinniped-concierge", "Namespace in which the concierge was installed") f.StringVar(&flags.concierge.namespace, "concierge-namespace", "pinniped-concierge", "Namespace in which the concierge was installed")
f.StringVar(&flags.concierge.authenticatorType, "concierge-authenticator-type", "", "Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)") f.StringVar(&flags.concierge.authenticatorType, "concierge-authenticator-type", "", "Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)")
f.StringVar(&flags.concierge.authenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name (default: autodiscover)") f.StringVar(&flags.concierge.authenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name (default: autodiscover)")
f.StringVar(&flags.concierge.apiGroupSuffix, "concierge-api-group-suffix", "pinniped.dev", "Concierge API group suffix")
f.StringVar(&flags.oidc.issuer, "oidc-issuer", "", "OpenID Connect issuer URL (default: autodiscover)") f.StringVar(&flags.oidc.issuer, "oidc-issuer", "", "OpenID Connect issuer URL (default: autodiscover)")
f.StringVar(&flags.oidc.clientID, "oidc-client-id", "pinniped-cli", "OpenID Connect client ID (default: autodiscover)") f.StringVar(&flags.oidc.clientID, "oidc-client-id", "pinniped-cli", "OpenID Connect client ID (default: autodiscover)")
@ -258,6 +260,7 @@ func configureConcierge(authenticator metav1.Object, flags *getKubeconfigParams,
// Append the flags to configure the Concierge credential exchange at runtime. // Append the flags to configure the Concierge credential exchange at runtime.
execConfig.Args = append(execConfig.Args, execConfig.Args = append(execConfig.Args,
"--enable-concierge", "--enable-concierge",
"--concierge-api-group-suffix="+flags.concierge.apiGroupSuffix,
"--concierge-namespace="+flags.concierge.namespace, "--concierge-namespace="+flags.concierge.namespace,
"--concierge-authenticator-name="+flags.concierge.authenticatorName, "--concierge-authenticator-name="+flags.concierge.authenticatorName,
"--concierge-authenticator-type="+flags.concierge.authenticatorType, "--concierge-authenticator-type="+flags.concierge.authenticatorType,

View File

@ -57,6 +57,7 @@ func TestGetKubeconfig(t *testing.T) {
kubeconfig [flags] kubeconfig [flags]
Flags: Flags:
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
--concierge-authenticator-name string Concierge authenticator name (default: autodiscover) --concierge-authenticator-name string Concierge authenticator name (default: autodiscover)
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover) --concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') (default: autodiscover)
--concierge-namespace string Namespace in which the concierge was installed (default "pinniped-concierge") --concierge-namespace string Namespace in which the concierge was installed (default "pinniped-concierge")
@ -313,6 +314,7 @@ func TestGetKubeconfig(t *testing.T) {
- login - login
- static - static
- --enable-concierge - --enable-concierge
- --concierge-api-group-suffix=pinniped.dev
- --concierge-namespace=test-namespace - --concierge-namespace=test-namespace
- --concierge-authenticator-name=test-authenticator - --concierge-authenticator-name=test-authenticator
- --concierge-authenticator-type=webhook - --concierge-authenticator-type=webhook
@ -358,6 +360,7 @@ func TestGetKubeconfig(t *testing.T) {
- login - login
- static - static
- --enable-concierge - --enable-concierge
- --concierge-api-group-suffix=pinniped.dev
- --concierge-namespace=test-namespace - --concierge-namespace=test-namespace
- --concierge-authenticator-name=test-authenticator - --concierge-authenticator-name=test-authenticator
- --concierge-authenticator-type=webhook - --concierge-authenticator-type=webhook
@ -410,6 +413,7 @@ func TestGetKubeconfig(t *testing.T) {
- login - login
- oidc - oidc
- --enable-concierge - --enable-concierge
- --concierge-api-group-suffix=pinniped.dev
- --concierge-namespace=pinniped-concierge - --concierge-namespace=pinniped-concierge
- --concierge-authenticator-name=test-authenticator - --concierge-authenticator-name=test-authenticator
- --concierge-authenticator-type=jwt - --concierge-authenticator-type=jwt
@ -429,6 +433,7 @@ func TestGetKubeconfig(t *testing.T) {
name: "autodetect nothing, set a bunch of options", name: "autodetect nothing, set a bunch of options",
args: []string{ args: []string{
"--kubeconfig", "./testdata/kubeconfig.yaml", "--kubeconfig", "./testdata/kubeconfig.yaml",
"--concierge-api-group-suffix", "tuna.io",
"--concierge-authenticator-type", "webhook", "--concierge-authenticator-type", "webhook",
"--concierge-authenticator-name", "test-authenticator", "--concierge-authenticator-name", "test-authenticator",
"--oidc-issuer", "https://example.com/issuer", "--oidc-issuer", "https://example.com/issuer",
@ -468,6 +473,7 @@ func TestGetKubeconfig(t *testing.T) {
- login - login
- oidc - oidc
- --enable-concierge - --enable-concierge
- --concierge-api-group-suffix=tuna.io
- --concierge-namespace=pinniped-concierge - --concierge-namespace=pinniped-concierge
- --concierge-authenticator-name=test-authenticator - --concierge-authenticator-name=test-authenticator
- --concierge-authenticator-type=webhook - --concierge-authenticator-type=webhook

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package cmd package cmd
@ -64,6 +64,7 @@ type oidcLoginFlags struct {
conciergeAuthenticatorName string conciergeAuthenticatorName string
conciergeEndpoint string conciergeEndpoint string
conciergeCABundle string conciergeCABundle string
conciergeAPIGroupSuffix string
} }
func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command { func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
@ -92,6 +93,7 @@ func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
cmd.Flags().StringVar(&flags.conciergeAuthenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name") cmd.Flags().StringVar(&flags.conciergeAuthenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name")
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Pinniped concierge endpoint") cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Pinniped concierge endpoint")
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the concierge") cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the concierge")
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", "pinniped.dev", "Concierge API group suffix")
mustMarkHidden(&cmd, "debug-session-cache") mustMarkHidden(&cmd, "debug-session-cache")
mustMarkRequired(&cmd, "issuer") mustMarkRequired(&cmd, "issuer")
@ -135,6 +137,7 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin
conciergeclient.WithEndpoint(flags.conciergeEndpoint), conciergeclient.WithEndpoint(flags.conciergeEndpoint),
conciergeclient.WithBase64CABundle(flags.conciergeCABundle), conciergeclient.WithBase64CABundle(flags.conciergeCABundle),
conciergeclient.WithAuthenticator(flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName), conciergeclient.WithAuthenticator(flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName),
conciergeclient.WithAPIGroupSuffix(flags.conciergeAPIGroupSuffix),
) )
if err != nil { if err != nil {
return fmt.Errorf("invalid concierge parameters: %w", err) return fmt.Errorf("invalid concierge parameters: %w", err)

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package cmd package cmd
@ -60,6 +60,7 @@ func TestLoginOIDCCommand(t *testing.T) {
--ca-bundle strings Path to TLS certificate authority bundle (PEM format, optional, can be repeated) --ca-bundle strings Path to TLS certificate authority bundle (PEM format, optional, can be repeated)
--ca-bundle-data strings Base64 endcoded TLS certificate authority bundle (base64 encoded PEM format, optional, can be repeated) --ca-bundle-data strings Base64 endcoded TLS certificate authority bundle (base64 encoded PEM format, optional, can be repeated)
--client-id string OpenID Connect client ID (default "pinniped-cli") --client-id string OpenID Connect client ID (default "pinniped-cli")
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
--concierge-authenticator-name string Concierge authenticator name --concierge-authenticator-name string Concierge authenticator name
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') --concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
--concierge-ca-bundle-data string CA bundle to use when connecting to the concierge --concierge-ca-bundle-data string CA bundle to use when connecting to the concierge
@ -175,6 +176,7 @@ func TestLoginOIDCCommand(t *testing.T) {
"--concierge-authenticator-name", "test-authenticator", "--concierge-authenticator-name", "test-authenticator",
"--concierge-endpoint", "https://127.0.0.1:1234/", "--concierge-endpoint", "https://127.0.0.1:1234/",
"--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(testCA.Bundle()), "--concierge-ca-bundle-data", base64.StdEncoding.EncodeToString(testCA.Bundle()),
"--concierge-api-group-suffix", "some.suffix.com",
}, },
wantOptionsCount: 7, wantOptionsCount: 7,
wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"exchanged-token"}}` + "\n", wantStdout: `{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1beta1","spec":{},"status":{"token":"exchanged-token"}}` + "\n",

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package cmd package cmd
@ -46,6 +46,7 @@ type staticLoginParams struct {
conciergeAuthenticatorName string conciergeAuthenticatorName string
conciergeEndpoint string conciergeEndpoint string
conciergeCABundle string conciergeCABundle string
conciergeAPIGroupSuffix string
} }
func staticLoginCommand(deps staticLoginDeps) *cobra.Command { func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
@ -66,6 +67,7 @@ func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
cmd.Flags().StringVar(&flags.conciergeAuthenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name") cmd.Flags().StringVar(&flags.conciergeAuthenticatorName, "concierge-authenticator-name", "", "Concierge authenticator name")
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Pinniped concierge endpoint") cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Pinniped concierge endpoint")
cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the concierge") cmd.Flags().StringVar(&flags.conciergeCABundle, "concierge-ca-bundle-data", "", "CA bundle to use when connecting to the concierge")
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", "pinniped.dev", "Concierge API group suffix")
cmd.RunE = func(cmd *cobra.Command, args []string) error { return runStaticLogin(cmd.OutOrStdout(), deps, flags) } cmd.RunE = func(cmd *cobra.Command, args []string) error { return runStaticLogin(cmd.OutOrStdout(), deps, flags) }
return &cmd return &cmd
} }
@ -83,6 +85,7 @@ func runStaticLogin(out io.Writer, deps staticLoginDeps, flags staticLoginParams
conciergeclient.WithEndpoint(flags.conciergeEndpoint), conciergeclient.WithEndpoint(flags.conciergeEndpoint),
conciergeclient.WithBase64CABundle(flags.conciergeCABundle), conciergeclient.WithBase64CABundle(flags.conciergeCABundle),
conciergeclient.WithAuthenticator(flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName), conciergeclient.WithAuthenticator(flags.conciergeAuthenticatorType, flags.conciergeAuthenticatorName),
conciergeclient.WithAPIGroupSuffix(flags.conciergeAPIGroupSuffix),
) )
if err != nil { if err != nil {
return fmt.Errorf("invalid concierge parameters: %w", err) return fmt.Errorf("invalid concierge parameters: %w", err)

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package cmd package cmd
@ -51,6 +51,7 @@ func TestLoginStaticCommand(t *testing.T) {
static [--token TOKEN] [--token-env TOKEN_NAME] [flags] static [--token TOKEN] [--token-env TOKEN_NAME] [flags]
Flags: Flags:
--concierge-api-group-suffix string Concierge API group suffix (default "pinniped.dev")
--concierge-authenticator-name string Concierge authenticator name --concierge-authenticator-name string Concierge authenticator name
--concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt') --concierge-authenticator-type string Concierge authenticator type (e.g., 'webhook', 'jwt')
--concierge-ca-bundle-data string CA bundle to use when connecting to the concierge --concierge-ca-bundle-data string CA bundle to use when connecting to the concierge

View File

@ -3,7 +3,7 @@
#@ load("@ytt:data", "data") #@ load("@ytt:data", "data")
#@ load("@ytt:json", "json") #@ load("@ytt:json", "json")
#@ load("helpers.lib.yaml", "defaultLabel", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix", "getAndValidateLogLevel") #@ load("helpers.lib.yaml", "defaultLabel", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix", "getAndValidateLogLevel", "pinnipedDevAPIGroupWithPrefix")
#@ if not data.values.into_namespace: #@ if not data.values.into_namespace:
--- ---
@ -37,6 +37,7 @@ data:
servingCertificate: servingCertificate:
durationSeconds: (@= str(data.values.api_serving_certificate_duration_seconds) @) durationSeconds: (@= str(data.values.api_serving_certificate_duration_seconds) @)
renewBeforeSeconds: (@= str(data.values.api_serving_certificate_renew_before_seconds) @) renewBeforeSeconds: (@= str(data.values.api_serving_certificate_renew_before_seconds) @)
apiGroupSuffix: (@= data.values.api_group_suffix @)
names: names:
servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @) servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @)
credentialIssuer: (@= defaultResourceNameWithSuffix("config") @) credentialIssuer: (@= defaultResourceNameWithSuffix("config") @)
@ -191,11 +192,11 @@ spec:
apiVersion: apiregistration.k8s.io/v1 apiVersion: apiregistration.k8s.io/v1
kind: APIService kind: APIService
metadata: metadata:
name: v1alpha1.login.concierge.pinniped.dev name: #@ pinnipedDevAPIGroupWithPrefix("v1alpha1.login.concierge")
labels: #@ labels() labels: #@ labels()
spec: spec:
version: v1alpha1 version: v1alpha1
group: login.concierge.pinniped.dev group: #@ pinnipedDevAPIGroupWithPrefix("login.concierge")
groupPriorityMinimum: 2500 groupPriorityMinimum: 2500
versionPriority: 10 versionPriority: 10
#! caBundle: Do not include this key here. Starts out null, will be updated/owned by the golang code. #! caBundle: Do not include this key here. Starts out null, will be updated/owned by the golang code.

View File

@ -1,4 +1,4 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved. #! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data") #@ load("@ytt:data", "data")
@ -12,6 +12,10 @@
#@ return data.values.app_name + "-" + suffix #@ return data.values.app_name + "-" + suffix
#@ end #@ end
#@ def pinnipedDevAPIGroupWithPrefix(prefix):
#@ return prefix + "." + data.values.api_group_suffix
#@ end
#@ def namespace(): #@ def namespace():
#@ if data.values.into_namespace: #@ if data.values.into_namespace:
#@ return data.values.into_namespace #@ return data.values.into_namespace

View File

@ -2,7 +2,7 @@
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data") #@ load("@ytt:data", "data")
#@ load("helpers.lib.yaml", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix") #@ load("helpers.lib.yaml", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix", "pinnipedDevAPIGroupWithPrefix")
#! Give permission to various cluster-scoped objects #! Give permission to various cluster-scoped objects
--- ---
@ -66,7 +66,9 @@ rules:
- apiGroups: [ "" ] - apiGroups: [ "" ]
resources: [ pods/exec ] resources: [ pods/exec ]
verbs: [ create ] verbs: [ create ]
- apiGroups: [ config.concierge.pinniped.dev, authentication.concierge.pinniped.dev ] - apiGroups:
- #@ pinnipedDevAPIGroupWithPrefix("config.concierge")
- #@ pinnipedDevAPIGroupWithPrefix("authentication.concierge")
resources: [ "*" ] resources: [ "*" ]
verbs: [ create, get, list, update, watch ] verbs: [ create, get, list, update, watch ]
- apiGroups: [apps] - apiGroups: [apps]
@ -124,7 +126,8 @@ metadata:
name: #@ defaultResourceNameWithSuffix("create-token-credential-requests") name: #@ defaultResourceNameWithSuffix("create-token-credential-requests")
labels: #@ labels() labels: #@ labels()
rules: rules:
- apiGroups: [ login.concierge.pinniped.dev ] - apiGroups:
- #@ pinnipedDevAPIGroupWithPrefix("login.concierge")
resources: [ tokencredentialrequests ] resources: [ tokencredentialrequests ]
verbs: [ create ] verbs: [ create ]
--- ---

View File

@ -57,3 +57,9 @@ log_level: #! By default, when this value is left unset, only warnings and error
run_as_user: 1001 #! run_as_user specifies the user ID that will own the local-user-authenticator process run_as_user: 1001 #! run_as_user specifies the user ID that will own the local-user-authenticator process
run_as_group: 1001 #! run_as_group specifies the group ID that will own the local-user-authenticator process run_as_group: 1001 #! run_as_group specifies the group ID that will own the local-user-authenticator process
#! Specify the API group suffix for all Pinniped API groups. By default, this is set to
#! pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev,
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
api_group_suffix: pinniped.dev

View File

@ -1,23 +1,33 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved. #! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:overlay", "overlay") #@ load("@ytt:overlay", "overlay")
#@ load("helpers.lib.yaml", "labels") #@ load("helpers.lib.yaml", "labels", "pinnipedDevAPIGroupWithPrefix")
#@ load("@ytt:data", "data")
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"credentialissuers.config.concierge.pinniped.dev"}}), expects=1 #@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"credentialissuers.config.concierge.pinniped.dev"}}), expects=1
--- ---
metadata: metadata:
#@overlay/match missing_ok=True #@overlay/match missing_ok=True
labels: #@ labels() labels: #@ labels()
name: #@ pinnipedDevAPIGroupWithPrefix("credentialissuers.config.concierge")
spec:
group: #@ pinnipedDevAPIGroupWithPrefix("config.concierge")
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"webhookauthenticators.authentication.concierge.pinniped.dev"}}), expects=1 #@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"webhookauthenticators.authentication.concierge.pinniped.dev"}}), expects=1
--- ---
metadata: metadata:
#@overlay/match missing_ok=True #@overlay/match missing_ok=True
labels: #@ labels() labels: #@ labels()
name: #@ pinnipedDevAPIGroupWithPrefix("webhookauthenticators.authentication.concierge")
spec:
group: #@ pinnipedDevAPIGroupWithPrefix("authentication.concierge")
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"jwtauthenticators.authentication.concierge.pinniped.dev"}}), expects=1 #@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"jwtauthenticators.authentication.concierge.pinniped.dev"}}), expects=1
--- ---
metadata: metadata:
#@overlay/match missing_ok=True #@overlay/match missing_ok=True
labels: #@ labels() labels: #@ labels()
name: #@ pinnipedDevAPIGroupWithPrefix("jwtauthenticators.authentication.concierge")
spec:
group: #@ pinnipedDevAPIGroupWithPrefix("authentication.concierge")

View File

@ -30,6 +30,7 @@ metadata:
data: data:
#@yaml/text-templated-strings #@yaml/text-templated-strings
pinniped.yaml: | pinniped.yaml: |
apiGroupSuffix: (@= data.values.api_group_suffix @)
names: names:
defaultTLSCertificateSecret: (@= defaultResourceNameWithSuffix("default-tls-certificate") @) defaultTLSCertificateSecret: (@= defaultResourceNameWithSuffix("default-tls-certificate") @)
labels: (@= json.encode(labels()).rstrip() @) labels: (@= json.encode(labels()).rstrip() @)

View File

@ -1,4 +1,4 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved. #! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data") #@ load("@ytt:data", "data")
@ -12,6 +12,10 @@
#@ return data.values.app_name + "-" + suffix #@ return data.values.app_name + "-" + suffix
#@ end #@ end
#@ def pinnipedDevAPIGroupWithPrefix(prefix):
#@ return prefix + "." + data.values.api_group_suffix
#@ end
#@ def namespace(): #@ def namespace():
#@ if data.values.into_namespace: #@ if data.values.into_namespace:
#@ return data.values.into_namespace #@ return data.values.into_namespace

View File

@ -1,8 +1,8 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved. #! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data") #@ load("@ytt:data", "data")
#@ load("helpers.lib.yaml", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix") #@ load("helpers.lib.yaml", "labels", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix", "pinnipedDevAPIGroupWithPrefix")
#! Give permission to various objects within the app's own namespace #! Give permission to various objects within the app's own namespace
--- ---
@ -16,13 +16,16 @@ rules:
- apiGroups: [""] - apiGroups: [""]
resources: [secrets] resources: [secrets]
verbs: [create, get, list, patch, update, watch, delete] verbs: [create, get, list, patch, update, watch, delete]
- apiGroups: [config.supervisor.pinniped.dev] - apiGroups:
- #@ pinnipedDevAPIGroupWithPrefix("config.supervisor")
resources: [federationdomains] resources: [federationdomains]
verbs: [update, get, list, watch] verbs: [update, get, list, watch]
- apiGroups: [idp.supervisor.pinniped.dev] - apiGroups:
- #@ pinnipedDevAPIGroupWithPrefix("idp.supervisor")
resources: [oidcidentityproviders] resources: [oidcidentityproviders]
verbs: [get, list, watch] verbs: [get, list, watch]
- apiGroups: [idp.supervisor.pinniped.dev] - apiGroups:
- #@ pinnipedDevAPIGroupWithPrefix("idp.supervisor")
resources: [oidcidentityproviders/status] resources: [oidcidentityproviders/status]
verbs: [get, patch, update] verbs: [get, patch, update]
#! We want to be able to read pods/replicasets/deployment so we can learn who our deployment is to set #! We want to be able to read pods/replicasets/deployment so we can learn who our deployment is to set

View File

@ -59,3 +59,9 @@ log_level: #! By default, when this value is left unset, only warnings and error
run_as_user: 1001 #! run_as_user specifies the user ID that will own the local-user-authenticator process run_as_user: 1001 #! run_as_user specifies the user ID that will own the local-user-authenticator process
run_as_group: 1001 #! run_as_group specifies the group ID that will own the local-user-authenticator process run_as_group: 1001 #! run_as_group specifies the group ID that will own the local-user-authenticator process
#! Specify the API group suffix for all Pinniped API groups. By default, this is set to
#! pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev,
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
api_group_suffix: pinniped.dev

View File

@ -1,17 +1,24 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved. #! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0 #! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:overlay", "overlay") #@ load("@ytt:overlay", "overlay")
#@ load("helpers.lib.yaml", "labels") #@ load("helpers.lib.yaml", "labels", "pinnipedDevAPIGroupWithPrefix")
#@ load("@ytt:data", "data")
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"federationdomains.config.supervisor.pinniped.dev"}}), expects=1 #@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"federationdomains.config.supervisor.pinniped.dev"}}), expects=1
--- ---
metadata: metadata:
#@overlay/match missing_ok=True #@overlay/match missing_ok=True
labels: #@ labels() labels: #@ labels()
name: #@ pinnipedDevAPIGroupWithPrefix("federationdomains.config.supervisor")
spec:
group: #@ pinnipedDevAPIGroupWithPrefix("config.supervisor")
#@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"oidcidentityproviders.idp.supervisor.pinniped.dev"}}), expects=1 #@overlay/match by=overlay.subset({"kind": "CustomResourceDefinition", "metadata":{"name":"oidcidentityproviders.idp.supervisor.pinniped.dev"}}), expects=1
--- ---
metadata: metadata:
#@overlay/match missing_ok=True #@overlay/match missing_ok=True
labels: #@ labels() labels: #@ labels()
name: #@ pinnipedDevAPIGroupWithPrefix("oidcidentityproviders.idp.supervisor")
spec:
group: #@ pinnipedDevAPIGroupWithPrefix("idp.supervisor")

View File

@ -0,0 +1,29 @@
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package apigroup provides centralized logic around Pinniped's API group parameterization.
package apigroup
import (
"fmt"
"strings"
)
// defaultAPIGroupSuffix is the default suffix of the Concierge API group. Our generated code uses
// this suffix, so we know that we can replace this suffix with the configured API group suffix.
const defaultAPIGroupSuffix = "pinniped.dev"
// Make constructs an API group from a baseAPIGroup and a parameterized apiGroupSuffix.
//
// We assume that all apiGroup's will end in "pinniped.dev", and therefore we can safely replace the
// reference to "pinniped.dev" with the provided apiGroupSuffix. If the provided baseAPIGroup does
// not end in "pinniped.dev", then this function will return an empty string and false.
//
// See Example_loginv1alpha1 and Example_string for more information on input/output pairs.
func Make(baseAPIGroup, apiGroupSuffix string) (string, bool) {
if !strings.HasSuffix(baseAPIGroup, defaultAPIGroupSuffix) {
return "", false
}
i := strings.LastIndex(baseAPIGroup, defaultAPIGroupSuffix)
return fmt.Sprintf("%s%s", baseAPIGroup[:i], apiGroupSuffix), true
}

View File

@ -0,0 +1,36 @@
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package apigroup
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
)
func TestMakeError(t *testing.T) {
_, ok := Make("bad-suffix", "shouldnt-matter.com")
require.False(t, ok)
}
func TestMakeSuffix(t *testing.T) {
s, ok := Make("something.pinniped.dev.something-else.pinniped.dev", "tuna.io")
require.Equal(t, "something.pinniped.dev.something-else.tuna.io", s)
require.True(t, ok)
}
func Example_loginv1alpha1() {
s, _ := Make(loginv1alpha1.GroupName, "tuna.fish.io")
fmt.Println(s)
// Output: login.concierge.tuna.fish.io
}
func Example_string() {
s, _ := Make("idp.supervisor.pinniped.dev", "marlin.io")
fmt.Println(s)
// Output: idp.supervisor.marlin.io
}

View File

@ -15,6 +15,7 @@ import (
genericoptions "k8s.io/apiserver/pkg/server/options" genericoptions "k8s.io/apiserver/pkg/server/options"
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1" loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
"go.pinniped.dev/internal/apigroup"
"go.pinniped.dev/internal/certauthority/dynamiccertauthority" "go.pinniped.dev/internal/certauthority/dynamiccertauthority"
"go.pinniped.dev/internal/concierge/apiserver" "go.pinniped.dev/internal/concierge/apiserver"
"go.pinniped.dev/internal/config/concierge" "go.pinniped.dev/internal/config/concierge"
@ -36,10 +37,6 @@ type App struct {
downwardAPIPath string downwardAPIPath string
} }
// This is ignored for now because we turn off etcd storage below, but this is
// the right prefix in case we turn it back on.
const defaultEtcdPathPrefix = "/registry/" + loginv1alpha1.GroupName
// New constructs a new App with command line args, stdout and stderr. // New constructs a new App with command line args, stdout and stderr.
func New(ctx context.Context, args []string, stdout, stderr io.Writer) *App { func New(ctx context.Context, args []string, stdout, stderr io.Writer) *App {
app := &App{} app := &App{}
@ -125,6 +122,7 @@ func (a *App) runServer(ctx context.Context) error {
startControllersFunc, err := controllermanager.PrepareControllers( startControllersFunc, err := controllermanager.PrepareControllers(
&controllermanager.Config{ &controllermanager.Config{
ServerInstallationInfo: podInfo, ServerInstallationInfo: podInfo,
APIGroupSuffix: *cfg.APIGroupSuffix,
NamesConfig: &cfg.NamesConfig, NamesConfig: &cfg.NamesConfig,
Labels: cfg.Labels, Labels: cfg.Labels,
KubeCertAgentConfig: &cfg.KubeCertAgentConfig, KubeCertAgentConfig: &cfg.KubeCertAgentConfig,
@ -146,6 +144,7 @@ func (a *App) runServer(ctx context.Context) error {
authenticators, authenticators,
dynamiccertauthority.New(dynamicSigningCertProvider), dynamiccertauthority.New(dynamicSigningCertProvider),
startControllersFunc, startControllersFunc,
*cfg.APIGroupSuffix,
) )
if err != nil { if err != nil {
return fmt.Errorf("could not configure aggregated API server: %w", err) return fmt.Errorf("could not configure aggregated API server: %w", err)
@ -167,7 +166,16 @@ func getAggregatedAPIServerConfig(
authenticator credentialrequest.TokenCredentialRequestAuthenticator, authenticator credentialrequest.TokenCredentialRequestAuthenticator,
issuer credentialrequest.CertIssuer, issuer credentialrequest.CertIssuer,
startControllersPostStartHook func(context.Context), startControllersPostStartHook func(context.Context),
apiGroupSuffix string,
) (*apiserver.Config, error) { ) (*apiserver.Config, error) {
// This is ignored for now because we turn off etcd storage below, but this is
// the right prefix in case we turn it back on.
apiGroup, ok := apigroup.Make(loginv1alpha1.GroupName, apiGroupSuffix)
if !ok {
return nil, fmt.Errorf("cannot make api group from %s/%s", loginv1alpha1.GroupName, apiGroupSuffix)
}
defaultEtcdPathPrefix := fmt.Sprintf("/registry/%s", apiGroup)
recommendedOptions := genericoptions.NewRecommendedOptions( recommendedOptions := genericoptions.NewRecommendedOptions(
defaultEtcdPathPrefix, defaultEtcdPathPrefix,
apiserver.Codecs.LegacyCodec(loginv1alpha1.SchemeGroupVersion), apiserver.Codecs.LegacyCodec(loginv1alpha1.SchemeGroupVersion),

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package concierge contains functionality to load/store Config's from/to // Package concierge contains functionality to load/store Config's from/to
@ -40,6 +40,7 @@ func FromPath(path string) (*Config, error) {
} }
maybeSetAPIDefaults(&config.APIConfig) maybeSetAPIDefaults(&config.APIConfig)
maybeSetAPIGroupSuffixDefault(&config.APIGroupSuffix)
maybeSetKubeCertAgentDefaults(&config.KubeCertAgentConfig) maybeSetKubeCertAgentDefaults(&config.KubeCertAgentConfig)
if err := validateAPI(&config.APIConfig); err != nil { if err := validateAPI(&config.APIConfig); err != nil {
@ -71,6 +72,12 @@ func maybeSetAPIDefaults(apiConfig *APIConfigSpec) {
} }
} }
func maybeSetAPIGroupSuffixDefault(apiGroupSuffix **string) {
if *apiGroupSuffix == nil {
*apiGroupSuffix = stringPtr("pinniped.dev")
}
}
func maybeSetKubeCertAgentDefaults(cfg *KubeCertAgentSpec) { func maybeSetKubeCertAgentDefaults(cfg *KubeCertAgentSpec) {
if cfg.NamePrefix == nil { if cfg.NamePrefix == nil {
cfg.NamePrefix = stringPtr("pinniped-kube-cert-agent-") cfg.NamePrefix = stringPtr("pinniped-kube-cert-agent-")

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package concierge package concierge
@ -30,6 +30,7 @@ func TestFromPath(t *testing.T) {
servingCertificate: servingCertificate:
durationSeconds: 3600 durationSeconds: 3600
renewBeforeSeconds: 2400 renewBeforeSeconds: 2400
apiGroupSuffix: some.suffix.com
names: names:
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
credentialIssuer: pinniped-config credentialIssuer: pinniped-config
@ -53,6 +54,7 @@ func TestFromPath(t *testing.T) {
RenewBeforeSeconds: int64Ptr(2400), RenewBeforeSeconds: int64Ptr(2400),
}, },
}, },
APIGroupSuffix: stringPtr("some.suffix.com"),
NamesConfig: NamesConfigSpec{ NamesConfig: NamesConfigSpec{
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate", ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
CredentialIssuer: "pinniped-config", CredentialIssuer: "pinniped-config",
@ -82,6 +84,7 @@ func TestFromPath(t *testing.T) {
DiscoveryInfo: DiscoveryInfoSpec{ DiscoveryInfo: DiscoveryInfoSpec{
URL: nil, URL: nil,
}, },
APIGroupSuffix: stringPtr("pinniped.dev"),
APIConfig: APIConfigSpec{ APIConfig: APIConfigSpec{
ServingCertificateConfig: ServingCertificateConfigSpec{ ServingCertificateConfig: ServingCertificateConfigSpec{
DurationSeconds: int64Ptr(60 * 60 * 24 * 365), // about a year DurationSeconds: int64Ptr(60 * 60 * 24 * 365), // about a year

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package concierge package concierge
@ -9,6 +9,7 @@ import "go.pinniped.dev/internal/plog"
type Config struct { type Config struct {
DiscoveryInfo DiscoveryInfoSpec `json:"discovery"` DiscoveryInfo DiscoveryInfoSpec `json:"discovery"`
APIConfig APIConfigSpec `json:"api"` APIConfig APIConfigSpec `json:"api"`
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
NamesConfig NamesConfigSpec `json:"names"` NamesConfig NamesConfigSpec `json:"names"`
KubeCertAgentConfig KubeCertAgentSpec `json:"kubeCertAgent"` KubeCertAgentConfig KubeCertAgentSpec `json:"kubeCertAgent"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// Package supervisor contains functionality to load/store Config's from/to // Package supervisor contains functionality to load/store Config's from/to
@ -34,6 +34,8 @@ func FromPath(path string) (*Config, error) {
config.Labels = make(map[string]string) config.Labels = make(map[string]string)
} }
maybeSetAPIGroupSuffixDefault(&config.APIGroupSuffix)
if err := validateNames(&config.NamesConfig); err != nil { if err := validateNames(&config.NamesConfig); err != nil {
return nil, fmt.Errorf("validate names: %w", err) return nil, fmt.Errorf("validate names: %w", err)
} }
@ -45,6 +47,12 @@ func FromPath(path string) (*Config, error) {
return &config, nil return &config, nil
} }
func maybeSetAPIGroupSuffixDefault(apiGroupSuffix **string) {
if *apiGroupSuffix == nil {
*apiGroupSuffix = stringPtr("pinniped.dev")
}
}
func validateNames(names *NamesConfigSpec) error { func validateNames(names *NamesConfigSpec) error {
missingNames := []string{} missingNames := []string{}
if names.DefaultTLSCertificateSecret == "" { if names.DefaultTLSCertificateSecret == "" {
@ -55,3 +63,7 @@ func validateNames(names *NamesConfigSpec) error {
} }
return nil return nil
} }
func stringPtr(s string) *string {
return &s
}

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package supervisor package supervisor
@ -24,6 +24,7 @@ func TestFromPath(t *testing.T) {
name: "Happy", name: "Happy",
yaml: here.Doc(` yaml: here.Doc(`
--- ---
apiGroupSuffix: some.suffix.com
labels: labels:
myLabelKey1: myLabelValue1 myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2 myLabelKey2: myLabelValue2
@ -31,6 +32,7 @@ func TestFromPath(t *testing.T) {
defaultTLSCertificateSecret: my-secret-name defaultTLSCertificateSecret: my-secret-name
`), `),
wantConfig: &Config{ wantConfig: &Config{
APIGroupSuffix: stringPtr("some.suffix.com"),
Labels: map[string]string{ Labels: map[string]string{
"myLabelKey1": "myLabelValue1", "myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2", "myLabelKey2": "myLabelValue2",
@ -48,6 +50,7 @@ func TestFromPath(t *testing.T) {
defaultTLSCertificateSecret: my-secret-name defaultTLSCertificateSecret: my-secret-name
`), `),
wantConfig: &Config{ wantConfig: &Config{
APIGroupSuffix: stringPtr("pinniped.dev"),
Labels: map[string]string{}, Labels: map[string]string{},
NamesConfig: NamesConfigSpec{ NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name", DefaultTLSCertificateSecret: "my-secret-name",

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package supervisor package supervisor
@ -7,6 +7,7 @@ import "go.pinniped.dev/internal/plog"
// Config contains knobs to setup an instance of the Pinniped Supervisor. // Config contains knobs to setup an instance of the Pinniped Supervisor.
type Config struct { type Config struct {
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
Labels map[string]string `json:"labels"` Labels map[string]string `json:"labels"`
NamesConfig NamesConfigSpec `json:"names"` NamesConfig NamesConfigSpec `json:"names"`
LogLevel plog.LogLevel `json:"logLevel"` LogLevel plog.LogLevel `json:"logLevel"`

View File

@ -18,6 +18,7 @@ import (
loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1" loginv1alpha1 "go.pinniped.dev/generated/1.20/apis/concierge/login/v1alpha1"
pinnipedclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned" pinnipedclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned"
pinnipedinformers "go.pinniped.dev/generated/1.20/client/concierge/informers/externalversions" pinnipedinformers "go.pinniped.dev/generated/1.20/client/concierge/informers/externalversions"
"go.pinniped.dev/internal/apigroup"
"go.pinniped.dev/internal/config/concierge" "go.pinniped.dev/internal/config/concierge"
"go.pinniped.dev/internal/controller/apicerts" "go.pinniped.dev/internal/controller/apicerts"
"go.pinniped.dev/internal/controller/authenticator/authncache" "go.pinniped.dev/internal/controller/authenticator/authncache"
@ -45,6 +46,9 @@ type Config struct {
// ServerInstallationInfo provides the name of the pod in which Pinniped is running and the namespace in which Pinniped is deployed. // ServerInstallationInfo provides the name of the pod in which Pinniped is running and the namespace in which Pinniped is deployed.
ServerInstallationInfo *downward.PodInfo ServerInstallationInfo *downward.PodInfo
// APIGroupSuffix is the suffix of the Pinniped API that should be targeted by these controllers.
APIGroupSuffix string
// NamesConfig comes from the Pinniped config API (see api.Config). It specifies how Kubernetes // NamesConfig comes from the Pinniped config API (see api.Config). It specifies how Kubernetes
// objects should be named. // objects should be named.
NamesConfig *concierge.NamesConfigSpec NamesConfig *concierge.NamesConfigSpec
@ -85,6 +89,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
return nil, fmt.Errorf("cannot create deployment ref: %w", err) return nil, fmt.Errorf("cannot create deployment ref: %w", err)
} }
_ = c.APIGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(dref) client, err := kubeclient.New(dref)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not create clients for the controllers: %w", err) return nil, fmt.Errorf("could not create clients for the controllers: %w", err)
@ -106,6 +111,12 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
Name: c.NamesConfig.CredentialIssuer, Name: c.NamesConfig.CredentialIssuer,
} }
groupName, ok := apigroup.Make(loginv1alpha1.GroupName, c.APIGroupSuffix)
if !ok {
return nil, fmt.Errorf("cannot make api group from %s/%s", loginv1alpha1.GroupName, c.APIGroupSuffix)
}
apiServiceName := loginv1alpha1.SchemeGroupVersion.Version + "." + groupName
// Create controller manager. // Create controller manager.
controllerManager := controllerlib. controllerManager := controllerlib.
NewManager(). NewManager().
@ -145,7 +156,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
apicerts.NewAPIServiceUpdaterController( apicerts.NewAPIServiceUpdaterController(
c.ServerInstallationInfo.Namespace, c.ServerInstallationInfo.Namespace,
c.NamesConfig.ServingCertificateSecret, c.NamesConfig.ServingCertificateSecret,
loginv1alpha1.SchemeGroupVersion.Version+"."+loginv1alpha1.GroupName, apiServiceName,
client.Aggregation, client.Aggregation,
informers.installationNamespaceK8s.Core().V1().Secrets(), informers.installationNamespaceK8s.Core().V1().Secrets(),
controllerlib.WithInformer, controllerlib.WithInformer,

View File

@ -37,6 +37,7 @@ type Client struct {
authenticator *corev1.TypedLocalObjectReference authenticator *corev1.TypedLocalObjectReference
caBundle string caBundle string
endpoint *url.URL endpoint *url.URL
apiGroupSuffix string
} }
// WithNamespace configures the namespace where the TokenCredentialRequest is to be sent. // WithNamespace configures the namespace where the TokenCredentialRequest is to be sent.
@ -112,9 +113,20 @@ func WithEndpoint(endpoint string) Option {
} }
} }
// WithAPIGroupSuffix configures the concierge's API group suffix (e.g., "pinniped.dev").
func WithAPIGroupSuffix(apiGroupSuffix string) Option {
return func(c *Client) error {
if apiGroupSuffix == "" {
return fmt.Errorf("api group suffix must not be empty")
}
c.apiGroupSuffix = apiGroupSuffix
return nil
}
}
// New validates the specified options and returns a newly initialized *Client. // New validates the specified options and returns a newly initialized *Client.
func New(opts ...Option) (*Client, error) { func New(opts ...Option) (*Client, error) {
c := Client{namespace: "pinniped-concierge"} c := Client{namespace: "pinniped-concierge", apiGroupSuffix: "pinniped.dev"}
for _, opt := range opts { for _, opt := range opts {
if err := opt(&c); err != nil { if err := opt(&c); err != nil {
return nil, err return nil, err
@ -151,6 +163,7 @@ func (c *Client) clientset() (conciergeclientset.Interface, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
_ = c.apiGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(kubeclient.WithConfig(cfg)) client, err := kubeclient.New(kubeclient.WithConfig(cfg))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -104,6 +104,15 @@ func TestNew(t *testing.T) {
}, },
wantErr: "WithEndpoint must be specified", wantErr: "WithEndpoint must be specified",
}, },
{
name: "empty api group suffix",
opts: []Option{
WithAuthenticator("jwt", "test-authenticator"),
WithEndpoint("https://example.com"),
WithAPIGroupSuffix(""),
},
wantErr: "api group suffix must not be empty",
},
{ {
name: "valid", name: "valid",
opts: []Option{ opts: []Option{
@ -114,6 +123,7 @@ func TestNew(t *testing.T) {
WithBase64CABundle(base64.StdEncoding.EncodeToString(testCA.Bundle())), WithBase64CABundle(base64.StdEncoding.EncodeToString(testCA.Bundle())),
WithAuthenticator("jwt", "test-authenticator"), WithAuthenticator("jwt", "test-authenticator"),
WithAuthenticator("webhook", "test-authenticator"), WithAuthenticator("webhook", "test-authenticator"),
WithAPIGroupSuffix("suffix.com"),
}, },
}, },
} }

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package integration package integration
@ -65,6 +65,7 @@ func TestCLIGetKubeconfigStaticToken(t *testing.T) {
args: []string{ args: []string{
"get", "kubeconfig", "get", "kubeconfig",
"--static-token", env.TestUser.Token, "--static-token", env.TestUser.Token,
"--concierge-api-group-suffix", env.APIGroupSuffix,
"--concierge-namespace", env.ConciergeNamespace, "--concierge-namespace", env.ConciergeNamespace,
"--concierge-authenticator-type", "webhook", "--concierge-authenticator-type", "webhook",
"--concierge-authenticator-name", authenticator.Name, "--concierge-authenticator-name", authenticator.Name,

View File

@ -1,4 +1,4 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package integration package integration
@ -13,8 +13,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
"go.pinniped.dev/internal/client"
"go.pinniped.dev/internal/here" "go.pinniped.dev/internal/here"
"go.pinniped.dev/pkg/conciergeclient"
"go.pinniped.dev/test/library" "go.pinniped.dev/test/library"
) )
@ -69,10 +69,18 @@ func TestClient(t *testing.T) {
// Using the CA bundle and host from the current (admin) kubeconfig, do the token exchange. // Using the CA bundle and host from the current (admin) kubeconfig, do the token exchange.
clientConfig := library.NewClientConfig(t) clientConfig := library.NewClientConfig(t)
client, err := conciergeclient.New(
conciergeclient.WithNamespace(env.ConciergeNamespace),
conciergeclient.WithCABundle(string(clientConfig.CAData)),
conciergeclient.WithEndpoint(clientConfig.Host),
conciergeclient.WithAuthenticator("webhook", webhook.Name),
conciergeclient.WithAPIGroupSuffix(env.APIGroupSuffix),
)
require.NoError(t, err)
var resp *clientauthenticationv1beta1.ExecCredential var resp *clientauthenticationv1beta1.ExecCredential
assert.Eventually(t, func() bool { assert.Eventually(t, func() bool {
resp, err = client.ExchangeToken(ctx, env.ConciergeNamespace, webhook, env.TestUser.Token, string(clientConfig.CAData), clientConfig.Host) resp, err = client.ExchangeToken(ctx, env.TestUser.Token)
return err == nil return err == nil
}, 10*time.Second, 500*time.Millisecond) }, 10*time.Second, 500*time.Millisecond)
require.NoError(t, err) require.NoError(t, err)

View File

@ -79,7 +79,7 @@ func TestAPIServingCertificateAutoCreationAndRotation(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel() defer cancel()
const apiServiceName = "v1alpha1.login.concierge.pinniped.dev" apiServiceName := "v1alpha1.login.concierge." + env.APIGroupSuffix
// Get the initial auto-generated version of the Secret. // Get the initial auto-generated version of the Secret.
secret, err := kubeClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, defaultServingCertResourceName, metav1.GetOptions{}) secret, err := kubeClient.CoreV1().Secrets(env.ConciergeNamespace).Get(ctx, defaultServingCertResourceName, metav1.GetOptions{})

View File

@ -138,6 +138,7 @@ func TestE2EFullIntegration(t *testing.T) {
// Run "pinniped get kubeconfig" to get a kubeconfig YAML. // Run "pinniped get kubeconfig" to get a kubeconfig YAML.
kubeconfigYAML, stderr := runPinnipedCLI(t, pinnipedExe, "get", "kubeconfig", kubeconfigYAML, stderr := runPinnipedCLI(t, pinnipedExe, "get", "kubeconfig",
"--concierge-api-group-suffix", env.APIGroupSuffix,
"--concierge-namespace", env.ConciergeNamespace, "--concierge-namespace", env.ConciergeNamespace,
"--concierge-authenticator-type", "jwt", "--concierge-authenticator-type", "jwt",
"--concierge-authenticator-name", authenticator.Name, "--concierge-authenticator-name", authenticator.Name,

View File

@ -1,46 +1,60 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved. // Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package integration package integration
import ( import (
"fmt"
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"go.pinniped.dev/test/library" "go.pinniped.dev/test/library"
) )
func TestGetAPIResourceList(t *testing.T) { func TestGetAPIResourceList(t *testing.T) {
library.SkipUnlessIntegration(t) env := library.IntegrationEnv(t)
client := library.NewClientset(t) client := library.NewClientset(t)
groups, resources, err := client.Discovery().ServerGroupsAndResources() groups, resources, err := client.Discovery().ServerGroupsAndResources()
require.NoError(t, err) require.NoError(t, err)
makeGV := func(firstSegment, secondSegment string) schema.GroupVersion {
return schema.GroupVersion{
Group: fmt.Sprintf("%s.%s.%s", firstSegment, secondSegment, env.APIGroupSuffix),
Version: "v1alpha1",
}
}
loginConciergeGV := makeGV("login", "concierge")
authenticationConciergeGV := makeGV("authentication", "concierge")
configConciergeGV := makeGV("config", "concierge")
idpSupervisorGV := makeGV("idp", "supervisor")
configSupervisorGV := makeGV("config", "supervisor")
tests := []struct { tests := []struct {
group metav1.APIGroup group metav1.APIGroup
resourceByVersion map[string][]metav1.APIResource resourceByVersion map[string][]metav1.APIResource
}{ }{
{ {
group: metav1.APIGroup{ group: metav1.APIGroup{
Name: "login.concierge.pinniped.dev", Name: loginConciergeGV.Group,
Versions: []metav1.GroupVersionForDiscovery{ Versions: []metav1.GroupVersionForDiscovery{
{ {
GroupVersion: "login.concierge.pinniped.dev/v1alpha1", GroupVersion: loginConciergeGV.String(),
Version: "v1alpha1", Version: loginConciergeGV.Version,
}, },
}, },
PreferredVersion: metav1.GroupVersionForDiscovery{ PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "login.concierge.pinniped.dev/v1alpha1", GroupVersion: loginConciergeGV.String(),
Version: "v1alpha1", Version: loginConciergeGV.Version,
}, },
}, },
resourceByVersion: map[string][]metav1.APIResource{ resourceByVersion: map[string][]metav1.APIResource{
"login.concierge.pinniped.dev/v1alpha1": { loginConciergeGV.String(): {
{ {
Name: "tokencredentialrequests", Name: "tokencredentialrequests",
Kind: "TokenCredentialRequest", Kind: "TokenCredentialRequest",
@ -53,20 +67,20 @@ func TestGetAPIResourceList(t *testing.T) {
}, },
{ {
group: metav1.APIGroup{ group: metav1.APIGroup{
Name: "config.supervisor.pinniped.dev", Name: configSupervisorGV.Group,
Versions: []metav1.GroupVersionForDiscovery{ Versions: []metav1.GroupVersionForDiscovery{
{ {
GroupVersion: "config.supervisor.pinniped.dev/v1alpha1", GroupVersion: configSupervisorGV.String(),
Version: "v1alpha1", Version: configSupervisorGV.Version,
}, },
}, },
PreferredVersion: metav1.GroupVersionForDiscovery{ PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "config.supervisor.pinniped.dev/v1alpha1", GroupVersion: configSupervisorGV.String(),
Version: "v1alpha1", Version: configSupervisorGV.Version,
}, },
}, },
resourceByVersion: map[string][]metav1.APIResource{ resourceByVersion: map[string][]metav1.APIResource{
"config.supervisor.pinniped.dev/v1alpha1": { configSupervisorGV.String(): {
{ {
Name: "federationdomains", Name: "federationdomains",
SingularName: "federationdomain", SingularName: "federationdomain",
@ -80,20 +94,20 @@ func TestGetAPIResourceList(t *testing.T) {
}, },
{ {
group: metav1.APIGroup{ group: metav1.APIGroup{
Name: "idp.supervisor.pinniped.dev", Name: idpSupervisorGV.Group,
Versions: []metav1.GroupVersionForDiscovery{ Versions: []metav1.GroupVersionForDiscovery{
{ {
GroupVersion: "idp.supervisor.pinniped.dev/v1alpha1", GroupVersion: idpSupervisorGV.String(),
Version: "v1alpha1", Version: idpSupervisorGV.Version,
}, },
}, },
PreferredVersion: metav1.GroupVersionForDiscovery{ PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "idp.supervisor.pinniped.dev/v1alpha1", GroupVersion: idpSupervisorGV.String(),
Version: "v1alpha1", Version: idpSupervisorGV.Version,
}, },
}, },
resourceByVersion: map[string][]metav1.APIResource{ resourceByVersion: map[string][]metav1.APIResource{
"idp.supervisor.pinniped.dev/v1alpha1": { idpSupervisorGV.String(): {
{ {
Name: "oidcidentityproviders", Name: "oidcidentityproviders",
SingularName: "oidcidentityprovider", SingularName: "oidcidentityprovider",
@ -113,20 +127,20 @@ func TestGetAPIResourceList(t *testing.T) {
}, },
{ {
group: metav1.APIGroup{ group: metav1.APIGroup{
Name: "config.concierge.pinniped.dev", Name: configConciergeGV.Group,
Versions: []metav1.GroupVersionForDiscovery{ Versions: []metav1.GroupVersionForDiscovery{
{ {
GroupVersion: "config.concierge.pinniped.dev/v1alpha1", GroupVersion: configConciergeGV.String(),
Version: "v1alpha1", Version: configConciergeGV.Version,
}, },
}, },
PreferredVersion: metav1.GroupVersionForDiscovery{ PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "config.concierge.pinniped.dev/v1alpha1", GroupVersion: configConciergeGV.String(),
Version: "v1alpha1", Version: configConciergeGV.Version,
}, },
}, },
resourceByVersion: map[string][]metav1.APIResource{ resourceByVersion: map[string][]metav1.APIResource{
"config.concierge.pinniped.dev/v1alpha1": { configConciergeGV.String(): {
{ {
Name: "credentialissuers", Name: "credentialissuers",
SingularName: "credentialissuer", SingularName: "credentialissuer",
@ -140,20 +154,20 @@ func TestGetAPIResourceList(t *testing.T) {
}, },
{ {
group: metav1.APIGroup{ group: metav1.APIGroup{
Name: "authentication.concierge.pinniped.dev", Name: authenticationConciergeGV.Group,
Versions: []metav1.GroupVersionForDiscovery{ Versions: []metav1.GroupVersionForDiscovery{
{ {
GroupVersion: "authentication.concierge.pinniped.dev/v1alpha1", GroupVersion: authenticationConciergeGV.String(),
Version: "v1alpha1", Version: authenticationConciergeGV.Version,
}, },
}, },
PreferredVersion: metav1.GroupVersionForDiscovery{ PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "authentication.concierge.pinniped.dev/v1alpha1", GroupVersion: authenticationConciergeGV.String(),
Version: "v1alpha1", Version: authenticationConciergeGV.Version,
}, },
}, },
resourceByVersion: map[string][]metav1.APIResource{ resourceByVersion: map[string][]metav1.APIResource{
"authentication.concierge.pinniped.dev/v1alpha1": { authenticationConciergeGV.String(): {
{ {
Name: "webhookauthenticators", Name: "webhookauthenticators",
SingularName: "webhookauthenticator", SingularName: "webhookauthenticator",
@ -182,7 +196,7 @@ func TestGetAPIResourceList(t *testing.T) {
testedGroups[tt.group.Name] = true testedGroups[tt.group.Name] = true
} }
for _, g := range groups { for _, g := range groups {
if !strings.Contains(g.Name, "pinniped.dev") { if !strings.Contains(g.Name, env.APIGroupSuffix) {
continue continue
} }
assert.Truef(t, testedGroups[g.Name], "expected group %q to have assertions defined", g.Name) assert.Truef(t, testedGroups[g.Name], "expected group %q to have assertions defined", g.Name)
@ -192,7 +206,7 @@ func TestGetAPIResourceList(t *testing.T) {
t.Run("every API categorized appropriately", func(t *testing.T) { t.Run("every API categorized appropriately", func(t *testing.T) {
t.Parallel() t.Parallel()
for _, r := range resources { for _, r := range resources {
if !strings.Contains(r.GroupVersion, "pinniped.dev") { if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
continue continue
} }
for _, a := range r.APIResources { for _, a := range r.APIResources {
@ -208,7 +222,7 @@ func TestGetAPIResourceList(t *testing.T) {
t.Run("Pinniped resources do not have short names", func(t *testing.T) { t.Run("Pinniped resources do not have short names", func(t *testing.T) {
t.Parallel() t.Parallel()
for _, r := range resources { for _, r := range resources {
if !strings.Contains(r.GroupVersion, "pinniped.dev") { if !strings.Contains(r.GroupVersion, env.APIGroupSuffix) {
continue continue
} }
for _, a := range r.APIResources { for _, a := range r.APIResources {

View File

@ -69,6 +69,7 @@ func TestKubeClientOwnerRef(t *testing.T) {
Name: parentSecret.Name, Name: parentSecret.Name,
UID: parentSecret.UID, UID: parentSecret.UID,
} }
_ = env.APIGroupSuffix // TODO: wire API group into kubeclient.
ownerRefClient, err := kubeclient.New( ownerRefClient, err := kubeclient.New(
kubeclient.WithMiddleware(ownerref.New(ref)), kubeclient.WithMiddleware(ownerref.New(ref)),
kubeclient.WithConfig(library.NewClientConfig(t)), kubeclient.WithConfig(library.NewClientConfig(t)),

View File

@ -31,6 +31,7 @@ import (
idpv1alpha1 "go.pinniped.dev/generated/1.20/apis/supervisor/idp/v1alpha1" idpv1alpha1 "go.pinniped.dev/generated/1.20/apis/supervisor/idp/v1alpha1"
conciergeclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned" conciergeclientset "go.pinniped.dev/generated/1.20/client/concierge/clientset/versioned"
supervisorclientset "go.pinniped.dev/generated/1.20/client/supervisor/clientset/versioned" supervisorclientset "go.pinniped.dev/generated/1.20/client/supervisor/clientset/versioned"
"go.pinniped.dev/internal/kubeclient"
// Import to initialize client auth plugins - the kubeconfig that we use for // Import to initialize client auth plugins - the kubeconfig that we use for
// testing may use gcloud, az, oidc, etc. // testing may use gcloud, az, oidc, etc.
@ -76,19 +77,19 @@ func NewClientsetWithCertAndKey(t *testing.T, clientCertificateData, clientKeyDa
func NewSupervisorClientset(t *testing.T) supervisorclientset.Interface { func NewSupervisorClientset(t *testing.T) supervisorclientset.Interface {
t.Helper() t.Helper()
return supervisorclientset.NewForConfigOrDie(NewClientConfig(t)) return newKubeclient(t, NewClientConfig(t)).PinnipedSupervisor
} }
func NewConciergeClientset(t *testing.T) conciergeclientset.Interface { func NewConciergeClientset(t *testing.T) conciergeclientset.Interface {
t.Helper() t.Helper()
return conciergeclientset.NewForConfigOrDie(NewClientConfig(t)) return newKubeclient(t, NewClientConfig(t)).PinnipedConcierge
} }
func NewAnonymousConciergeClientset(t *testing.T) conciergeclientset.Interface { func NewAnonymousConciergeClientset(t *testing.T) conciergeclientset.Interface {
t.Helper() t.Helper()
return conciergeclientset.NewForConfigOrDie(newAnonymousClientRestConfig(t)) return newKubeclient(t, newAnonymousClientRestConfig(t)).PinnipedConcierge
} }
func NewAggregatedClientset(t *testing.T) aggregatorclient.Interface { func NewAggregatedClientset(t *testing.T) aggregatorclient.Interface {
@ -132,6 +133,14 @@ func newAnonymousClientRestConfigWithCertAndKeyAdded(t *testing.T, clientCertifi
return config return config
} }
func newKubeclient(t *testing.T, config *rest.Config) *kubeclient.Client {
t.Helper()
_ = IntegrationEnv(t).APIGroupSuffix // TODO: wire API group into kubeclient.
client, err := kubeclient.New(kubeclient.WithConfig(config))
require.NoError(t, err)
return client
}
// CreateTestWebhookAuthenticator 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 // automatically deleted at the end of the current test's lifetime. It returns a corev1.TypedLocalObjectReference which
// describes the test webhook authenticator within the test namespace. // describes the test webhook authenticator within the test namespace.

View File

@ -38,6 +38,7 @@ type TestEnv struct {
SupervisorHTTPSIngressAddress string `json:"supervisorHttpsIngressAddress"` SupervisorHTTPSIngressAddress string `json:"supervisorHttpsIngressAddress"`
SupervisorHTTPSIngressCABundle string `json:"supervisorHttpsIngressCABundle"` SupervisorHTTPSIngressCABundle string `json:"supervisorHttpsIngressCABundle"`
Proxy string `json:"proxy"` Proxy string `json:"proxy"`
APIGroupSuffix string `json:"apiGroupSuffix"`
TestUser struct { TestUser struct {
Token string `json:"token"` Token string `json:"token"`
@ -106,6 +107,14 @@ func needEnv(t *testing.T, key string) string {
return value return value
} }
func wantEnv(key, dephault string) string {
value, ok := os.LookupEnv(key)
if !ok {
return dephault
}
return value
}
func filterEmpty(ss []string) []string { func filterEmpty(ss []string) []string {
filtered := []string{} filtered := []string{}
for _, s := range ss { for _, s := range ss {
@ -154,6 +163,7 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
result.SupervisorCustomLabels = supervisorCustomLabels result.SupervisorCustomLabels = supervisorCustomLabels
require.NotEmpty(t, result.SupervisorCustomLabels, "PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS cannot be empty") require.NotEmpty(t, result.SupervisorCustomLabels, "PINNIPED_TEST_SUPERVISOR_CUSTOM_LABELS cannot be empty")
result.Proxy = os.Getenv("PINNIPED_TEST_PROXY") result.Proxy = os.Getenv("PINNIPED_TEST_PROXY")
result.APIGroupSuffix = wantEnv("PINNIPED_TEST_API_GROUP_SUFFIX", "pinniped.dev")
result.CLITestUpstream = TestOIDCUpstream{ result.CLITestUpstream = TestOIDCUpstream{
Issuer: needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER"), Issuer: needEnv(t, "PINNIPED_TEST_CLI_OIDC_ISSUER"),