Skip to content

Releases: Nobrac/ADTierKit

v1.2.0

Choose a tag to compare

@Nobrac Nobrac released this 25 Sep 15:05

v1.2.0

Review and hardening release. It closes gaps in the tier boundary itself, makes the audit and the
recovery script do what their documentation says, and adds the pieces the review found missing:
a neutral landing zone for new computers, Kerberos armoring for enforceable silos, checks of the
attack paths into Tier 0, account and access group hygiene, DSRM through LAPS, and CI.

Run Update-TierConfiguration.ps1 on an existing configuration before the next deploy, then
review the plan: it moves groups, adds deny ACEs and GPO settings. The neutral staging OU is
added disabled by the updater - switching it on is a decision.

Security

  • The break-glass account is kept out of the authentication policy silos. Silo membership
    was derived from the role groups without looking at excludeFromSilo, so the break-glass
    account - a member of G-T0-Admins - was assigned like every other administrator, contrary to
    the README. Accounts marked excludeFromSilo are now skipped; if one is already assigned,
    audit reports it as a High finding and deploy/sync removes the assignment.
  • Operators no longer hold every control access right on the service account OU. The
    delegation ReadProperty, ExtendedRight without an object type granted all extended rights,
    Reset Password on service account users included - Tier 0 operators could take over Tier 0
    service accounts. It never granted gMSA password retrieval either; that is controlled per
    account by PrincipalsAllowedToRetrieveManagedPassword. The delegation is gone from the
    generator and the shipped configuration. The tool only adds ACEs, so remove an existing one
    by hand
    , per tier, on OU=Service-Accounts,OU=<tier>,OU=<root>,..., for example with
    dsacls "<OU DN>" /R "<DOMAIN>\G-T0-Operators" (this removes all explicit ACEs of that
    group on the OU - there are no others in the shipped model).
  • Deny logon and GPO exception groups live in the top tier. Kept in their own tier's branch,
    they were writable by that tier's administrators through the branch delegation: a Tier 2 admin
    could remove G-T0-Admins from DL-T2-DenyLogon or exempt workstations from
    T2-Logon-Restrictions, switching off exactly the protection Tier 0 credentials rely on.
    Both groups now default to Tier-0/Groups, and existing groups are moved there by the Group
    and GPO stages (new Move-TierObjectToOu; audit reports a misplaced group as drift).
  • Tier administrators below the top tier cannot block Group Policy inheritance. The branch
    delegation includes WriteProperty on every sub-OU and with it gPOptions. A deny on
    gPOptions for the tier admin group is now part of the granular delegation. The LAPS policy
    link, which a Block Inheritance used to switch off, is now enforced like the other tier links.

Added

  • Neutral staging OU. A staging block, expanded at load time like roles, creates
    OU=Staging below the model root: a deny logon group holding every role group of every tier,
    a quarantine GPO denying them logon, a join group with the domain-join set and nothing else,
    top tier management of the OU and a LAPS policy readable by the top tier only.
    redirectComputersTo: "$Staging" sends new computers there instead of into the lowest tier,
    whose administrators used to control every new server until somebody classified it. The audit
    lists machines waiting there and for how long. New OU reference $Staging.
  • Kerberos armoring. The DC baseline carries KDC support for claims, compound
    authentication and Kerberos armoring
    (level Supported), every tier GPO the matching client
    setting. Test-TierKerberosArmoring checks configuration and deployed policy.
  • Two-way silo reconciliation. Objects assigned to a silo that no longer qualify are
    reported, or removed with options.authenticationPolicySiloReconcile: "Enforce". An account
    that qualifies for two silos is a High conflict and is assigned to neither, instead of flapping
    between them on every run.
  • Attack path checks in the audit (Test-TierAttackPath, attackPathChecks block): dangerous
    ACEs and foreign owners on the domain head (DCSync included), AdminSDHolder, the Policies
    container, the Domain Controllers OU and

v1.1.0

Choose a tag to compare

@Nobrac Nobrac released this 24 Aug 08:22

ADTierKit 1.1.0

Hardening and documentation release. The three code changes came out of an external review of
1.0.0 — none changes what a converged directory looks like.

Security

InstallTask now checks who can modify the files it schedules. The sync task runs the
script and configuration as SYSTEM on a domain controller. Registration now refuses paths that
principals outside SYSTEM, Administrators, TrustedInstaller and the Domain/Enterprise Admins
can write to — including the parent directories — and names the offending principals.
-SkipAclCheck bypasses the check deliberately. If your kit lives somewhere like C:\Temp,
move it (e.g. under Program Files) before re-registering the task; existing tasks keep
running unchanged.

Fixed

  • The password generator's Fisher-Yates shuffle now uses the same rejection-sampled randomness
    as the character picks, removing a (practically negligible) positional modulo bias.
  • LAPS reset permissions are now verified against the OU ACL instead of
    Find-LapsADExtendedRights (which only reports read holders), so they no longer get
    re-granted and reported as Created on every run.

Added

  • Operator's Guide — the complete change inventory (every setting and
    default value the tool writes), the working model, day-two operations, the rollout playbook
    with per-phase checks, and a verification checklist.
  • README: What belongs in Tier 0 — the classification
    test and the systems most deployments forget (PKI, Entra Connect, backup, hypervisors
    hosting DCs, endpoint management, the kit's own directory).
  • README: silo pre-enforcement warning — PAWs must be in memberComputerOus and synced
    before enforcing, and the AuthenticationPolicyFailures-DomainController log is disabled by
    default and must be enabled on every DC for the audit phase to prove anything.

Upgrading from 1.0.0

Drop-in: replace the files, no configuration schema change (schemaVersion unchanged,
Update-TierConfiguration.ps1 not needed). Run -Mode Deploy without -Apply once — the plan
should show no pending changes for an already-converged directory. The only behavioural
difference you may notice: -Mode InstallTask can now refuse (see above), and the LAPS stage
stops reporting Created for reset permissions that were already in place.

Full changelog: CHANGELOG.md

v1.0.0

Choose a tag to compare

@Nobrac Nobrac released this 14 Aug 10:02

ADTierKit 1.0.0

Deploys and maintains an Active Directory administrative tier model — OU structure, AGDLP groups,
granular delegation, logon restriction policies, Windows LAPS and Kerberos authentication policy
silos — from one JSON configuration, idempotently, with -WhatIf support throughout.

Deployed and exercised against a Windows Server 2019, 2022 and 2025 lab domain: 238 objects, 0 failures, 0
created on the second run.

What's in this release

Roles. A role is not one object — it is a group, a template account, a set of ACEs, a
membership in the deny logon group of every other tier, and a membership in the tier's
authentication silo. Four of those five are easy to forget, and forgetting the deny nesting means
the new group can log on everywhere, which is exactly the boundary the model exists to draw. The
roles block declares it once and generates all of it.

Two roles ship ready to use. The Group Policy one grants write access to gpLink and read only to
gpOptions — the GPMC permission called Link GPOs grants both, and write access to gpOptions
is the ability to block inheritance and cancel out the baseline. The DNS one holds its permissions
by being nested into DnsAdmins, which stays empty of direct members and is now watched.

Ownership enforcement. An owner holds WRITE_DAC implicitly, so every object a delegated
administrator creates is one whose permissions they can rewrite — the granular delegation is
binding only until somebody creates something. The new stage reports it, and optionally corrects
it.

Per-policy Group Policy delegation, six new OU references for targets outside the tier model,
SACL coverage on CN=Policies, AdminSDHolder and CN=MicrosoftDNS, and offline test suites.

Upgrading

There is nothing to upgrade from — this is the first tagged release. A configuration written from
an earlier commit needs Update-TierConfiguration.ps1, which adds the new keys without touching
anything that already exists and refuses to guess where guessing would be unsafe.

One thing worth reading

The lab run found seven defects, and the expensive one was this: Set-ADObject on
nTSecurityDescriptor writes the DACL and drops the owner portion silently. The ownership
stage reported a correction on every run while the owner never changed. It was caught by running
the same enforce stage twice and noticing the same object drift again.

Owner writes now read back and compare before reporting anything as corrected, and the habit is
worth keeping by hand too: run enforce operations twice and expect zero the second time. A
security tool that reports a control it did not apply is worse than one that reports nothing,
because it stops anyone from looking.

Requirements

Windows PowerShell 5.1, the ActiveDirectory and GroupPolicy modules, Domain Admin, and a domain at
functional level 2016 or higher for authentication policy silos.

Not covered

No production directory, no multi-domain forest, no second engineer's review, no code signing. The
offline suites in tests/ cover configuration logic against mocks, not a directory — they would
not have caught any of the seven defects the lab run found. See
Limitations & notes.