Skip to content

Commit

Permalink
[v13] check for discovered kube cluster name exact match
Browse files Browse the repository at this point in the history
backports #31744 to branch/v13.
  • Loading branch information
GavinFrazar committed Sep 19, 2023
1 parent 6159fb5 commit 7304a08
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 6 deletions.
39 changes: 34 additions & 5 deletions tool/tsh/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -1300,10 +1300,7 @@ func checkClusterSelection(cf *CLIConf, clusters types.KubeClusters, name string
query: cf.PredicateExpression,
}
if len(clusters) == 0 {
if selectors.IsEmpty() {
return trace.NotFound("no kubernetes clusters found, check 'tsh kube ls' for a list of known clusters")
}
return trace.NotFound("%v not found, check 'tsh kube ls' for a list of known clusters", selectors.String())
return trace.NotFound(formatKubeNotFound(cf.SiteName, selectors))
}
errMsg := formatAmbiguousKubeCluster(cf, selectors, clusters)
return trace.BadParameter(errMsg)
Expand All @@ -1322,18 +1319,40 @@ func matchClustersByName(nameOrPrefix string, clusters types.KubeClusters) types
if nameOrPrefix == "" {
return clusters
}
var prefixMatches types.KubeClusters

// look for an exact full name match.
for _, kc := range clusters {
if kc.GetName() == nameOrPrefix {
return types.KubeClusters{kc}
}
}

// or look for exact "discovered name" matches.
if clusters, ok := findKubeClustersByDiscoveredName(clusters, nameOrPrefix); ok {
return clusters
}

// or just filter by prefix.
var prefixMatches types.KubeClusters
for _, kc := range clusters {
if strings.HasPrefix(kc.GetName(), nameOrPrefix) {
prefixMatches = append(prefixMatches, kc)
}
}
return prefixMatches
}

func findKubeClustersByDiscoveredName(clusters types.KubeClusters, name string) (types.KubeClusters, bool) {
var out types.KubeClusters
for _, kc := range clusters {
discoveredName, ok := kc.GetLabel(types.DiscoveredNameLabel)
if ok && discoveredName == name {
out = append(out, kc)
}
}
return out, len(out) > 0
}

func (c *kubeLoginCommand) printUserMessage(cf *CLIConf, tc *client.TeleportClient, names []string) {
if tc.Profile().RequireKubeLocalProxy() {
c.printLocalProxyUserMessage(cf, names)
Expand Down Expand Up @@ -1599,6 +1618,16 @@ func formatAmbiguousKubeCluster(cf *CLIConf, selectors resourceSelectors, kubeCl
return formatAmbiguityErrTemplate(cf, selectors, listCommand, table, fullNameExample)
}

func formatKubeNotFound(clusterFlag string, selectors resourceSelectors) string {
listCmd := formatKubeListCommand(clusterFlag)
if selectors.IsEmpty() {
return fmt.Sprintf("no kubernetes clusters found, check '%v' for a list of known clusters",
listCmd)
}
return fmt.Sprintf("%v not found, check '%v' for a list of known clusters",
selectors, listCmd)
}

func formatKubeListCommand(clusterFlag string) string {
if clusterFlag == "" {
return "tsh kube ls"
Expand Down
49 changes: 48 additions & 1 deletion tool/tsh/kube_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,22 @@ import (
"path"
"strings"
"testing"
"time"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"

"github.com/gravitational/teleport/api/types"
apiutils "github.com/gravitational/teleport/api/utils"
"github.com/gravitational/teleport/api/utils/keypaths"
"github.com/gravitational/teleport/lib/kube/kubeconfig"
"github.com/gravitational/teleport/lib/service/servicecfg"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/srv/alpnproxy/common"
"github.com/gravitational/teleport/lib/utils"
"github.com/gravitational/teleport/tool/teleport/testenv"
Expand Down Expand Up @@ -94,7 +98,8 @@ func TestProxyKubeComplexSelectors(t *testing.T) {
testenv.WithResyncInterval(t, 0)
kubeFoo := "foo"
kubeFooBar := "foo-bar"
kubeBaz := "baz"
kubeBaz := "baz-qux"
kubeBazEKS := "baz-eks-us-west-1-123456789012"
kubeFooLeaf := "foo"
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
Expand All @@ -106,6 +111,9 @@ func TestProxyKubeComplexSelectors(t *testing.T) {
cfg.Kube.ListenAddr = utils.MustParseAddr(localListenerAddr())
cfg.Kube.KubeconfigPath = newKubeConfigFile(t, kubeFoo, kubeFooBar, kubeBaz)
cfg.Kube.StaticLabels = map[string]string{"env": "root"}
cfg.Kube.ResourceMatchers = []services.ResourceMatcher{{
Labels: map[string]apiutils.Strings{"*": {"*"}},
}}
}),
withLeafCluster(),
withLeafConfigFunc(
Expand All @@ -126,6 +134,34 @@ func TestProxyKubeComplexSelectors(t *testing.T) {
return len(rootClusters) == 3 && len(leafClusters) == 1
}),
)
// setup a fake "discovered" kube cluster by adding a discovered name label
// to a dynamic kube cluster.
kc, err := types.NewKubernetesClusterV3(
types.Metadata{
Name: kubeBazEKS,
Labels: map[string]string{
types.DiscoveredNameLabel: "baz",
types.OriginLabel: types.OriginDynamic,
},
},
types.KubernetesClusterSpecV3{
Kubeconfig: newKubeConfig(t, kubeBazEKS),
},
)
require.NoError(t, err)
err = s.root.GetAuthServer().CreateKubernetesCluster(ctx, kc)
require.NoError(t, err)
require.EventuallyWithT(t, func(c *assert.CollectT) {
servers, err := s.root.GetAuthServer().GetKubernetesServers(ctx)
assert.NoError(c, err)
for _, ks := range servers {
if ks.GetName() == kubeBazEKS {
return
}
}
assert.Fail(c, "kube server not found")
}, time.Second*10, time.Millisecond*500, "failed to find dynamically created kube cluster %v", kubeBazEKS)

rootClusterName := s.root.Config.Auth.ClusterName.GetClusterName()
leafClusterName := s.leaf.Config.Auth.ClusterName.GetClusterName()

Expand All @@ -146,6 +182,17 @@ func TestProxyKubeComplexSelectors(t *testing.T) {
},
args: []string{kubeFoo, "--insecure"},
},
{
desc: "with discovered name",
makeValidateCmdFn: func(t *testing.T) func(*exec.Cmd) error {
return func(cmd *exec.Cmd) error {
config := kubeConfigFromCmdEnv(t, cmd)
checkKubeLocalProxyConfig(t, s, config, rootClusterName, kubeBazEKS)
return nil
}
},
args: []string{"baz", "--insecure"},
},
{
desc: "with prefix name",
makeValidateCmdFn: func(t *testing.T) func(*exec.Cmd) error {
Expand Down
19 changes: 19 additions & 0 deletions tool/tsh/kube_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,25 @@ func newKubeConfigFile(t *testing.T, clusterNames ...string) string {
return kubeConfigLocation
}

func newKubeConfig(t *testing.T, name string) []byte {
kubeConf := clientcmdapi.NewConfig()

kubeConf.Clusters[name] = &clientcmdapi.Cluster{
Server: newKubeSelfSubjectServer(t),
InsecureSkipTLSVerify: true,
}
kubeConf.AuthInfos[name] = &clientcmdapi.AuthInfo{}

kubeConf.Contexts[name] = &clientcmdapi.Context{
Cluster: name,
AuthInfo: name,
}

buf, err := clientcmd.Write(*kubeConf)
require.NoError(t, err)
return buf
}

func newKubeSelfSubjectServer(t *testing.T) string {
srv, err := kubeserver.NewKubeAPIMock()
require.NoError(t, err)
Expand Down

0 comments on commit 7304a08

Please sign in to comment.