-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Windows user creation #24780
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
Windows user creation #24780
Changes from all commits
2273cff
6594888
840ade2
89d89a8
41c7243
229f2a6
3df2874
27cb87f
89056a6
76eb7b9
299ac3a
7c5f950
235c6e2
cd07741
b351b24
7166f28
07e0e11
1ee9f5a
4d1cf76
1b802f8
225204a
71a3551
15bfcf2
e76f95c
e486435
bf8c640
fb353bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -455,7 +455,12 @@ func (s *WindowsService) tlsConfigForLDAP() (*tls.Config, error) { | |
| using to sign in. This is set to become a strict requirement by May 2023, | ||
| please update your configuration file before then.`) | ||
| } | ||
| certDER, keyDER, err := s.generateCredentials(s.closeCtx, user, s.cfg.Domain, windowsDesktopServiceCertTTL, s.cfg.SID) | ||
| certDER, keyDER, err := s.generateCredentials(s.closeCtx, generateCredentialsRequest{ | ||
| username: user, | ||
| domain: s.cfg.Domain, | ||
| ttl: windowsDesktopServiceCertTTL, | ||
| activeDirectorySID: s.cfg.SID, | ||
| }) | ||
| if err != nil { | ||
| return nil, trace.Wrap(err) | ||
| } | ||
|
|
@@ -857,10 +862,16 @@ func (s *WindowsService) connectRDP(ctx context.Context, log logrus.FieldLogger, | |
| tdpConn.OnRecv = s.makeTDPReceiveHandler(ctx, sw, delay, &identity, string(sessionID), desktop.GetAddr(), tdpConn) | ||
|
|
||
| sessionStartTime := s.cfg.Clock.Now().UTC().Round(time.Millisecond) | ||
| groups, err := authCtx.Checker.DesktopGroups(desktop) | ||
| if err != nil && !trace.IsAccessDenied(err) { | ||
| s.onSessionStart(ctx, sw, &identity, sessionStartTime, windowsUser, string(sessionID), desktop, err) | ||
| return trace.Wrap(err) | ||
| } | ||
| createUsers := err == nil | ||
| rdpc, err := rdpclient.New(rdpclient.Config{ | ||
| Log: log, | ||
| GenerateUserCert: func(ctx context.Context, username string, ttl time.Duration) (certDER, keyDER []byte, err error) { | ||
| return s.generateUserCert(ctx, username, ttl, desktop) | ||
| return s.generateUserCert(ctx, username, ttl, desktop, createUsers, groups) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could be mistaken, but my understanding is that a role that allows for creating users looks like kind: "role"
version: "v5"
metadata:
name: "example"
spec:
options:
create_desktop_user: true
allow:
desktop_groups: [ "reader", "writer", "{{external.desktop_groups}}" ]
windows_desktop_logins: ['DBAdmin']
windows_desktop_labels:
'env': ['staging', 'test']and that such a role would only allow a user to create the kind: "role"
version: "v5"
metadata:
name: "another-example"
spec:
options:
create_desktop_user: true
allow:
desktop_groups: [ "reader" ]
windows_desktop_logins: ['SystemAdmin']
windows_desktop_labels:
'env': ['staging', 'test']In that case, the user's intention would be to only allow
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is how it would work, this behavior matches what we have in server access, login is not considered there when gathering groups, only node labels,
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha. I see that as an error prone API design and think we should reconsider making it "role-bound", but beyond the scope here. |
||
| }, | ||
| CertTTL: windows.CertTTL, | ||
| Addr: desktop.GetAddr(), | ||
|
|
@@ -1097,7 +1108,7 @@ func timer() func() int64 { | |
|
|
||
| // generateUserCert generates a keypair for the given Windows username, | ||
| // optionally querying LDAP for the user's Security Identifier. | ||
| func (s *WindowsService) generateUserCert(ctx context.Context, username string, ttl time.Duration, desktop types.WindowsDesktop) (certDER, keyDER []byte, err error) { | ||
| func (s *WindowsService) generateUserCert(ctx context.Context, username string, ttl time.Duration, desktop types.WindowsDesktop, createUsers bool, groups []string) (certDER, keyDER []byte, err error) { | ||
| var activeDirectorySID string | ||
| if !desktop.NonAD() { | ||
| // Find the user's SID | ||
|
|
@@ -1130,24 +1141,51 @@ func (s *WindowsService) generateUserCert(ctx context.Context, username string, | |
| } | ||
| s.cfg.Log.Debugf("Found objectSid %v for Windows username %v", activeDirectorySID, username) | ||
| } | ||
| return s.generateCredentials(ctx, username, desktop.GetDomain(), ttl, activeDirectorySID) | ||
| return s.generateCredentials(ctx, generateCredentialsRequest{ | ||
| username: username, | ||
| domain: desktop.GetDomain(), | ||
| ttl: ttl, | ||
| activeDirectorySID: activeDirectorySID, | ||
| createUser: createUsers, | ||
| groups: groups, | ||
| }) | ||
| } | ||
|
|
||
| // generateCredentialsRequest are the request parameters for generating a windows cert/key pair | ||
| type generateCredentialsRequest struct { | ||
| // username is the Windows username | ||
| username string | ||
| // domain is the Windows domain | ||
| domain string | ||
| // ttl for the certificate | ||
| ttl time.Duration | ||
| // activeDirectorySID is the SID of the Windows user | ||
| // specified by Username. If specified (!= ""), it is | ||
| // encoded in the certificate per https://go.microsoft.com/fwlink/?linkid=2189925. | ||
| activeDirectorySID string | ||
| // createUser specifies if Windows user should be created if missing | ||
| createUser bool | ||
| // groups are groups that user should be member of | ||
| groups []string | ||
| } | ||
|
|
||
| // generateCredentials generates a private key / certificate pair for the given | ||
| // Windows username. The certificate has certain special fields different from | ||
| // the regular Teleport user certificate, to meet the requirements of Active | ||
| // Directory. See: | ||
| // https://docs.microsoft.com/en-us/windows/security/identity-protection/smart-cards/smart-card-certificate-requirements-and-enumeration | ||
| func (s *WindowsService) generateCredentials(ctx context.Context, username, domain string, ttl time.Duration, activeDirectorySID string) (certDER, keyDER []byte, err error) { | ||
| func (s *WindowsService) generateCredentials(ctx context.Context, request generateCredentialsRequest) (certDER, keyDER []byte, err error) { | ||
| return windows.GenerateWindowsDesktopCredentials(ctx, &windows.GenerateCredentialsRequest{ | ||
| CAType: types.UserCA, | ||
| Username: username, | ||
| Domain: domain, | ||
| TTL: ttl, | ||
| Username: request.username, | ||
| Domain: request.domain, | ||
| TTL: request.ttl, | ||
| ClusterName: s.clusterName, | ||
| ActiveDirectorySID: activeDirectorySID, | ||
| ActiveDirectorySID: request.activeDirectorySID, | ||
| LDAPConfig: s.cfg.LDAPConfig, | ||
| AuthClient: s.cfg.AuthClient, | ||
| CreateUser: request.createUser, | ||
| Groups: request.groups, | ||
| }) | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.