mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-24 16:17:11 +08:00
Add Moderated Sessions licensing (#11388)
This commit is contained in:
+636
-592
File diff suppressed because it is too large
Load Diff
@@ -465,6 +465,8 @@ message Features {
|
||||
bool HSM = 9 [ (gogoproto.jsontag) = "hsm" ];
|
||||
// Desktop enables desktop access product
|
||||
bool Desktop = 10 [ (gogoproto.jsontag) = "desktop" ];
|
||||
// ModeratedSessions enables moderated sessions product
|
||||
bool ModeratedSessions = 11 [ (gogoproto.jsontag) = "moderated_sessions" ];
|
||||
}
|
||||
|
||||
// DeleteUserRequest is the input value for the DeleteUser method.
|
||||
|
||||
@@ -71,6 +71,11 @@ type License interface {
|
||||
// SetSupportsDesktopAccess sets desktop access support flag
|
||||
SetSupportsDesktopAccess(Bool)
|
||||
|
||||
// GetSupportsModeratedSessions returns moderated sessions support flag
|
||||
GetSupportsModeratedSessions() Bool
|
||||
// SetSupportsModeratedSessions sets moderated sessions support flag
|
||||
SetSupportsModeratedSessions(Bool)
|
||||
|
||||
// SetLabels sets metadata labels
|
||||
SetLabels(labels map[string]string)
|
||||
|
||||
@@ -284,6 +289,16 @@ func (c *LicenseV3) SetSupportsDesktopAccess(value Bool) {
|
||||
c.Spec.SupportsDesktopAccess = value
|
||||
}
|
||||
|
||||
// GetSupportsModeratedSessions returns database access support flag
|
||||
func (c *LicenseV3) GetSupportsModeratedSessions() Bool {
|
||||
return c.Spec.SupportsDesktopAccess
|
||||
}
|
||||
|
||||
// SetSupportsModeratedSessions sets database access support flag
|
||||
func (c *LicenseV3) SetSupportsModeratedSessions(value Bool) {
|
||||
c.Spec.SupportsDesktopAccess = value
|
||||
}
|
||||
|
||||
// String represents a human readable version of license enabled features
|
||||
func (c *LicenseV3) String() string {
|
||||
var features []string
|
||||
@@ -305,6 +320,9 @@ func (c *LicenseV3) String() string {
|
||||
if c.GetSupportsDesktopAccess() {
|
||||
features = append(features, "supports desktop access")
|
||||
}
|
||||
if c.GetSupportsModeratedSessions() {
|
||||
features = append(features, "supports moderated sessions")
|
||||
}
|
||||
if c.GetCloud() {
|
||||
features = append(features, "is hosted by Gravitational")
|
||||
}
|
||||
@@ -341,4 +359,6 @@ type LicenseSpecV3 struct {
|
||||
ReportsUsage Bool `json:"usage,omitempty"`
|
||||
// Cloud is turned on when teleport is hosted by Gravitational
|
||||
Cloud Bool `json:"cloud,omitempty"`
|
||||
// SupportsModeratedSessions turns on moderated sessions
|
||||
SupportsModeratedSessions Bool `json:"moderated_sessions,omitempty"`
|
||||
}
|
||||
|
||||
+1
-1
Submodule e updated: 9956b32428...8e42bfe054
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2022 Gravitational, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/backend/memory"
|
||||
"github.com/gravitational/teleport/lib/modules"
|
||||
"github.com/gravitational/teleport/lib/services/local"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestUnmoderatedSessionsAllowed tests that we allow creating unmoderated sessions even if the
|
||||
// moderated sessions feature is disabled via modules.
|
||||
func TestUnmoderatedSessionsAllowed(t *testing.T) {
|
||||
modules.SetTestModules(t, &modules.TestModules{TestFeatures: modules.Features{
|
||||
ModeratedSessions: false, // Explicily turn off moderated sessions.
|
||||
}})
|
||||
|
||||
bk, err := memory.New(memory.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
srv, err := local.NewSessionTrackerService(bk)
|
||||
require.NoError(t, err)
|
||||
|
||||
tracker, err := srv.CreateSessionTracker(context.Background(), &proto.CreateSessionTrackerRequest{
|
||||
ID: "foo",
|
||||
Initiator: &types.Participant{},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, tracker)
|
||||
}
|
||||
|
||||
// TestModeratedSessionsDisabled makes sure moderated sessions can be disabled via modules.
|
||||
// Since moderated sessions require trackers, we mediate this in the tracker creation function.
|
||||
func TestModeratedSessionsDisabled(t *testing.T) {
|
||||
modules.SetTestModules(t, &modules.TestModules{TestFeatures: modules.Features{
|
||||
ModeratedSessions: false, // Explicily turn off moderated sessions.
|
||||
}})
|
||||
|
||||
bk, err := memory.New(memory.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
srv, err := local.NewSessionTrackerService(bk)
|
||||
require.NoError(t, err)
|
||||
|
||||
tracker, err := srv.CreateSessionTracker(context.Background(), &proto.CreateSessionTrackerRequest{
|
||||
ID: "foo",
|
||||
Initiator: &types.Participant{},
|
||||
HostPolicies: []*types.SessionTrackerPolicySet{
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "5",
|
||||
RequireSessionJoin: []*types.SessionRequirePolicy{
|
||||
{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.Error(t, err)
|
||||
require.Nil(t, tracker)
|
||||
require.Contains(t, err.Error(), "this Teleport cluster is not licensed for moderated sessions, please contact the cluster administrator")
|
||||
}
|
||||
|
||||
// TestModeratedSessionsEnabled verifies that we can create session trackers with moderation
|
||||
// requirements when the feature is enabled.
|
||||
func TestModeratedSesssionsEnabled(t *testing.T) {
|
||||
modules.SetTestModules(t, &modules.TestModules{TestFeatures: modules.Features{
|
||||
ModeratedSessions: true,
|
||||
}})
|
||||
|
||||
bk, err := memory.New(memory.Config{})
|
||||
require.NoError(t, err)
|
||||
|
||||
srv, err := local.NewSessionTrackerService(bk)
|
||||
require.NoError(t, err)
|
||||
|
||||
tracker, err := srv.CreateSessionTracker(context.Background(), &proto.CreateSessionTrackerRequest{
|
||||
ID: "foo",
|
||||
Initiator: &types.Participant{},
|
||||
HostPolicies: []*types.SessionTrackerPolicySet{
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "5",
|
||||
RequireSessionJoin: []*types.SessionRequirePolicy{
|
||||
{
|
||||
Name: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, tracker)
|
||||
}
|
||||
@@ -55,6 +55,8 @@ type Features struct {
|
||||
HSM bool
|
||||
// Desktop enables desktop access product
|
||||
Desktop bool
|
||||
// ModeratedSessions turns on moderated sessions
|
||||
ModeratedSessions bool
|
||||
}
|
||||
|
||||
// ToProto converts Features into proto.Features
|
||||
@@ -70,6 +72,7 @@ func (f Features) ToProto() *proto.Features {
|
||||
Cloud: f.Cloud,
|
||||
HSM: f.HSM,
|
||||
Desktop: f.Desktop,
|
||||
ModeratedSessions: f.ModeratedSessions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,10 +150,11 @@ func (p *defaultModules) PrintVersion() {
|
||||
// Features returns supported features
|
||||
func (p *defaultModules) Features() Features {
|
||||
return Features{
|
||||
Kubernetes: true,
|
||||
DB: true,
|
||||
App: true,
|
||||
Desktop: true,
|
||||
Kubernetes: true,
|
||||
DB: true,
|
||||
App: true,
|
||||
Desktop: true,
|
||||
ModeratedSessions: false, // moderated sessions is supported in enterprise only
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,13 +40,14 @@ func (l *LicenseSuite) TestUnmarshal(c *check.C) {
|
||||
testCases := []testCase{
|
||||
{
|
||||
description: "simple case",
|
||||
input: `{"kind": "license", "version": "v3", "metadata": {"name": "Teleport Commercial"}, "spec": {"account_id": "accountID", "usage": true, "k8s": true, "app": true, "db": true, "desktop": true, "aws_account": "123", "aws_pid": "4"}}`,
|
||||
input: `{"kind": "license", "version": "v3", "metadata": {"name": "Teleport Commercial"}, "spec": {"account_id": "accountID", "usage": true, "k8s": true, "app": true, "db": true, "desktop": true, "moderated_sessions": true, "aws_account": "123", "aws_pid": "4"}}`,
|
||||
expected: MustNew("Teleport Commercial", types.LicenseSpecV3{
|
||||
ReportsUsage: types.NewBool(true),
|
||||
SupportsKubernetes: types.NewBool(true),
|
||||
SupportsApplicationAccess: types.NewBoolP(true),
|
||||
SupportsDatabaseAccess: types.NewBool(true),
|
||||
SupportsDesktopAccess: types.NewBool(true),
|
||||
SupportsModeratedSessions: types.NewBool(true),
|
||||
Cloud: types.NewBool(false),
|
||||
AWSAccountID: "123",
|
||||
AWSProductID: "4",
|
||||
@@ -55,13 +56,14 @@ func (l *LicenseSuite) TestUnmarshal(c *check.C) {
|
||||
},
|
||||
{
|
||||
description: "simple case with string booleans",
|
||||
input: `{"kind": "license", "version": "v3", "metadata": {"name": "license"}, "spec": {"account_id": "accountID", "usage": "yes", "k8s": "yes", "app": "yes", "db": "yes", "desktop": "yes", "aws_account": "123", "aws_pid": "4"}}`,
|
||||
input: `{"kind": "license", "version": "v3", "metadata": {"name": "license"}, "spec": {"account_id": "accountID", "usage": "yes", "k8s": "yes", "app": "yes", "db": "yes", "desktop": "yes", "moderated_sessions": "yes", "aws_account": "123", "aws_pid": "4"}}`,
|
||||
expected: MustNew("license", types.LicenseSpecV3{
|
||||
ReportsUsage: types.NewBool(true),
|
||||
SupportsKubernetes: types.NewBool(true),
|
||||
SupportsApplicationAccess: types.NewBoolP(true),
|
||||
SupportsDatabaseAccess: types.NewBool(true),
|
||||
SupportsDesktopAccess: types.NewBool(true),
|
||||
SupportsModeratedSessions: types.NewBool(true),
|
||||
Cloud: types.NewBool(false),
|
||||
AWSAccountID: "123",
|
||||
AWSProductID: "4",
|
||||
@@ -72,14 +74,15 @@ func (l *LicenseSuite) TestUnmarshal(c *check.C) {
|
||||
description: "with cloud flag",
|
||||
input: `{"kind": "license", "version": "v3", "metadata": {"name": "license"}, "spec": {"cloud": "yes", "account_id": "accountID", "usage": "yes", "k8s": "yes", "aws_account": "123", "aws_pid": "4"}}`,
|
||||
expected: MustNew("license", types.LicenseSpecV3{
|
||||
ReportsUsage: types.NewBool(true),
|
||||
SupportsKubernetes: types.NewBool(true),
|
||||
SupportsDatabaseAccess: types.NewBool(false),
|
||||
SupportsDesktopAccess: types.NewBool(false),
|
||||
Cloud: types.NewBool(true),
|
||||
AWSAccountID: "123",
|
||||
AWSProductID: "4",
|
||||
AccountID: "accountID",
|
||||
ReportsUsage: types.NewBool(true),
|
||||
SupportsKubernetes: types.NewBool(true),
|
||||
SupportsDatabaseAccess: types.NewBool(false),
|
||||
SupportsDesktopAccess: types.NewBool(false),
|
||||
SupportsModeratedSessions: types.NewBool(false),
|
||||
Cloud: types.NewBool(true),
|
||||
AWSAccountID: "123",
|
||||
AWSProductID: "4",
|
||||
AccountID: "accountID",
|
||||
}),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/gravitational/teleport/api/client/proto"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/gravitational/teleport/lib/backend"
|
||||
"github.com/gravitational/teleport/lib/modules"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
"github.com/gravitational/trace"
|
||||
@@ -130,6 +131,16 @@ func (s *sessionTracker) GetActiveSessionTrackers(ctx context.Context) ([]types.
|
||||
|
||||
// CreateSessionTracker creates a tracker resource for an active session.
|
||||
func (s *sessionTracker) CreateSessionTracker(ctx context.Context, req *proto.CreateSessionTrackerRequest) (types.SessionTracker, error) {
|
||||
// Don't allow sessions that require moderation without the enterprise feature enabled.
|
||||
for _, policySet := range req.HostPolicies {
|
||||
if len(policySet.RequireSessionJoin) != 0 {
|
||||
if !modules.GetModules().Features().ModeratedSessions {
|
||||
return nil, trace.AccessDenied(
|
||||
"this Teleport cluster is not licensed for moderated sessions, please contact the cluster administrator")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
spec := types.SessionTrackerSpecV1{
|
||||
|
||||
Reference in New Issue
Block a user