Approval Tier 0 / Tier 1¶
Goal: the Tier 1 technicians create the GPOs of their servers; a Tier 0 administrator approves each one before it applies, and decides whether its creators may still change it.
Everything relies on the rights of the domain: the directory and SYSVOL refuse what a technician may not do, even outside the console. The console only sets these rights, and spares the technician the actions that would be refused.
sequenceDiagram
participant T0 as Tier 0 (approver)
participant AD as Directory and SYSVOL
participant T1 as Tier 1 (creator)
T0->>AD: Initialize-PSGPOWorkflow -Apply (delegation)
T1->>AD: New GPO: owned by the creator, applies to nobody
T1->>AD: Edits its settings
T0->>AD: Approve: owner Tier 0, rights of the creators, APPLY_ / DENY_ groups
T0->>T0: Backup labelled Approved
T1-->>AD: Edits it (EditSettings only)
T0->>T0: Drift from the approved version, approve again
1. Configure the workflow (Tier 0, once)¶
In the console, as a domain administrator (the Settings button is greyed for the other
accounts), Settings opens the configuration of the domain, in
SYSVOL\<domain>\PSGPOTools\Configuration.psd1, the same for every console of the domain:
- In Setting, choose
Workflow.Enabled; in Value,True; Set the value. - In Setting, choose
Workflow.Creators; in Value, the groups of the creators, separated by commas: those of the scripts of the lab,GPO-Tier1-Admins, GPO-Tier2-Admins; Set the value. - Keep
Workflow.ApproversandWorkflow.ApprovedOwner(Domain Admins) or set your Tier 0 groups, then Save.
The settings of the domain show Set for the domain, the others Default.
The configuration file then holds:
@{
Workflow = @{
Enabled = $true
Approvers = 'Domain Admins' # Tier 0
Creators = 'GPO-Tier1-Admins, GPO-Tier2-Admins' # Tier 1, Tier 2
ApprovedOwner = 'Domain Admins'
CreatorRights = 'ReadOnly' # what the approval proposes
}
}
The role of an account is read in its groups (tokenGroups, nested groups included): an
approver, a creator, or neither. The details of the domain show it. If a group of the workflow
cannot be found, no GPO can be created until it is fixed: a GPO of a creator would apply
before its approval.
2. Delegate the creation of GPOs (Tier 0, once)¶
Initialize-PSGPOWorkflow -Server dc.hardenbox.labo # what is there, what is missing
Initialize-PSGPOWorkflow -Server dc.hardenbox.labo -Apply # adds what is missing
The creators get two rights, and not Group Policy Creator Owners (which would let them create GPOs outside the workflow):
| Where | Right | To |
|---|---|---|
CN=Policies,CN=System,<domain> |
create groupPolicyContainer objects (f30e3bc2-9ff0-11d1-b603-0000f80367c1), this object only |
each group of creators |
\\<dc>\SYSVOL\<domain>\Policies |
list, read and create folders (0x1200AD), this folder only |
each group of creators |
| the same folder | full control of the folders and files it creates (OI CI IO) |
CREATOR OWNER |
Run the check again after samba-tool ntacl sysvolreset, which gives SYSVOL its default ACL back.
3. Create a GPO (Tier 1)¶
The technician manages only its OUs, the others are greyed (delegation), and the details of the domain say that its GPOs wait for an approval:
It creates the GPO as usual (Create a GPO in this domain, and Link it here...); the form says it will wait, and offers no security filtering groups: a GPO filtered on a group would apply to its members before its approval. They are set at the approval.
What the domain gives it, and what the console adds:
| Directory (the GPO container) | SYSVOL (its folder and every file in it) | |
|---|---|---|
| Owner | the creator | the creator |
| The creator | full control (CREATOR OWNER of the class) | full control |
| Its groups of creators | Edit settings (0x200B7) |
modify, without delete (0x1201FF) |
| Authenticated Users | read, no "Apply Group Policy" | read |
It applies to nobody, even linked, until it is approved. In the tree it shows (waiting for approval); its details say who created it.
Its creator owns it while it waits, and the owner of an object can always change its permissions:
with another tool than the console (ldbmodify, ADSI), the creator could give "Apply Group Policy"
back to someone. The console then says so, in red: (waiting for approval, but it applies) in the
tree, who it applies to in its details and in the approval form. The approval rebuilds its
permissions whatever they are (below). To keep a creator from making a GPO apply by linking it,
give the creators no right to link GPOs (gPLink) where they should not apply.
Why every file of the folder
Samba checks the NT ACL of a file and its POSIX ACL, and only changes the POSIX ACL of a file for its owner. The rights of the groups of creators are set on every file while the creator owns them; they stay there once the GPO is approved.
4. Approve it (Tier 0)¶
The GPOs waiting for approval are found without expanding the tree: Waiting for approval (N), below Group Policy Objects, lists them, expanded when the console opens, and an OU says how many are linked below it (Tier 1 (1 waiting for approval)). An approver sees every one; a creator only its own, the GPOs it edits, not the ones of the other tiers.
Right click the GPO > Approve...:
- The creators: read it only (they cannot change it anymore), or keep editing its settings (each change then differs from its approved version);
- Create the security filtering groups: the approver creates
APPLY_<GPO>andDENY_<GPO>, as the New GPO form does (the prefixes, scope and container of the configuration); the GPO applies to the first and is denied to the second. If they cannot be created, the GPO is not approved and stays pending; - or Applies to / Denied to: groups of the domain (Authenticated Users to apply it to
everyone). When the groups
APPLY_<GPO>andDENY_<GPO>exist already, they are proposed. - The settings the console does not interpret, when the GPO has some (a client-side extension
whose settings it does not read, a file of the GPO no reader reads): listed, and the GPO is
approved only once I reviewed these settings with GPMC, or in the files of the GPO is checked.
Approve-PSGPOsays them in a warning and in its confirmation (hardening).
# Its groups created in the Groups OU of Tier 1
Approve-PSGPO -Server dc.hardenbox.labo -Name 'T1 - Servers - Proxy' -CreateFilteringGroups -GroupContainer 'OU=Groups,OU=Tier 1'
# Groups that exist
Approve-PSGPO -Server dc.hardenbox.labo -Name 'T1 - Servers - Proxy' -ApplyTo 'GG-T1-Proxy-Servers' -DenyTo 'GG-T1-Proxy-Excluded'
Without -ApplyTo nor -CreateFilteringGroups, Approve-PSGPO uses the groups APPLY_<GPO> and
DENY_<GPO> when they exist and an approver or an administrator of the domain owns them, else
Authenticated Users; a group of that name someone else owns stops it (hardening).
The approval approves the GPO as it was when the form opened (or before the confirmation of
Approve-PSGPO): if its creator changed it since, it is not approved, and stays pending until it
is reviewed again.
The approval:
- gives the GPO, the containers it holds (
CN=Machine,CN=User...), its SYSVOL folder and every file and folder in it to the owner of the approved GPOs: an owner can always change the permissions, so the creator would give itself its rights back otherwise; - rebuilds its permissions from what an approved GPO may hold, not from what the pending GPO
holds: the allow ACEs of the owners an approved GPO may have (the owner of the approved GPOs,
the approvers, Domain Admins, Enterprise Admins, Administrators, SYSTEM) and of CREATOR OWNER,
and the read of Authenticated Users and of the domain controllers. Every other explicit ACE is
removed: those of the creator and of the groups of creators, and any other one (an ACE a
creator added outside the console, a deny ACE, OWNER RIGHTS). Those last ones are unexpected:
the console,
Approve-PSGPO(RemovedPermissions, and a warning) and the comment of the approved backup list them, in SDDL, so that the approver finds out who added them. On Windows, each file of the folder loses its explicit ACEs and only inherits the folder; - gives the groups of creators of the creator Edit settings (EditSettings), or nothing more than the reading of everyone (ReadOnly);
- sets who applies the GPO and who is denied it (a deny ACE for "Apply Group Policy", first in the DACL), Authenticated Users keeping the reading;
- backs it up with the approved label, its comment saying who approved it, who created it, what the creators keep, who applies it and who is denied it.
It writes SYSVOL first, then the containers the GPO holds, then the GPO last: its owner is what makes it approved. If one of these writes fails, the GPO is still pending, says so, and can be approved again once fixed; it is never approved with a SYSVOL folder its creator still owns.
In the lab, the approval of T1 - Servers - Proxy with its groups gave:
| Owner | Domain Admins (the GPO, CN=Machine, CN=User, the SYSVOL folder and every file) |
DENY_T1 - Servers - Proxy |
"Apply Group Policy" denied (first ACE) |
APPLY_T1 - Servers - Proxy |
read and "Apply Group Policy"; read and execute on SYSVOL |
GPO-Tier1-Admins |
Edit settings (EditSettings) |
| Authenticated Users | read only |
| The two groups | in OU=Groups,OU=Tier 1, owned by Domain Admins |
Who manages the members manages the scope
Whoever manages the members of APPLY_<GPO> decides where the approved GPO applies. The groups
the approver creates are its own: the Tier 1 technicians cannot add their servers to them. To
let them choose the servers of their GPOs, delegate the members of these groups (or of their
OU) to the Tier 1 group, knowingly.
5. What a technician can do then¶
Tested in the lab with the account tiers1, outside the console (smbclient, LDAP):
| Attempt | ReadOnly | EditSettings |
|---|---|---|
change a setting (Registry.pol) |
refused (NT_STATUS_ACCESS_DENIED) |
allowed |
| create a file in the GPO | refused | allowed |
| give itself rights back on the GPO | refused (no write dacl access) | refused |
| take ownership of a file | refused (Access Denied) | refused |
| delete the GPO | refused | refused (insufficient access rights) |
With EditSettings, each change makes the GPO differ from its approved version: the History tab
shows it in orange, Get-PSGPODrift lists it, and a Tier 0 approves it again, or restores the
approved version.
Limits¶
- While it waits, its creator owns the GPO: with another tool than the console, it can give
"Apply Group Policy" back to someone, and the GPO applies until it is approved or deleted. The
console shows it, and the approval removes it; it cannot prevent it, the domain gives every
owner that right. An ACE for OWNER RIGHTS (
S-1-3-4) would; it is not set. - The role of the account is read in its groups: when the server does not say which account the console uses (LDAP "Who am I?"), or that account is not found, no GPO can be created until it is fixed.
- After an approval with EditSettings, a file a technician creates in the GPO is owned by it: the next approval gives it back to the owner of the approved GPOs.
- Approving a GPO again needs it to be pending; to review the changes of an approved GPO, use its drift and approve its backup.










