Importing Devices in Microsoft Active Directory

The Microsoft Active Directory is a place where you can find different kind of objects;

  • Users
  • Computers
  • Servers
  • Printers
  • (Security) Groups
  • etc.

One thing you don't find are generic devices. And with devices I mean devices according to the LDAP definition (ObjectClass: device). The following screenshots show that there's no 'Add device' (or other object) available in the Active Directory Users and Computers GUI.

But why would you want to have these devices in your Active Directory? Well, the use is relatively specific, and has to do with Network Access Control (NAC). If a device / operating system is not able to authenticate to the network (RADIUS server) you can use the device MAC Address to authenticate it. I know, it's not that secure, since it can easily be spoofed, but it's better than doing nothing at all. Just make sure that you use other means of protection (Access Lists, Firewalls, etc.) to protect the rest of the network.

Anyway, to authenticate these devices you need a database to store these devices. Most companies have an Active Directory, so that would be the ideal place to store these objects.

There is a problem with using the AD as a repository for these MAC Address devices, since by default the object that you need to create is a user account. The specifics of that account are that the user-name and password are the same; namely the MAC address. And for this to keep working, the password cannot be changed or expire. This means that anyone who can find a device and read the MAC address of the back (or its bottom) of it has all the things to (POTENTIALLY) log on to the Active Directory.

These password expiration and complexity requirements for MAC address authentication is disastrous for the older Microsoft Active Directory platform., because it impacts all other object in the AD. Since Microsoft Active Directory 2008 there is the option to change the password security requirements for a group, so it has no impact on the regular accounts.
To make sure that the MAC address accounts are not able to log on to computers (console or over the network), you should also remove remove several rights (Group Policy). this way the accounts have no way of logging on to Active Directory resources.

An alternative scenario is to use a different (LDAP) sever to host the MAC addresses, but requires additional resources to maintain. So it would still be nice to use the existing AD for this purpose.

An obvious way is to use a more suitable LDAP object to 'authenticate' these MAC addresses. One of those is the device object class. This class even has a macAddress attribute, so why not use that?
The problem with the device object class is that the Active Directory Users and Computers GUI has no way of adding these kind of objects, so you need to add them through other means. If you need to add one or two addresses you can use ADSIEdit (which is the Microsoft LDAP editor), but for hundreds of them you might want to consider importing object by using an LDIF import.

Importing the MAC addresses isn't enough, since you would also want the MAC addresses grouped based on type or function. These devices will be allowed access (or not) based on their group membership (printers, IP Phones, IP Cameras, etc).

IF device is member of IP Phones
    THEN assign VLAN 10
IF device is member of Printers
    THEN assign VLAN 20

Grouping these devices is another thing that cannot be done through the use of the Active Directory Users and Computers tool. This only allows you to add the common objects to groups, and the device object doesn't have a 'member of' tab in its properties. So this also needs to be done through an LFID import (you can add, modify, delete, etc. objects in an LDAP by using LDIF).

LDIF requires a (very) specific data format, and that a list with MAC addresses is generally a list or CSV file, so you need to convert the one into the other. To accomplish this I wrote a Python script.

DISCLAIMER: Even though I did some programming in the previous century / another life, my skills (if there were any) have degraded. So there might be some code that's not as efficient as it could or should be. So any positive criticism / feedback on the topic is appreciated.

The script (at the end of this post) converts a CSV file which contains 4 columns:

<name>,<mac address>,<group>,<description>

The name is used to define the objects distinguished name (dn), while the description will be combined with the MAC address in the LDAP to make searching for the device in the Active Directory a little easier. The group membership column makes sure that the device will be added to the appropriate group.

Other mutations (like deleting objects) should be done through the Active Directory native interface, since relative small errors in an LDIF file can be disastrous for the Active Directory.

I tend to use the Apache Directory Studio program for LDAP interaction (including the Active Directory). This lets you import LDIF files through a graphical user interface instead of some command-line tool (like LDIFDE.exe).

The following screenshots show the import process by using the Apache Directory Studio program, as well as some result details of the created object and modified groups.

NOTE: You do need the appropriate rights (your bind dn) to add objects to the Active Directory.

The screenshot show the import dialogue, and the results. Note that I also used an LDIF to create the OU's and the groups through the init.ldif. This LDIF is also created by the Python script. It uses a config files which contains the distinguished names of the objects. These are combined with the data from the CSV file (containing the group information). This way there's little room for typos.

The second import (add.ldif) creates the actual MAC address objects and adds these to the corresponding groups.

config.ini

[LDAP]
# mabDN defines the base OU location
# macDN defines the OU location where all the MAC addresses are stored in the LDAP / Active Directory
# groupDN defines the OU location where all groups (or device types) are stored in the LDAP / Active Directory
mabDN = OU=mab,DC=testdomain,DC=local
macDN = OU=mac adressen,OU=mab,DC=testdomain,DC=local
groupDN = OU=Groups,OU=mab,DC=testdomain,DC=local

Sample MAC Address CSV file

printer 9,1abbccddeeff,printer,Full Color Printer
printer 8,2baaccddeeff,printer,BW Printer
Phone 7,3caabbddeeff,phone,IP Phone
printer63,3baaccddeeff,printer,Color Printer
Phone X,4dbbccddeeff,phone,IP Phone

Resulting LDIF for OU's and Groups (init.ldif)

dn: OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: mab
description: Top MAC address container

dn: OU=Groups,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: Groups
description: Device group container

dn: OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: organizationalUnit
ou: mac adressen
description: MAC address container

dn: CN=phone,OU=Groups,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: group
sAMAccountName: phone
cn: phone
name: phone

dn: CN=printer,OU=Groups,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: group
sAMAccountName: printer
cn: printer
name: printer

LDIF for device object creation and group membership (add.ldif)

dn: CN=printer 1,OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: device
macAddress: 1abbccddeeff
name: printer 1
description: Full Color Printer (1abbccddeeff)

dn: CN=printer 2,OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: device
macAddress: 2baaccddeeff
name: printer 2
description: BW Printer (2baaccddeeff)

dn: CN=Phone 1,OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: device
macAddress: 3caabbddeeff
name: Phone 1
description: IP Phone (3caabbddeeff)

dn: CN=printer 3,OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: device
macAddress: 3baaccddeeff
name: printer 3
description: Color Printer (3baaccddeeff)

dn: CN=Phone 2,OU=mac adressen,OU=mab,DC=testdomain,DC=local
changetype: add
objectClass: top
objectClass: device
macAddress: 4dbbccddeeff
name: Phone 2
description: IP Phone (4dbbccddeeff)

dn: CN=phone,OU=Groups,OU=mab,DC=testdomain,DC=local
changetype: modify
add: member
member: CN=Phone 1,OU=mac adressen,OU=mab,DC=testdomain,DC=local
member: CN=Phone 2,OU=mac adressen,OU=mab,DC=testdomain,DC=local

dn: CN=printer,OU=Groups,OU=mab,DC=testdomain,DC=local
changetype: modify
add: member
member: CN=printer 1,OU=mac adressen,OU=mab,DC=testdomain,DC=local
member: CN=printer 2,OU=mac adressen,OU=mab,DC=testdomain,DC=local
member: CN=printer 3,OU=mac adressen,OU=mab,DC=testdomain,DC=local

createLDIF.py file

The Python scripts need command-line arguments to function:

-a, --action
valid options are init, or add (init creates the OU's and Groups, and is optional if these already exist), add creates the MAC addresses + group membership

-i, --input
the input (csv) file

-o, --output
the resulting output file (if it exists, it gets overwritten)

-c, --config
the config file to use which contains the dn's of the OU's that needs to be created and/or used by the import.

Click HERE to download the Python script.

NOTE: I haven't put any thought yet into a version system of the code (like git, svn, etc), so if there are going to be (major) changes, I'll add a new link with the new code.
Even though the script works, I still want to add additional features to validate the inputs etc.

Posted on June 2, 2015 and filed under Security, Tips'n Tricks, Programming.