diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index cf4cceea27438..09273952a12a8 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -72,7 +72,6 @@ import ( apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/api/types/installers" "github.com/gravitational/teleport/api/types/wrappers" - apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/accessmonitoringrules/accessmonitoringrulesv1" "github.com/gravitational/teleport/lib/auth/assist/assistv1" "github.com/gravitational/teleport/lib/auth/clusterconfig/clusterconfigv1" @@ -2140,68 +2139,11 @@ func (g *GRPCServer) DeleteAllKubernetesServers(ctx context.Context, req *authpb // version for some features of the role returns a shallow copy of the given // role downgraded for compatibility with the older version. func maybeDowngradeRole(ctx context.Context, role *types.RoleV6) (*types.RoleV6, error) { - clientVersionString, ok := metadata.ClientVersionFromContext(ctx) - if !ok { - // This client is not reporting its version via gRPC metadata. Teleport - // clients have been reporting their version for long enough that older - // clients won't even support v6 roles at all, so this is likely a - // third-party client, and we shouldn't assume that downgrading the role - // will do more good than harm. - return role, nil - } - - clientVersion, err := semver.NewVersion(clientVersionString) - if err != nil { - return nil, trace.BadParameter("unrecognized client version: %s is not a valid semver", clientVersionString) - } - - role = maybeDowngradeRoleHostUserCreationMode(role, clientVersion) + // Teleport 16 supports all role features that Teleport 15 does, + // so no downgrade is necessary. return role, nil } -var minSupportedInsecureDropModeVersions = map[int64]semver.Version{ - 12: {Major: 12, Minor: 4, Patch: 30}, - 13: {Major: 13, Minor: 4, Patch: 11}, - 14: {Major: 14, Minor: 2, Patch: 2}, -} - -// maybeDowngradeRoleHostUserCreationMode tests the client version passed through the gRPC metadata, and -// if the client version is less than the minimum supported version for the insecure-drop -// host user creation mode returns a shallow copy of the role with mode drop. If the -// passed in role does not have mode insecure-drop or the client is a supported version, -// the role is returned unchanged. -func maybeDowngradeRoleHostUserCreationMode(role *types.RoleV6, clientVersion *semver.Version) *types.RoleV6 { - if role.GetOptions().CreateHostUserMode != types.CreateHostUserMode_HOST_USER_MODE_INSECURE_DROP { - return role - } - minSupportedVersion, ok := minSupportedInsecureDropModeVersions[clientVersion.Major] - // Check if insecure-drop is supported. insecure-drop is not supported below - // v12, supported for some versions of v12 through v14, and supported for v15+. - if clientVersion.Major >= 12 && (!ok || !clientVersion.LessThan(minSupportedVersion)) { - return role - } - - // Make a shallow copy of the role so that we don't mutate the original. - // This is necessary because the role is shared - // between multiple clients sessions when notifying about changes in watchers. - // If we mutate the original role, it will be mutated for all clients - // which can cause panics since it causes a race condition. - role = apiutils.CloneProtoMsg(role) - options := role.GetOptions() - options.CreateHostUserMode = types.CreateHostUserMode_HOST_USER_MODE_DROP - role.SetOptions(options) - - reason := fmt.Sprintf(`Client version %q does not support the host creation user mode `+ - `'insecure-drop'. Role %q will be downgraded to use 'drop' mode instead. `+ - `In order to support 'insecure-drop', all clients must be updated to version %q or higher.`, - clientVersion, role.GetName(), minSupportedVersion) - if role.Metadata.Labels == nil { - role.Metadata.Labels = make(map[string]string, 1) - } - role.Metadata.Labels[types.TeleportDowngradedLabel] = reason - return role -} - // GetRole retrieves a role by name. func (g *GRPCServer) GetRole(ctx context.Context, req *authpb.GetRoleRequest) (*types.RoleV6, error) { auth, err := g.authenticate(ctx) diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index 26a97cfb3f5cc..b6006617955d3 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -49,7 +49,6 @@ import ( "google.golang.org/protobuf/types/known/emptypb" "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/constants" apidefaults "github.com/gravitational/teleport/api/defaults" @@ -4267,177 +4266,6 @@ func TestPing_VersionCheck_AccessMonitoringFlag(t *testing.T) { require.True(t, ping.ServerFeatures.AccessMonitoring.Enabled, "expected field AccessMonitoring.Enabled to be true") } -func TestRoleVersions(t *testing.T) { - t.Parallel() - srv := newTestTLSServer(t) - - newRole := func(name string, version string, spec types.RoleSpecV6) types.Role { - role, err := types.NewRoleWithVersion(name, version, spec) - meta := role.GetMetadata() - role.SetMetadata(meta) - require.NoError(t, err) - return role - } - - role := newRole("test_role_1", types.V7, types.RoleSpecV6{ - Allow: types.RoleConditions{ - Rules: []types.Rule{ - types.NewRule(types.KindRole, services.RW()), - }, - }, - Options: types.RoleOptions{ - CreateHostUserMode: types.CreateHostUserMode_HOST_USER_MODE_INSECURE_DROP, - }, - }) - - user, err := CreateUser(context.Background(), srv.Auth(), "user", role) - require.NoError(t, err) - - client, err := srv.NewClient(TestUser(user.GetName())) - require.NoError(t, err) - - for _, tc := range []struct { - desc string - clientVersions []string - expectError bool - inputRole types.Role - expectedRole types.Role - expectDowngraded bool - }{ - { - desc: "up to date", - clientVersions: []string{ - "15.1.2", api.Version, "", - }, - inputRole: role, - expectedRole: role, - }, - { - desc: "downgrade host user creation mode only", - clientVersions: []string{ - "14.0.0-alpha.1", - }, - inputRole: role, - expectedRole: newRole(role.GetName(), types.V7, types.RoleSpecV6{ - Allow: types.RoleConditions{ - Rules: []types.Rule{ - types.NewRule(types.KindRole, services.RW()), - }, - }, - Options: types.RoleOptions{ - CreateHostUserMode: types.CreateHostUserMode_HOST_USER_MODE_DROP, - }, - }), - expectDowngraded: true, - }, - } { - t.Run(tc.desc, func(t *testing.T) { - for _, clientVersion := range tc.clientVersions { - t.Run(clientVersion, func(t *testing.T) { - // setup client metadata - ctx := context.Background() - if clientVersion == "" { - ctx = context.WithValue(ctx, metadata.DisableInterceptors{}, struct{}{}) - } else { - ctx = metadata.AddMetadataToContext(ctx, map[string]string{ - metadata.VersionKey: clientVersion, - }) - } - - checkRole := func(gotRole types.Role) { - t.Helper() - if tc.expectError { - return - } - require.Empty(t, cmp.Diff(tc.expectedRole, gotRole, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Labels"))) - // The downgraded label value won't match exactly because it - // includes the client version, so just check it's not empty - // and ignore it in the role diff. - if tc.expectDowngraded { - require.NotEmpty(t, gotRole.GetMetadata().Labels[types.TeleportDowngradedLabel]) - } - } - checkErr := func(err error) { - t.Helper() - if tc.expectError { - require.Error(t, err) - } else { - require.NoError(t, err) - } - } - - // Test GetRole - gotRole, err := client.GetRole(ctx, tc.inputRole.GetName()) - checkErr(err) - checkRole(gotRole) - - // Test GetRoles - gotRoles, err := client.GetRoles(ctx) - checkErr(err) - if !tc.expectError { - foundTestRole := false - for _, gotRole := range gotRoles { - if gotRole.GetName() != tc.inputRole.GetName() { - continue - } - checkRole(gotRole) - foundTestRole = true - break - } - require.True(t, foundTestRole, "GetRoles result does not include expected role") - } - - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) - defer cancel() - - // Test WatchEvents - watcher, err := client.NewWatcher(ctx, types.Watch{Name: "roles", Kinds: []types.WatchKind{{Kind: types.KindRole}}}) - require.NoError(t, err) - defer watcher.Close() - - // Swallow the init event - e := <-watcher.Events() - require.Equal(t, types.OpInit, e.Type) - - // Re-upsert the role so that the watcher sees it, do this - // on the auth server directly to avoid the - // TeleportDowngradedLabel check in ServerWithRoles - tc.inputRole, err = srv.Auth().UpsertRole(ctx, tc.inputRole) - require.NoError(t, err) - - gotRole, err = func() (types.Role, error) { - for { - select { - case <-watcher.Done(): - return nil, watcher.Error() - case e := <-watcher.Events(): - if gotRole, ok := e.Resource.(types.Role); ok && gotRole.GetName() == tc.inputRole.GetName() { - return gotRole, nil - } - } - } - }() - checkErr(err) - checkRole(gotRole) - - if !tc.expectError { - // Try to re-upsert the role we got. If it was - // downgraded, it should be rejected due to the - // TeleportDowngradedLabel - _, err = client.UpsertRole(ctx, gotRole) - if tc.expectDowngraded { - require.Error(t, err) - } else { - require.NoError(t, err) - } - } - }) - } - }) - } -} - func TestUpsertApplicationServerOrigin(t *testing.T) { t.Parallel()