Hello and, again, welcome to the Aperture Science computer-aided enrichment center.
We hope your brief detention in the relaxation vault has been a pleasant one.
Managed Service Accounts (MSA) appeared first in the Windows Server 2008 R2 and received major overhaul (gMSA) in the Windows Server 2012. Those accounts have automatically managed passwords and tied to specific computer (WS 2008 R2) or group of computers (WS 2012). They cannot be locked out, and cannot perform interactive logons, which makes them ideal for running services. Under the hood MSA are the user accounts that inherit from a parent object class of “Computer” and the only supported way to manage them is the PowerShell.
To do so, you have to use cmdlets in the Active Directory module. This is two-step process: first, you create gMSA in the AD and then “install” this account on the target computer(s).
Here is the cmdlets used for the AD part of the process:
And here is the ones used to manage gMSA on the target computers:
When life gives you lemons, don’t make lemonade. Make life take the lemons back!
Get mad! I don’t want your damn lemons, what the hell am I supposed to do with these?
Demand to see life’s manager! Make life rue the day it thought it could give Cave Johnson lemons!
— Cave Johnson
While I don’t often create gMSAs in the AD, I do need to be able to install them en-masse on a servers, preferably via remote PowerShell session. And here comes the pain.
For starters, Active Directory module is not installed by default, unless the server is a domain controller. While this is easily solved by running
Import-Module ServerManager Add-WindowsFeature RSAT-AD-PowerShell
You still have to do it for every machine you’re trying to use gMSA on. Even with automation, this is another thing to bear in mind.
But this is only minor issue, comparing to what comes next. This is what you get when you try to import Active Directory module in the remote session on a machine where you need to install gMSA:
Import-Module ActiveDirectory WARNING: Error initializing default drive: 'Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running.'.
This is the classic double hop issue, which can be fixed using several methods, some of them better than the others. Here is the most used ones:
Pass fresh credentials inside the Invoke-Command scriptblock
Pros: It works.
Cons: Makes unattended automation ungainly.
When using CredSSP, PowerShell will perform a “Network Clear-text Logon” instead of a “Network Logon”. Network Clear-text Logon works by sending the user’s clear-text password to the remote server
I definitely do not want to send plaintext passwords over network, even if the channel itself is encrypted. Because guess what? When it arrives at the destination server, it will be stored in memory in the plain sight. So if the target server is compromised, attacker can grab my domain admin credentials using Mimikatz with no effort at all. And even if you’re extra careful, and use non-privileged account for remoting, it’s still a valid AD account.
Use Resource-Based Kerberos Constrained Delegation
With Windows server 2012, Microsoft made improvements to the Kerberos delegation mechanism, which means that with some simple configuration, you can use solve double-hop issues in easy and secure manner: PowerShell Remoting Kerberos Double Hop Solved Securely.
Pros: Works, has no security issues.
Cons: Requires Windows Server 2012 and above for most servers involved.
Do you know who I am? I’m the man who’s gonna burn your house down! With the lemons!
I’m gonna get my engineers to invent a combustible lemon that burns your house down!
— Cave Johnson
All of my servers are Windows Server 2012 R2 and have resource-based Kerberos constrained delegation configured. This is what I use daily for my remoting tasks. Unfortunately I couldn’t make Active directory module work in the PSRemoting with it. No matter what I’ve tried, I still got the error message from above. So with this module, it’s CredSSP or nothing.
I’m OK with occasionally logging on the DC via RDP to create gMSAs, but repeating the same steps over and over for the every server where gMSA has to be installed? Hell no!
So the question is: do we really need the Active Directory module to install gMSAs on the target server? I did some digging and found that Active Directory module is using a set of the Win32 API functions to manage gMSA’s locally:
After that is was fairly easy to write my own implementation of the cmdlets that are used to install gMSA locally. For the sake of simplicity, I’ve decided to not create a full-blown module and instead made a self-contained function which even can be copy-pasted into the remote session. It doesn’t use the Active Directory module and works fine with resource-based Kerberos constrained delegation. You can grab it from my GitHub repo:
Here is the quick breakdown of original Active Directory gMSA cmdlets and their
'GMSA_Acount' | Use-ServiceAccount -Add
This will install Group Managed Service Account with SAM account name
GMSA_Accounton the computer on which the cmdlet is run.
'GMSA_Acount' | Use-ServiceAccount -Query
Used to query the status of the service account from the local computer. Using
-Detailedswitch you can even get MSA_INFO_STATE enumeration containing detailed information on (g)MSA state:
'GMSA_Acount' | Use-ServiceAccount -Query -Detailed
'GMSA_Acount' | Use-ServiceAccount -Remove
Removes gMSA from the local computer or standalone managed service account (sMSA) from Active Directory. If local computer is disconnected from the domain, you can remove service account object and the stored in the LSA using
'GMSA_Acount' | Use-ServiceAccount -Remove -ForceRemoveLocal
As a bonus, you can also test whether the specified standalone managed service account (sMSA) or group managed service account (gMSA) exists in the Netlogon store on the this server. This action has no Active Directory module counterpart:
'GMSA_Acount' | Use-ServiceAccount -Test
Thank you for participating in this Aperture Science computer-aided enrichment activity.
Debugging this issue and writing Use-ServiceAccount function was fun, but I’d really like to avoid this altogether. If any of you managed to get Active Directory module working with resource-based Kerberos constrained delegation — don’t hesitate to let me know! And be sure drop a comment or create an issue on the GitHub if something doesn’t work for you.