How Managed Service Accounts in Active Directory Work
Have you ever heard of these things called Managed Service Accounts? They allow you to run programs as an account that doesn't require a password while still having the security of a strong password. They're pretty neat. pic.twitter.com/p7nfDnyUqp
— Steve Syfuhs (@SteveSyfuhs) February 4, 2021
Twitter warning: Like all good things this is mostly correct, with a few details fuzzier than others for reasons: a) details are hard on twitter; b) details are fudged for greater clarity; c) maybe I'm just dumb.
To be more precise, it's not that they don't have passwords, it's that they don't require you the administrator to know the password. The password is managed by Active Directory for you. That means not worrying about weak passwords or having to manually rotate them. Neat, right?
These are also just regular accounts in AD. They're special in that they're managed, but under the covers they're computer accounts, which inherit from user accounts. They walk and talk like principals in AD, so they have usernames, credentials, and service principal names.
This therefore means they can log in to Active Directory through Kerberos and NTLM. That makes them perfect for hosting services and tasks that require authenticating users or operating in authenticated sessions.
Which is great, but how do they work? How does Windows know how to use them and how can this be done securely since no one knows the password?
Well, it turns out it's partly super simple, and partly super complicated. The super simple part is that when you create a managed account you specify what other accounts are allowed to see the password.
The things in PrincipalsAllowedToRetrieveManagedPassword can be computers, users, or groups. These things are put into an ACL on an AD LDAP attribute of the (g)MSA that say if you present a SID in this list you can query this attribute.
Add-KdsRootKey -EffectiveTime ((get-date).addhours(-10))
New-ADServiceAccount gmsa1 -DNSHostName gmsa1.corp.identityintervention.com `
-PrincipalsAllowedToRetrieveManagedPassword djpp$ `
-KerberosEncryptionType RC4, AES128, AES256
$gmsa = Get-ADServiceAccount -Identity 'gmsa1'-Properties 'msDS-ManagedPassword'
($gmsa.'msDS-ManagedPassword'|ForEach-Object ToString X2) -join ' '
So when something needs to log in as that user it can query the LDAP attribute and get the password. Easy! ...ish. Well, not so easy. The value in this attribute is...complicated.
"But Steve" you say "the whole point of a managed service account is that you don't need to know the password. How does Windows know to get this password?"
That's a great question, wish I thought of it myself. The answer is actually a little silly.
Windows doesn't actually know it's dealing with a managed account. The administrator configured [whatever thing] to log on as an account, and left the password blank.
There's no rule that says ALL USERS MUST HAVE A PASSWORD. Windows allows users to not have passwords. Active Directory even lets you not have passwords (PSA: FOR THE LOVE OF ALL THINGS HOLY DON'T ALLOW THIS PLEASE).
So back to the question: how? Well, it turns out Windows just accepts that this might be a (g)MSA so during a logon call it opens a connection to AD and asks for the the password in the msDS-ManagedPassword attribute.
PS C:\Windows\system32> $gmsa = Get-ADServiceAccount -Identity 'gmsa1'-Properties 'msDS-ManagedPassword'
PS C:\Windows\system32> ($gmsa.'msDS-ManagedPassword'|ForEach-Object ToString X2) -join ' '
01 00 00 00 22 01 00 00 10 00 00 00 12 01 1A 01 34 47 EB 28 EE C4 F4 2E 0D E9 83 3E F3 5C 05 58 EA E5 3E 7D C7 BB 3F F1 28 AA 49 84 51 46 DF 8A CF 33 34 83 10 7A 94 BC FB A2 11 27 8E 31 B7 70 C1 D7 7D CA 8D 33 6F 7D 07 33 7E 69 64 05 24 8F 57 2B A5 AA 74 4E 86 03 30 E1 A7 19 69 1B 76 F7 63 60 43 DA 7C 8D 56 46 99 8A F1 1F A7 F1 ED 2B E9 8B 8F 51 FD 17 16 42 19 5C 10 DA D8 53 4B D1 76 9E 88 0F 1F C4 8F 54 E8 DE 8F E0 A5 F0 82 13 CA 89 33 D9 0A 5E 19 6E FA BE CD 50 33 82 A1 CE 9E FF 09 92 06 96 75 7E A5 B2 E6 FB 8B 7A 9A 75 61 DC 06 C4 80 49 33 9C CA B7 C5 A9 BF 36 72 FF A6 7F 31 C8 E4 74 3D C6 B6 2A BE 8A DD A7 41 42 DB 9E EE C1 BB 0A 9F 0F A0 F3 C2 6A 0E B8 FD 23 A7 7D C5 10 F6 4E 59 B4 CE 35 49 47 17 C0 C9 FD 6F E2 F1 77 DF 0A E6 93 1D 84 F3 3F 45 6A AB 42 54 49 3B DD 9F 9B E8 0D 4E CC 57 80 3E 56 BE C4 00 00 EB 66 BA 80 28 14 00 00 EB 08 EA CD 27 14 00 00
Now you're looking at this kinda funny thinking waaaaaait a minute how does this bullsh*t work? Well remember, computers have machine accounts in AD. The computer logs in to AD, gets a Kerberos ticket to the DC asking for this attribute and does an ACL check.
Does principal djpp$ have a SID in their PAC that matches the ACL on the attribute? Yes? Here you go. It's plain old SSO. How Windows Single Sign-On Works (syfuhs.net)
So now the computer has the password (and a bunch of metadata from that attribute? Odd... 🤔). Windows takes that password and the username and...logs it on. Whoa. What Happens When you Type Your Password into Windows? (syfuhs.net)
P.S. another shameless plug: I did a video on how this works too. OPS108: Windows authentication internals in a hybrid world (syfuhs.net)
At this point the account has logged on and has all the usual accoutrement of a logon session. Nothing special. Any application running as that user has the usual SSO. Incoming requests can be authenticated using Kerberos (assuming someone registered an SPN on the attribute).
This is all well and good until the password expires. Wait what? Expires? Who expires it? When? What? Huh?
So the funny thing about managed account passwords is that they aren't real. They aren't
pwd = unicode(rand(254))
as many people might expect. They're derived secrets from a special root key.
In Active Directory you have this thing called a Root Key. It's the base (root) of all derived secrets in a forest. You take this root, append a bunch of localized metadata, and out pops a derived key.
This is incidentally how we can do things like group encryption with PFX files. Take the root key and append the group SID. Stand up a service in AD that accepts tickets, and if the requisite SID is in the PAC it'll provide the metadata to generate the same key and decrypt. Ish.
That isn't exactly how that works. How it actually works is complicated and makes anyone that isn't a cryptographer cry.
But back to managed accounts. The passwords are derived secrets computed from the root key and metadata. That metadata is basically accountKeyId + createdTime + interval. The interval and start time are critical. This allows the password to rotate regularly. Here's how it works.
Your root is "abc" with an interval of 30 days.
"abc" at 12:42 Feb 4 2021 = "aaa"
"abc" at 12:42 Mar 6 2021 = "bbb"
"abc" at 12:42 Apr 5 2021 = "ccc"
Following? This means at any given time AD knows what the password should be, will be, and was. Since the metadata is included in the blob, Windows also knows the interval. It doesn't have the root key so it can't derive it, but it can refresh it on that interval.
"But Steve" you say again "isn't that a bit overkill? It's just a password."
It is. But stuff breaks when the password is wrong.
There are some constants in life. One of them is that Active Directory is a multi-master replicated database, and that means life finds a way when replication fails.
So if we took out this derived key business, we could maybe make the PDC act as the password changer. It runs a scheduled task that goes through every managed account and rotates it regularly. Sure. Works well enough. Except then the PDC needs to replicate that out to everyone.
Another fact of life is that customers have thooooousands of DCs in their environments. Some are on cargo ships in the middle of the ocean and only check in every few hours. Some are in submarines that check in weekly.
If the PDC has to push out passwords and these DCs can't communicate, then these DCs are using an expired password. Breaks policy. Bad.
So option two is just give each DC the control to change the password. That's all great until you have two DCs that aren't talking to each other change the password. Eventually they'll sync up and latest wins, but until then you've got mismatched passwords and, well, screw that.
So when you add this all up you get a requirement that everyone must know the real password at all times.
Of course I left out one big huge thing about managed accounts! There's two kinds! Managed Service Accounts (MSA) and Group Managed Service Accounts (gMSA). What's the diff?
Originally MSAs were designed to be installed only on one computer at a time. What you'd do is register the MSA. This stamped the AD object such that only that one computer could get the password. If you tried it from another it would fail even if it had permission.
In theory this was great because you could very easily lock down who could see the password, and rotate it whenever the MSA was deployed to another machine. Until you decided to deploy a cluster. Oops.
A service gets deployed to 2 machines with a load balancer splitting traffic between them. The service requires Kerberos, so an SPN is registered on... the computer? No, there's two of them. Okay spin up a service account. Ooooh, managed don't need to know the password, great.
So you spin up an MSA and install it on box one and register the SPN and then go to install it on box two and... womp womp. Can't. Okay, spin up a SECOND account and add...the...SPN.........dammit! And now we're back to regular accounts and passwords.
So here we have *Group* Managed Service Accounts. The difference with gMSAs (I have no idea why we lowercase the G) is that they don't get installed on machines. You grant the machine(s) the right to read the password, and that's it.
Why don't you install it? Because installing it was intended to lock the MSA to the machine. Since it's group-based there's just no need to lock it.
These days you can use managed accounts for all sorts of things: running services, scheduled tasks, IIS app pools, etc. You generally have to be running as SYSTEM since you're granting rights to the computer account, but they're easy once you get the hang of them.
You can even try it out with PsExec:
psexec.exe -i -u corp\gmsa1$ -p ~ cmd.exe
So what are you waiting for? Go forth and deploy gMSAs.