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

Windows Service Provider Doesn't Support gMSAs #9328

Open
holysoles opened this issue Apr 22, 2024 · 2 comments
Open

Windows Service Provider Doesn't Support gMSAs #9328

holysoles opened this issue Apr 22, 2024 · 2 comments
Labels
enhancement New feature or request triaged Jira issue has been created for this

Comments

@holysoles
Copy link

holysoles commented Apr 22, 2024

Use Case

gMSAs are domain accounts used to run services, and are a more secure alternative than traditional managed service accounts for running services or other automation.

When attempting to provide a gMSA as the logonaccount for a service resource, an error is encountered:

> puppet resource service someservice logonaccount='DOMAIN\msvc_automation$'
Error: The given password is invalid for user 'DOMAIN\msvc_automation$'.
Error: /Service[someservice]/logonaccount: change from 'DOMAIN\svc_user' to 'DOMAIN\msvc_automation$' failed" The given password is invalid for user 'DOMAIN\msvc_automation$'.

This continues to occur event with alternative attempts, such as with the ~ used as a password placeholder in PsExec.

> puppet resource service someservice logonaccount='DOMAIN\msvc_automation$' logonpassword=undef
> puppet resource service someservice logonaccount='DOMAIN\msvc_automation$' logonpassword='~'

Describe the Solution You Would Like

Support configuring services as gMSAs with the oob service resource on Windows.

Describe Alternatives You've Considered

Alternatives include using an exec resource that reconfigures the service to run as a gMSA:

exec { "Configure someservice logon account":
  command  => "${facts['os']['windows']['system32']}\\sc.exe config someservice obj= 'DOMAIN\\msvc_automation$'",
  unless   => "${facts['os']['windows']['system32']}\\sc.exe qc someservice | ${facts['os']['windows']['system32']}\\findstr.exe -li 'DOMAIN\\msvc_automation$'",
  provider => powershell,
}

Additional Context

In the windows service provider, there is a check done to validate the logon credentials here

That eventually takes us here where we call the Windows API to get an impersonation token. The logon type LOGON32_LOGON_NETWORK is attempted, and if that fails, LOGON32_LOGON_INTERACTIVE is used.

gMSA cleartext password retrieval is fairly complex, but can be done with assistance from the PS Module DSInternals in the ConvertFrom-ADManagedPasswordBlob function , and the general process is described in this blog post. Forcing a Puppet user to provide this value is not user friendly though.

Alternatively, if user context is SYSTEM (or another account with the "Act as part of the operating system" privledge) during the LogonUserW call, and if the logontype is specified as LOGON32_LOGON_SERVICE, the cleartext password can be provided as _SA_{262E99C9-6160-4871-ACEC-4E61736B6F21}, which is defined in lmaccess.h as the constant SERVICE_ACCOUNT_PASSWORD . This is detailed in this MS discussion and the constant is noted in this Rust winapi wrapper (among other places like the windows sdk).

I see a few possible solutions when credentials are being validated, or the password is being set for the resource:

  • detect if the provided account is a gMSA, then specify the value for SERVICE_ACCOUNT_PASSWORD, and a logon type of LOGON32_LOGON_SERVICE when authenticating. I think this is most preferred, although it would only work when Puppet is run as SYSTEM.
  • as a third fallback when trying to get an impersonation token, use a logon type of LOGON32_LOGON_SERVICE when authenticating. Isnt user friendly since the user needs to provide the SERVICE_ACCOUNT_PASSWORD value, but would at least allow Puppet, in some contexts (needs to be running as SYSTEM), to set a gMSA as a service logon.
  • detect if the provided account is a gMSA, retrieve the gMSA password from AD in cleartext, then pass it to the relevant function. I havent tested this but i suspect it would work, albeit is likely complex.
  • Further investigate whats available in the Windows API, there may be solutions I'm overlooking

for the scheduled_task resource here, testing if a user is a gMSA is done simply by checking if the last character is $ which seems reasonable. However it seems like proper testing is doable via NetIsServiceAccount

@holysoles holysoles added the enhancement New feature or request label Apr 22, 2024
@cthorn42 cthorn42 added the triaged Jira issue has been created for this label Apr 23, 2024
Copy link

Migrated issue to PUP-12036

@cthorn42
Copy link
Collaborator

@holysoles thanks for the great and in depth issue. This will be looked into.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request triaged Jira issue has been created for this
Projects
None yet
Development

No branches or pull requests

2 participants