Microsoft Active Directory (AD) has decent capabilities for setting permissions on objects. You can use these permissions to allow delegated administration of users, groups, or computers to any security principal. In this way, many daily operations don't need to be performed by domain administrators. But when it comes to making specific data visible to only those users who need to see it—either because typical users shouldn't see the objects or because the data is truly confidential—the default AD permissions can make the task rather complex.
This four-part series has discussed AD data-hiding options. These options can be based on using normal AD permissions, a special AD permission feature called List Object mode (or List Mode), or a more advanced option, the confidentiality bit (a lesser-known option introduced a few years back in Windows Server 2003 Service Pack 1—SP1). With respect to setting permissions on AD data, there have been only minor enhancements in Windows Server 2008 R2 and Windows Server 2008. I'll describe those enhancements in this article. (See the Learning Path for a list of the previous articles in the series.) I'll also describe use of the confidentiality bit, as well as how it relates to configuring which attributes are replicated to a read-only domain controller (RODC).
Using the Confidentiality Bit
The last of the various options to hide confidential data in AD is the confidentiality bit. This feature was added to AD specifically to support another Windows Server 2003 SP1 security-related feature: the Credential Roaming feature, officially called the Digital Identity Management Service (DIMS).
DIMS enhances the options for storing a user's master key, which is used for encrypted data such as the Encrypting File System (EFS). This key is typically stored in the user profile, causing various challenges when a user works on multiple machines and thus has different master keys. Although roaming profiles allow users to use the same master key on multiple machines, the profiles have their own challenges. With the introduction of DIMS, Microsoft offers a way to store the master key files in AD by extending the schema with a few extra attributes (i.e., ms-PKI-DPAPIMasterKey, ms-PKI-AccountCredentials, and ms-PKI-RoamingTimeStamp) for the userClass schema object. (The schema isn't extended automatically to make these attributes available; you must add them separately.)
This article won't discuss DIMS in great detail, but from the short introduction you can see that the new DIMS feature stores very sensitive data—the master key files—on a user object.
As I explain in the previous articles in this series, each user has Read permission to all the attributes of his or her user object; the well-known SELF security principal is granted the Read All Properties permission to a user object. Also, many companies grant a special group the Read All Properties permission to a whole tree of objects (if not the whole domain or forest). For example, you can use this approach to allow certain service accounts to read any data from AD, without requiring domain admin privileges.
So how do you prevent access to sensitive data for accounts that have been granted Read access to certain attributes either directly, through property sets, or through the all-encompassing Read All Properties permission? Sensitive data might include the attributes that hold the master keys, employee social security numbers, or even employee IDs—whatever your company considers to be sensitive. This is where the confidentiality bit comes in.
The confidentiality bit was introduced in Windows Server 2003 SP1. As the name implies, it configures specific attributes in AD to be confidential; normal Read privileges are insufficient to be granted Read access on these attributes.
I'll cover how to mark an attribute as confidential and how to grant access to read a confidential attribute in a moment, but the basic idea is to do the following:
- The new confidentiality bit is set as bit 7 (=128 decimal) in the searchFlags property of the respective attributeSchema object in the AD schema. Add 128 to any existing value to designate the attribute as confidential.
- To grant access to a confidential attribute to users or groups that need to read the confidential data in the attribute, you must give them the CONTROL_ACCESS permission on the attribute for the respective objects. This introduces a way for AD to impose additional security checks that control Read access to selected attributes.
When trying to use the confidentiality bit, be aware of this important limitation: Microsoft doesn't let you apply the bit to the base schema attributes. In other words, you can't leverage the confidentiality bit for 90 percent of the default attributes that come with AD.
The base schema attributes are Category 1 attributeSchema objects and can be identified by using their systemFlags attribute, as bit 4 (=16 decimal). But not all default attributes are Category 1 attributes. The AD schema comes out of the box with 863 attributes in Windows 2000 and 1,070 in Windows Server 2003. Windows Server 2003 R2 adds another 81 attributes (mostly for Services for UNIX—SFU—and DFS Replication—DFSR). Since then, the Windows Server OS releases have added further attributes to the base schema. By now, you'll find 1,264 base schema attributes in Windows Server 2012.
To figure out which attributes are Category 1, we'll use the native LDAP query tool LDP.exe to search for all attributeSchema objects with bit 4 enabled. You could simply dump all attributeSchema objects, along with their systemFlag property, with a filter such as (objectCategory=attributeSchema) and then perform the analysis using some other tool, such as Microsoft Excel. But it's much nicer to run an LDAP query that gives you the final result right away. Yet we can't run a query checking for a simple decimal value in the systemFlag property; an attribute can have other bits set in systemFlags as well. We need to run an LDAP query with a bitwise test, by adding the RuleOID 1.2.840.1135220.127.116.113 into the search filter. There are two RuleOIDs for bitwise operations (matching rules): 1.2.840.113518.104.22.1683 is an AND condition (i.e., true only if all bits of the decimal value are matched), and 1.2.840.113522.214.171.1244 is an OR condition (i.e., true if any bit of the decimal value is matched). As such, our LDAP search filter would be as follows:
We expect a value above 1,000, so we need to enable a paged query in LDP. Open the Search Options dialog box, and set the Search Call Type to Paged, as shown in Figure 1.
Enter the Object Identifier (OID) 1.1 in the Attributes field to tell LDP to return only distinguished names (DNs) and no attributes. Depending on the version of LDP that you use, the Attributes field might be visible only in the Search dialog box, where you can also enter the value 1.1 for the same result.
The results of the paged query against the Schema naming context (NC) of a Windows Server 2003 AD, using the filter shown in Figure 1, returns 1,007 attributes that belong to Category 1, as Figure 2 shows. (Windows Server 2003 R2 doesn't add any Category 1 attributes to AD.)
If you run the query, you'll notice that many potential confidential AD attribute candidates are actually Category 1 attributes and thus can't be used in combination with the confidentiality bit. These include the attributes in Table 1.
As such, it's advisable to slightly edit the LDAP query to show only those attributes that aren't Category 1 (i.e., don't have bit 4 of systemFlags enabled). You can do this by adding a NOT expression to the filter:
The result is 63 attributes for Windows Server 2003 and 144 attributes for Windows Server 2003 R2, all of which can potentially be used with the confidentiality bit. With, you'd even get 164 attributes. To put this into perspective, the attributes in Table 2 are only those attributes in a Windows Server 2003 AD forest that can be used with the user class object, bringing the number down to 25 attributes.
There isn't much sense in questioning why Microsoft specifically chose these attributes to be base schema attributes. Basically, Microsoft wanted to limit the use of the confidential data feature to custom AD extensions, such as an attribute containing the Social Security number of a user, which isn't part of the default schema.
Nevertheless, some companies might want to store the employeeID in AD. They would like to store this data in an attribute that can be changed to a confidential attribute so that only authorized users can read and edit it. If that's the case, they can choose not to store the data in the attribute called employeeID, but instead to use the employeeNumber attribute. The latter isn't a Category 1 attribute. As such, it can be configured as a confidential attribute. Because its searchFlag attribute is empty, writing the value 128 into the searchFlags property of the employeeNumber attribute in the schema, as Figure 3 shows, is sufficient.
If the searchFlags property isn't empty, then you need to add the number. The searchFlags attribute defines various other options for an attribute, such as whether it's indexed (bit 1) or remains in the tombstone object at deletion (bit 3). For more details about searchFlags, check out the Microsoft article "Search-Flags Attribute (Windows)."
If you try to set the confidentiality bit on a Category 1 attribute (base schema), you'll receive a misleading error message, as shown in Figure 4.
Always remember that base schema attributes can't be made confidential.
As soon as this flag is set (and the schema-cache is updated), a populated employeeNumber attribute is no longer be visible to a user who is granted the Read All Attributes via the SELF security principal in the default permissions. Figure 5 shows the contents of the attribute before (on the left) and after (on the right) activating the confidentiality bit.
Another challenge is already ahead of us: How do we set the CONTROL_ACCESS permission for a hidden attribute? This should actually be an easy thing, but Microsoft didn't supply any command-line tools with Windows Server 2003 SP1 that could set this access at the attribute level. However, Windows Server 2008 and later versions have an updated Dsacls version that fully supports this capability, as tested on a Windows Server 2012 DC.
The correct syntax to add the CONTROL_ACCESS permission via Dsacls is as follows:
DSACLS <DN of object> /G <secprin>:CA;<property>
When you assign CONTROL_ACCESS permissions at the property level to a user or group, you must specify the display name of the property—in our case, employeeNumber:
DSACLS "CN=Root-User1,OU=UserAccounts,DC=root,DC=net" /G root\HR-users:employeeNumber
Unfortunately, ever since the CONTROL_ACCESS permission was introduced, there hasn't been a really useful UI to manage or view this permission. This is still true in Windows Server 2012. But since Windows Server 2003 R2, the LDP.exe editor does include a powerful security editor that allows you to view and set the CONTROL_ACCESS flag on a specific object attribute.
Navigate to the object on which you want to change the permissions. Right-click the object and choose Advanced, Security Descriptor. LDP then pops up a dialog box, which you can use to set the options for displaying the Security Descriptor. Don't choose the Text dump, which dumps the descriptor to the output window. Using the default settings starts the new Security Editor (see Figure 6).
Choose Add ACE to grant the control access permission for the employeeNumber attribute (see Figure 7).
Managing the permissions for attributes on a list of separate objects in AD doesn't work very efficiently when using a UI. If you need to manage the permissions on confidential attributes and are still operating your AD on a version earlier than Windows Server 2008, consider setting up a tool server with a newer Windows Server OS. Doing so will allow you to use the newer Dsacls version—it's worth the effort!
RODC Filtered Attribute Set
Hiding data in AD takes yet another twist when it comes to the RODC, which was the key architectural change in AD with Windows Server 2008. Although the confidentiality bit allows us to hide data in attributes from particular users with normal Read permissions, you might want to hinder the same data from replicating to locations where you've deployed RODCs. After all, the concept of an RODC is that of a DC located in an untrusted environment.
To give you this extra security control, Microsoft added the filtered attribute set (FAS) to the RODC replication logic. This feature essentially allows you to flag attributes in the AD schema when you don't want the content of those attributes to be replicated to any RODC in the forest. As with the configuration of the confidentiality bit, you set the FAS bit via the search-flag of the attribute that you want to control; in this case, bit 9 (=512 decimal). Once set, the Read-Write DCs in the forest will no longer allow data in the respective attributes to be replicated to RODCs. Note that FAS is restricted to the same attributes as the confidentiality bit: You can't use it for any base-schema attributes. But FAS certainly works just fine for any attributes that you have extended in your AD schema.
You can leverage the confidentiality bit to control access to sensitive attributes. This approach allows you to hide specific attributes from users (e.g., the SELF security principal) who otherwise are granted general Read access via the default permissions on objects in AD.
You must remember a few things when considering the use of the confidentiality bit to hide attributes from general Read access in AD. As with the other data-hiding options, the confidentiality bit doesn't hinder domain or organizational unit (OU) admins from viewing the confidential attributes of an object in AD. However, it does hinder those users that are merely granted general Read permissions on the whole object or via a property that's set to read the data in an attribute that's configured to be confidential.
Marking an attribute confidential immediately changes the permissions of the respective attribute for all objects in AD. Most default attributes in AD (all of which are base schema attributes) can't be marked confidential. As with the change of Property-Sets, no re-ACLing of the objects in AD is required to activate the change of permission in an AD forest. However, to grant read access to non-admins, you need to grant the target group the CONTROL_ACCESS permission to the confidential attribute.
Although it took a while for Microsoft to properly update the Dsacls command-line tool to efficiently manage the required attribute permissions, with the latest server versions, there's no excuse for not properly configuring your AD permissions to hide confidential data.