I like free, so I like TACACS+

Yes, I still like free stuff, even though I’m turning into a bit of a Mac fanboy. Ubuntu and I remain very close, just not as my daily (desktop) driver.

I am leaning on Ubuntu as my new server platform at work, however, since it’s so much easier to count on than CentOS. And as I wrote last, TACACS+ authentication for network device administration is one of my current projects.

There are several pieces to that project,

  • setting up two servers
  • configuring them the same
  • configuring TACACS+ user accounts that can’t login to the server
  • sync-ing the TACACS+ user accounts between servers, with one as primary
  • sync-ing the TACACS+ config file between servers

but this post is only going to focus on getting TACACS+ installed on Ubuntu 11.10 server (64-bit) and the configuration file. In a later post, we’ll take a look at IOS, ASA, and NX OS configurations for AAA that I’ve found to work well. As always, “your mileage may vary”, but I’d love to know of any tricks or tips others might have. I’m definitely not claiming to have invented this stuff.

On to the installation!

With Ubuntu 11.10, the command line installation process is extremely complicated:

[email protected]:~$ sudo aptitude install tacacs+

Ubuntu will install any required dependencies and will create a sample config file, /etc/tacacs+/tac_plus.conf. Generally speaking, I like to copy the original config file for safe keeping before I make any changes to it, so let’s do that before we move on.

[email protected]:~$ sudo cp /etc/tacacs+/tac_plus.conf /etc/tacacs+/tac_plus.conf.orig

Whew! It felt good to be so responsible!

It’s also important to know that many Ubuntu servers/services have “config” files in /etc/default that set values or start-up parameters, so if we take a look there, we see that a file does exist for TACACS+ and it states which config file to use when the service starts:

[email protected]:~$ more /etc/default/tacacs+
# This is the configuration file for /etc/init.d/tacacs+
# You can overwrite default arguments passed to the daemon here.
# See man(8) tac_plus

DAEMON_OPTS="-C /etc/tacacs+/tac_plus.conf"
[email protected]:~$

The default config file location is good with me, so I’ll leave that file as it is. It’s also important to know that root is the only user who can do anything with the TACACS+ config file, which is a critical part of securing this service.

[email protected]:~$ ls -la /etc/tacacs+/
total 16
drwxr-xr-x 2 root root 4096 2012-01-18 14:25 .
drwxr-xr-x 83 root root 4096 2012-02-05 23:19 ..
-rw------- 1 root root 3348 2012-02-05 23:12 tac_plus.conf
-rw------- 1 root root 1413 2012-01-18 14:25 tac_plus.conf.orig
[email protected]:~$

My goal, when configuring these servers, is to have user accounts that are local Linux accounts–so all user accounts can be administered in one place–but I don’t want those Linux users to be able to login to the server locally or via ssh. The config file below reflects Linux accounts, though you should note that it’s possible to create user accounts in a separate config file, that are not Linux user accounts. That wasn’t a part of my plan, so I’m not going to cover it.

Here’s my config file:

# Created by Henry-Nicolas Tourneur([email protected])
# See man(5) tac_plus.conf for more details

# Define where to log accounting data, this is the default.
#
accounting file = /var/log/tac_plus_acct.log

# This is the key that clients have to use to access Tacacs+
#
key = your_secret_key_here

# Use /etc/passwd file to do authentication
#    
default authentication = file /etc/passwd

#
# ACLs that may be used to restrict users' access to certain hosts
#
acl = switch01_users_acl {
        # allow access to only one device, switch01
        permit = 10.10.10.10                
}

#
# These tacacs+ user groups are not actually tied to the local
# Linux groups, but we'll use the same names here.
#
#
# "level 3" users, with no restrictions
#
group = l3_tacacs_users {
        default service = permit
        login = file /etc/passwd
        enable = file /etc/passwd
        service = exec {
                priv-lvl = 15
                }
}

#
# "level 2" users who cannot "debug" or "config"
#
group = l2_tacacs_users {
        default service = permit
        login = file /etc/passwd
        enable = file /etc/passwd
        service = exec {
                priv-lvl = 15
                }
        cmd = configure {
                deny "."
                }
        cmd = debug {
                deny "."
                }
}

#
# "level 1" users permitted to "show", "ping", "telnet",
# "exit", and "quit"
#
group = l1_tacacs_users {
        default service = deny
        login = file /etc/passwd
        enable = file /etc/passwd
        service = exec {
                priv-lvl = 15
                }
        cmd = show {
                permit "."
        }
        cmd = ping {
                permit "."
        }
        cmd = telnet {
                permit "."
        }
        cmd = exit {
                permit "^(<cr>)?$"
        }
        cmd = quit {
                permit "^(<cr>)?$"
        }
}

#
# Users outside of Net-Ops group, probably restricted to specific hosts
# and specific commands.
#
group = switch01_users {
        default service = permit                  
        login = file /etc/passwd
        enable = file /etc/passwd
        service = exec {
                priv-lvl = 15
                }
        cmd = show {
                permit "."
        }
        cmd = ping {
                permit "."
        }
        cmd = exit {
                permit "^(<cr>)?$"
        }
        cmd = quit {
                permit "^(<cr>)?$"
        }
        acl = switch01_users_acl
}

#
# Assign Linux users to tacacs+ groups
#
user = dave {
        member = l3_tacacs_users
}

user = simon {
        member = l2_tacacs_users
}

user = theodore {
        member = l1_tacacs_users
}

user = alvin {
        member = switch01_users
}

# You can use feature like per host key with different enable passwords
#host = 127.0.0.1 {
#        key = test 
#        type = cisco
#        enable = <des|cleartext> enablepass
#        prompt = "Welcome XXX ISP Access Router \n\nUsername:"
#}

# We also can define local users and specify a file where data is stored.
# That file may be filled using tac_pwd
#user = test1 {
#    name = "Test User"
#    member = staff
#    login = file /etc/tacacs/tacacs_passwords
#}

# We can also specify rules valid per group of users.
#group = group1 {
#       cmd = conf {
#               deny
#       }
#}

# Another example : forbid configure command for some hosts
# for a define range of clients
#group = group1 {
#       login = PAM
#       service = ppp
#       protocol = ip {
#               addr = 10.10.0.0/24
#       }
#       cmd = conf {
#               deny .*
#       }
#}

user = DEFAULT {
        login = PAM
        service = ppp protocol = ip {}
}

# Much more features are available, like ACL, more service compatibilities,
# commands authorization, scripting authorization.
# See the man page for those features.

If you read through the comments, you can get a pretty good idea of what my goals are:

  • modularity
  • at least 4 levels of user–level-3, level-2, level-1, and special cases
  • use the local Linux user database, rather than another config file with either clear-text passwords, or passwords I’d have to encrypt with tac_pwd

Though I’m not 100% positive, I believe that they order of the sections is very important. During my testing with ACLs, it seemed that ACLs had to come first, then groups, then users. I also didn’t have any luck with not assigning a user to a group and trying to assign an ACL to him.

This is a working config, though, tested on real Cisco equipment–IOS, ASA, and NX OS. And it’s free. Well, you do have to have internet access to read it, so not completely free, unless you’ve hacked your neighbor’s wireless, though you didn’t learn that from me.