11.3 Designing Permission Schemes

Having worked through many designs for different domain structures, we have come up with a series of rules or guidelines you can follow to structure the design process effectively. The idea is that if you design your permissions schemes using these rules, you will be more likely to create a design with global scope and minimum effort.

11.3.1 The Five Golden Rules of Permissions Design

This list is not exhaustive. We are sure you will be able to think of others beyond these. If, however, these rules spark your creative juices and help you design more effectively, they will have done their job.

The rules are:

  1. Whenever possible, assign object permissions to groups of users rather than individual users.

  2. Design group permissions so that you have a minimum of duplication.

  3. Manage permissions globally from the ACL window.

  4. Allow inheritance: do not orphan sections of the tree.

  5. Keep a log of every unusual change that you have made to the tree, especially when you have orphaned sections of it or applied special rights to certain users.

Let's look at these rules in more detail. Rule 1Apply permissions to groups whenever possible

By default, you should use groups to manage your user permissions. At its simplest, this rule makes sense whenever you have more than one user for whom you wish to set certain permissions.

Global Group and Local Group Permissions Under Windows NT 4.0

Under Windows NT 4.0, Microsoft's preferred method of applying file and directory permissions was to create two sets of groups: Local Groups, which had permissions, and Domain Global Groups, which contained users.

The Local Group would exist on the server that had the resource, and the relevant permissions were assigned to that. Local groups were allowed to contain both users and groups. Domain Users were then placed in Domain Global Groups, which themselves were placed in the Local Groups on each server. Domain Global Groups were allowed to contain only users and not other groups. This may sound complicated, but it worked well in practice. A good way of demonstrating this is through an example.

Consider an NT 4.0 domain called Mycorp containing a Global Domain Group called Marketing. This group has four members. Within Mycorp are two servers, called Server1 and Server2, each of which has published a share. Each server also has a Local Group SH_USERS, which contains the Global Group Marketing as a member. Each SH_USERS group has read access to the relevant share on the same server.

You use global groups in this scenario because it is faster to deal with a large number of users as one group than it is to deal with them individually. In a similar vein, it makes sense to keep control over permissions to resources by creating Local Groups, each with a relevant set of permissions. That way, if you ever need to modify the permissions for a particular set of users, you need to modify only the Local Group's permissions.

So if we decide that Keith and Sue should have full permissions to the share on Server1, we could create a Local Group on Server1 with full permissions and add a newly created Global Group, say MKTG_ADMIN, to it with Keith and Sue as members. Future users who need full permissions are added to this Global Group.

Some things need to be made very clear about how groups are different between Windows NT and Active Directory:

  • Active Directory supports the concept of two types of group: security and distribution. A distribution group is one that contains users for mailing purposes and cannot have security rights assigned to it. Consequently, we are only dealing with security groups here.

  • Windows 2000 mixed-mode and Windows Server 2003 Interim domains natively support Security groups that have two types of scope: Global or Local. These correspond to the Windows NT 4.0 Domain Global and Local groups.

  • Windows 2000 native-mode or Windows Server 2003 domains have access to a third scope, universal. Universal groups contain other groups and have permissions assigned to them.

More detailed information on the differences between Windows NT groups and Active Directory groups and how Active Directory groups differ in the various modes and functional levels can be found in Chapter 2.

Under Windows 2000 mixed-mode and Windows Server 2003 Interim functional level, the paths you can choose are clear. You either follow the method outlined in the sidebar, or you choose to assign permissions in some other manner of your own choosing.

When you convert your domain to native mode, you have a more difficult decision: do you choose "Domain users go into universal groups, universal groups go into universal groups, universal groups are assigned resources"? Or do you move to "Domain users go into universal groups, universal groups are assigned resources"? Or do you assign permissions in a manner of your own choosing?

We're not advocating the use of one group or two, as we'll explain in more detail in the next section on how to plan permissions. We are advocating that whichever way you choose to implement group permissions, you should add users to groups and apply permissions to groups, even if the group initially contains only one user. This removes organizational dependence on one particular account. Time after time, we have seen organizations in which individual users with a whole raft of permissions to various objects suddenly leave or change roles. The new administrator then has to go in and unravel differing permissions settings from this account. We have even seen one administrator, who looked in anguish at the tangled mess of a recently departed administrator's account, delete his own account and rename the departed user's account just so that he could get the correct permission set without having to figure out the mess! If the old administrator had been a member of, say, five different groups, each with the relevant permissions, the new administrator could simply have replaced the group memberships of the old account with his new account. This is a much simpler approach, and we are sure that none of the preceding common sense is very new to systems administrators. Rule 2Design group permissions so that you have minimum duplication

It makes much more sense to create groups with simple permission sets than it does to create multiple groups with overlapping permissions. If you decide that some of your users need, say, create and modify, while others need modify and delete, and a third set needs just modify, it makes much more sense to create three separate groups with create, delete, and modify, than it does to make three groups with the permissions sets described. Let's consider an example. We will call the three groups CRE_MOD, MOD_DEL, and MOD. Let's now say we add 10 users to each group. If the only modifications ever to happen to these groups are occasional membership changes, this solution fits adequately. However, let's say that as with every large organization, the permissions requirements change over time. If Dave Peace, a member of CRE_MOD, now needs delete, what do we do? Do we make a special case of Dave's account and add the delete permission to his account only? Arguably, that is the simple solution, but according to Rule 1, we really should create a group to manage the permission. Do we create a DEL group and add Dave's account or create a CRE_MOD_DEL group and move his membership from CRE_MOD to the new group? Both are valid solutions.

Let's say we go with the former and create a DEL group, adding Dave as a member of that group. Things change again, and Mark Newell joins. Mark needs to be a member of groups giving him both MOD and DEL, so do we add him to MOD_DEL or MOD and DEL? Either way, we now have potential confusion. Whenever we have to check for members who can modify and delete, we have to check three groups, not one.

If we'd taken the second approach and chosen to create CRE_MOD_DEL rather than the DEL group, Mark is added to MOD_DEL when he joins, and things seem to be working fine. Paul Burke now moves from another team and requires create only, so a CRE group is created and his account added to that. Later, three others join the CRE group, but Paul now needs create and delete, so CRE_DEL is created, and he is moved to this group. Now we have six groups: CRE, MOD, CRE_DEL, CRE_MOD, MOD_DEL, and CRE_MOD_DEL. Unfortunately, if we ever have to check who has create and modify permission, we have to check the three groups: CRE, MOD, and CRE_MOD.

This example has been heavily contrived. However, we hope it serves to show that duplication will occur whenever you have users requiring separate permissions to an object or property and users requiring combinations of those permissions. It is for this very reason that we suggest creating separate groups for the lowest-common-denominator permissions that you need to set.

For example, if you have users who always need read, list, and create but require different combinations of delete and modify, it makes no sense to have three groupsone each for read, list, and create. You would instead create one group with the read, list, and create permissions assigned to it, one group for delete, and one for modify. Then you would use multiple group memberships to assemble the group permissions as you require them.

The most important point to note is that we are talking about minimizing and simplifying the number of groups. If you need only CRE_MOD_DEL to an object, you do not create three groups; you create one.

If after you have created a group with multiple permissions, you find that you now need groups with individual permissions, create the smaller groups and migrate the users. Then you can remove the larger group. This simplifies your workload, meaning not only do you manage fewer groups, but you also are revising and extending your permissions design to cope with changes. In fact, following this rule allows you to create a permissions scheme that you can be confident is fully flexible and enables you to cope with any changes in the future. Rule 3Manage Advanced permissions only when absolutely necessary

(Please note that this says "permissions" and not "auditing." Auditing entries can be accessed only from the Advanced tab, so this rule makes less sense for auditing entries.)

Whenever you right-click an object to view its properties, the Security Properties window that appears has an Advanced button on it. This was shown in Figure 11-1 in the previous section. The Security Properties window itself typically has the following allow and deny options as General Permissions:

  • Full control

  • Read

  • Write

  • Create all child objects

  • Delete all child objects

The screen also allows you to specify whether the object inherits permissions from its parent. In other words, it allows you to orphan the object from its parents.

The general permissions are not limited to those five in the previous list, and indeed they change depending on the object you are looking at. For example, the security properties for any user object display additional general permissions, such as Reset Password, Modify Web Information, and Send As. While these general permissions make sense for the user object, they are not all appropriate for other objects. This rule suggests that you manage permissions for objects from the Security Properties window as often as you can. You should choose the Advanced button only when you wish to allow or deny a permission to one aspect of an object rather than the whole object. An example would be manipulating the permission to a user object's telephone number rather than the whole account details.

While there is nothing wrong with managing atomic permissions to objects and properties, permissions are much easier to manage from a higher level. The main permissions that administrators might want to set were put here for this express purpose, so that users and groups can easily manage the tree without having to worry about the large amount of individual properties. Rule 4Allow inheritance; do not orphan branches of the domain tree unless you have to

If you allow or deny permission for a group or user to all objects of a certain type in a container, by default the permissions are applied recursively to all objects of that type in all the child containers down the tree. It is possible to block inheritance, but we recommend leaving inheritance in place (the default) and orphaning other branches on an individual basis only when there are good justifications for doing so. The reason is simple: if you specify that children do not inherit certain permissions from their parents, you are setting your Active Directory up to be more complex to manage. Here is a very contrived example of when it could be appropriate to orphan a branch. Let's say you have a domain tree called mycorp.com with a policy that all members of Mycorp should be able to print to all printers in the organization. Consequently, everyone has print rights to every printer down the tree by default. Now mycorp.com has, among others, two Organizational Units called Finance and Sales off the root. The Finance Organizational Unit has two printers that the Finance people specifically do not want Sales staff using. Consequently, having obtained a special dispensation from management to override the policy, they specify that a domain group containing all sales staff, called SALES_GRP and contained in the Sales Organizational Unit, has no access to view or list the printers in the Finance Organizational Unit and all its children. This is effectively using a PE window on the Finance Organizational Unit and setting a Deny on Full Control to apply this to Print-Queue Objects only.

Now the Finance Organizational Unit has three child Organizational Units called Loans, Borrowing, and Markets. The Sales team regularly uses a legacy application, which has to print results to a printer in the Borrowing Organizational Unit. Unfortunately, as SALES_GRP has no access to printers in the Borrowing Organizational Unit because of the permissions restriction, they are initially out of luck. Here are three of the many solutions to the problem:

  • Create a second printer, which resides in Sales, to the same device, and allow SALES_GRP to print to that.

  • Remove the SALES_GRP restriction from the Finance Organizational Unit and its children down the tree; that brings you back to the starting point where you allow everyone to print to every printer. Now manually apply the same restrictions for SALES_GRP to the Finance, Loans, and Markets Organizational Units, but do not apply them down the tree. Of course this means that everyone in Sales can print to all printers in Borrowing, but we could further restrict this by applying restrictions on all printers to which Sales should have no access.

  • Orphan the Borrowing Organizational Unit so that it does not inherit the printer permissions for SALES_GRP from its parent. This should allow print permission for the SALES_GRP to the printers in the Borrowing Organizational Unit.

Both the second and third items should allow print permission for the SALES_GRP to the printers in the Borrowing Organizational Unit. At first glance, the second and third items may appear to be identical. However, if the number of Organizational Units under Finance were 20 or 30, we would much rather choose the third method than the second. We have better things to do than to manually assign 20 or 30 sets of permissions.

There are two other important differences between the second and the third items. First, if we add a new Organizational Unit called Payments under Finance, in the third example Payments automatically inherits the permissions from Finance as they are applied down the tree on creation. Consequently, all the printers in Payments are restricted from SALES_GRP as per the dispensation. In the second example, the permissions are not applied down the tree and the administrator has to remember to apply restrictions to SALES_GRP for Payments if the dispensation is to be consistently applied.

The second point is that the Borrowing Organizational Unit in the third example loses all inherited permissions that would be applied by inheritance from its parent. This is significant if Borrowing had multiple inherited entries and every other inherited entry should stay put. When you orphan the Organizational Unit, you could specify that the inherited permissions for the Organizational Unit be converted to normal permission entries specific to this Organizational Unit. This saves you the trouble of manually applying inherited permission entries now. However, these manual changes will have to be remembered for the day when the permissions are changed on the parent, so that the administrator can come back and manually change them on Borrowing.

Ultimately, the preceding example shows that there is nothing wrong with orphaning sections of the tree or choosing not to apply permissions down the branch of a tree. It is just important to remember that every time you do it, you are creating slightly more work for yourself. As an administrator of a tree, you should keep track of these changes in a log, so that you can easily reference your special cases when required. Rule 5Keep a log of unusual changes

This may sound like an obvious statement, but it is surprising how many administrators overlook such a simple requirement. Simply put, it is always wise to keep a log of custom changes that you make to a default installation so that you and others have something to refer back to. There will be times when you may not be available and this sort of information is required. The following list shows the relevant fields of a basic Active Directory ACL log:

  • Unique name of object or LDAP location of object in tree

  • Object class being modified

  • Object or property being modified

  • User or group to whom permissions are being assigned

  • Permissions being assigned

  • Notes on reasons why this change is being made

Let's now look at how you can put these rules into practice in your own designs.

11.3.2 How to Plan Permissions

There are a number of Active Directory Users and Computers permission sets that administrators may need to implement in their organizations. Some examples are:

  • A set of centralized teams, each with responsibility for certain areas. Users can be members of more than one area: account modifiers, printer managers, computer account managers, publishing managers, and so on.

  • A manager for each individual major Organizational Unit under a domain.

  • Again, a manager for each individual major Organizational Unit under a domain, but this time each manager is also able to delegate responsibility for lower Organizational Units.

  • An administrator of the top-level domain is given permission to every subdomain by each subdomain's administrators.

While we could go through each of the preceding settings and show how to design permissions in each case, every organization is different. For that reason, it seems better to try to show what we consider to be the best way to design Active Directory permissions for all types of organizations.

First, create two documents, one called Allow and the other called Deny. On each document, label two sections, one called Global Tree Permissions and the other Specific Tree Permissions. Place two subheadings under each of the two sections, calling one General Permissions and the other Special Permissions. You should end up with three columns for each general and special heading: LDAP path, What to set, and To whom.

The first six columns relate to permissions that will apply throughout the whole tree; the last six relate to permissions that will apply to specific locations in the tree. The latter is likely to be the much larger of the two. The General columns relate to permissions that can be set without recourse to the use of the Advanced button, such as read access to all objects below an Organizational Unit. The Special columns relate to those permissions that you have to manually bring up a PE window for, such as allowing read access to all telephone numbers of user objects below a particular Organizational Unit. The last three columns relate to the LDAP path to the object that is to have properties set, the permissions that are being set, and the group or user to whom the permissions are being assigned.

The LDAP path under Global Tree Permissions is, strictly speaking, unnecessary, since these columns relate to permissions applied to the domain as a whole. If, however, you have a special need to apply permissions to a large number of Organizational Units directly below the root, you could use this column for this purpose.

Now you should go through your Active Directory design and begin to populate both the Allow and Deny tables. For a first pass, you should concentrate on a thorough design, listing all the permissions that you think you will need. Print out a number of copies of the table. Once you have a list in front of you, you can start amalgamating identical permissions into groups. It is likely that you will need to go through many iterations of these designs until you get a pared-down list that you are happy with. As you go through the design, you will start identifying groups of users to which you need to apply permissions. When designing the groups, you have two choices, as previously discussed under Rule 2. You can either create a single group to which permissions are set and which contains users, or you can create two groups, one to hold permissions and one to hold users.

The decision on whether to go for single or dual groups is not necessarily an easy one. My preference is to use single groups as often as possible, unless we need extra flexibility or have a lot of permissions to assign to many groups. In order to help you to make a bit more sense of the decision, a few reasons why you would want to consider one or the other are shown in Table 11-1.

Table 11-1. When to consider user groups and permission groups or combined groups

You should consider one group if

You should consider two groups if

You want to keep the number of groups to a minimum.

You want greater flexibility. Having one group for permissions and one for users means that you are always able to manage the system with a minimum of fuss.

You have only a small or simple tree, where it would be fairly easy to track down problems.

You have a large or complex tree, in which you need to be able to identify any problems quickly.

You need to assign only a few simple permissions.

You need to assign a large number of permissions.

You have very little change in the membership of groups and very few changes to permissions.

You have regular changes in your group membership or permissions.

You have little cross-membership of groups.

You have major cross-membership of groups, where a user could exist in more than one group with conflicting permissions. (Two groups make it easier to debug problems in a large environment.)

You very rarely need new groups.

You regularly need new groups with subsets of your existing users who have been assigned to some task.

You very rarely have to split user groups so that each user group subset has different permissions than the original group had.

You regularly have to split an existing group into more than one group, because each requires a different set of permissions than the old group used to have.

One last point: if you are creating permission groups and user groups, remember to name them sensibly from the outset, using something like pg_Finance and ug_ Finance, for example. It makes it easier when managing and scripting if you can easily identify which type of groups are which.

11.3.3 Bringing Order Out of Chaos

We've had people ask what we would recommend to someone arriving at a new company where the previous directory services administrator had left a tree with no proper permissions design or consistency. In this situation, start by analyzing what the organization requires and work from there. You also should analyze what permissions Active Directory currently has assigned, although concentrating solely on this could be detrimental. After all, if the last administrator was not competent or knowledgeable enough to set up a sensible permissions scheme from the start, he may not have accurately implemented the permissions required by the organization.

When analyzing Active Directory, you need to start by identifying the members of the built-in groups on the server, such as Domain Administrators, Backup Operators, and so on. Now do the same for the other groups that are specific to the organization. Once this is done, using the previously described tables, you need to list the permissions on the root of the first domain in the tree you are responsible for. From there you should look at the permissions for the first container or Organizational Unit in that list. Then navigate the branch represented by that container, looking sequentially at the child containers, continually recursing the tree. Once this first branch of the root is mapped out for the container permissions, you may be getting an idea of what permissions are required. Now go through all the objects in that branch, including printers, users, shares, and so on. This is time-consuming and annoying, but after a while you may start getting an idea of what is going on. All of this is just a sensible approach to going through Active Directory, not a quick-fix solution. You still have to continue throughout the domains you are responsible for to complete the process. It is also legitimate to use a script to iterate through Active Directory and print all the ACLs out to a file. For help on this, consult Chapter 23.

Your first main goal should be to move the individual user permissions to groups with users assigned to them as often as possible, thus making Active Directory simpler to manage and comprehend. These groups should be sensibly named for what they do rather than whom they contain (after all, you are looking to understand Active Directory first). Ideally, you can start consolidating users with identical permissions into the same group.

Your second goal is to remove permissions that users or your newly created groups should not have. This may of course mean that your new groups need to have their members split into two or more separate extra groups. For example, a group that has Read All Properties and Write All Properties to an object may actually need three groups with permissions instead: one to have Read All Properties, one to have both Read and Write All Properties, and one to have Read and selected Write rather than complete Write access. This may be evident from your Active Directory analysis, or it may come out of discussions with users or their managers, with whom you should at least confirm the changes before implementing them just to make sure your analysis is correct.

Ultimately, your third goal, having rationalized the array of Active Directory permissions, is to try to limit the orphaning of objects and branches and to try to move as many advanced permissions to general permissions as you can. You might think that it makes more sense to do this earlier, and in some cases this is true, especially when the whole tree is almost a complete set of orphaned objects. However, if you complete the first two goals, you will have an Active Directory tree that you understand and that has been brought back into line with sensible rules. It is much easier to attempt to fix problems with orphaning and advanced permissions once you have a manageable and rationalized tree. You may end up going back and changing groups or permissions that you already sorted out in attaining the first two goals, but consider how much more difficult it would be to attempt to do these concurrently. After all, you are trying to make the best of an already annoying task. There is no sense in trying to do everything at once. As you go through the tree checking for orphaning, you should document the orphans, as specified in Rule 5, just as if you had set up the orphans from scratch yourself. That way, you can use the tables to analyze and keep track, crossing off those that are of no use as you rationalize the tree.

    Part II: Designing an Active Directory Infrastructure
    Part III: Scripting Active Directory with ADSI, ADO, and WMI