How can I set the ACL of a CA programmatically?

th flag

When launching the CA console (certsrv.msc), I can right-click on my CA, select Properties and then I can modify the ACL of my CA in the Security tab. When I modify it, the changes are applied to the AD object at:

CN=MY-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com

When I view it in the ADSI editor, the modified ACL entries are not inherited, but directly applied (as expected). But when I change the ACL of this object programmatically, e. g. by:

Import-Module ActiveDirectory
$path = 'AD:CN=MY-CA,CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com'
$acl = Get-Acl -Path $path
Set-Acl -Path $path -AclObject $acl

Then I can see those changes in the ADSI editor, but I cannot see those changes, when I view the ACL of my CA via the CA console.

So, am I doing something wrong? Do I have to modify other objects programmatically as well?

What I tried:

  • After the change, I forced the AD to sync with: repadmin /syncall /Aed
  • I restarted the CA service certsvc

But it does not seem to be a "sync" problem...

cn flag

These ACLs are somewhat different. The ACL on AD object affects only AD entry and they are not propagated down to CA.

The ACL you see in CA Management console, are stored in CA configuration, in registry.

I'm not sure if there is an easy way to edit permissions on CA using PowerShell natively (without 3rd party tools). However, I would recommend to use the PowerShell PKI module to simplify the task. The module contains several ACL-related commands:

p.s. I'm the author of this PSPKI module

Every command has built-in and online help with useful examples on how to use each command.

cn flag
You have to restart CA service after writing to registry. CA reads configuration only on service startup and don't look for changes until next start.
th flag

Thanks to the pointers of Crypt32 and some additional sources1, I came up with the additionally needed changes that have to be performed in the registry of the CA:

# Get binary security descriptor of the CA from the registry
$sd_bin = Get-ItemPropertyValue -Path 'Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\MY-CA' -Name 'Security'

# Create security descriptor object of it
$sd = New-Object -TypeName System.Security.AccessControl.CommonSecurityDescriptor -ArgumentList @($false, $false, $sd_bin, 0)

# Modify the DACL in place
$sd.DiscretionaryAcl.AddAccess([System.Security.AccessControl.AccessControlType]::Allow, "<SID>", <INT32_PERMISSIONS>, [System.Security.AccessControl.InheritanceFlags]::None, [System.Security.AccessControl.PropagationFlags]::None)

# Convert the security descriptor back to binary form
$sd_bin_new = [System.Byte[]]::CreateInstance([System.Byte], $sd.BinaryLength)
$sd.GetBinaryForm($sd_bin_new, 0)

# Write it back to the registry
Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\MY-CA' -Name 'Security' -Value $sd_bin_new

# Restart the certificate services
Restart-Service -Name CertSvc

1Further reading:


Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.