Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create WindowsDesktops for matching DynamicWindowsDesktops #46991

Merged
merged 80 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
e98d320
Add DynamicWindowsDesktop to proto
probakowski Sep 26, 2024
f61f87c
Add resource matchers to Windows desktop service config
probakowski Sep 26, 2024
9705056
Implement API and backend for DynamicWindowsDesktop
probakowski Sep 27, 2024
30d239e
Cache and watcher support for DynamicWindowsDesktop
probakowski Sep 27, 2024
afdf39e
Create WindowsDesktops for matching DynamicWindowsDesktops
probakowski Sep 27, 2024
129bfff
Fix imports
probakowski Sep 30, 2024
f4bb0da
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Sep 30, 2024
9117711
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Sep 30, 2024
99a4683
fix test
probakowski Oct 1, 2024
f28a6ed
Merge branch 'probakowski/register-resources-cache' into probakowski/…
probakowski Oct 1, 2024
30f6a78
lint
probakowski Oct 1, 2024
19c4ef2
review comments
probakowski Oct 1, 2024
263baee
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 2, 2024
5767426
move rpc to separate server
probakowski Oct 2, 2024
476f221
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 2, 2024
f99db8b
rework api and grpc more towards 153-style
probakowski Oct 7, 2024
f518ab7
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 7, 2024
3aca083
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 7, 2024
b4da04f
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 7, 2024
d54b692
e
probakowski Oct 7, 2024
34c79ce
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 7, 2024
d547d83
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 7, 2024
1b568fd
remove dynamic windows from paginated resource
probakowski Oct 7, 2024
752a822
Merge branch 'probakowski/register-resources-config' into probakowski…
probakowski Oct 7, 2024
4013534
add tests
probakowski Oct 8, 2024
c483888
add tests
probakowski Oct 8, 2024
2eba6c7
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 9, 2024
bed7d62
Update api/proto/teleport/legacy/types/types.proto
probakowski Oct 10, 2024
b3f7598
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 10, 2024
99f6282
lint
probakowski Oct 10, 2024
8fabe56
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 14, 2024
247bed9
Merge branch 'probakowski/register-resources-proto' into probakowski/…
probakowski Oct 14, 2024
bf9c121
Merge branch 'master' into probakowski/register-resources-config
probakowski Oct 14, 2024
b3ff70a
gci
probakowski Oct 14, 2024
57310c0
Merge branch 'probakowski/register-resources-config' into probakowski…
probakowski Oct 15, 2024
5dff168
cleanup
probakowski Oct 15, 2024
b57b8d0
cleanup
probakowski Oct 15, 2024
14987eb
use generic service
probakowski Oct 16, 2024
0ccf188
cleanup
probakowski Oct 16, 2024
37c409d
cleanup
probakowski Oct 16, 2024
c8a44c4
cleanup
probakowski Oct 16, 2024
8a4e4a5
Merge branch 'master' into probakowski/register-resources-api
probakowski Oct 16, 2024
b26df6d
cleanup
probakowski Oct 16, 2024
ef90d0d
cleanup
probakowski Oct 16, 2024
e594197
gci
probakowski Oct 16, 2024
52e7576
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Oct 16, 2024
970503d
rework cache
probakowski Oct 16, 2024
9511bdd
rework cache
probakowski Oct 16, 2024
aa8e25c
Merge branch 'probakowski/register-resources-cache' into probakowski/…
probakowski Oct 16, 2024
97f2b7e
add admin action checks
probakowski Oct 16, 2024
4a51c03
move service
probakowski Oct 16, 2024
5c86920
add service test
probakowski Oct 16, 2024
641dc78
Merge branch 'master' into probakowski/register-resources-api
probakowski Oct 16, 2024
7ec6842
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Oct 16, 2024
fe18d8b
gci
probakowski Oct 17, 2024
cd91373
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Oct 17, 2024
f7140e2
Merge branch 'probakowski/register-resources-cache' into probakowski/…
probakowski Oct 17, 2024
76aa31c
update discovery
probakowski Oct 17, 2024
2f0a5e4
add discovery test
probakowski Oct 17, 2024
af5dc06
review comments
probakowski Oct 17, 2024
7592f48
review comments
probakowski Oct 17, 2024
88753c6
review comments
probakowski Oct 17, 2024
84af7ce
Merge branch 'master' into probakowski/register-resources-api
probakowski Oct 17, 2024
2be0499
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Oct 17, 2024
b904a83
update interfaces
probakowski Oct 17, 2024
982e1dc
Merge branch 'probakowski/register-resources-cache' into probakowski/…
probakowski Oct 17, 2024
4e62b8f
gci
probakowski Oct 17, 2024
ca49642
gci
probakowski Oct 17, 2024
61db837
review comments
probakowski Oct 21, 2024
e3527b1
review comments
probakowski Oct 21, 2024
8a32003
Merge branch 'master' into probakowski/register-resources-api
probakowski Oct 22, 2024
c990cf5
Merge branch 'master' into probakowski/register-resources-api
probakowski Oct 22, 2024
873e6c4
Merge branch 'probakowski/register-resources-api' into probakowski/re…
probakowski Oct 22, 2024
fc53d29
Merge remote-tracking branch 'origin/master' into probakowski/registe…
probakowski Oct 22, 2024
0dd0ac2
fix loggers
probakowski Oct 22, 2024
f1c86fb
Merge branch 'probakowski/register-resources-cache' into probakowski/…
probakowski Oct 22, 2024
21b2853
Merge branch 'master' into probakowski/register-resources-discovery
probakowski Oct 22, 2024
f26a120
Merge branch 'master' into probakowski/register-resources-discovery
probakowski Oct 23, 2024
26e4856
Merge branch 'master' into probakowski/register-resources-discovery
probakowski Oct 23, 2024
b690d44
fix tctl
probakowski Oct 23, 2024
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
2 changes: 1 addition & 1 deletion api/client/dynamicwindows/dynamicwindows.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (c *Client) GetDynamicWindowsDesktop(ctx context.Context, name string) (typ
return desktop, trace.Wrap(err)
}

func (c *Client) ListDynamicWindowsDesktop(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error) {
func (c *Client) ListDynamicWindowsDesktops(ctx context.Context, pageSize int, pageToken string) ([]types.DynamicWindowsDesktop, string, error) {
resp, err := c.grpcClient.ListDynamicWindowsDesktops(ctx, &dynamicwindows.ListDynamicWindowsDesktopsRequest{
PageSize: int32(pageSize),
PageToken: pageToken,
Expand Down
3 changes: 3 additions & 0 deletions lib/auth/authclient/clt.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/crownjewel"
"github.com/gravitational/teleport/api/client/databaseobject"
"github.com/gravitational/teleport/api/client/dynamicwindows"
"github.com/gravitational/teleport/api/client/externalauditstorage"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/client/secreport"
Expand Down Expand Up @@ -1600,6 +1601,8 @@ type ClientI interface {
types.WebSessionsGetter
types.WebTokensGetter

DynamicDesktopClient() *dynamicwindows.Client

// TrustClient returns a client to the Trust service.
TrustClient() trustpb.TrustServiceClient

Expand Down
90 changes: 90 additions & 0 deletions lib/srv/desktop/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"errors"
"fmt"
"log/slog"
"maps"
"net"
"net/netip"
"strings"
Expand All @@ -32,6 +33,7 @@ import (
"github.com/go-ldap/ldap/v3"
"github.com/gravitational/trace"

"github.com/gravitational/teleport"
apidefaults "github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/windows"
Expand Down Expand Up @@ -306,3 +308,91 @@ func (s *WindowsService) ldapEntryToWindowsDesktop(ctx context.Context, entry *l
desktop.SetExpiry(s.cfg.Clock.Now().UTC().Add(apidefaults.ServerAnnounceTTL * 3))
return desktop, nil
}

// startDynamicReconciler starts resource watcher and reconciler that registers/unregisters Windows desktops
// according to the up-to-date list of dynamic Windows desktops resources.
func (s *WindowsService) startDynamicReconciler(ctx context.Context) (*services.DynamicWindowsDesktopWatcher, error) {
if len(s.cfg.ResourceMatchers) == 0 {
s.cfg.Logger.DebugContext(ctx, "Not starting dynamic desktop resource watcher.")
return nil, nil
}
s.cfg.Logger.DebugContext(ctx, "Starting dynamic desktop resource watcher.")
dynamicDesktopClient := s.cfg.AuthClient.DynamicDesktopClient()
watcher, err := services.NewDynamicWindowsDesktopWatcher(ctx, services.DynamicWindowsDesktopWatcherConfig{
DynamicWindowsDesktopGetter: dynamicDesktopClient,
ResourceWatcherConfig: services.ResourceWatcherConfig{
Component: teleport.ComponentWindowsDesktop,
Client: s.cfg.AccessPoint,
},
})
if err != nil {
return nil, trace.Wrap(err)
}

currentResources := make(map[string]types.WindowsDesktop)
var newResources map[string]types.WindowsDesktop

reconciler, err := services.NewReconciler(services.ReconcilerConfig[types.WindowsDesktop]{
Matcher: func(desktop types.WindowsDesktop) bool {
return services.MatchResourceLabels(s.cfg.ResourceMatchers, desktop.GetAllLabels())
},
GetCurrentResources: func() map[string]types.WindowsDesktop {
return currentResources
},
GetNewResources: func() map[string]types.WindowsDesktop {
return newResources
},
OnCreate: s.upsertDesktop,
OnUpdate: s.updateDesktop,
OnDelete: s.deleteDesktop,
})
if err != nil {
return nil, trace.Wrap(err)
}
go func() {
defer s.cfg.Logger.DebugContext(ctx, "DynamicWindowsDesktop resource watcher done.")
defer watcher.Close()
for {
select {
case desktops := <-watcher.DynamicWindowsDesktopsC:
newResources = make(map[string]types.WindowsDesktop)
for _, dynamicDesktop := range desktops {
desktop, err := s.toWindowsDesktop(dynamicDesktop)
if err != nil {
s.cfg.Logger.WarnContext(ctx, "Can't create desktop resource", "error", err)
continue
}
newResources[dynamicDesktop.GetName()] = desktop
}
if err := reconciler.Reconcile(ctx); err != nil {
s.cfg.Logger.WarnContext(ctx, "Reconciliation failed, will retry", "error", err)
continue
}
currentResources = newResources
case <-watcher.Done():
return
case <-ctx.Done():
return
}
}
}()
return watcher, nil
}

func (s *WindowsService) toWindowsDesktop(dynamicDesktop types.DynamicWindowsDesktop) (*types.WindowsDesktopV3, error) {
width, height := dynamicDesktop.GetScreenSize()
desktopLabels := dynamicDesktop.GetAllLabels()
labels := make(map[string]string, len(desktopLabels)+1)
maps.Copy(labels, desktopLabels)
labels[types.OriginLabel] = types.OriginDynamic
return types.NewWindowsDesktopV3(dynamicDesktop.GetName(), labels, types.WindowsDesktopSpecV3{
Addr: dynamicDesktop.GetAddr(),
Domain: dynamicDesktop.GetDomain(),
HostID: s.cfg.Heartbeat.HostUUID,
NonAD: dynamicDesktop.NonAD(),
ScreenSize: &types.Resolution{
Width: width,
Height: height,
},
})
}
133 changes: 133 additions & 0 deletions lib/srv/desktop/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import (
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/auth/windows"
"github.com/gravitational/teleport/lib/services"
logutils "github.com/gravitational/teleport/lib/utils/log"
)

Expand Down Expand Up @@ -169,3 +171,134 @@ func TestDNSErrors(t *testing.T) {
require.Less(t, time.Since(start), dnsQueryTimeout-1*time.Second)
require.Error(t, err)
}

func TestDynamicWindowsDiscovery(t *testing.T) {
t.Parallel()
authServer, err := auth.NewTestAuthServer(auth.TestAuthServerConfig{
ClusterName: "test",
Dir: t.TempDir(),
})
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, authServer.Close())
})

tlsServer, err := authServer.NewTestTLSServer()
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, tlsServer.Close())
})

client, err := tlsServer.NewClient(auth.TestServerID(types.RoleWindowsDesktop, "test-host-id"))
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, client.Close())
})

dynamicWindowsClient := client.DynamicDesktopClient()

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

for _, testCase := range []struct {
name string
labels map[string]string
expected int
}{
{
name: "no labels",
expected: 0,
},
{
name: "no matching labels",
labels: map[string]string{"xyz": "abc"},
expected: 0,
},
{
name: "matching labels",
labels: map[string]string{"foo": "bar"},
expected: 1,
},
{
name: "matching wildcard labels",
labels: map[string]string{"abc": "abc"},
expected: 1,
},
} {
t.Run(testCase.name, func(t *testing.T) {
s := &WindowsService{
cfg: WindowsServiceConfig{
Heartbeat: HeartbeatConfig{
HostUUID: "1234",
},
Logger: slog.New(logutils.NewSlogTextHandler(io.Discard, logutils.SlogTextHandlerConfig{})),
Clock: clockwork.NewFakeClock(),
AuthClient: client,
AccessPoint: client,
ResourceMatchers: []services.ResourceMatcher{{
Labels: types.Labels{
"foo": {"bar"},
},
}, {
Labels: types.Labels{
"abc": {"*"},
},
}},
},
dnsResolver: &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return nil, errors.New("this resolver always fails")
},
},
}
reconciler, err := s.startDynamicReconciler(ctx)
require.NoError(t, err)
t.Cleanup(func() {
reconciler.Close()
require.NoError(t, authServer.AuthServer.DeleteAllWindowsDesktops(ctx))
require.NoError(t, authServer.AuthServer.DeleteAllDynamicWindowsDesktops(ctx))
})

desktop, err := types.NewDynamicWindowsDesktopV1("test", testCase.labels, types.DynamicWindowsDesktopSpecV1{
Addr: "addr",
})
require.NoError(t, err)

_, err = dynamicWindowsClient.CreateDynamicWindowsDesktop(ctx, desktop)
require.NoError(t, err)

time.Sleep(10 * time.Millisecond)

desktops, err := client.GetWindowsDesktops(ctx, types.WindowsDesktopFilter{})
require.NoError(t, err)
require.Len(t, desktops, testCase.expected)
if testCase.expected > 0 {
require.Equal(t, desktop.GetName(), desktops[0].GetName())
require.Equal(t, desktop.GetAddr(), desktops[0].GetAddr())
}

desktop.Spec.Addr = "addr2"
_, err = dynamicWindowsClient.UpdateDynamicWindowsDesktop(ctx, desktop)
require.NoError(t, err)

time.Sleep(10 * time.Millisecond)
desktops, err = client.GetWindowsDesktops(ctx, types.WindowsDesktopFilter{})
require.NoError(t, err)
require.Len(t, desktops, testCase.expected)
if testCase.expected > 0 {
require.Equal(t, desktop.GetName(), desktops[0].GetName())
require.Equal(t, desktop.GetAddr(), desktops[0].GetAddr())
}

require.NoError(t, dynamicWindowsClient.DeleteDynamicWindowsDesktop(ctx, "test"))

time.Sleep(10 * time.Millisecond)

desktops, err = client.GetWindowsDesktops(ctx, types.WindowsDesktopFilter{})
require.NoError(t, err)
require.Empty(t, desktops)
})

}
}
4 changes: 4 additions & 0 deletions lib/srv/desktop/windows_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ func NewWindowsService(cfg WindowsServiceConfig) (*WindowsService, error) {
return nil, trace.Wrap(err)
}

if _, err := s.startDynamicReconciler(ctx); err != nil {
return nil, trace.Wrap(err)
}

if len(s.cfg.DiscoveryBaseDN) > 0 {
if err := s.startDesktopDiscovery(); err != nil {
return nil, trace.Wrap(err)
Expand Down
2 changes: 1 addition & 1 deletion tool/tctl/common/resource_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -2522,7 +2522,7 @@ func (rc *ResourceCommand) getCollection(ctx context.Context, client *authclient
pageToken := ""
desktops := make([]types.DynamicWindowsDesktop, 0, 100)
for {
d, next, err := dynamicDesktopClient.ListDynamicWindowsDesktop(ctx, 100, pageToken)
d, next, err := dynamicDesktopClient.ListDynamicWindowsDesktops(ctx, 100, pageToken)
if err != nil {
return nil, trace.Wrap(err)
}
Expand Down
Loading