OS X Moutain Lion RADIUS: Logging & SACL

In our follow-up of RADIUS on OS X Mountain Lion we will look at some logging options and setting up a Service Access Control List (SACL).

RADIUS Logging:

The radiusconfig command can be used to adjust how freeRADIUS will do some of its logging, more specifically whether it logs authentication requests.

Again we will use a root shell (sudo -s) simply because making any changes to the radius server requires root priviledges for all the commands, so instead of typing sudo all the time, we can avoid that temporarily by using a root shell. You will require a root shell in any case in order to explore some of the radius directories, including where it logs to.

First up, let run radiusconfig -getconfig, here you will notice the following output.

"radiusd.conf" =     {
        auth = no;
        "auth_badpass" = no;
        "auth_goodpass" = no;
        "cleanup_delay" = 5;
        "hostname_lookups" = no;
        "max_request_time" = 30;
        "max_requests" = 1024;
    };

The keys we are interested in are the top three. auth = no, control whether it will log authentication requests. The two below it, determines whether it will log a bad password attempt and/or a good password attempt. To enable authentication logging, we execute the following command:

radiusconfig -setconfig auth yes

To enable logging the other two is as simple as:

radiusconfig -setconfig auth_badpass yes
radiusconfig -setconfig auth_goodpass yes

If we run radiusconfig -getconfig, it should now look like this:

"radiusd.conf" =     {
        auth = yes;
        "auth_badpass" = yes;
        "auth_goodpass" = yes;
        "cleanup_delay" = 5;
        "hostname_lookups" = no;
        "max_request_time" = 30;
        "max_requests" = 1024;
    };

If you plan to enable this type of logging its best to also enable auto rotation of the log file, again radiusconfig will do the trick.

radiusconfig -autorotatelog on

Any changes to the RADIUS server requires it to be restarted. You can use either one of the following options.

To stop RADIUS:

radiusconfig -stop
launchctl unload -w /System/Library/LaunchDaemons/org.freeradius.radiusd.plist

To start RADIUS:

radiusconfig -start (to start the server)
launchctl load -w /System/Library/LaunchDaemons/org.freeradius.radiusd.plist

Log files are stored in /var/log/radius.

Service Access Control List (SACL)

Having a SACL implemented for a service such as RADIUS is useful, as we can then control who has access to wifi. Without it, any user on our OS X Server has access to wifi, including ones from connected Directories. Lets dig in...

The SACL we are interested in is com.apple.access_radius. How do we know this? Lets quickly run our RADIUS server in debug mode, thus stop the server if its currently running, then run radiusd -sfX. Open another Terminal window and run the following, be sure to change user and password to a valid user on your system:

radtest user password localhost 0 testing123

If you look closely at the debug output you'll notice this section:

[opendirectory] The SACL group "com.apple.access_radius" does not exist on this system.
[opendirectory] The host 127.0.0.1 does not have an access group.
[opendirectory] User raduser1 exists in OD
[opendirectory] no access control groups, all OD users allowed.
[opendirectory] Setting Auth-Type = opendirectory

From that we can draw the conclusion that if we had such a SACL group, that it would check whether a user is part of the group and grant or deny access as required. 

Creating the group can be achieved with dseditgroup.  The following command will create a group in the local directory node called com.apple.access_radius.

dseditgroup -o create com.apple.access_radius

If you stopped the RADIUS server, start it in debug mode again and repeat the step above with radtest. You will now see the output reflects our new SACL and looks like this:

[opendirectory] The host 127.0.0.1 does not have an access group.
[opendirectory] User raduser1 exists in OD
[opendirectory] User raduser1 is not a member of the RADUIS SACL
++[opendirectory] returns reject
Invalid user (User is not authorized): [raduser1/raduser1pw] (from client localhost port 0)
Using Post-Auth-Type Reject

As per the text in bold we can see the user is rejected as it doesn't have the required authorisation due to not being part of the SACL group.

Keep the RADIUS server running.

Adding Users to the SACL

Using Server app, we first need to enable viewing of System Accounts, this can be done by clicking on the View > Show System Accounts in the menu bar. Select Groups in the Server app's sidebar. Then select "Local Groups" and scroll down and double click com.apple.access_radius. Add the same test user you used in the radtest command earlier.

See the screenshot below.

Run our radtest again. Notice the difference now in radiusd's debug output.

[opendirectory] The host 127.0.0.1 does not have an access group.
[opendirectory] User raduser1 exists in OD
[opendirectory] User raduser1 is a member of the RADUIS SACL

In our example, raduser1 is granted access due to being part the com.apple.access_radius group and as such is authorised to use the RADIUS service .

You can now stop radiusd and set it to run as per usual:

launchctl -load -w /System/Library/LaunchDaemons/org.freeradius.radiusd.plist

There you have it. Now we have a working RADIUS server with a way to control who has access by adding/removing users as needed from the com.apple.access_radius group.

A more neat solution would be to create a new Network Group called "Wifi Access" or something similar, then adding this group to our com.apple.access_radius SACL. That way we can hide the System Accounts and add/remove users as per normal to "Wifi Access" instead.

Configure RADIUS on OS X Moutain Lion 10.8

Apple’s OS X Server has always been capable of running as a RADIUS server for as long as I care to remember. The now defunct Server Admin was able to target Apple’s Airport Extreme and Time Capsule, enabling them to create WPA2/WPA Enterprise Wifi networks. 

The underlying technology back then and still is freeRADIUS. 

Today however, there are no more tools available other than Server app, which if your Apple base station is configured in a certain way, will show up in the sidebar of Server app.  Setting up RADIUS is now a mere checkbox and requires an Apple base station if you want to enable RADIUS via a GUI. 

Perhaps you don’t have an Apple base station and/or would like to set up RADIUS for another type of Wifi access point. Fear not there is hope! You just have to delve into command line to get things done. 

This guide assumes you have OS X 10.8.3 installed with Server app, Open Directory configured and have a WPAx Enterprise capable Wifi access point with an IP address of 192.168.1.1

There are a few steps to complete.

  • Add a Network Access Server (NAS)
  • Configure certificates
  • Configure Wifi Access Point

Add a Network Access Server (NAS)

Open up the Terminal app and enter a root shell by running sudo -s and entering your admin password.

Add your NAS device as follow. Note: After running the command you’ll be prompted enter a shared secret, ideally this should be a strong password.

radiusconfig -addclient 192.168.1.1 ZyXEL

You can double check that it was added correctly by running this:

radiusconfig -naslist

Configuring Certificates

For this exercise we will make use of a default SSL certificate that can be found in /etc/certificates, called Server Fallback SSL Certificate.

Installing the certificate is done by running radiusconfig -installcerts <private-key> <certificate> <trusted-ca>. Your certificates will have a different name. Just follow my example and replace certname in each of the three paths with your certificate's name in the command below.

radiusconfig -installcerts /etc/certificates/certname.key.pem /etc/certificates/certname.cert.pem /etc/certificates/certname.chain.pem

As we are using a certificates generated via Certificate Assistant, we need to make a tiny adjustment to the eap.conf file in /etc/raddb. To do this we use the following command.

radiusconfig -setconfig private_key_password Apple:UseCertAdmin

For interest sake, all this does is change the eap.conf file as per the before/after screenshot below.

At this point you server is ready to go, test it by running radiusd in debug mode:

radiusd -sfX

This will run your server in debug mode for testing purposes. If all is well, the last line will say “Ready to process requests.”

Configure Wifi Access Point

We still have to configure our Wifi access point though. How you do this will vary from device to device, I will just provide a guideline here of what it looks like on a ZyXEL router’s Wifi configuration.

Once completed, try connecting to your new WPAx Enterprise wifi network and look at the debug output of radiusd. You should see some output saying “Sending Access-Accept of id.....” That indicates that the client was accepted and is connected.

Hit Ctrl+C to stop the server.

Finally have radiusd launch persistently.

launchctl load -w /System/Library/LaunchDaemons/org.freeradius.radiusd.plist

Exit your root shell.

You now have a very basic RADIUS server running on OS X Mountain Lion!

In a follow up post I will detail a bit more about logging and the SACL that can be implemented on top of our existing RADIUS server.

Configuring DHCP in Mountain Lion Server

Apple made a somewhat confusing decision with OS X Mountain Lion Server by not creating a interface from which DHCP can be configured. In previous iterations of OS X Server, DHCP could be configured via Server Admin, now also 6 feet under. Personally I see no reason why Server app in Mountain Lion can't have a DHCP section, fortunately all is not lost, just a tad more complicated now! According to Apple's knowledge base, DHCP is still around, but you're directed to check out the man page for 'bootpd', thus DHCP is now configurable via CLI (command line interface) only. The exceptions to this rule: Enabling the NetInstall service or enabling Internet Sharing will still activate DHCP, but you have no control over it, unless you go dig around in CLI.

It's a bit more time consuming to create a config from scratch every time, so I decided to put together a template for future use. The template follows the structure in the man page for 'bootpd'.

Whats involved in creating a configuration? Just the following three files.

  • /etc/bootpd.plist (main configuration)
  • /etc/bootptab (static/reserved IP table)
  • /System/Library/LaunchDaemons/bootps.plist

We'll work these three files through from the top.

bootpd.plist Configuration

As per the man page, this file is an XML property list (plist). At the root of the plist is a dictionary which contain three main configuration areas. They are: Service Controls & Filters, Subnets & Netboot. I've structured my template according to these three areas in that order, so its easy to reference along with the man page should you add more advanced functionality to the file.

You can grab the correctly formatted and complete plist on Github.

I'll be using some sections from the plist and discuss them accordingly.

Looking at the root of the XML dictionary, we have Service Controls & Filters. Essentially this is where you enable/disable functionality of 'bootpd'. In this example, of the 4 main service controls, only DHCP is enabled on en0 (ignore the orange line, we're getting to that), the rest is disabled and denoted by the <false/> boolean values. No filters are specified here, such as denying DHCP for certain MAC addresses. Should you wish to add an additional interface you would simply add another string line such as the one in orange, inside the array. Alternatively, instead of using an array, simply specify <true/>, right below <key>dhcp_enabled</key>, which will enable for all interfaces.

<dict> <key>bootp_enabled</key> <false/> <key>dhcp_enabled</key> <array> <string>en0</string> <string>en1</string> </array> <key>netboot_enabled</key> <false/> <key>relay_enabled</key> <false/>

Subnets

Here we specify everything about the DHCP subnet and what information it will hand out to our clients. The keys we use are fairly self-explanatory. Only thing to note is that Subnets has its own dictionary in the XML plist that contains the subnet info. Service Controls & Filters were in the root dictionary. Read the man page for info on each key.

<key>Subnets</key> <array> <dict> <key>name</key> <string>192.168.5.0/24</string> <key>net_mask</key> <string>255.255.255.0</string> <key>net_address</key> <string>192.168.5.0</string> <key>net_range</key> <array> <string>192.168.5.2</string> <string>192.168.5.254</string> </array> <key>allocate</key> <true/> <key>lease_max</key> <integer>3600</integer> <key>dhcp_router</key> <string>192.168.5.1</string> <key>dhcp_domain_name_server</key> <array> <string>192.168.5.1</string> </array> <key>dhcp_domain_search</key> <array> <string>revolvingsq.net</string> </array> </dict>

bootptab Configuration

This file is used to reserve IPs for hosts based on MAC addresses and follows a very simple format, to get more info just type man bootptab in Terminal.

#
# bootptab for My Client
# %%
# Reservations have the following format:
#
#hostname    hwtype    hwaddr                           ipaddr
# iMac               1          00:00:74:85:53:85          192.168.5.10

Mixing everything together

Once you have configured the bootpd.plist and bootptab (optional), we have to fire up the bootpd daemon. To do this this we will run the following command:

sudo launchctl load -w /System/Library/LaunchDaemons/bootps.plist

To stop the daemon, change "load" to "unload".

To monitor what is happening, follow the system.log in either Console or in Terminal type (grep to limit output to bootpd only): tail -f /var/log/system.log | grep bootpd

Run at Startup

In order for bootpd to load at startup, you have to edit /System/Libary/LaunchDaemons/bootps.plist and make the following change: The text in orange is by default "true", simply change this to "false" and the daemon will launch at startup.

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Disabled</key> <false/>

Troubleshooting

Should things not go quite according to plan, you can enable verbose mode for the bootpd daemon by editing the same file as above and adding the orange text in the array under the ProgramArguments key.

<key>ProgramArguments</key> <array> <string>/usr/libexec/bootpd</string> <string>-v</string> </array>

Should you be making changes to bootptab while the bootpd service is running, you can force it to reload the leases by sending a SIGHUP (-1) signal to the bootpd daemon.

sudo killall -1 bootpd

There you have it. All done!

ps. Most likely going to take more time reading this post than actually setting DHCP up :)