Skip to main content
This is not an official U.S. federal government website. The Federal Modernization Workbook is independent technical analysis. It does not represent the position of, and has not been reviewed or endorsed by, any federal agency.

Training module · Draft

Module 8: Convert Kerberos accounts to gMSAs and dMSAs

Gate G5 and workbook Chapter 06: give every Kerberos account a reviewed disposition, plan its move to a gMSA or a Windows Server 2025 dMSA, list what stays on the Kerberos island with an SPN owner and an end date, reconcile every gMSA and dMSA with the end state, and run the plan only by its approved hash. About 60 minutes, with a lab on fixtures and a test domain lab.

Status — Draft

This page is still being written. Expect gaps and changes; it is not part of the workbook's production guidance. Last reviewed 2026-11-09.

Part of the Non-Person Identity learning path. Gate G5 Conversion. Workbook Chapter 06. About 60 minutes.

Watch: the narrated deck for this module: Deck · ▶ Watch (about 16 minutes, captions) · MP4 · Script · Captions.

Also: the chapter’s narrated tour, about 11 minutes: ▶ Watch.

Introduction (3 minutes)

Some workloads can’t leave Kerberos yet. A traditional service account with an SPN and a password that never expires is the riskiest of them. A gMSA gives the same workload a password that Windows changes for it. A dMSA, on a Windows Server 2025 domain, supersedes the old account and disables its password.

But a gMSA works only while Active Directory is authoritative. So converting isn’t the end. Every gMSA and dMSA must either move to a workload identity, retire, or sit on a dated Kerberos island list with an end date and, where it has SPNs, an SPN owner. In this module you plan all three, and you see the write path refuse a plan nobody approved.

The federal requirement. The Kerberos accounts are the on-premises part of Gate G5. The guide’s Validate (G5 Conversion) step names IA-5, IA-9 and AU-2. The workbook chapter’s Federal requirements and evidence table has a row for every lab step.

Requirement KSI Evidence
IA-5 Authenticator Management; CM-3 Configuration Change Control KSI-IAM-SNU; KSI-CMT-LMC kerberos-plan.json, with the register’s and each input’s SHA-256
AC-2 Account Management; IA-5 KSI-IAM-SNU findings.json, NPI-KRB-01 to -07 and -09
AC-6 Least Privilege; CM-5 Access Restrictions for Change KSI-IAM-ELP, KSI-IAM-JIT (AC-6); KSI-CMT-RVP (CM-5) Get-NpiKrbRequiredRight for the read and write tasks; password-retrievers.json
CM-8 System Component Inventory; AC-2 KSI-PIY-GIV; KSI-IAM-SNU island-list.csv; reconciliation.json
CM-3; AC-2(3) Disable Accounts KSI-CMT-LMC; KSI-IAM-AAM results.json and manifest.json in the apply folder

KSIs are FedRAMP 20x indicators for cloud service providers. The agency lines this evidence up with what its providers report against them; it doesn’t report KSIs itself. Which file supports which indicator is the program’s mapping (design guidance). The guide’s Evidence section explains both.

Learning objectives (1 minute)

After this module, you’ll be able to:

  • name the four dispositions a Kerberos account can have, and what each one needs;
  • explain why a dMSA can’t be used for an MSA or an account with unconstrained delegation;
  • read the plan, the island list and the reconciliation for a fictional domain;
  • show that the write path runs only a plan whose SHA-256 was approved, and never deletes.

Prerequisites (1 minute)

  • Module 1: the lab reads Chapter 01’s register.
  • Module 3: the matrix sends Kerberos-only accounts to a gMSA or a dMSA.

Unit 1: The gate and the end date (8 minutes)

Read the guide’s Step 5: build the target, give it two owners, run old and new in parallel for 30 days, then disable, never delete. Then read:

Unit 2: The plan and the island (12 minutes)

Read the workbook chapter in this order:

Exercise: Lab 1, fixtures, no tenant (25 minutes)

This is the workbook’s Chapter 06, Lab 1, which explains each result. Its step 1 here makes the three runs Chapter 06 reads (Chapter 01’s register, Chapter 02’s owners and Chapter 03’s decisions), so the chapter’s steps 1 to 9 are steps 2 to 10 below. Work in examples/non-person-identity, in PowerShell 7. The domain is fictional, and -Apply changes only a fake, in memory.

NoteEvery command in Lab 1

Every command in this lab, in order, from examples/non-person-identity. Each step below says what it does and what to look for.

# Step 1: Make the runs Chapter 06 reads
./Invoke-NpiInventory.ps1 -Cloud gcc -FixturePath tests/fixtures/estate.json -OutputPath out/inventory | Out-Null
./Invoke-NpiOwnership.ps1 -Cloud gcc -RegisterRun out/inventory -FixturePath tests/fixtures/estate.json -InputPath tests/fixtures/inputs -OutputPath out/ownership | Out-Null
./Invoke-NpiMatrix.ps1 -Cloud gcc -RegisterRun out/inventory -OwnershipRun out/ownership -InputPath tests/fixtures/ch03/inputs -FixturePath tests/fixtures/estate.json -SkuFixturePath tests/fixtures/ch03/subscribed-skus.json -OutputPath out/matrix | Out-Null

# Step 2: Run Learn's procedures against the stand-ins
Invoke-Pester -Path tests/KerberosIslandSamples.Tests.ps1 -Output None -PassThru |
    Select-Object PassedCount, FailedCount, NotRunCount

# Step 3: List what each task runs
Import-Module ./powershell/NpiKerberosIsland/NpiKerberosIsland.psm1
foreach ($t in 'kerberos-island', 'kerberos-apply') { $r = Get-NpiKrbRequiredRight -Task $t; "$t : " + ($r.Cmdlets -join ', ') }

# Step 4: Check the Kerberos accounts and build the plan
./Invoke-NpiKerberosIsland.ps1 -Cloud gcc -RegisterRun out/inventory -MatrixRun out/matrix -ProgramDatesPath tests/fixtures/ch03/inputs/program-dates.json -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -InputPath tests/fixtures/ch06/inputs -OutputPath out/kerberos

# Step 5: Read the findings
Get-Content out/kerberos/findings.json -Raw | ConvertFrom-Json | Sort-Object Rule | Format-Table Rule, Severity, ObjectKey

# Step 6: Read the plan
Get-Content out/kerberos/kerberos-plan.json -Raw | ConvertFrom-Json | Select-Object -ExpandProperty actions | Format-Table Action, Account, Write, Cmdlet

# Step 7: Read the island list and the reconciliation
Import-Csv out/kerberos/island-list.csv | Format-Table Account, Type, Disposition, SpnOwnerUpn, EndDate, AoAcceptedBy, ReadyForP46
Get-Content out/kerberos/reconciliation.json -Raw | ConvertFrom-Json | Format-Table Account, Type, Planned, Destination, Outcome

# Step 8: Dry-run the plan with its approved hash
$sha = (Get-FileHash out/kerberos/kerberos-plan.json -Algorithm SHA256).Hash.ToLower()
./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 $sha -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-dryrun

# Step 9: Apply it to the fake, then try a hash nobody approved
./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 $sha -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-apply -Apply
./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 ('0' * 64) -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-x

# Step 10: Run the tests
Invoke-Pester -Path tests

# After the steps
Remove-Item -Recurse -Force out
  1. Make the runs Chapter 06 reads:

    ./Invoke-NpiInventory.ps1 -Cloud gcc -FixturePath tests/fixtures/estate.json -OutputPath out/inventory | Out-Null
    ./Invoke-NpiOwnership.ps1 -Cloud gcc -RegisterRun out/inventory -FixturePath tests/fixtures/estate.json -InputPath tests/fixtures/inputs -OutputPath out/ownership | Out-Null
    ./Invoke-NpiMatrix.ps1 -Cloud gcc -RegisterRun out/inventory -OwnershipRun out/ownership -InputPath tests/fixtures/ch03/inputs -FixturePath tests/fixtures/estate.json -SkuFixturePath tests/fixtures/ch03/subscribed-skus.json -OutputPath out/matrix | Out-Null

    It prints nothing. The three folders hold the register, the owners and the owners’ D-NP3 decisions, which Chapter 06 reads instead of a second list.

  2. Run Learn’s procedures against the stand-ins:

    Invoke-Pester -Path tests/KerberosIslandSamples.Tests.ps1 -Output None -PassThru |
        Select-Object PassedCount, FailedCount, NotRunCount

    Expect PassedCount 17, FailedCount 0, NotRunCount 0.

  3. List what each task runs:

    Import-Module ./powershell/NpiKerberosIsland/NpiKerberosIsland.psm1
    foreach ($t in 'kerberos-island', 'kerberos-apply') { $r = Get-NpiKrbRequiredRight -Task $t; "$t : " + ($r.Cmdlets -join ', ') }
    kerberos-island : Get-ADComputer, Get-ADDomainController, Get-ADObject, Get-ADServiceAccount, Get-ADUser
    kerberos-apply : Complete-ADServiceAccountMigration, Disable-ADAccount, Get-ADComputer, Get-ADDomainController, Get-ADObject, Get-ADServiceAccount, Get-ADUser, New-ADServiceAccount, Set-ADServiceAccount, Start-ADServiceAccountMigration

    The read task runs only Get-AD* cmdlets. No cmdlet that removes or undoes is on either list.

  4. Check the Kerberos accounts and build the plan:

    ./Invoke-NpiKerberosIsland.ps1 -Cloud gcc -RegisterRun out/inventory -MatrixRun out/matrix -ProgramDatesPath tests/fixtures/ch03/inputs/program-dates.json -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -InputPath tests/fixtures/ch06/inputs -OutputPath out/kerberos
    Kerberos accounts: 9 in scope; KDS root key Ready
    Findings: 5 Finding, 1 Warn, 2 Info
    Plan: 9 actions, 4 of them writes (1 CompleteDmsaMigration, 2 CreateGmsa, 1 SetRetrievers); nothing sent
    Island list: 6 accounts, 4 ready for P4.6; hand-off ready: False
    Reconciliation (D11 KerberosIsland): 1 HandedOff, 4 OnIslandList, 1 Unreconciled
    Plan SHA-256: e8fb8355ee0989d9ce9d7b107cd52f45d0eea5f155a49c1667a1bf5840de9cca

    -MatrixRun is Chapter 03’s run, where the dispositions come from; -ProgramDatesPath is the one program-dates file, which the run refuses unless its SHA-256 is the one Chapter 03’s run recorded. The plan’s hash is the same on every run with these inputs.

  5. Read the findings:

    Get-Content out/kerberos/findings.json -Raw | ConvertFrom-Json | Sort-Object Rule | Format-Table Rule, Severity, ObjectKey
    Rule       Severity ObjectKey
    ----       -------- ---------
    NPI-KRB-03 Finding  gmsa-web$
    NPI-KRB-05 Finding  svc-intranet
    NPI-KRB-05 Finding  svc-webfront
    NPI-KRB-06 Finding  svc-intranet
    NPI-KRB-07 Finding  gmsa-intranet$
    NPI-KRB-08 Warn     gmsa-ops$
    NPI-KRB-09 Info     gmsa-sql$
    NPI-KRB-09 Info     svc-sqlprod

    svc-webfront is trusted for unconstrained delegation, which stops working once a dMSA migration completes, so in Chapter 03 its owner kept it on Kerberos (KeepKerberos) with the authorizing official’s acceptance; NPI-KRB-05 flags it because it has no SPN owner. NPI-KRB-05 and -06 flag svc-intranet: Chapter 03 re-platforms it to a gMSA, but it has no SPN owner and its end date (2028) is after program G5. The kept gMSAs gmsa-ops$ and gmsa-web$ end August 31, 2027, after D08 but before program G5, which is their bound, as in Chapter 03; gmsa-ops$ has no SPNs, so it needs no SPN owner. NPI-KRB-08 warns that gmsa-ops$ is in Domain Admins.

  6. Read the plan:

    Get-Content out/kerberos/kerberos-plan.json -Raw | ConvertFrom-Json | Select-Object -ExpandProperty actions | Format-Table Action, Account, Write, Cmdlet
    Action                Account      Write Cmdlet
    ------                -------      ----- ------
    Island                gmsa-ops$    False
    HandedOff             gmsa-sql$    False
    Island                gmsa-web$    False
    SetRetrievers         gmsa-web$     True Set-ADServiceAccount
    CreateGmsa            msa-print01$  True New-ADServiceAccount
    CompleteDmsaMigration svc-hrsync    True Complete-ADServiceAccountMigration
    CreateGmsa            svc-intranet  True New-ADServiceAccount
    HandedOff             svc-sqlprod  False
    Island                svc-webfront False

    Four writes: SetRetrievers for gmsa-web$, CreateGmsa for msa-print01$ and svc-intranet, and CompleteDmsaMigration for svc-hrsync, whose migration started 40 days ago. gmsa-ops$, gmsa-web$ and svc-webfront stay on the island, as Chapter 03 decided.

  7. Read the island list and the reconciliation:

    Import-Csv out/kerberos/island-list.csv | Format-Table Account, Type, Disposition, SpnOwnerUpn, EndDate, AoAcceptedBy, ReadyForP46
    Get-Content out/kerberos/reconciliation.json -Raw | ConvertFrom-Json | Format-Table Account, Type, Planned, Destination, Outcome
    Account        Type        Disposition  SpnOwnerUpn                   EndDate    AoAcceptedBy       ReadyForP46
    -------        ----        -----------  -----------                   -------    ------------       -----------
    dmsa-hrsync$   dMSA        Replatform   hr-apps.owner@contoso.example 2027-06-30                    True
    gmsa-intranet$ gMSA        Replatform                                 2028-12-31                    False
    gmsa-ops$      gMSA        Keep                                       2027-08-31                    True
    gmsa-print$    gMSA        Replatform   print.owner@contoso.example   2027-06-30                    True
    gmsa-web$      gMSA        Keep         erin@contoso.example          2027-08-31                    True
    svc-webfront   Traditional KeepKerberos                               2027-05-31 ao@contoso.example False
    
    Account        Type Planned Destination Outcome
    -------        ---- ------- ----------- -------
    dmsa-hrsync$   dMSA   False Island      OnIslandList
    gmsa-ops$      gMSA   False Island      OnIslandList
    gmsa-sql$      gMSA   False HandedOff   HandedOff
    gmsa-web$      gMSA   False Island      OnIslandList
    gmsa-intranet$ gMSA    True Island      Unreconciled
    gmsa-print$    gMSA    True Island      OnIslandList

    Six island rows, four ready for P4.6. gmsa-intranet$ has no SPN owner and ends 2028-12-31, so it isn’t ready, and its reconciliation outcome is Unreconciled. svc-webfront carries the authorizing official’s acceptance from Chapter 03, so it becomes ready once it has an SPN owner.

  8. Dry-run the plan with its approved hash:

    $sha = (Get-FileHash out/kerberos/kerberos-plan.json -Algorithm SHA256).Hash.ToLower()
    ./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 $sha -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-dryrun
    DryRun: 4 WouldSend
      WouldSend SetRetrievers         gmsa-web$       Set-ADServiceAccount
      WouldSend CreateGmsa            msa-print01$    New-ADServiceAccount
      WouldSend CompleteDmsaMigration svc-hrsync      Complete-ADServiceAccountMigration
      WouldSend CreateGmsa            svc-intranet    New-ADServiceAccount
  9. Apply it to the fake, then try a hash nobody approved:

    ./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 $sha -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-apply -Apply
    ./Invoke-NpiKerberosIslandAction.ps1 -PlanPath out/kerberos/kerberos-plan.json -ApprovedSha256 ('0' * 64) -FixturePath tests/fixtures/estate.json -KerberosFixturePath tests/fixtures/ch06/ad-kerberos.json -OutputPath out/kerberos-x

    Expect Apply: 4 Sent. Then the refusal: The plan's SHA-256 is e8fb8355…, not the approved 0000…; refusing to run a plan nobody reviewed.

  10. Run the tests:

    Invoke-Pester -Path tests

    Expect 513 tests passed, 0 failed.

Delete out when you’re done:

Remove-Item -Recurse -Force out

Exercise: Lab 2, your test domain (5 minutes to read)

Not run by the authors. Follow the workbook’s Chapter 06, Lab 2. It has the exact commands.

  • You need: a test Active Directory domain, never production, with at least one Windows Server 2025 domain controller, a Windows Server 2025 member server, an existing KDS root key, and Chapter 01’s Lab 2 run.
  • What you do: make a traditional test account and a test MSA, grant the read only msKds-UseStartTime and msKds-CreateTime, run the check, then apply the plan as a person with Domain Admins or equivalent rights, start the dMSA migration, and complete it after the 30-day parallel run.
  • Back-out: step 6 runs Learn’s Undo-ADServiceAccountMigration by hand (the code never runs it), re-enables the test account, removes the test objects by hand, and deletes the out folders.

Knowledge check (5 minutes)

  1. An account is kept on Kerberos (KeepKerberos). What must it have?
    1. A client secret in Key Vault
    2. The authorizing official’s acceptance, an SPN owner and an end date no later than D08’s
    3. A Conditional Access policy
    4. Nothing, until G5
  2. Why would this chapter block a dMSA for svc-webfront, the reason its owner kept it on Kerberos?
    1. It’s a SQL Server account
    2. It’s trusted for unconstrained delegation, which stops working once a dMSA migration completes
    3. Its domain has no KDS root key
    4. It already has a gMSA
  3. What does the write path do to the old account when a dMSA migration completes?
    1. Deletes it
    2. Moves it to another domain
    3. Nothing: Complete-ADServiceAccountMigration disables it and moves its SPNs to the dMSA; no delete cmdlet exists in the code
    4. Resets its password
  4. You pass a hash of zeros to Invoke-NpiKerberosIslandAction.ps1. What happens?
    1. It runs in dry-run mode
    2. It refuses, because the plan’s SHA-256 isn’t the approved one
    3. It applies the plan and logs a warning
    4. It asks for confirmation
  5. Why does the read task hold no domain administration?
    1. It reads only the KDS root key’s start and create times, with a delegated read, plus the default read
    2. Domain administration isn’t available in GCC
    3. The read runs as a gMSA
    4. Learn forbids it
  1. b. Chapter 03’s rule for an account kept on Kerberos; a kept gMSA or dMSA ends by program G5 instead, and needs an SPN owner only if it has SPNs. Taught in The context the code depends on.
  2. b. NPI-KRB-04. Taught in The check and the plan and the chapter’s Lab 1.
  3. c. Never delete. Taught in The check and the plan and the chapter’s Dangers.
  4. b. Taught in The separate write path.
  5. a. Taught in The separate write path.

Summary (2 minutes)

You checked nine Kerberos accounts in a fictional domain, read a plan with four writes, an island list and a reconciliation, applied the plan to a fake by its hash, and saw a plan nobody approved refused.

The evidence an ISSO keeps for G5 from this module: kerberos-plan.json with its approved SHA-256, findings.json, island-list.csv, reconciliation.json, and the apply folder’s results.json and manifest.json, dated; and the test result. Before shipping, work through the chapter’s Checklist.

Next: Module 9: Govern AI agent identities.

Back to top