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
9 changes: 9 additions & 0 deletions api/types/restrictions.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"time"

"github.com/gravitational/trace"

"github.com/gravitational/teleport/api/utils"
)

// NetworkRestrictions defines network restrictions applied to SSH session.
Expand All @@ -33,6 +35,8 @@ type NetworkRestrictions interface {
GetDeny() []AddressCondition
// SetDeny sets a list of denied network addresses (overrides Allow list)
SetDeny(deny []AddressCondition)
// Clone returns a copy of the network restrictions.
Clone() NetworkRestrictions
}

// NewNetworkRestrictions creates a new NetworkRestrictions with the given name.
Expand All @@ -46,6 +50,11 @@ func NewNetworkRestrictions() NetworkRestrictions {
}
}

// Clone returns a copy of the network restrictions.
func (r *NetworkRestrictionsV4) Clone() NetworkRestrictions {
return utils.CloneProtoMsg(r)
}

func (r *NetworkRestrictionsV4) setStaticFields() {
if r.Version == "" {
r.Version = V4
Expand Down
16 changes: 0 additions & 16 deletions lib/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,6 @@ type Cache struct {
accessCache services.Access
dynamicAccessCache services.DynamicAccessExt
presenceCache services.Presence
restrictionsCache services.Restrictions
userGroupsCache services.UserGroups
discoveryConfigsCache services.DiscoveryConfigs
headlessAuthenticationsCache services.HeadlessAuthenticationService
Expand Down Expand Up @@ -970,7 +969,6 @@ func New(config Config) (*Cache, error) {
accessCache: local.NewAccessService(config.Backend),
dynamicAccessCache: local.NewDynamicAccessService(config.Backend),
presenceCache: local.NewPresenceService(config.Backend),
restrictionsCache: local.NewRestrictionsService(config.Backend),
userGroupsCache: userGroupsCache,
discoveryConfigsCache: discoveryConfigsCache,
headlessAuthenticationsCache: identityService,
Expand Down Expand Up @@ -1733,20 +1731,6 @@ func (c *Cache) processEvent(ctx context.Context, event types.Event) error {
return nil
}

// GetNetworkRestrictions gets the network restrictions.
func (c *Cache) GetNetworkRestrictions(ctx context.Context) (types.NetworkRestrictions, error) {
ctx, span := c.Tracer.Start(ctx, "cache/GetNetworkRestrictions")
defer span.End()

rg, err := readLegacyCollectionCache(c, c.legacyCacheCollections.networkRestrictions)
if err != nil {
return nil, trace.Wrap(err)
}
defer rg.Release()

return rg.reader.GetNetworkRestrictions(ctx)
}

// ListDiscoveryConfigs returns a paginated list of all DiscoveryConfig resources.
func (c *Cache) ListDiscoveryConfigs(ctx context.Context, pageSize int, nextKey string) ([]*discoveryconfig.DiscoveryConfig, string, error) {
ctx, span := c.Tracer.Start(ctx, "cache/ListDiscoveryConfigs")
Expand Down
2 changes: 1 addition & 1 deletion lib/cache/cert_authority_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func TestNodeCAFiltering(t *testing.T) {
Access: p.cache.accessCache,
DynamicAccess: p.cache.dynamicAccessCache,
Presence: p.cache.presenceCache,
Restrictions: p.cache.restrictionsCache,
Restrictions: p.cache.Restrictions,
SAMLIdPServiceProviders: p.samlIDPServiceProviders,
UserGroups: p.userGroups,
StaticHostUsers: p.staticHostUsers,
Expand Down
9 changes: 9 additions & 0 deletions lib/cache/collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ type collections struct {
gitServers *collection[types.Server, gitServerIndex]
databaseObjects *collection[*dbobjectv1.DatabaseObject, databaseObjectIndex]
staticHostUsers *collection[*userprovisioningv2.StaticHostUser, staticHostUserIndex]
networkRestrictions *collection[types.NetworkRestrictions, networkingRestrictionIndex]
}

// setupCollections ensures that the appropriate [collection] is
Expand Down Expand Up @@ -639,6 +640,14 @@ func setupCollections(c Config) (*collections, error) {

out.staticHostUsers = collect
out.byKind[resourceKind] = out.staticHostUsers
case types.KindNetworkRestrictions:
collect, err := newNetworkingRestrictionCollection(c.Restrictions, watch)
if err != nil {
return nil, trace.Wrap(err)
}

out.networkRestrictions = collect
out.byKind[resourceKind] = out.networkRestrictions
}
}

Expand Down
47 changes: 0 additions & 47 deletions lib/cache/legacy_collections.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ type legacyCollections struct {
secReports collectionReader[services.SecurityReportGetter]
secReportsStates collectionReader[services.SecurityReportStateGetter]
discoveryConfigs collectionReader[services.DiscoveryConfigsGetter]
networkRestrictions collectionReader[networkRestrictionGetter]
provisioningStates collectionReader[provisioningStateGetter]
identityCenterPrincipalAssignments collectionReader[identityCenterPrincipalAssignmentGetter]
}
Expand All @@ -113,15 +112,6 @@ func setupLegacyCollections(c *Cache, watches []types.WatchKind) (*legacyCollect
return nil, trace.BadParameter("missing parameter DynamicAccess")
}
collections.byKind[resourceKind] = &genericCollection[types.AccessRequest, noReader, accessRequestExecutor]{cache: c, watch: watch}
case types.KindNetworkRestrictions:
if c.Restrictions == nil {
return nil, trace.BadParameter("missing parameter Restrictions")
}
collections.networkRestrictions = &genericCollection[types.NetworkRestrictions, networkRestrictionGetter, networkRestrictionsExecutor]{
cache: c,
watch: watch,
}
collections.byKind[resourceKind] = collections.networkRestrictions
case types.KindDiscoveryConfig:
if c.DiscoveryConfigs == nil {
return nil, trace.BadParameter("missing parameter DiscoveryConfigs")
Expand Down Expand Up @@ -284,43 +274,6 @@ type userGetter interface {

var _ executor[types.User, userGetter] = userExecutor{}

type networkRestrictionsExecutor struct{}

func (networkRestrictionsExecutor) getAll(ctx context.Context, cache *Cache, loadSecrets bool) ([]types.NetworkRestrictions, error) {
restrictions, err := cache.Restrictions.GetNetworkRestrictions(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
return []types.NetworkRestrictions{restrictions}, nil
}

func (networkRestrictionsExecutor) upsert(ctx context.Context, cache *Cache, resource types.NetworkRestrictions) error {
return cache.restrictionsCache.SetNetworkRestrictions(ctx, resource)
}

func (networkRestrictionsExecutor) deleteAll(ctx context.Context, cache *Cache) error {
return cache.restrictionsCache.DeleteNetworkRestrictions(ctx)
}

func (networkRestrictionsExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error {
return cache.restrictionsCache.DeleteNetworkRestrictions(ctx)
}

func (networkRestrictionsExecutor) isSingleton() bool { return true }

func (networkRestrictionsExecutor) getReader(cache *Cache, cacheOK bool) networkRestrictionGetter {
if cacheOK {
return cache.restrictionsCache
}
return cache.Config.Restrictions
}

type networkRestrictionGetter interface {
GetNetworkRestrictions(context.Context) (types.NetworkRestrictions, error)
}

var _ executor[types.NetworkRestrictions, networkRestrictionGetter] = networkRestrictionsExecutor{}

// collectionReader extends the collection interface, adding routing capabilities.
type collectionReader[R any] interface {
legacyCollection
Expand Down
78 changes: 78 additions & 0 deletions lib/cache/network_restrictions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cache

import (
"context"

"github.com/gravitational/trace"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/services"
)

type networkingRestrictionIndex string

const networkingRestrictionNameIndex networkingRestrictionIndex = "name"

func newNetworkingRestrictionCollection(upstream services.Restrictions, w types.WatchKind) (*collection[types.NetworkRestrictions, networkingRestrictionIndex], error) {
if upstream == nil {
return nil, trace.BadParameter("missing parameter Restrictions")
}

return &collection[types.NetworkRestrictions, networkingRestrictionIndex]{
store: newStore(map[networkingRestrictionIndex]func(types.NetworkRestrictions) string{
networkingRestrictionNameIndex: types.NetworkRestrictions.GetName,
}),
fetcher: func(ctx context.Context, loadSecrets bool) ([]types.NetworkRestrictions, error) {
restrictions, err := upstream.GetNetworkRestrictions(ctx)
if err != nil {
return nil, trace.Wrap(err)
}
return []types.NetworkRestrictions{restrictions}, nil
},
headerTransform: func(hdr *types.ResourceHeader) types.NetworkRestrictions {
return &types.NetworkRestrictionsV4{
Kind: hdr.Kind,
Version: hdr.Version,
Metadata: types.Metadata{
Name: hdr.Metadata.Name,
},
}
},
watch: w,
}, nil
}

// GetNetworkRestrictions gets the network restrictions.
func (c *Cache) GetNetworkRestrictions(ctx context.Context) (types.NetworkRestrictions, error) {
ctx, span := c.Tracer.Start(ctx, "cache/GetNetworkRestrictions")
defer span.End()

getter := genericGetter[types.NetworkRestrictions, networkingRestrictionIndex]{
cache: c,
collection: c.collections.networkRestrictions,
index: networkingRestrictionNameIndex,
upstreamGet: func(ctx context.Context, s string) (types.NetworkRestrictions, error) {
restriction, err := c.Config.Restrictions.GetNetworkRestrictions(ctx)
return restriction, trace.Wrap(err)
},
clone: types.NetworkRestrictions.Clone,
}
out, err := getter.get(ctx, types.MetaNameNetworkRestrictions)
return out, trace.Wrap(err)
}
52 changes: 52 additions & 0 deletions lib/cache/networking_restrictions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Teleport
// Copyright (C) 2025 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cache

import (
"context"
"testing"

"github.com/gravitational/trace"

"github.com/gravitational/teleport/api/types"
)

func TestNetworkRestrictions(t *testing.T) {
t.Parallel()

p := newTestPack(t, ForAuth)
t.Cleanup(p.Close)

testResources(t, p, testFuncs[types.NetworkRestrictions]{
newResource: func(name string) (types.NetworkRestrictions, error) {
return types.NewNetworkRestrictions(), nil
},
create: p.restrictions.SetNetworkRestrictions,
list: func(ctx context.Context) ([]types.NetworkRestrictions, error) {
restrictions, err := p.restrictions.GetNetworkRestrictions(ctx)
return []types.NetworkRestrictions{restrictions}, trace.Wrap(err)
},
cacheList: func(ctx context.Context) ([]types.NetworkRestrictions, error) {
restrictions, err := p.cache.GetNetworkRestrictions(ctx)
if trace.IsNotFound(err) {
return nil, nil
}
return []types.NetworkRestrictions{restrictions}, trace.Wrap(err)
},
deleteAll: p.restrictions.DeleteNetworkRestrictions,
})
}
7 changes: 1 addition & 6 deletions lib/services/local/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -1842,16 +1842,11 @@ func (p *networkRestrictionsParser) match(key backend.Key) bool {
func (p *networkRestrictionsParser) parse(event backend.Event) (types.Resource, error) {
switch event.Type {
case types.OpDelete:
name := event.Item.Key.TrimPrefix(backend.NewKey(restrictionsPrefix, network)).String()
if name == "" {
return nil, trace.NotFound("failed parsing %v", event.Item.Key.String())
}

return &types.ResourceHeader{
Kind: types.KindNetworkRestrictions,
Version: types.V1,
Metadata: types.Metadata{
Name: strings.TrimPrefix(name, backend.SeparatorString),
Name: types.MetaNameNetworkRestrictions,
Namespace: apidefaults.Namespace,
},
}, nil
Expand Down
Loading