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:
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 forSERVICE_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
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:This continues to occur event with alternative attempts, such as with the
~
used as a password placeholder in PsExec.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:
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 constantSERVICE_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:
SERVICE_ACCOUNT_PASSWORD
, and a logon type ofLOGON32_LOGON_SERVICE
when authenticating. I think this is most preferred, although it would only work when Puppet is run as SYSTEM.LOGON32_LOGON_SERVICE
when authenticating. Isnt user friendly since the user needs to provide theSERVICE_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.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