This article is about the TAC_PLUS-NG server software. A free server implementation for the TACACS+ protocol. Availble for linux, and BSD/UNIX operating systems. Author is Marc Huber.

The TAC_PLUS-NG server server is ran using a simple configuration (for authenticacion only), and uses system availble cryptographic libraries:

  • Blowfish
  • SHA-512
  • SHA-256
  • MD5
  • 3DES

Without the need for installation and configuration of additional cryptographic software, libraries, or any other software dependencies. It is achived using configuration options available in TAC_PLUS-NG and the standard OS options.

There are 2 existing open-source TACACS+ protocol server implementations available:

The Pro-Bono-Publico software offers 2 different TAC_PLUS daemon implementations out of the box. Mentioning this since perhaps while reading the documentation for the first time, it is easy overlooked and leads to confusion while working on TACACS+. No matter which implementation is used.

According to the manual official documentation, TAC_PLUS-NG is the more advanced of both implementations. Meaning, more features, and more recent code. TAC_PLUS implementation has been deprecated in favour of TAC_PLUS-NG.

📘 Note
Do NOT use TAC_PLUS for new installations. TAC_PLUS has been deprecated

Brief overview over the actual state of the TACACS+ protocol and its recent 25 years of history:

The TACACS+ protocol has never really been officially published and standardised. But it is the de facto standard for handling AAA requests from networking equipment. If you are interested in sound engineering, there is something very similar to the TACACS+ protocol. The Yamaha NS-10 speakers, black box with white membrane. These speakers, NS-10, are the de facto standard near-field speakers for professional audio editing engineering sound-mixing too.

The RFC8907 states, that the TACACS+ protocol has been widely deployed based mainly on a simple DRAFT document only. That TACACS+ draft document here is from 1997 called THE_DRAFT. It has never been officially "released". In September 2020 the first, real informational RFC appeared has been published. This literally means, all implementations out there are written based on a DRAFT only document.

TAC_PLUS-NG supports additionally following non-standard implementation. According to the documentation, this is operating code, already used in productive networks.

  • SSH Public Key Authentication
  • SSH Certificate Authentication.

If the both NON-STANDARD implementations prove stable and operational success, it might end up in a RFC. At least this is the aim and has good chance to get that far. Especially then, when it is already used by customer groups, and there is no other implementation available at the market. At least not a free one. The commercial AAA daemons available, will have their own, proprietary Key/Certificate AAA solution. But that mostly does not end up in a RFC draft if the company is not big enough. These are not part of this simple netlab.

Alpinelinux has published a tacacs+ng community package, a binary, at the beginning of this year. It is available in the community package repostiory. Using the binary version, the following Installation part can be skipped.

Installation

git clone the source and build it on the target node (here AAA server). Install. For the official build instructions follow the Mini-HowTo: Integrating TACACS+ (NG) with ActiveDirectory. The first steps 1 - 3. right at the top, skipping the AD part completely.

user % git clone https://github.com/MarcJHuber/event-driven-servers.git event-driven-servers.git
user % cd event-driven-servers.git
user % ./configure --help

The most basic TAC_PLUS-NG software configuration, without any additional dependencies to external applications, like f.e. LDAP, RADIUS.

  • --minimum
  • tac_plus
  • mavis
  • spawnd

For the netlab following, minimal configuration options are needed: ./configure --minimum tac_plus mavis spawnd to build the software. The mavis module is not needed; it will be used in following articles:

user % ./configure --minimum tac_plus-ng mavis spawnd

After the configuration options have been set, build the software using the make command:

user % make

The default installation path is set to /usr/local/. This is good, notifying me these are binaries out of the portage tree, installed using this manual building method.

root # make install

The software is installed. If you wonder about the deamon or systemd unit starup file. This is not needed here. The tac_plus-ng daemon will be run in interactive mode in the shell, not started as system daemon.

Configuration

Configuration examples shown are for Authentication only. Authorization and Authentication is not configured.

The most basic tac_plus-ng configuration consists of following, mandatory parts:

  • spawnd: IP address family; port
  • tac_plus-ng:
    • host profile
      • source address or better source network of incoming requests
      • key TACACS
    • profile template profile netadmin
    • group template group admin
    • user credentials
      • authentication type
      • group membership
    • ruleset
📗 Hint
Testing works without having root on the system. Change the TACACS+ port from the system default 49 setting, to some a TCP port in the range of x > 1024 f.e. 4949.

Authentication options

The configuration examples shown below are for the tac_plus-ng implementation only.

Using TAC_PLUS-NG and TAC_PLUS (Shrubbery Implementation) it is possible to use linux system encryption methods to save the hashed password.

Configuration examples presented below use following encryption:

  • Blowfish
  • SHA-512
  • SHA-256
  • MD5
  • 3DES
  • Plaintext (not encrypted)

To verify which of the above presented algorithms are supported by the currently used linux distirbution read man 3 crypt on the local system, where TAC_PLUS-NG is supposed to run as a AAA daemon. The Blowfish encryption is not granted to be always available or operating, according to the manpages. In the terms of trying things out, running configurations in a netlab environment, I would suggest trying all displayed configurations.

Take notice about its prefix crypt compared with configuration above. this is a function for calling the system lib crypto library. More details seem man 3 crypt. This lists the encryption algorithms available to your current linux operating system. Well back to the configuration:

Plaintext password

This is the most basic, functional, configuration of TAC_PLUS-NG. Less configuration is not possible without losing generic function. This configuration is intended to be starting point, for adding furhter configuration options This is the most simple and basic tac_plus-ng configuration using plain password.

Following the first example in the official TAC_PLUS-NG

This is a plain password configuration example:

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n  Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = clear cisco
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }
}

From here on.as soon as the most basic authentication method is verified using clear, the configuration is easy to expand.

Blowfish hash

This example is using the Blowfish password encryption algorithm.

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = crypt $2a$10$34.ioPXaLJDD.PdEk.4Mle3g0cQw8e16thH1g0nQEC1.jW.sEHi1S
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }
}

If then target platform/OS does not support Blowfish encryption, use the next example's SHA-512 encryption.

SHA-512 hash

SHA-512 is supported on all linux distributions. This works on all platforms:

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = crypt $6$ftVsx3AbgE0hp7Qf$vw8PS995n9Z6es2jfnTB9r09KYEhbnxHvkpX3xzB1gnpCiwPmfGDUJBBR.3iys8b.DRPbTyAfWXt0Cdh8f4xY1
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }
}

SHA-256 hash

This configuration shown is identical to the clear password example, except the password is a hash, SHA-256 hash.

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = crypt $5$4SHZUEdXAeJT$E.6/SNih4a/VkLs5yguDsqJA0mv3DjriQ850nQaJjd3
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }

}

MD5 hash

This configuration is identical to the above, except the password is a hash, MD5 hash.

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = crypt $1$.okxg.0B$eiXZX6K38gA8IFmgMr.Gy1
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }
}

3DES hash

This is the example using the 3DES hash.

#!/usr/local/sbin/tac_plus-ng
id = spawnd {
    listen = { address = 0.0.0.0 port = 4949 }
}

id = tac_plus-ng {
    host IPv4only {
        address = 0.0.0.0/0
            welcome banner = "\n Welcome to TACACS+NG\n\n"
            key = 123-my_tacacs_key
    }

    profile netadmin {
        script {
            if (service == shell) {
                    if (cmd == "") {
                        set priv-lvl = 15
                        permit
                }
            }
        }
    }

    group admin

    user cisco {
        password login = crypt IOxJZZGow3nhc
        member = admin
    }

    ruleset {
        rule {
            script {
                if (member == admin) { profile = netadmin permit }
            }
        }
    }
}

Verify Configuration

Before starting the daemon verify the configuration is valid. To sanitize or verify the actually used configuration is using valid syntax and runs run tac_plus in the command line, it will display the availble running options:

tac_plus
Usage: tac_plus-ng [ <Options> ] <configuration file> [ <id> ]

Options:
-P                parse configuration file, then quit
-1                enable single-process ("degraded") mode
-v                show version, then quit
-b                force going to background
-f                force staying in foreground
-i <child-id>     select child configuration id
-I <spawnd-id>    select spawnd configuration id
-p <pid-file>     write master process ID to the file specified
-d <debug-level>  set debugging level

Version: 2421e29b7a50ae6a21b47a133d04f57960591d96/PCRE2

Copyright (C) 1996-2023 by Marc Huber <Marc.Huber@web.de>
Portions Copyright (C) 1995-1998 by Cisco Systems, Inc.

Home site:  https://www.pro-bono-publico.de/projects/
Soure code: https://github.com/MarcJHuber/event-driven-servers/

Using the shown help the resulting command line will be following:

user % tac_plus -P tac_plus-ng.cfg

If the configuration is valid, no output will be generated. NO news is GOOD news. It just quits.

Running tac_plus-ng

To run tac_plus-ng in interactive mode, as a regular linux/UNIX system user, use HAVE TO configure it to bind its TCP/IP socket to the a port > 1024.

This runs as a regular system user, interactively on port 4949. Not the standard, IANA assigned system port 49. Verification using grep -i taca /etc/services.

user % grep -i taca /etc/services

tacacs 49/tcp # Login Host Protocol (TACACS) tacacs 49/udp ...

Run this using following command, this will run silently:

user % tac_plus-ng -f tac_plus-ng.cfg

To see interaction between the communicating participants use the -d debug mode. Here it is ran using the authentication debugging. The debug output looks like depicted below:

user % tac_plus-ng -f tac_plus-ng.cfg -d 4

13050: 12:43:00.300 0/00000000: - Version 2421e29b7a50ae6a21b47a133d04f57960591d96 initialized 13049: 12:43:00.300 0/00000000: - Version 2421e29b7a50ae6a21b47a133d04f57960591d96 initialized 13049: 12:43:03.493 0/50982dc9: 10.100.100.101 authen: hdr->seq_no: 1 13049: 12:43:04.859 0/50982dc9: 10.100.100.101 authen: hdr->seq_no: 3 13049: 12:43:04.859 0/50982dc9: 10.100.100.101 looking for user cisco realm default 13049: 12:43:04.859 0/50982dc9: 10.100.100.101 user lookup succeded 13049: 12:43:06.618 0/50982dc9: 10.100.100.101 authen: hdr->seq_no: 5 13049: 12:43:06.618 0/50982dc9: 10.100.100.101 looking for user cisco realm default 13049: 12:43:06.618 0/50982dc9: 10.100.100.101 user lookup succeded 13049: 12:43:06.618 0/50982dc9: 10.100.100.101 shell login for 'cisco' from 10.100.100.10 on tty2 succeeded (profile=netadmin)

The router used in setup is a Cisco IOS router. The authentication configuration for IOS in the official documentation at 4.2.3.20. Configuring Authentication on the NAS.

Summary

The configuration examples show how to configure TAC_PLUS-NG to use the operating systems encryption capabilities, using the crypt keyword. This is nothing new. All available open source implementations of TACACS+ server, support running in this mode, or configuration option mentioned here.

The official documentation of TAC_PLUS-NG focuses on the advanced AAA options using additional protocols like LDAP and RADIUS and Microsoft AD (proprietary LDAP), implementing a broker etc. Eventually also because of that reason, focusing on the advanced topic the simple configurations are not its focus.

This is a try to fill the missing documentation gap, focusing on the most simple authentication using TAC_PLUS-NG. Much like Mr. Alan McKinnon has written over a decade ago on the Shrubbery Mailing list:

[...] Many folks don't seem to know how tac_plus uses hashes, so a quick summary is probably in order:

tac_plus uses the crypt() library in the underlying operating system and asks it to hash a given password against the hash in tac_plus.conf. This will of course either succeed or fail. As such, you can transparently put any hash value you like in tac_plus.conf as long as crypt() supports it and it will JustWork(tm).

On most modern Linuxes these days blowfish, sha-256 and sha-512 are supported out of the box. One just needs to read man 3 crypt to find the methods supported and man openssl to find the option switches to generate those hashes. [...]

For advanced setups use the official documentation, ask in the official mailing list of Event-Driven-Servers.

References