After my post the other day I couldn’t help but think that perhaps I had an ordering problem. I was really outlining the solution to a problem which had not yet been scoped. Let’s take a step back.
We so often throw the term “ACL” around, like it’s some thing that we all implicitly know. But what’s going on there under the hood? What is an ACL in AD anyway?
Well, to start, the term ACL should really be clarified as it’s something of a catch-all that we use. What we’re really talking about is a security descriptor. A security descriptor (SD), according to MSDN, is:
A security descriptor contains the security information associated with a securable object.
There are a couple of interesting terms there. First, we mentioned the term security descriptor. If I could, I’d like to skip defining this term for now. I would like to define securable object though.
“Securable object” implies that some objects are securable, and some are not. This is a property I think many people tend to forget. There are a subset of objects in Windows that can not be secured via the mechanisms we are discussing. While this discussion is slightly out of scope for this post, if you are interested in more information around that, please do visit the following link: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/securable_objects.asp
I think it's time that we get back to the original term that started this, ACL. Again looking to MSDN for some wording:
An access control list (ACL) is a list of access control entries (ACE). Each ACE in an ACL identifies a trustee and specifies the access rights allowed, denied, or audited for that trustee. The security descriptor for a securable object can contain two types of ACLs: a DACL and a SACL.
Now while I’ll grant that most people are more interested in DACLs than SACLs, the SACL should not be forgotten. Discretionary Access Control Lists (DACLs) define the trustees that are denied access to or allowed access to a securable object, as well as the type of access they are denied/allowed. System Access Control Lists (SACLs) are used for defining the audit policy on the object.
If you recall, a few paragraphs ago we skipped the term security descriptor. With all of the other pieces that we’ve put together so far, let’s go ahead and revisit that term. Security descriptor is defined as:
A structure and associated data that contains the security information for a securable object. A security descriptor identifies the object's owner and primary group. It can also contain a DACL that controls access to the object, and a SACL that controls the logging of attempts to access the object.
It’s starting to come together. In reality, a security descriptor is nothing more than a hunk of data that contains a SACL, a DACL and some other elements (owner, etc.). Each DACL/SACL is made up of ACEs. Makes sense.
While this has all been entertaining I’m sure, let’s get to the point, shall we? Why did we need to do the single instance store thing for security descriptors in AD? What problem were we really trying to solve?
Well, security descriptors are written in a language called Security Descriptor Definition Language (SDDL). In reality, it’s nothing more than a well formatted string. Here’s a sample bit of SDDL: D:(A;;CCDC;;;PS)
While scary looking, that’s actually not so bad to translate. Let’s break it up…
The “D:” part tells me that the forthcoming elements are part of a DACL. Other possibilities for that are enumerated here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp
Next we have the ACE string in the ( )’s. This field is broken up as follows:
So if we look at this particular string, we find the following:
This is, of course, just one example. For the sake of brevity, I did not define every possible element. More information on this format can be found here: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp
Anyway, these security descriptors can get quite large. For example, let's look at the default security descriptor for users created in AD:
Wow! That’s pretty large for just a single user. Remember, we place that on each object of this class created. That's a lot of space lost to duplication.
Enter Single Instance Store of Security Descriptors. In most environments, we’ve found that many objects tend to have the same security descriptors on many objects. This property makes sense; most ACLs are applied to containers and set to inherit so as to save administrative overhead, and ACLs on individual objects tend to be from the default and not custom for each object. Since SDs can be quite large, we felt that if we stored only unique copies of them in a single table and then kept pointers to the appropriate SD that table, we would save a substantial amount of space. So far, we think we’ve helped a lot of people with this one. Please do holler with your experiences, good or bad.
since you've started it - is it really a single instance store or is it mainly for the purpose to provide a single store for inherited ACLs? How detailed is it - does it go down to every ACE? And is it only taking care of inherited or also manual created ACLs? (e.g. if I create two objects with the same ACL manually, will this be detected and "single stored"?
Hey Eric - great post, but I'd say there's one more thing that should be mentioned to complete the picture in terms of why there is such a nice benefit with the single-instance store:
when inheriting permissions to child objects in an OU hierarchy, AD doesn't just store these permissions at the OU level => it actually stamps the permissions onto every object down the tree which causes the security descriptor for every object to increase the same way as the one object where the actual permission was set on. So the default DACL of every new User object (which in itself is already rather large as you've described) is further increased by those other permissions inherited down the various OUs.
This "static inheritance" allows quick access to the permissions on an object when eveluating these, with the downside of increasing the storage space for ACLs (to compare: Novell uses "dynamic inheritance", where the inherited ACLs are not stamped on the objects - instead they are determined at runtime when doing the security evaluation at access-time of an object).
With the Win2003 SIS, I believe MS combined the best of both worlds, since the increased storage is no longer an issue while still keeping the high speed during security evaluations.
Ulf - I'll let Eric confirm this for sure, but I'd think that SIS also works for manually created ACLs (i.e. explicit ACLs, which are the same on different objects), since there shouldn't be a way for the system to differentiate these from the explicit ACLs that come from the default security descriptor during creation time of an object.
Guido is right on. It doesn't care what type of ACLs are in a particular SD, it SISs them all the same, explicit or inherited. The nature of inherited ACLs tends to be that they tend to be similar across many objects, so you see more of a savings. But that’s more of a general property than anything else….if you explicitly ACL 100 objects identically, you certainly will feel the savings there (although I question why you explicitly ACL’d so many objects the same when you could have ACL’d a single container and let ACL prop do the work for you….easier mgmt that way….I digress).
The point re: inheritance is a good one Guido. I intentionally left it off in this post as I didn't feel I could give it the attention it deserves in this post w/o diluting the rest of the post. I don't want them to be novels. :) Digging in to that is on my todo for the future though.