Add teleport proxy addr to the kubeconfig exec args when specified (#9899)

Because the `current-profile` file is used when `--proxy` is not
specified, it can be difficult to work with multiple clusters at once.
This allows the teleport proxy to be added as an exec arg to the kube
config, making opearting with multiple clusters as easy as changing the
kubectl context.

NOTE: Teleport already merges the kube config when `tsh login` is run
for different clusters. This change only improves the UX so that
updating `current-profile` is not required.

Co-authored-by: Zac Bergquist <zmb3@users.noreply.github.com>
This commit is contained in:
Garrett T 2022-01-28 11:37:55 -07:00 committed by GitHub
parent bbf013ce80
commit d877354799
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 4 deletions

View file

@ -54,6 +54,9 @@ type Values struct {
// If not set, static key/cert from Credentials are written to kubeconfig
// instead.
Exec *ExecValues
// ProxyAddr is the host:port address provided when running tsh kube login.
// This value is empty if a proxy was not specified.
ProxyAddr string
// TLSServerName is SNI host value passed to the server.
TLSServerName string
@ -110,14 +113,18 @@ func Update(path string, v Values) error {
for _, c := range v.Exec.KubeClusters {
contextName := ContextName(v.TeleportClusterName, c)
authName := contextName
execArgs := []string{"kube", "credentials",
fmt.Sprintf("--kube-cluster=%s", c),
fmt.Sprintf("--teleport-cluster=%s", v.TeleportClusterName),
}
if v.ProxyAddr != "" {
execArgs = append(execArgs, fmt.Sprintf("--proxy=%s", v.ProxyAddr))
}
authInfo := &clientcmdapi.AuthInfo{
Exec: &clientcmdapi.ExecConfig{
APIVersion: "client.authentication.k8s.io/v1beta1",
Command: v.Exec.TshBinaryPath,
Args: []string{"kube", "credentials",
fmt.Sprintf("--kube-cluster=%s", c),
fmt.Sprintf("--teleport-cluster=%s", v.TeleportClusterName),
},
Args: execArgs,
},
}
if v.Exec.TshBinaryInsecure {

View file

@ -267,6 +267,67 @@ func TestUpdateWithExec(t *testing.T) {
require.NoError(t, err)
require.Equal(t, wantConfig, config)
}
func TestUpdateWithExecAndProxy(t *testing.T) {
const (
clusterName = "teleport-cluster"
clusterAddr = "https://1.2.3.6:3080"
proxy = "my-teleport-proxy:3080"
tshPath = "/path/to/tsh"
kubeCluster = "my-cluster"
homeEnvVar = "TELEPORT_HOME"
home = "/alt/home"
)
kubeconfigPath, initialConfig := setup(t)
creds, caCertPEM, err := genUserKey()
require.NoError(t, err)
err = Update(kubeconfigPath, Values{
TeleportClusterName: clusterName,
ClusterAddr: clusterAddr,
Credentials: creds,
ProxyAddr: proxy,
Exec: &ExecValues{
TshBinaryPath: tshPath,
KubeClusters: []string{kubeCluster},
Env: map[string]string{
homeEnvVar: home,
},
},
})
require.NoError(t, err)
wantConfig := initialConfig.DeepCopy()
contextName := ContextName(clusterName, kubeCluster)
wantConfig.Clusters[clusterName] = &clientcmdapi.Cluster{
Server: clusterAddr,
CertificateAuthorityData: caCertPEM,
LocationOfOrigin: kubeconfigPath,
Extensions: map[string]runtime.Object{},
}
wantConfig.AuthInfos[contextName] = &clientcmdapi.AuthInfo{
LocationOfOrigin: kubeconfigPath,
Extensions: map[string]runtime.Object{},
Exec: &clientcmdapi.ExecConfig{
APIVersion: "client.authentication.k8s.io/v1beta1",
Command: tshPath,
Args: []string{"kube", "credentials",
fmt.Sprintf("--kube-cluster=%s", kubeCluster),
fmt.Sprintf("--teleport-cluster=%s", clusterName),
fmt.Sprintf("--proxy=%s", proxy),
},
Env: []clientcmdapi.ExecEnvVar{{Name: homeEnvVar, Value: home}},
},
}
wantConfig.Contexts[contextName] = &clientcmdapi.Context{
Cluster: clusterName,
AuthInfo: contextName,
LocationOfOrigin: kubeconfigPath,
Extensions: map[string]runtime.Object{},
}
config, err := Load(kubeconfigPath)
require.NoError(t, err)
require.Equal(t, wantConfig, config)
}
func TestRemove(t *testing.T) {
const (

View file

@ -347,6 +347,7 @@ func buildKubeConfigUpdate(cf *CLIConf, kubeStatus *kubernetesStatus) (*kubeconf
ClusterAddr: kubeStatus.clusterAddr,
TeleportClusterName: kubeStatus.teleportClusterName,
Credentials: kubeStatus.credentials,
ProxyAddr: cf.Proxy,
TLSServerName: kubeStatus.tlsServerName,
}