Skip to content

Commit

Permalink
Dont allow cloud tenants to update certain cluster networking fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex McGrath committed Jul 11, 2023
1 parent caacc54 commit 5c7897b
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 0 deletions.
50 changes: 50 additions & 0 deletions lib/auth/auth_with_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -4111,9 +4111,51 @@ func (a *ServerWithRoles) SetClusterNetworkingConfig(ctx context.Context, newNet
return trace.AccessDenied("proxy peering is an enterprise-only feature")
}

oldNetConf, err := a.authServer.GetClusterNetworkingConfig(ctx)
if err != nil {
return trace.Wrap(err)
}

if err := a.validateCloudNetworkConfigUpdate(newNetConfig, oldNetConf); err != nil {
return trace.Wrap(err)
}

return a.authServer.SetClusterNetworkingConfig(ctx, newNetConfig)
}

func cloudTenantNetworkingError(field string) string {
return fmt.Sprintf("cloud tenants cannot update %q", field)
}

func (a *ServerWithRoles) validateCloudNetworkConfigUpdate(newConfig, oldConfig types.ClusterNetworkingConfig) error {
if a.hasBuiltinRole(types.RoleAdmin) {
return nil
}

if !modules.GetModules().Features().Cloud {
return nil
}

if newConfig.GetProxyListenerMode() != oldConfig.GetProxyListenerMode() {
return trace.BadParameter(cloudTenantNetworkingError("proxy_listener_mode"))
}
newtst, newerr := newConfig.GetTunnelStrategyType()
oldtst, olderr := oldConfig.GetTunnelStrategyType()
if newerr != olderr || newtst != oldtst {
return trace.BadParameter(cloudTenantNetworkingError("tunnel_strategy"))
}

if newConfig.GetKeepAliveInterval() != oldConfig.GetKeepAliveInterval() {
return trace.BadParameter(cloudTenantNetworkingError("keep_alive_interval"))
}

if newConfig.GetKeepAliveCountMax() != oldConfig.GetKeepAliveCountMax() {
return trace.BadParameter(cloudTenantNetworkingError("keep_alive_count_max"))
}

return nil
}

// ResetClusterNetworkingConfig resets cluster networking configuration to defaults.
func (a *ServerWithRoles) ResetClusterNetworkingConfig(ctx context.Context) error {
storedNetConfig, err := a.authServer.GetClusterNetworkingConfig(ctx)
Expand All @@ -4129,6 +4171,14 @@ func (a *ServerWithRoles) ResetClusterNetworkingConfig(ctx context.Context) erro
return trace.Wrap(err)
}
}
oldNetConf, err := a.authServer.GetClusterNetworkingConfig(ctx)
if err != nil {
return trace.Wrap(err)
}

if err := a.validateCloudNetworkConfigUpdate(types.DefaultClusterNetworkingConfig(), oldNetConf); err != nil {
return trace.Wrap(err)
}

return a.authServer.SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())
}
Expand Down
99 changes: 99 additions & 0 deletions lib/auth/auth_with_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
libdefaults "github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/events/eventstest"
"github.com/gravitational/teleport/lib/modules"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/session"
"github.com/gravitational/teleport/lib/tlsca"
Expand Down Expand Up @@ -1137,6 +1138,104 @@ func TestAuthPreferenceRBAC(t *testing.T) {
})
}

func TestClusterNetworkingCloudUpdates(t *testing.T) {
srv := newTestTLSServer(t)
ctx := context.Background()
srv.Auth().SetClusterNetworkingConfig(ctx, types.DefaultClusterNetworkingConfig())

user, _, err := CreateUserAndRole(srv.Auth(), "username", []string{}, []types.Rule{
{
Resources: []string{
types.KindClusterNetworkingConfig,
},
Verbs: services.RW(),
},
})
require.NoError(t, err)

for _, tc := range []struct {
cloud bool
identity TestIdentity
expectSetErr string
clusterNetworkingConfig types.ClusterNetworkingConfig
name string
}{
{
name: "non admin user can set existing values to the same value",
cloud: true,
identity: TestUser(user.GetName()),
clusterNetworkingConfig: types.DefaultClusterNetworkingConfig(),
},
{
name: "non admin user cannot set keep_alive_interval",
cloud: true,
identity: TestUser(user.GetName()),
expectSetErr: cloudTenantNetworkingError("keep_alive_interval"),
clusterNetworkingConfig: newClusterNetworkingConf(t, types.ClusterNetworkingConfigSpecV2{
KeepAliveInterval: types.Duration(time.Second * 20),
}),
},
{
name: "non admin user can set client_idle_timeout",
cloud: true,
identity: TestUser(user.GetName()),
clusterNetworkingConfig: newClusterNetworkingConf(t, types.ClusterNetworkingConfigSpecV2{
ClientIdleTimeout: types.Duration(time.Second * 67),
}),
},
{
name: "admin user can set keep_alive_interval",
cloud: true,
identity: TestAdmin(),
clusterNetworkingConfig: newClusterNetworkingConf(t, types.ClusterNetworkingConfigSpecV2{
KeepAliveInterval: types.Duration(time.Second * 67),
}),
},
{
name: "non admin user can set keep_alive_interval on non cloud cluster",
cloud: false,
identity: TestUser(user.GetName()),
clusterNetworkingConfig: newClusterNetworkingConf(t, types.ClusterNetworkingConfigSpecV2{
KeepAliveInterval: types.Duration(time.Second * 67),
}),
},
} {
t.Run(tc.name, func(t *testing.T) {
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
Cloud: tc.cloud,
},
})

client, err := srv.NewClient(tc.identity)
require.NoError(t, err)

err = client.SetClusterNetworkingConfig(ctx, tc.clusterNetworkingConfig)
if err != nil {
require.NotEmpty(t, tc.expectSetErr)
require.ErrorContains(t, err, tc.expectSetErr)
} else {
require.Empty(t, tc.expectSetErr)
}
})
}
}

func newClusterNetworkingConf(t *testing.T, spec types.ClusterNetworkingConfigSpecV2) types.ClusterNetworkingConfig {
c := &types.ClusterNetworkingConfigV2{
Metadata: types.Metadata{
Labels: map[string]string{
types.OriginLabel: types.OriginDynamic,
},
},
Spec: spec,
}
err := c.CheckAndSetDefaults()
require.NoError(t, err)
return c
}

func TestClusterNetworkingConfigRBAC(t *testing.T) {
t.Parallel()
ctx := context.Background()
Expand Down

0 comments on commit 5c7897b

Please sign in to comment.