diff --git a/integration/proxy/proxy_helpers.go b/integration/proxy/proxy_helpers.go index 513417cd44534..eee6649fd9214 100644 --- a/integration/proxy/proxy_helpers.go +++ b/integration/proxy/proxy_helpers.go @@ -48,11 +48,13 @@ import ( clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "github.com/gravitational/teleport/api/breaker" + kubeproto "github.com/gravitational/teleport/api/gen/proto/go/teleport/kube/v1" "github.com/gravitational/teleport/api/types" apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/integration/helpers" "github.com/gravitational/teleport/lib/auth" + "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/fixtures" "github.com/gravitational/teleport/lib/reversetunnel" @@ -441,23 +443,28 @@ func mustClosePostgresClient(t *testing.T, client *pgconn.PgConn) { require.NoError(t, err) } +const ( + kubeClusterName = "gke_project_europecentral2a_cluster1" + kubeClusterDefaultNamespace = "default" + kubePodName = "firstcontainer-66b6c48dd-bqmwk" +) + func k8ClientConfig(serverAddr, sni string) clientcmdapi.Config { - const clusterName = "gke_project_europecentral2a_cluster1" return clientcmdapi.Config{ Clusters: map[string]*clientcmdapi.Cluster{ - clusterName: { + kubeClusterName: { Server: serverAddr, InsecureSkipTLSVerify: true, TLSServerName: sni, }, }, Contexts: map[string]*clientcmdapi.Context{ - clusterName: { - Cluster: clusterName, - AuthInfo: clusterName, + kubeClusterName: { + Cluster: kubeClusterName, + AuthInfo: kubeClusterName, }, }, - CurrentContext: clusterName, + CurrentContext: kubeClusterName, } } @@ -470,7 +477,8 @@ func mkPodList() *v1.PodList { Items: []v1.Pod{ { ObjectMeta: metav1.ObjectMeta{ - Name: "firstcontainer-66b6c48dd-bqmwk", + Name: kubePodName, + Namespace: kubeClusterDefaultNamespace, }, }, }, @@ -781,3 +789,21 @@ func mustRegisterUsingIAMMethod(t *testing.T, proxyAddr utils.NetAddr, token str }) require.NoError(t, err, trace.DebugReport(err)) } + +func mustFindKubePod(t *testing.T, tc *client.TeleportClient) { + t.Helper() + + serviceClient, err := tc.NewKubernetesServiceClient(context.Background(), tc.SiteName) + require.NoError(t, err) + + response, err := serviceClient.ListKubernetesResources(context.Background(), &kubeproto.ListKubernetesResourcesRequest{ + ResourceType: types.KindKubePod, + KubernetesCluster: kubeClusterName, + KubernetesNamespace: kubeClusterDefaultNamespace, + TeleportCluster: tc.SiteName, + }) + require.NoError(t, err) + require.Len(t, response.Resources, 1) + require.Equal(t, types.KindKubePod, response.Resources[0].Kind) + require.Equal(t, kubePodName, response.Resources[0].GetName()) +} diff --git a/integration/proxy/proxy_test.go b/integration/proxy/proxy_test.go index d48229cb9edc3..1b1c046d650bb 100644 --- a/integration/proxy/proxy_test.go +++ b/integration/proxy/proxy_test.go @@ -1542,3 +1542,75 @@ func TestALPNSNIProxyGRPCInsecure(t *testing.T) { mustRegisterUsingIAMMethod(t, *albAddr, provisionToken.GetName(), nodeCredentials) }) } + +// TestALPNSNIProxyGRPCSecure tests ALPN protocol ProtocolProxyGRPCSecure +// by creating a KubeServiceClient for pod search. +func TestALPNSNIProxyGRPCSecure(t *testing.T) { + lib.SetInsecureDevMode(true) + defer lib.SetInsecureDevMode(false) + + const ( + localK8SNI = "kube.teleport.cluster.local" + k8User = "alice@example.com" + k8RoleName = "kubemaster" + ) + + kubeAPIMockSvr := startKubeAPIMock(t) + kubeConfigPath := mustCreateKubeConfigFile(t, k8ClientConfig(kubeAPIMockSvr.URL, localK8SNI)) + + username := helpers.MustGetCurrentUser(t).Username + kubeRoleSpec := types.RoleSpecV6{ + Allow: types.RoleConditions{ + Logins: []string{username}, + KubernetesLabels: types.Labels{types.Wildcard: []string{types.Wildcard}}, + KubeGroups: []string{kube.TestImpersonationGroup}, + KubeUsers: []string{k8User}, + KubernetesResources: []types.KubernetesResource{ + { + Kind: types.KindKubePod, Name: types.Wildcard, Namespace: types.Wildcard, + }, + }, + }, + } + kubeRole, err := types.NewRole(k8RoleName, kubeRoleSpec) + require.NoError(t, err) + + suite := newSuite(t, + withRootClusterConfig(rootClusterStandardConfig(t), func(config *servicecfg.Config) { + config.Proxy.Kube.Enabled = true + config.Version = defaults.TeleportConfigVersionV3 + config.Kube.Enabled = true + config.Kube.KubeconfigPath = kubeConfigPath + config.Kube.ListenAddr = utils.MustParseAddr( + helpers.NewListener(t, service.ListenerKube, &config.FileDescriptors)) + }), + withLeafClusterConfig(leafClusterStandardConfig(t)), + withRootAndLeafClusterRoles(kubeRole), + withStandardRoleMapping(), + ) + + t.Run("root", func(t *testing.T) { + tc, err := suite.root.NewClient(helpers.ClientConfig{ + Login: username, + Cluster: suite.root.Secrets.SiteName, + Host: helpers.Loopback, + Port: helpers.Port(t, suite.root.SSH), + }) + require.NoError(t, err) + mustFindKubePod(t, tc) + }) + t.Run("ALPN conn upgrade", func(t *testing.T) { + // Make a mock ALB which points to the Teleport Proxy Service. + albProxy := mustStartMockALBProxy(t, suite.root.Config.Proxy.WebAddr.Addr) + + tc, err := suite.root.NewClient(helpers.ClientConfig{ + Login: username, + Cluster: suite.root.Secrets.SiteName, + Host: helpers.Loopback, + Port: helpers.Port(t, suite.root.SSH), + ALBAddr: albProxy.Addr().String(), + }) + require.NoError(t, err) + mustFindKubePod(t, tc) + }) +} diff --git a/lib/client/api.go b/lib/client/api.go index dab5328f0384b..1c54c9dc72981 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -4738,6 +4738,8 @@ func (tc *TeleportClient) NewKubernetesServiceClient(ctx context.Context, cluste Credentials: []client.Credentials{ client.LoadTLS(tlsConfig), }, + ALPNConnUpgradeRequired: tc.TLSRoutingConnUpgradeRequired, + InsecureAddressDiscovery: tc.InsecureSkipVerify, }) if err != nil { return nil, trace.Wrap(err)