Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "tsh kube" commands #4769

Merged
merged 1 commit into from Nov 11, 2020
Merged

Add "tsh kube" commands #4769

merged 1 commit into from Nov 11, 2020

Conversation

awly
Copy link
Contributor

@awly awly commented Nov 10, 2020

  1. tsh kube clusters - lists registered kubernetes clusters
    note: this only includes clusters connected via kubernetes_service

  2. tsh kube credentials - returns TLS credentials for a specific kube
    cluster; this is a hidden command used as an exec plugin for kubectl

  3. tsh kube login - switches the kubectl context to one of the
    registered clusters; roughly equivalent to kubectl config use-context

When updating kubeconfigs, tsh now uses the exec plugin mode:
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
This means that on each kubectl run, kubectl will execute tsh with
special arguments to get the TLS credentials.

Using tsh as exec plugin allows us to put a login prompt when certs
expire. It also lets us lazy-initialize TLS certs for kubernetes
clusters.

Updates #3952
Fixes #3691

As before, sending this out for review before all unit tests are finished. I'll be adding those shortly.

lib/client/interfaces.go Outdated Show resolved Hide resolved
kubeCerts := make(map[string][]byte)
// Optionally, read kube TLS certs.
// TODO(awly): unit test this.
if clusterName != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is introducing a lot of change in the existing client code and adds another task for the function it should not ideally perform. Have you considered adding GetKubeClusterKey as an alternative? It is an aggregation of GetKey with kube cert lookup:

func GetKubeClusterKey(store *FSLocalKeyStore, proxyHost, username, clusterName string) (*Key, error) {
	key, err := store.GetKey(proxyHost, username)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	dirPath, err := store.dirFor(proxyHost, false)
	if err != nil {
		return nil, trace.Wrap(err)
	}
	kubeCerts, err := ReadKubeCerts(dirPath, clusterName)
	if err != nil {
		store.log.Error(err)
		return nil, trace.Wrap(err)
	}
	key.ClusterName = clusterName
	key.KubeTLSCerts = kubeCerts
	return key, nil
}

ReadKubeCerts could be tested separately and GetKubeClusterKey needn't be tested at all since it solely calls into APIs which are tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid point.
Since we'll be storing database and app certs in a similar way, I changed it to use pluggable options.
WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it is an improvement in that it will isolate the code so it becomes easier to test, yes.
You should consider doing this for other related APIs - e.g. DeleteKey.

lib/kube/kubeconfig/kubeconfig.go Show resolved Hide resolved
lib/services/server.go Show resolved Hide resolved
tool/tsh/kube.go Show resolved Hide resolved
lib/kube/kubeconfig/kubeconfig.go Outdated Show resolved Hide resolved
kubeCerts := make(map[string][]byte)
// Optionally, read kube TLS certs.
// TODO(awly): unit test this.
if clusterName != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it is an improvement in that it will isolate the code so it becomes easier to test, yes.
You should consider doing this for other related APIs - e.g. DeleteKey.

Copy link
Collaborator

@r0mant r0mant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm with a few comments

lib/client/keystore.go Outdated Show resolved Hide resolved
APIVersion: "client.authentication.k8s.io/v1beta1",
Command: v.Exec.TshBinaryPath,
Args: []string{"kube", "credentials",
fmt.Sprintf("--kube-cluster=%s", c),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would consider quoting the flag values, =%q, here and below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These args are passed directly to exec, not to a shell.
Quotes won't be stripped (like they would be with a shell) and tsh will see --kube-cluster as "foo" instead of foo

},
}
if v.Exec.TshBinaryInsecure {
authInfo.Exec.Args = append(authInfo.Exec.Args, "--insecure")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is --insecure flag going to be recognized fine when appended? I've run into some issues with that before, that it had to go right after tsh. I'd consider prepending it instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it worked fine when I tested, but I can see it being a problem for tsh ssh where it expects flags before arguments

tool/tsh/kube.go Outdated Show resolved Hide resolved
tool/tsh/kube.go Outdated Show resolved Hide resolved
@awly awly force-pushed the andrew/tsh_kube_commands branch 2 times, most recently from b7598c0 to af43459 Compare November 11, 2020 18:13
1. `tsh kube clusters` - lists registered kubernetes clusters
   note: this only includes clusters connected via `kubernetes_service`

2. `tsh kube credentials` - returns TLS credentials for a specific kube
   cluster; this is a hidden command used as an exec plugin for kubectl

3. `tsh kube login` - switches the kubectl context to one of the
   registered clusters; roughly equivalent to `kubectl config
   use-context`

When updating kubeconfigs, tsh now uses the exec plugin mode:
https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
This means that on each kubectl run, kubectl will execute tsh with
special arguments to get the TLS credentials.

Using tsh as exec plugin allows us to put a login prompt when certs
expire. It also lets us lazy-initialize TLS certs for kubernetes
clusters.
@awly awly merged commit 52c52c7 into master Nov 11, 2020
@awly awly deleted the andrew/tsh_kube_commands branch November 11, 2020 22:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use tsh as an exec plugin from kubeconfig
3 participants