Merge pull request #563 from mattmoyer/cli-caching-enhancements
CLI cluster-specific credentials enhancements (followup to #562)
This commit is contained in:
commit
abf606ab72
@ -87,6 +87,8 @@ type getKubeconfigParams struct {
|
|||||||
oidc getKubeconfigOIDCParams
|
oidc getKubeconfigOIDCParams
|
||||||
concierge getKubeconfigConciergeParams
|
concierge getKubeconfigConciergeParams
|
||||||
generatedNameSuffix string
|
generatedNameSuffix string
|
||||||
|
credentialCachePath string
|
||||||
|
credentialCachePathSet bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
|
func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
|
||||||
@ -132,7 +134,7 @@ func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
|
|||||||
f.DurationVar(&flags.timeout, "timeout", 10*time.Minute, "Timeout for autodiscovery and validation")
|
f.DurationVar(&flags.timeout, "timeout", 10*time.Minute, "Timeout for autodiscovery and validation")
|
||||||
f.StringVarP(&flags.outputPath, "output", "o", "", "Output file path (default: stdout)")
|
f.StringVarP(&flags.outputPath, "output", "o", "", "Output file path (default: stdout)")
|
||||||
f.StringVar(&flags.generatedNameSuffix, "generated-name-suffix", "-pinniped", "Suffix to append to generated cluster, context, user kubeconfig entries")
|
f.StringVar(&flags.generatedNameSuffix, "generated-name-suffix", "-pinniped", "Suffix to append to generated cluster, context, user kubeconfig entries")
|
||||||
|
f.StringVar(&flags.credentialCachePath, "credential-cache", "", "Path to cluster-specific credentials cache")
|
||||||
mustMarkHidden(cmd, "oidc-debug-session-cache")
|
mustMarkHidden(cmd, "oidc-debug-session-cache")
|
||||||
|
|
||||||
mustMarkDeprecated(cmd, "concierge-namespace", "not needed anymore")
|
mustMarkDeprecated(cmd, "concierge-namespace", "not needed anymore")
|
||||||
@ -147,6 +149,7 @@ func kubeconfigCommand(deps kubeconfigDeps) *cobra.Command {
|
|||||||
defer func() { _ = out.Close() }()
|
defer func() { _ = out.Close() }()
|
||||||
cmd.SetOut(out)
|
cmd.SetOut(out)
|
||||||
}
|
}
|
||||||
|
flags.credentialCachePathSet = cmd.Flags().Changed("credential-cache")
|
||||||
return runGetKubeconfig(cmd.Context(), cmd.OutOrStdout(), deps, flags)
|
return runGetKubeconfig(cmd.Context(), cmd.OutOrStdout(), deps, flags)
|
||||||
}
|
}
|
||||||
return cmd
|
return cmd
|
||||||
@ -233,6 +236,11 @@ func runGetKubeconfig(ctx context.Context, out io.Writer, deps kubeconfigDeps, f
|
|||||||
cluster.CertificateAuthorityData = flags.concierge.caBundle
|
cluster.CertificateAuthorityData = flags.concierge.caBundle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If --credential-cache is set, pass it through.
|
||||||
|
if flags.credentialCachePathSet {
|
||||||
|
execConfig.Args = append(execConfig.Args, "--credential-cache="+flags.credentialCachePath)
|
||||||
|
}
|
||||||
|
|
||||||
// If one of the --static-* flags was passed, output a config that runs `pinniped login static`.
|
// If one of the --static-* flags was passed, output a config that runs `pinniped login static`.
|
||||||
if flags.staticToken != "" || flags.staticTokenEnvName != "" {
|
if flags.staticToken != "" || flags.staticTokenEnvName != "" {
|
||||||
if flags.staticToken != "" && flags.staticTokenEnvName != "" {
|
if flags.staticToken != "" && flags.staticTokenEnvName != "" {
|
||||||
|
@ -73,6 +73,7 @@ func TestGetKubeconfig(t *testing.T) {
|
|||||||
--concierge-endpoint string API base for the Concierge endpoint
|
--concierge-endpoint string API base for the Concierge endpoint
|
||||||
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
--concierge-mode mode Concierge mode of operation (default TokenCredentialRequestAPI)
|
||||||
--concierge-skip-wait Skip waiting for any pending Concierge strategies to become ready (default: false)
|
--concierge-skip-wait Skip waiting for any pending Concierge strategies to become ready (default: false)
|
||||||
|
--credential-cache string Path to cluster-specific credentials cache
|
||||||
--generated-name-suffix string Suffix to append to generated cluster, context, user kubeconfig entries (default "-pinniped")
|
--generated-name-suffix string Suffix to append to generated cluster, context, user kubeconfig entries (default "-pinniped")
|
||||||
-h, --help help for kubeconfig
|
-h, --help help for kubeconfig
|
||||||
--kubeconfig string Path to kubeconfig file
|
--kubeconfig string Path to kubeconfig file
|
||||||
@ -642,6 +643,7 @@ func TestGetKubeconfig(t *testing.T) {
|
|||||||
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
"--kubeconfig", "./testdata/kubeconfig.yaml",
|
||||||
"--static-token-env", "TEST_TOKEN",
|
"--static-token-env", "TEST_TOKEN",
|
||||||
"--skip-validation",
|
"--skip-validation",
|
||||||
|
"--credential-cache", "",
|
||||||
},
|
},
|
||||||
conciergeObjects: []runtime.Object{
|
conciergeObjects: []runtime.Object{
|
||||||
&configv1alpha1.CredentialIssuer{
|
&configv1alpha1.CredentialIssuer{
|
||||||
@ -699,6 +701,7 @@ func TestGetKubeconfig(t *testing.T) {
|
|||||||
- --concierge-authenticator-type=webhook
|
- --concierge-authenticator-type=webhook
|
||||||
- --concierge-endpoint=https://fake-server-url-value
|
- --concierge-endpoint=https://fake-server-url-value
|
||||||
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
- --concierge-ca-bundle-data=ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==
|
||||||
|
- --credential-cache=
|
||||||
- --token-env=TEST_TOKEN
|
- --token-env=TEST_TOKEN
|
||||||
command: '.../path/to/pinniped'
|
command: '.../path/to/pinniped'
|
||||||
env: []
|
env: []
|
||||||
@ -809,6 +812,7 @@ func TestGetKubeconfig(t *testing.T) {
|
|||||||
"--oidc-request-audience", "test-audience",
|
"--oidc-request-audience", "test-audience",
|
||||||
"--skip-validation",
|
"--skip-validation",
|
||||||
"--generated-name-suffix", "-sso",
|
"--generated-name-suffix", "-sso",
|
||||||
|
"--credential-cache", "/path/to/cache/dir/credentials.yaml",
|
||||||
},
|
},
|
||||||
conciergeObjects: []runtime.Object{
|
conciergeObjects: []runtime.Object{
|
||||||
&configv1alpha1.CredentialIssuer{
|
&configv1alpha1.CredentialIssuer{
|
||||||
@ -862,6 +866,7 @@ func TestGetKubeconfig(t *testing.T) {
|
|||||||
- --concierge-authenticator-type=webhook
|
- --concierge-authenticator-type=webhook
|
||||||
- --concierge-endpoint=https://explicit-concierge-endpoint.example.com
|
- --concierge-endpoint=https://explicit-concierge-endpoint.example.com
|
||||||
- --concierge-ca-bundle-data=%s
|
- --concierge-ca-bundle-data=%s
|
||||||
|
- --credential-cache=/path/to/cache/dir/credentials.yaml
|
||||||
- --issuer=https://example.com/issuer
|
- --issuer=https://example.com/issuer
|
||||||
- --client-id=pinniped-cli
|
- --client-id=pinniped-cli
|
||||||
- --scopes=offline_access,openid,pinniped:request-audience
|
- --scopes=offline_access,openid,pinniped:request-audience
|
||||||
|
@ -5,6 +5,8 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
clientauthv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||||
|
"k8s.io/client-go/tools/auth/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint: gochecknoglobals
|
//nolint: gochecknoglobals
|
||||||
@ -20,3 +22,15 @@ var loginCmd = &cobra.Command{
|
|||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(loginCmd)
|
rootCmd.AddCommand(loginCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loadClusterInfo() *clientauthv1beta1.Cluster {
|
||||||
|
obj, _, err := exec.LoadExecCredentialFromEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cred, ok := obj.(*clientauthv1beta1.ExecCredential)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cred.Spec.Cluster
|
||||||
|
}
|
||||||
|
@ -97,7 +97,7 @@ func oidcLoginCommand(deps oidcLoginCommandDeps) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the 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", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||||
cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Cluster-specific credentials cache path (\"\" disables the cache)")
|
cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Path to cluster-specific credentials cache (\"\" disables the cache)")
|
||||||
|
|
||||||
mustMarkHidden(cmd, "debug-session-cache")
|
mustMarkHidden(cmd, "debug-session-cache")
|
||||||
mustMarkRequired(cmd, "issuer")
|
mustMarkRequired(cmd, "issuer")
|
||||||
@ -167,11 +167,13 @@ func runOIDCLogin(cmd *cobra.Command, deps oidcLoginCommandDeps, flags oidcLogin
|
|||||||
opts = append(opts, oidcclient.WithClient(client))
|
opts = append(opts, oidcclient.WithClient(client))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up cached credentials based on a hash of all the CLI arguments.
|
// Look up cached credentials based on a hash of all the CLI arguments and the cluster info.
|
||||||
cacheKey := struct {
|
cacheKey := struct {
|
||||||
Args []string `json:"args"`
|
Args []string `json:"args"`
|
||||||
|
ClusterInfo *clientauthv1beta1.Cluster `json:"cluster"`
|
||||||
}{
|
}{
|
||||||
Args: os.Args[1:],
|
Args: os.Args[1:],
|
||||||
|
ClusterInfo: loadClusterInfo(),
|
||||||
}
|
}
|
||||||
var credCache *execcredcache.Cache
|
var credCache *execcredcache.Cache
|
||||||
if flags.credentialCachePath != "" {
|
if flags.credentialCachePath != "" {
|
||||||
|
@ -64,7 +64,7 @@ func TestLoginOIDCCommand(t *testing.T) {
|
|||||||
--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
|
||||||
--concierge-endpoint string API base for the Concierge endpoint
|
--concierge-endpoint string API base for the Concierge endpoint
|
||||||
--credential-cache string Cluster-specific credentials cache path ("" disables the cache) (default "` + cfgDir + `/credentials.yaml")
|
--credential-cache string Path to cluster-specific credentials cache ("" disables the cache) (default "` + cfgDir + `/credentials.yaml")
|
||||||
--enable-concierge Use the Concierge to login
|
--enable-concierge Use the Concierge to login
|
||||||
-h, --help help for oidc
|
-h, --help help for oidc
|
||||||
--issuer string OpenID Connect issuer URL
|
--issuer string OpenID Connect issuer URL
|
||||||
|
@ -72,7 +72,7 @@ func staticLoginCommand(deps staticLoginDeps) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the Concierge endpoint")
|
cmd.Flags().StringVar(&flags.conciergeEndpoint, "concierge-endpoint", "", "API base for the 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", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
cmd.Flags().StringVar(&flags.conciergeAPIGroupSuffix, "concierge-api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||||
cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Cluster-specific credentials cache path (\"\" disables the cache)")
|
cmd.Flags().StringVar(&flags.credentialCachePath, "credential-cache", filepath.Join(mustGetConfigDir(), "credentials.yaml"), "Path to cluster-specific credentials cache (\"\" disables the cache)")
|
||||||
|
|
||||||
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) }
|
||||||
|
|
||||||
@ -117,13 +117,15 @@ func runStaticLogin(out io.Writer, deps staticLoginDeps, flags staticLoginParams
|
|||||||
}
|
}
|
||||||
cred := tokenCredential(&oidctypes.Token{IDToken: &oidctypes.IDToken{Token: token}})
|
cred := tokenCredential(&oidctypes.Token{IDToken: &oidctypes.IDToken{Token: token}})
|
||||||
|
|
||||||
// Look up cached credentials based on a hash of all the CLI arguments and the current token value.
|
// Look up cached credentials based on a hash of all the CLI arguments, the current token value, and the cluster info.
|
||||||
cacheKey := struct {
|
cacheKey := struct {
|
||||||
Args []string `json:"args"`
|
Args []string `json:"args"`
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
ClusterInfo *clientauthv1beta1.Cluster `json:"cluster"`
|
||||||
}{
|
}{
|
||||||
Args: os.Args[1:],
|
Args: os.Args[1:],
|
||||||
Token: token,
|
Token: token,
|
||||||
|
ClusterInfo: loadClusterInfo(),
|
||||||
}
|
}
|
||||||
var credCache *execcredcache.Cache
|
var credCache *execcredcache.Cache
|
||||||
if flags.credentialCachePath != "" {
|
if flags.credentialCachePath != "" {
|
||||||
|
@ -57,7 +57,7 @@ func TestLoginStaticCommand(t *testing.T) {
|
|||||||
--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
|
||||||
--concierge-endpoint string API base for the Concierge endpoint
|
--concierge-endpoint string API base for the Concierge endpoint
|
||||||
--credential-cache string Cluster-specific credentials cache path ("" disables the cache) (default "` + cfgDir + `/credentials.yaml")
|
--credential-cache string Path to cluster-specific credentials cache ("" disables the cache) (default "` + cfgDir + `/credentials.yaml")
|
||||||
--enable-concierge Use the Concierge to login
|
--enable-concierge Use the Concierge to login
|
||||||
-h, --help help for static
|
-h, --help help for static
|
||||||
--token string Static token to present during login
|
--token string Static token to present during login
|
||||||
|
@ -49,11 +49,13 @@ func TestCLIGetKubeconfigStaticToken(t *testing.T) {
|
|||||||
// Build pinniped CLI.
|
// Build pinniped CLI.
|
||||||
pinnipedExe := library.PinnipedCLIPath(t)
|
pinnipedExe := library.PinnipedCLIPath(t)
|
||||||
|
|
||||||
|
credCacheDir := testutil.TempDir(t)
|
||||||
stdout, stderr := runPinnipedCLI(t, nil, pinnipedExe, "get", "kubeconfig",
|
stdout, stderr := runPinnipedCLI(t, nil, pinnipedExe, "get", "kubeconfig",
|
||||||
"--static-token", env.TestUser.Token,
|
"--static-token", env.TestUser.Token,
|
||||||
"--concierge-api-group-suffix", env.APIGroupSuffix,
|
"--concierge-api-group-suffix", env.APIGroupSuffix,
|
||||||
"--concierge-authenticator-type", "webhook",
|
"--concierge-authenticator-type", "webhook",
|
||||||
"--concierge-authenticator-name", authenticator.Name,
|
"--concierge-authenticator-name", authenticator.Name,
|
||||||
|
"--credential-cache", credCacheDir+"/credentials.yaml",
|
||||||
)
|
)
|
||||||
assert.Contains(t, stderr, "discovered CredentialIssuer")
|
assert.Contains(t, stderr, "discovered CredentialIssuer")
|
||||||
assert.Contains(t, stderr, "discovered Concierge endpoint")
|
assert.Contains(t, stderr, "discovered Concierge endpoint")
|
||||||
@ -383,6 +385,7 @@ func oidcLoginCommand(ctx context.Context, t *testing.T, pinnipedExe string, ses
|
|||||||
"--scopes", "offline_access,openid,email,profile",
|
"--scopes", "offline_access,openid,email,profile",
|
||||||
"--listen-port", callbackURL.Port(),
|
"--listen-port", callbackURL.Port(),
|
||||||
"--session-cache", sessionCachePath,
|
"--session-cache", sessionCachePath,
|
||||||
|
"--credential-cache", testutil.TempDir(t)+"/credentials.yaml",
|
||||||
"--skip-browser",
|
"--skip-browser",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user