Delegating access in AD to BitLocker recovery information
Normally in AD, all attributes are readable by “Authenticated Users”. Some attributes should inherit permissions, but should not be readable by “just anyone” To protect attributes like this, they can be marked as “confidential”.
There are 3 attributes relating BitLocker to which are marked in the schema as “confidential”.
This is done by marking the searchFlags attribute as enabled for bit 7 (128 decimal) in the schema where the attribute is defined. See here for more information on searchFlags: https://support.microsoft.com/kb/922836
These attributes are:
Attribute |
Applies to Object |
Used for |
msTPM-OwnerInformation |
computer |
Contains the owner information of a computers TPM. |
msFVE-KeyPackage |
msFVE-RecoveryInformation |
Contains a volumes BitLocker encryption key secured by the corresponding recovery password. |
msFVE-RecoveryPassword |
msFVE-RecoveryInformation |
Contains a password that can recover a BitLocker-encrypted volume. |
An object of type “msFVE-RecoveryInformation” is created for every encrypted volume and is stored as a sub-object of the computers object where the volume was encrypted.
Simply granting “read” access to these attributes will not allow a user to read the information in these attributes. A user who wants to read the attribute must also have an Access Mask for “Control_Access”. This is a special type of ACE (Access Control Entry). See here for more information on Access Masks: https://msdn.microsoft.com/en-us/library/aa374896(v=vs.85).aspx
GUI Tool to Manage Permissions
The only GUI tool which can set and view these special Control_Access ACEs is LDP.exe (using the version from Windows Server 2003 R2 ADAM or newer). This is shown below:
The "Control_Access" flag is needed in ADDITION to the normal "Read Propery" right. The "Control_Access" flag gets you past the confidentiality bit. You still need to be able to read the contents of the attribute.
Apply the permission once at the top of EACH DOMAIN where you need to delegate access to the recovery information of BitLocker volumes. Usually this does not include forest root domains or resource forests. Ensure the “inheritance” box is checked on each ACE so that it propagates to every msFVE-RecoveryInformation or Computer object and only to its relevant attributes.
(Note from Ryans comment below: You can aply this permission anywhere in the OU structure if you'd like to split the delegation bewteen groups - e.g. Help Desk users can access the keys for Standard Workstations and the Server Admins can access the keys for servers etc. You could apply the "read propery" ACE at the top of the domain to a super-group for everyone who is allowed to access the keys, and then have different groups able to use the "Control_Access" flags for their particular OUs. This will help limit ACE bloat in lsass.exe working set while still locking down the keys in the way you'd expect.)
Here are sample scripts to add the "Control_Access" flag to the top of the domain:
DelegateBitLocker.vbs
Taken from: https://technet.microsoft.com/en-us/library/cc771778(WS.10).aspx
'To refer to other groups, change the group name (ex: change to "DOMAIN\Help Desk Staff") strGroupName = "BitLocker Recoverers" ' ----------------------------------------------------------- ' Access Control Entry (ACE) constants ' ----------------------------------------------------------- '- From the ADS_ACETYPE_ENUM enumeration Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5 'Allows an object to do something '- From the ADS_ACEFLAG_ENUM enumeration Const ADS_ACEFLAG_INHERIT_ACE = &H2 'ACE applies to target and inherited child objects Const ADS_ACEFLAG_INHERIT_ONLY_ACE = &H8 'ACE does NOT apply to target (parent) object '- From the ADS_RIGHTS_ENUM enumeration Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100 'The right to view confidential attributes Const ADS_RIGHT_DS_READ_PROP = &H10 ' The right to read attribute values '- From the ADS_FLAGTYPE_ENUM enumeration Const ADS_FLAG_OBJECT_TYPE_PRESENT = &H1 'Target object type is present in the ACE Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = &H2 'Target inherited object type is present in the ACE ' ----------------------------------------------------------- ' BitLocker schema object GUID's ' ----------------------------------------------------------- '- ms-FVE-RecoveryInformation object: ' includes the BitLocker recovery password and key package attributes SCHEMA_GUID_MS_FVE_RECOVERYINFORMATION = "{EA715D30-8F53-40D0-BD1E-6109186D782C}" '- ms-FVE-RecoveryPassword attribute: 48-digit numerical password SCHEMA_GUID_MS_FVE_RECOVERYPASSWORD = "{43061AC1-C8AD-4CCC-B785-2BFAC20FC60A}" '- ms-FVE-KeyPackage attribute: binary package for repairing damages SCHEMA_GUID_MS_FVE_KEYPACKAGE = "{1FD55EA8-88A7-47DC-8129-0DAA97186A54}" '- Computer object SCHEMA_GUID_COMPUTER = "{BF967A86-0DE6-11D0-A285-00AA003049E2}" 'Reference: "Platform SDK: Active Directory Schema" ' ----------------------------------------------------------- ' Set up the ACE to allow reading of all BitLocker recovery information properties ' ----------------------------------------------------------- Set objAce1 = createObject("AccessControlEntry") objAce1.AceFlags = ADS_ACEFLAG_INHERIT_ACE + ADS_ACEFLAG_INHERIT_ONLY_ACE objAce1.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objAce1.Flags = ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT objAce1.Trustee = strGroupName objAce1.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS + ADS_RIGHT_DS_READ_PROP objAce1.InheritedObjectType = SCHEMA_GUID_MS_FVE_RECOVERYINFORMATION ' Note: ObjectType is left blank above to allow reading of all properties ' ----------------------------------------------------------- ' Connect to Discretional ACL (DACL) for domain object ' ----------------------------------------------------------- Set objRootLDAP = GetObject("LDAP://rootDSE") strPathToDomain = "LDAP://" & objRootLDAP.Get("defaultNamingContext") ' e.g. string dc=fabrikam,dc=com Set objDomain = GetObject(strPathToDomain) WScript.Echo "Accessing object: " + objDomain.Get("distinguishedName") Set objDescriptor = objDomain.Get("ntSecurityDescriptor") Set objDacl = objDescriptor.DiscretionaryAcl ' ----------------------------------------------------------- ' Add the ACEs to the Discretionary ACL (DACL) and set the DACL ' ----------------------------------------------------------- objDacl.AddAce objAce1 objDescriptor.DiscretionaryAcl = objDacl objDomain.Put "ntSecurityDescriptor", Array(objDescriptor) objDomain.SetInfo WScript.Echo "SUCCESS!" |
DelegateTMPOwners.vbs
Taken from: https://technet.microsoft.com/en-us/library/cc771778(WS.10).aspx
'To refer to other groups, change the group name (ex: change to "DOMAIN\TPM Owners") strGroupName = "TPM Owners" ' ------------------------------------------------------------ ' Access Control Entry (ACE) constants ' ------------------------------------------------------------ '- From the ADS_ACETYPE_ENUM enumeration Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5 'Allows an object to do something '- From the ADS_ACEFLAG_ENUM enumeration Const ADS_ACEFLAG_INHERIT_ACE = &H2 'ACE applies to target and inherited child objects Const ADS_ACEFLAG_INHERIT_ONLY_ACE = &H8 'ACE does NOT apply to target (parent) object '- From the ADS_RIGHTS_ENUM enumeration Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100 'The right to view confidential attributes Const ADS_RIGHT_DS_READ_PROP = &H10 ' The right to read attribute values '- From the ADS_FLAGTYPE_ENUM enumeration Const ADS_FLAG_OBJECT_TYPE_PRESENT = &H1 'Target object type is present in the ACE Const ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT = &H2 'Target inherited object type is present in the ACE ' ------------------------------------------------------------ ' TPM and FVE schema object GUID's ' ------------------------------------------------------------ '- ms-TPM-OwnerInformation attribute: SHA-1 hash of the TPM owner password SCHEMA_GUID_MS_TPM_OWNERINFORMATION = "{AA4E1A6D-550D-4E05-8C35-4AFCB917A9FE}" '- Computer object SCHEMA_GUID_COMPUTER = "{BF967A86-0DE6-11D0-A285-00AA003049E2}" 'Reference: "Platform SDK: Active Directory Schema" ' ------------------------------------------------------------ ' Set up the ACE to allow reading of TPM owner information ' ------------------------------------------------------------ Set objAce1 = createObject("AccessControlEntry") objAce1.AceFlags = ADS_ACEFLAG_INHERIT_ACE + ADS_ACEFLAG_INHERIT_ONLY_ACE objAce1.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objAce1.Flags = ADS_FLAG_OBJECT_TYPE_PRESENT + ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT objAce1.Trustee = strGroupName objAce1.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS + ADS_RIGHT_DS_READ_PROP objAce1.ObjectType = SCHEMA_GUID_MS_TPM_OWNERINFORMATION objAce1.InheritedObjectType = SCHEMA_GUID_COMPUTER ' ------------------------------------------------------------ ' Connect to Discretional ACL (DACL) for domain object ' ------------------------------------------------------------ Set objRootLDAP = GetObject("LDAP://rootDSE") strPathToDomain = "LDAP://" & objRootLDAP.Get("defaultNamingContext") ' e.g. string dc=fabrikam,dc=com Set objDomain = GetObject(strPathToDomain) WScript.Echo "Accessing object: " + objDomain.Get("distinguishedName") Set objDescriptor = objDomain.Get("ntSecurityDescriptor") Set objDacl = objDescriptor.DiscretionaryAcl ' ------------------------------------------------------------ ' Add the ACEs to the Discretionary ACL (DACL) and set the DACL ' ------------------------------------------------------------ objDacl.AddAce objAce1 objDescriptor.DiscretionaryAcl = objDacl objDomain.Put "ntSecurityDescriptor", Array(objDescriptor) objDomain.SetInfo WScript.Echo "SUCCESS!" |
And this script can help pull the assigned ACEs out to show you who has been delegated access: https://gallery.technet.microsoft.com/ScriptCenter/0bd4af9e-968a-4ae6-9950-2b2450afda37/