Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions e2e/aws/eks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,18 @@ func awsEKSDiscoveryMatchedCluster(t *testing.T) {
return err == nil && len(kubeServers) == 1
}, 2*time.Minute, time.Second, "wait for the kubernetes service to create a KubernetesServer")

clusters, err := authC.GetKubernetesClusters(context.Background())
require.NoError(t, err)

// kubeClient is a Kubernetes client for the user created above
// that will be used to verify that the user can access the cluster and
// the permissions are correct.
kubeClient, _, err := kube.ProxyClient(kube.ProxyConfig{
T: teleport,
Username: username,
KubeUsers: kubeUsers,
KubeGroups: kubeGroups,
T: teleport,
Username: username,
KubeUsers: kubeUsers,
KubeGroups: kubeGroups,
KubeCluster: clusters[0].GetName(),
})
require.NoError(t, err)

Expand Down
20 changes: 14 additions & 6 deletions integration/kube/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type ProxyConfig struct {
PinnedIP string
KubeUsers []string
KubeGroups []string
KubeCluster string
Impersonation *rest.ImpersonationConfig
RouteToCluster string
CustomTLSServerName string
Expand Down Expand Up @@ -91,13 +92,20 @@ func ProxyClient(cfg ProxyConfig) (*kubernetes.Clientset, *rest.Config, error) {
return nil, nil, trace.Wrap(err)
}

kubeServers, _ := authServer.GetKubernetesServers(ctx)
kubeCluster := cfg.KubeCluster
if cfg.KubeCluster == "" && len(kubeServers) > 0 {
kubeCluster = kubeServers[0].GetCluster().GetName()
}

id := tlsca.Identity{
Username: cfg.Username,
Groups: user.GetRoles(),
KubernetesUsers: cfg.KubeUsers,
KubernetesGroups: cfg.KubeGroups,
RouteToCluster: cfg.RouteToCluster,
PinnedIP: cfg.PinnedIP,
Username: cfg.Username,
Groups: user.GetRoles(),
KubernetesUsers: cfg.KubeUsers,
KubernetesGroups: cfg.KubeGroups,
RouteToCluster: cfg.RouteToCluster,
KubernetesCluster: kubeCluster,
PinnedIP: cfg.PinnedIP,
}
subj, err := id.Subject()
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions integration/kube_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) {
T: main,
Username: username,
KubeGroups: mainKubeGroups,
KubeCluster: clusterAux,
Impersonation: &rest.ImpersonationConfig{UserName: "bob", Groups: []string{kube.TestImpersonationGroup}},
RouteToCluster: clusterAux,
})
Expand All @@ -695,6 +696,7 @@ func testKubeTrustedClustersClientCert(t *testing.T, suite *KubeSuite) {
T: main,
Username: username,
KubeGroups: mainKubeGroups,
KubeCluster: clusterAux,
RouteToCluster: clusterAux,
})
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions integration/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ func TestALPNSNIProxyKube(t *testing.T) {
PinnedIP: "127.0.0.1",
KubeUsers: kubeRoleSpec.Allow.KubeGroups,
KubeGroups: kubeRoleSpec.Allow.KubeUsers,
KubeCluster: "root.example.com",
CustomTLSServerName: localK8SNI,
TargetAddress: suite.root.Config.Proxy.WebAddr,
})
Expand Down Expand Up @@ -489,6 +490,7 @@ func TestALPNSNIProxyKubeV2Leaf(t *testing.T) {
PinnedIP: "127.0.0.1",
KubeUsers: kubeRoleSpec.Allow.KubeGroups,
KubeGroups: kubeRoleSpec.Allow.KubeUsers,
KubeCluster: "gke_project_europecentral2a_cluster1",
CustomTLSServerName: localK8SNI,
TargetAddress: suite.root.Config.Proxy.WebAddr,
RouteToCluster: suite.leaf.Secrets.SiteName,
Expand Down Expand Up @@ -640,6 +642,7 @@ func TestKubePROXYProtocol(t *testing.T) {
Username: kubeRoleSpec.Allow.Logins[0],
KubeUsers: kubeRoleSpec.Allow.KubeGroups,
KubeGroups: kubeRoleSpec.Allow.KubeUsers,
KubeCluster: kubeClusterName,
CustomTLSServerName: kubeCluster,
TargetAddress: targetAddr,
RouteToCluster: testCluster.Secrets.SiteName,
Expand Down Expand Up @@ -767,6 +770,7 @@ func TestKubeIPPinning(t *testing.T) {
PinnedIP: tc.pinnedIP,
KubeUsers: kubeRoleSpec.Allow.KubeGroups,
KubeGroups: kubeRoleSpec.Allow.KubeUsers,
KubeCluster: kubeClusterName,
CustomTLSServerName: kubeCluster,
TargetAddress: suite.root.Config.Proxy.WebAddr,
RouteToCluster: tc.routeToCluster,
Expand Down
17 changes: 7 additions & 10 deletions lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2581,16 +2581,13 @@ func generateCert(a *Server, req certRequest, caType types.CertAuthType) (*proto
if err != nil && !trace.IsNotFound(err) {
return nil, trace.Wrap(err)
}
// Only validate/default kubernetes cluster name for the current teleport
// cluster. If this cert is targeting a trusted teleport cluster, leave all
// the kubernetes cluster validation up to them.
if req.routeToCluster == clusterName {
req.kubernetesCluster, err = kubeutils.CheckOrSetKubeCluster(a.closeCtx, a, req.kubernetesCluster, clusterName)
if err != nil {
if !trace.IsNotFound(err) {
return nil, trace.Wrap(err)
}
log.Debug("Failed setting default kubernetes cluster for user login (user did not provide a cluster); leaving KubernetesCluster extension in the TLS certificate empty")
// Ensure that the Kubernetes cluster name specified in the request exists
// when the certificate is intended for a local Kubernetes cluster.
// If the certificate is targeting a trusted Teleport cluster, it is the
// responsibility of the cluster to ensure its existence.
if req.routeToCluster == clusterName && req.kubernetesCluster != "" {
if err := kubeutils.CheckKubeCluster(a.closeCtx, a, req.kubernetesCluster); err != nil {
return nil, trace.Wrap(err)
}
}

Expand Down
46 changes: 20 additions & 26 deletions lib/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,6 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
require.Equal(t, *gotID, wantID)

// Register a kubernetes cluster to verify the defaulting logic in TLS cert
// generation.
kubeCluster, err := types.NewKubernetesClusterV3(
types.Metadata{
Name: "root-kube-cluster",
Expand Down Expand Up @@ -410,8 +408,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
require.Equal(t, *gotID, wantID)

// Login without specifying kube cluster. A registered one should be picked
// automatically.
// Login without specifying kube cluster. Kube cluster in the certificate should be empty.
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Expand All @@ -429,16 +426,15 @@ func TestAuthenticateSSHUser(t *testing.T) {
gotTLSCert, err = tlsca.ParseCertificatePEM(resp.TLSCert)
require.NoError(t, err)
wantID = tlsca.Identity{
Username: user,
Groups: []string{role.GetName()},
Principals: []string{user, teleport.SSHSessionJoinPrincipal},
KubernetesUsers: []string{user},
KubernetesGroups: []string{"system:masters"},
KubernetesCluster: "root-kube-cluster",
Expires: gotTLSCert.NotAfter,
RouteToCluster: s.clusterName.GetClusterName(),
TeleportCluster: s.clusterName.GetClusterName(),
PrivateKeyPolicy: keys.PrivateKeyPolicyNone,
Username: user,
Groups: []string{role.GetName()},
Principals: []string{user, teleport.SSHSessionJoinPrincipal},
KubernetesUsers: []string{user},
KubernetesGroups: []string{"system:masters"},
Expires: gotTLSCert.NotAfter,
RouteToCluster: s.clusterName.GetClusterName(),
TeleportCluster: s.clusterName.GetClusterName(),
PrivateKeyPolicy: keys.PrivateKeyPolicyNone,
}
gotID, err = tlsca.FromSubject(gotTLSCert.Subject, gotTLSCert.NotAfter)
require.NoError(t, err)
Expand Down Expand Up @@ -475,8 +471,7 @@ func TestAuthenticateSSHUser(t *testing.T) {
require.NoError(t, err)
require.Equal(t, *gotID, wantID)

// Login without specifying kube cluster. A registered one should be picked
// automatically.
// Login without specifying kube cluster. Kube cluster in the certificate should be empty.
resp, err = s.a.AuthenticateSSHUser(ctx, AuthenticateSSHRequest{
AuthenticateUserRequest: AuthenticateUserRequest{
Username: user,
Expand All @@ -494,16 +489,15 @@ func TestAuthenticateSSHUser(t *testing.T) {
gotTLSCert, err = tlsca.ParseCertificatePEM(resp.TLSCert)
require.NoError(t, err)
wantID = tlsca.Identity{
Username: user,
Groups: []string{role.GetName()},
Principals: []string{user, teleport.SSHSessionJoinPrincipal},
KubernetesUsers: []string{user},
KubernetesGroups: []string{"system:masters"},
KubernetesCluster: "root-kube-cluster",
Expires: gotTLSCert.NotAfter,
RouteToCluster: s.clusterName.GetClusterName(),
TeleportCluster: s.clusterName.GetClusterName(),
PrivateKeyPolicy: keys.PrivateKeyPolicyNone,
Username: user,
Groups: []string{role.GetName()},
Principals: []string{user, teleport.SSHSessionJoinPrincipal},
KubernetesUsers: []string{user},
KubernetesGroups: []string{"system:masters"},
Expires: gotTLSCert.NotAfter,
RouteToCluster: s.clusterName.GetClusterName(),
TeleportCluster: s.clusterName.GetClusterName(),
PrivateKeyPolicy: keys.PrivateKeyPolicyNone,
}
gotID, err = tlsca.FromSubject(gotTLSCert.Subject, gotTLSCert.NotAfter)
require.NoError(t, err)
Expand Down
22 changes: 3 additions & 19 deletions lib/kube/proxy/forwarder.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ import (
"github.com/gravitational/teleport/lib/httplib/reverseproxy"
"github.com/gravitational/teleport/lib/kube/proxy/responsewriters"
"github.com/gravitational/teleport/lib/kube/proxy/streamproto"
kubeutils "github.com/gravitational/teleport/lib/kube/utils"
"github.com/gravitational/teleport/lib/multiplexer"
"github.com/gravitational/teleport/lib/reversetunnelclient"
"github.com/gravitational/teleport/lib/service/servicecfg"
Expand Down Expand Up @@ -754,37 +753,22 @@ func (f *Forwarder) setupContext(
return nil, trace.AccessDenied("access denied: remote user can not access remote cluster")
}

kubeCluster := identity.KubernetesCluster
// Only set a default kube cluster if the user is not accessing a specific cluster.
// The check for kubeCluster != "" is happens in the next code section.
if !isRemoteCluster && kubeCluster == "" {
kc, err := kubeutils.CheckOrSetKubeCluster(ctx, f.cfg.CachingAuthClient, identity.KubernetesCluster, teleportClusterName)
if err != nil {
if !trace.IsNotFound(err) {
return nil, trace.Wrap(err)
}
// Fallback for old clusters and old user certs. Assume that the
// user is trying to access the default cluster name.
kubeCluster = teleportClusterName
} else {
kubeCluster = kc
}
}

var (
kubeServers []types.KubeServer
kubeResource *types.KubernetesResource
apiResource apiResource
err error
)

kubeCluster := identity.KubernetesCluster
// Only check k8s principals for local clusters.
//
// For remote clusters, everything will be remapped to new roles on the
// leaf and checked there.
if !isRemoteCluster {
kubeServers, err = f.getKubernetesServersForKubeCluster(ctx, kubeCluster)
if err != nil || len(kubeServers) == 0 {
return nil, trace.NotFound("cluster %q not found", kubeCluster)
return nil, trace.NotFound("Kubernetes cluster %q not found", kubeCluster)
}
}
if f.isLocalKubeCluster(isRemoteCluster, kubeCluster) {
Expand Down
Loading