• Skip to main content
  • Skip to footer

NetworkJutsu

Networking & Security Services | San Francisco Bay Area

  • Blog
  • Services
  • Testimonials
  • About
    • About Us
    • Terms of Use
    • Privacy Policy
  • Contact Us

Security

Securing Cisco ASA SSH server

07/15/2018 By Andrew Roderos Leave a Comment

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Last year, I wrote a post about securing the Cisco IOS SSH server. It also makes sense to create one for Cisco ASA especially when my old post about enabling SSH on Cisco ASA was back in 2012. That blog post didn’t include the advanced configurations that will improve the security of the Cisco ASA SSH server. With this post, I’d like to share the minimum advanced SSH configurations that network engineers should consider adding to their ASA template.

Enabling Cisco ASA SSH server

Before we can connect to our Cisco ASA via SSH, we need to have a checklist of things we need to configure.

  1. While it’s a good idea to have enable password configured, it is optional for SSH.
  2. You must have at least one user account locally.
  3. Configure ASA’s authentication method. The authentication method can be local, RADIUS, or TACACS+.
  4. Generate RSA key pair.
  5. Configure ACL to allow a specific IP address or range(s).

Setting enable password

My old post covered how to set enable password. It’s the same command on how to set the enable password, but in the newer ASA software, it uses PBKDF2 to encrypt the password compared to the MD5-based hash in older ASA software.

ASA5506(config)# enable password strongpasswordhere
ASA5506(config)# sh run | i enable password
enable password $sha512$5000$XEBAb1W7gNRdaxFbPHiF6A==$NlSiKyjZpreT3hbRL9gBsg== pbkdf2

Generating RSA keys

As covered in my old post, to enable SSH on the ASA, we’ll need to generate RSA key pair first. Current NIST recommendation is to use 2048-bit or above. In this post, I am going to use 4096-bit key pair.

ASA5506(config)# crypto key generate rsa modulus 4096

SSH Version

Configuring the Cisco ASA SSH server to accept only version 2 is best practice. The reason for this is because SSHv1 has vulnerabilities. That said, make sure to add this to your ASA template.

ASA5506# show ssh 
Idle Timeout: 10 minutes Versions allowed: 1 and 2 
<-- Output omitted --> 
ASA5506# config t 
ASA5506(config)# ssh version 2 
ASA5506(config)# show ssh 
Idle Timeout: 10 minutes Version allowed: 2 
<-- Output omitted -->

SSH Encryption Algorithms

By default, it seems that the ASA’s encryption algorithm is configured to use the medium settings. Unfortunately, I cannot seem to verify it using the show run all command. However, the combination of show ssh and show ssh ciphers does the trick.

ASA5506# show ssh
Idle Timeout: 10 minutes
Versions allowed: 2
Cipher encryption algorithms enabled:	 aes128-cbc   aes192-cbc   aes256-cbc   aes128-ctr   aes192-ctr   aes256-ctr
<-- Output omitted -->
ASA5506# show ssh ciphers
Available SSH Encryption and Integrity Algorithms
Encryption Algorithms:
	all:	 3des-cbc     aes128-cbc   aes192-cbc   aes256-cbc   aes128-ctr   aes192-ctr   aes256-ctr
	low:	 3des-cbc     aes128-cbc   aes192-cbc   aes256-cbc   aes128-ctr   aes192-ctr   aes256-ctr
	medium:	 aes128-cbc   aes192-cbc   aes256-cbc   aes128-ctr   aes192-ctr   aes256-ctr
	fips:	 aes128-cbc   aes256-cbc
	high:	 aes256-cbc   aes256-ctr
<-- Output omitted -->

The client and server negotiate the encryption algorithm. That said, it is possible that the client would pick a weaker cipher. To avoid that, we’re going to specify the use of a safer cipher. According to this thread, the use of EAX or GCM is preferable when available. If not, the use CTR over CBC mode. By specifying the encryption algorithm, we’re telling ASA to only offer the AES-256-CTR mode to any clients that try to connect to it.

Here’s the verbose output of my SSH to a Cisco ASA using the default SSH cipher encryption.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug2: ciphers ctos: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
debug2: ciphers stoc: aes128-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr
<-- Output omitted -->

Let’s configure the ASA to only use AES256 CTR mode.

A5506(config)# ssh cipher encryption custom aes256-ctr ASA5506(config)# show ssh Idle Timeout: 10 minutes Version allowed: 2 Cipher encryption algorithms enabled:  aes256-ctr Cipher integrity  algorithms enabled:  hmac-sha1    hmac-sha1-96

Here’s the verbose output of my SSH connection to a Cisco ASA device using the SSH cipher encryption configuration mentioned above.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug2: ciphers ctos: aes256-ctr
debug2: ciphers stoc: aes256-ctr
<-- Output omitted -->

SSH Integrity Algorithm

By default, it seems that the ASA’s integrity algorithm is configured to use the medium settings. Unfortunately, I cannot seem to verify it using the show run all command. However, the combination of show ssh and show ssh ciphers does the trick.

ASA5506# show ssh
Idle Timeout: 10 minutes
Version allowed: 2
Cipher encryption algorithms enabled:	 aes256-ctr
Cipher integrity  algorithms enabled:	 hmac-sha1    hmac-sha1-96
<-- Output omitted -->
ASA5506# show ssh ciphers
Available SSH Encryption and Integrity Algorithms
<-- Output omitted -->
Integrity Algorithms:
	all:	 hmac-sha1    hmac-sha1-96 hmac-md5     hmac-md5-96
	low:	 hmac-sha1    hmac-sha1-96 hmac-md5     hmac-md5-96
	medium:	 hmac-sha1    hmac-sha1-96
	fips:	 hmac-sha1
	high:	 hmac-sha1

The default setting for the ASA SSH integrity algorithm is medium. Which means, it will accept both HMAC-SHA1 and HMAC-SHA1-96. The difference between the two algorithms is the digest length. The HMAC-SHA1-96 is a truncated message digest. From my limited understanding, the HMAC-SHA1-96 is the weakened version of HMAC-SHA1 due to the shortened message digest.

Here’s the verbose output of my SSH to a Cisco ASA using the default SSH integrity algorithm.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug2: MACs ctos: hmac-sha1,hmac-sha1-96
debug2: MACs stoc: hmac-sha1,hmac-sha1-96
<-- Output omitted -->

Let’s configure the ASA to only use HMAC-SHA1.

ASA5506(config)# ssh cipher integrity custom aes256-ctr
ASA5506(config)# show ssh
Idle Timeout: 10 minutes
Version allowed: 2
Cipher encryption algorithms enabled:	 aes256-ctr
Cipher integrity  algorithms enabled:	 hmac-sha1

Here’s the verbose output of my SSH connection to a Cisco ASA device using the SSH integrity algorithm configuration mentioned above.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug2: MACs ctos: hmac-sha1,hmac-sha1-96
debug2: MACs stoc: hmac-sha1,hmac-sha1-96
<-- Output omitted -->

SSH Key Exchange

The ASA support two Diffie-Hellman key exchange methods and these are DH Group 1 (768-bit) and DH Group 14 (2048-bit). By default, the ASA is set to use Diffie-Hellman Group 1. Unfortunately, this is below what NIST recommends to use in this day and age.

Here’s a Cisco ASA with default SSH key exchange configuration. I issued the no ssh key-exchange to be sure.

ASA5506(config)# no ssh key-exchange
ASA5506(config)# sh run all | i ssh key-exchange
ssh key-exchange group dh-group1-sha1

Here’s the verbose output of my SSH connection to a Cisco ASA using the default SSH key exchange.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug1: kex: algorithm: diffie-hellman-group1-sha1
debug1: kex: host key algorithm: ssh-rsa
debug1: kex: server->client cipher: aes256-ctr MAC: hmac-sha1 compression: none
debug1: kex: client->server cipher: aes256-ctr MAC: hmac-sha1 compression: none
<-- Output omitted -->

Let’s configure the ASA to use DH Group 14.

ASA5506(config)# ssh key-exchange group dh-group14-sha1

Here’s the verbose output of my SSH connection to the Cisco ASA after changing the key exchange method.

Mac-mini:~ networkjutsu$ ssh -vvv ASA5506
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted -->
debug1: kex: algorithm: diffie-hellman-group14-sha1
debug1: kex: host key algorithm: ssh-rsa
debug1: kex: server->client cipher: aes256-ctr MAC: hmac-sha1 compression: none
debug1: kex: client->server cipher: aes256-ctr MAC: hmac-sha1 compression: none
<-- Output omitted -->

SSH ACL

Restricting remote management to a certain IP address is a best practice. It is also required to add the ACL, or we won’t be able to access the Cisco ASA via SSH. That said, I included the command here.

ssh 192.168.1.0 255.255.255.0 management

Final Words

All of the configurations covered here are what I’d say minimum security standard for all Cisco ASA devices. It is, after all, a network security device, so it is a must to secure it properly. Though this post is just a small part of protecting the management plane and network engineers must incorporate other security configurations.

Are you ready to improve your network security?

Let us answer more questions by contacting us. We’re here to listen and provide solutions that are right for you.

ENGAGE US

NetworkJutsu provides networking and network security consulting services for startups, a more established small and medium-sized business (SMB), or large business throughout the San Francisco Bay Area.

Want to learn more about ASA?

Cisco ASA: All-in-one Next-Generation Firewall, IPS, and VPN Services (3rd Edition)
Cisco ASA for Accidental Administrators: An Illustrated Step-by-Step ASA Learning and Configuration Guide

Disclosure

NetworkJutsu.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

FreeRADIUS 3.0 with Two-Factor Authentication (2FA)

06/01/2018 By Andrew Roderos 13 Comments

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Last year, I talked about migrating my FreeRADIUS server with two-factor authentication (2FA) to a Docker container. Today, I will cover how to configure FreeRADIUS 3.0 with two-factor authentication using Google Authenticator in a Docker container with Ubuntu 18.04 image.

Related: What is multi-factor authentication (MFA)?

The new version of Ubuntu Server LTS edition (18.04 at this time of writing) changed the FreeRADIUS version from 2.x to 3.0. The change made my old post as invalid. With that said, I want to share my working configuration with you.

If you wish to learn more about FreeRADIUS, there is a book out there available for purchase. However, it is an older book, so you may need to do some more research. Though, one of the Amazon reviews mentioned that the difference between 2.x and 3.0 are minor so it may still be helpful.

Writing FreeRADIUS 3.0 Dockerfile

I am sure there are FreeRADIUS 3.0 Docker images out there, but I like to write my own as much as I can. By writing a Dockerfile, it helps me learn more about Linux and Docker. I do, however, recognize that I am running the Docker container as root. As I learn more about this, I will eventually write one that isn’t using root. If you decide to copy this Dockerfile, beware the security risks running root on your container.

Without further ado, below is my Dockerfile that I wrote that satisfies my needs.

# Use Base Ubuntu image
FROM ubuntu:18.04
# Author of this Dockerfile
MAINTAINER NetworkJutsu <networkjutsu.com>
# Update & upgrades
RUN apt-get update && apt-get dist-upgrade -y
# Install FreeRADIUS and Google Authenticator
RUN apt-get install freeradius libpam-google-authenticator -y
# Clear local repo
RUN apt-get clean
# Add user to container with home directory
RUN useradd -m -d /home/networkjutsu -s /bin/bash networkjutsu
# Add password to networkjutsu account
RUN echo 'networkjutsu:letsmakemypasswordgreatagain' | chpasswd
# Edit /etc/pam.d/radiusd file
RUN sed -i 's/@include/#@include/g' /etc/pam.d/radiusd
RUN echo "auth requisite pam_google_authenticator.so forward_pass secret=/etc/freeradius/3.0/networkjutsu/.google_authenticator user=freerad" >> /etc/pam.d/radiusd
RUN echo "auth required pam_unix.so use_first_pass" >> /etc/pam.d/radiusd
# Edit /etc/freeradius/3.0/mods-config/files/authorize file
# This is the real file for /etc/freeradius/3.0/users
RUN sed -i '1s/^/# Instruct FreeRADIUS to use PAM to authenticate users\n/' /etc/freeradius/3.0/mods-config/files/authorize
RUN sed -i '2s/^/DEFAULT Auth-Type := PAM\n/' /etc/freeradius/3.0/mods-config/files/authorize
# Copy existing /etc/freeradius/sites-available/default file to container
# This is the real file for /etc/freeradius/3.0/sites-enabled/default
COPY default /etc/freeradius/3.0/sites-available/default
# Change owner of the file to freerad
RUN chown freerad:freerad /etc/freeradius/3.0/sites-available/default
# Copy existing /etc/freeradius/clients.conf file to container
COPY clients.conf /etc/freeradius/3.0/clients.conf
# Copy existing .google_authenticator file to container
COPY .google_authenticator /home/networkjutsu
# Create a symbolic link
RUN ln -s /etc/freeradius/3.0/mods-available/pam /etc/freeradius/3.0/mods-enabled/pam
# Create a folder in /etc/freeradius equal to the user name
RUN mkdir /etc/freeradius/3.0/networkjutsu
# Change owner of the directory to freerad
RUN chown freerad:freerad /etc/freeradius/3.0/networkjutsu
# Copy .google_authenticator file to /etc/freeradius/networkjutsu
RUN cp /home/networkjutsu/.google_authenticator /etc/freeradius/3.0/networkjutsu
# Change owner to freerad
RUN chown freerad:freerad /etc/freeradius/3.0/networkjutsu/.google_authenticator
# Expose the port
EXPOSE 1812/udp 1813/udp 18120/udp
# Run FreeRADIUS as a foreground process
CMD ["freeradius","-f"]

FreeRADIUS changes in Ubuntu

If you compare my old post and this post, you could tell that the directories have changed from /etc/freeradius to /etc/freeradius/3.0. One of the reasons why my old post would not work in Ubuntu 18.04.

Another change is the /etc/freeradius/3.0/users file. It is now a symbolic link compared to a regular file in Ubuntu 16.04. That said, I had to edit the original file and not the symbolic link.

The last change, at least for my purposes, is the requirement to create a symbolic link for the /etc/freeradius/3.0/mods-available/pam file. We need this file to enable PAM, without it the two-factor authentication wouldn’t work.

FreeRADIUS configuration files

I copied a lot of configuration files to the container because it was much faster for me to do it in a text editor than trying to figure out the proper sed commands. I am still new to sed command so it will take me several minutes or hours to figure out a simple thing to do in VI editor. While it will help me learn more about it, I haven’t had much time on my hands lately.

Some of the configuration files may have changed contents as a result of the upgrade. However, my old post covered all the changes I’ve made to them. Well, you could say I revised /etc/freeradius/3.0/radiusd file. The revision was very minor. I only did it because I wanted to show how to edit files without using a text editor, like VI editor.

Final Words

The changes to FreeRADIUS in Ubuntu 18.04 is minor, at least for my purposes. However, if you decide to upgrade your host or edit the Dockerfile to use the latest Ubuntu version without making the changes covered here, then it will break your instance.

A few weeks ago, I made a mistake of just changing the FROM ubuntu:16.04 to FROM ubuntu:18.04 and broke my FreeRADIUS container. If the FreeRADIUS version didn’t change, upgrading the OS would’ve been easy and fast compared to a VM. One of the reasons why I like to use Docker container as much as possible.

With this FreeRADIUS container, you could point your devices to this server as your primary RADIUS server. Since this server also makes use of Google Authenticator, you gain two-factor authentication feature. I use this container for my remote access VPN at home and also pointing my networking devices that support RADIUS authentication.

Are you ready to improve your network security?

Let us answer more questions by contacting us. We’re here to listen and provide solutions that are right for you.

ENGAGE US

You might also like to read

Adding Two-Factor Authentication to FreeRADIUS
Securing SSH with Google Authenticator
Adding Two-Factor Authentication to TACACS+

Disclosure

NetworkJutsu.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Securing Cisco IOS SSH server

12/16/2017 By Andrew Roderos Leave a Comment

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Back in 2011, I wrote a post on how to enable SSH on Cisco routers and switches. Unfortunately, it didn’t contain any of the advanced configurations that will harden Cisco IOS SSH server. To be fair, there were older IOS software versions that didn’t include advanced SSH commands that I will cover here. With this post, I’d like to share at least the minimum advanced SSH configuration that network engineers should consider adding to their template.

SSH Encryption Algorithms

If you’re a macOS 10.13.2 user and you use it to connect to Cisco routers and switches, you may have seen this error message already.

Mac mini:~ networkjutsu$ ssh router01
Unable to negotiate with 192.168.100.200 port 22: no matching cipher found. Their offer: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc

The issue here is that OpenSSH has deprecated the weaker ciphers in the default SSH configuration of the newest version of macOS. Unfortunately, older Cisco IOS software uses AES 3DES-CBC for the SSH server, by default. Below is an example of a Cisco router running an older version of IOS which uses default SSH configuration.

router01>sh ssh
Connection Version Mode Encryption  Hmac	     State	               Username
0          2.0     IN   3des-cbc    hmac-sha1    Session started       networkjutsu
0          2.0     OUT  3des-cbc    hmac-sha1    Session started       networkjutsu
%No SSHv1 server connections running.

There are two options to get rid of the error message. One of the options is by configuring the client side to accept the legacy ciphers. The right course of action, in my opinion, is to change SSH server configurations. However, we still need to be able to connect to our Cisco IOS devices to correct the issue.

SSH client options

A quick fix here is to keep using compatible ciphers that the client would accept. There are three options that one could use for this workaround. Technically, they are all doing the same thing but just different approach.

Option #1

With this option, the user just needs to specify the cipher and KEX algorithms in the SSH command when connecting to an SSH server. One could create an alias to include all the necessary command flags for shorter keystrokes.

Mac mini:~ networkjutsu$ ssh -oKexAlgorithms=diffie-hellman-group1-sha1 -c 3des-cbc router01
Password:
router01>

Option #2

With this option, the user does not need to create an alias or type the whole command shown above. The .ssh/config file is a user-specific configuration file. OpenSSH receives its configuration from this file when the command issued doesn’t include command flags.

Mac mini:~ networkjutsu$ cat .ssh/config
# ***
# *** General settings (these apply to all connections)
# ***
HostkeyAlgorithms +ssh-dss
KexAlgorithms +diffie-hellman-group1-sha1
Ciphers +3des-cbc

Option #3

With this option, all users are affected by this configuration file. However, the command issued and user-specific configuration file take precedence over the global configuration file.

Mac mini:~ networkjutsu$ cat /etc/ssh/ssh_config
HostkeyAlgorithms +ssh-dss
KexAlgorithms +diffie-hellman-group1-sha1
Ciphers +3des-cbc

SSH server options

As mentioned earlier, the server side option is the correct course of action. However, one still needs to connect the Cisco IOS devices to fix the issue. That said, the SSH client workaround still plays an important role.

SSH encryption algorithm

The command shown below is used to change SSH encryption key algorithm used on a Cisco IOS device. If one gets an error message, then the command is not available in that IOS version.

router01(config)#ip ssh server algorithm encryption ?
  3des-cbc    Three-key 3DES in CBC mode
  aes128-cbc  AES with 128-bit key in CBC mode
  aes128-ctr  AES with 128-bit key in CTR mode
  aes192-cbc  AES with 192-bit key in CBC mode
  aes192-ctr  AES with 192-bit key in CTR mode
  aes256-cbc  AES with 256-bit key in CBC mode
  aes256-ctr  AES with 256-bit key in CTR mode
router01(config)#ip ssh server algorithm encryption aes256-ctr

In this particular IOS version, the SSH server supports the encryption algorithms: AES-CTR, AES-CBC, and 3DES. According to this thread, use EAX or GCM, if available. If not, the author said to use CTR over CBC mode. By specifying the encryption algorithm, we’re telling Cisco IOS to only offer the AES-256-CTR mode to any clients that try to connect to it.

Below shows the verbose output of a Cisco IOS device using default SSH configuration.

Mac mini:~ networkjutsu$ ssh -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug2: peer server KEXINIT proposal
debug2: ciphers ctos: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
debug2: ciphers stoc: aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc

Below shows the verbose output of a Cisco IOS device using the SSH configuration mentioned above.

Mac-mini:~ networkjutsu$ ss -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug2: peer server KEXINIT proposal
debug2: ciphers ctos: aes256-ctr
debug2: ciphers stoc: aes256-ctr

SSH MAC algorithm

To change the default SSH MAC algorithm used on a Cisco IOS device, use the command below.

router01(config)#ip ssh server algorithm mac ?
  hmac-sha1     HMAC-SHA1 (digest length = key length = 160 bits)
  hmac-sha1-96  HMAC-SHA1-96 (digest length = 96 bits, key length = 160 bits)
router01(config)#ip ssh server algorithm mac hmac-sha1

UPDATE: Newer IOS supports higher than SHA1.

router01(config)#ip ssh server algorithm mac ?
  hmac-sha1      HMAC-SHA1 (digest length = key length = 160 bits)
  hmac-sha1-96   HMAC-SHA1-96 (digest length = 96 bits, key length = 160 bits)
  hmac-sha2-256  HMAC-SHA2-256 (digest length = 256 bits, key length = 256 bits)
  hmac-sha2-512  HMAC-SHA2-512 (digest length = 512 bits, key length = 512 bits)
router01(config)#ip ssh server algorithm mac hmac-sha2-512

In this particular IOS version, the SSH server supports two Message Authentication Code (MAC) algorithms: HMAC-SHA1 and HMAC-SHA1-96. The difference between the two algorithms is the digest length. The HMAC-SHA1-96 is a truncated message digest. From my limited understanding, the HMAC-SHA1-96 is the weakened version of HMAC-SHA1 due to the shortened message digest.

Below shows the verbose output of a Cisco IOS device using default SSH configuration.

Mac-mini:~ networkjutsu$ ss -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug2: MACs ctos: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96
debug2: MACs stoc: hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96

Below shows the verbose output of a Cisco IOS device using the SSH configuration mentioned above.

Mac-mini:~ networkjutsu$ ss -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug2: peer server KEXINIT proposal
debug2: MACs ctos: hmac-sha1
debug2: MACs stoc: hmac-sha1

UPDATE: Configured with SHA2

Mac-mini:~ networkjutsu$ ss -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug2: MACs ctos: hmac-sha2-512
debug2: MACs stoc: hmac-sha2-512

Key Exchange Algorithm

If my memory serves me right, even before macOS High Sierra, OpenSSH also deprecated the use of Diffie-Hellman key exchange with SHA-1. That said, users that tried to connect to Cisco IOS devices with default SSH configurations were greeted by an error message, like the one below.

Mac mini:~ networkjutsu$ ssh router01
Unable to negotiate with 192.168.100.200 port 22: no matching key exchange method found. Their offer: diffie-hellman-group1-sha1

The real issue is that most of the Cisco IOS versions use 1024-bit key size for Diffie-Hellman used for key exchange, by default. Though, there are old Cisco IOS versions that use 768-bit DH key size, by default. Prior the year of 2016, 1024-bit key size is adequate. However, NIST’s recommendation is to use 2048-bit key size or higher. Furthermore, the authors of the LogJam paper believes that it may be possible for a nation-state to break 1024-bit groups. Therefore, the authors recommend disabling DH Group 1.

router01(config)#sh ip ssh
<-- Output omitted for brevity -->
Minimum expected Diffie Hellman key size : 1024 bits
router01(config)#ip ssh dh min size ?
  1024  Diffie Group 1 1024-bit key
  2048  Diffie Group 14 2048-bit key
  4096  Diffie Group 16 4096-bit key
router01(config)#ip ssh dh min size 4096

Below shows the verbose output of a Cisco IOS device using the SSH configuration mentioned above.

Mac-mini:~ networkjutsu$ ss -vvv router01
OpenSSH_7.6p1, LibreSSL 2.6.2
<-- Output omitted for brevity -->
debug1: kex: algorithm: diffie-hellman-group-exchange-sha1
debug1: kex: host key algorithm: ssh-rsa
debug1: kex: server->client cipher: aes256-ctr MAC: hmac-sha1 compression: none
debug1: kex: client->server cipher: aes256-ctr MAC: hmac-sha1 compression: none

Note: Changing the DH key size to 4096 value may break some applications that connect to Cisco IOS devices. For example, HPE Opsware Network Automation (now Micro Focus) uses a Java-based SSH client that is incompatible with SSH servers that use higher than 2048-bit DH key.

Additional SSH configuration

The commands covered here deserves consideration since they increase the level of protection to Cisco IOS SSH server.

RSA keys

As covered in this post, I used 4096-bit modulus in the second example. Cisco IOS users should consider generating higher than NIST’s recommendation of the 2048-bit modulus. Generating higher than the recommended value may take a minute or two (depending on the platform). Additionally, it may take few seconds to get the prompt when connecting to a Cisco IOS device. That said, make sure to take the two facts into consideration before using higher than the recommended value. In theory, newer Cisco platforms could handle the higher values without a significant impact on performance.

router01(config)#crypto key gen rsa mod ?
  <360-4096>  size of the key modulus [360-4096]
router01(config)#crypto key gen rsa modulus 4096 label SSH_KEY
The name for the keys will be: SSH_KEY
% The key modulus size is 4096 bits
% Generating 4096 bit RSA keys, keys will be non-exportable...
[OK] (elapsed time was 103 seconds)

If you’re confused about the difference between RSA and DH mentioned here, then I recommend you to read this article. The article did a great job explaining the SSH connection process. If you just want to know the difference between the RSA and DH, then skip to the Negotiating Encryption for the Session section.

SSH authentication timeout

There is no reason to have a high authentication timeout, so it is recommended to lower the value to 60 seconds or less. This particular router has the SSH authentication timeout set to 120 seconds. We’ll change it to 30 seconds.

router01#sh ip ssh
SSH Enabled - version 2.0
Authentication methods:publickey,keyboard-interactive,password
Authentication timeout: 120 secs; Authentication retries: 3
<-- Output omitted for brevity -->
router01#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
router01(config)#ip ssh time-out 30
router01(config)#do sh ip ssh
SSH Enabled - version 2.0
Authentication methods:publickey,keyboard-interactive,password
Authentication timeout: 30 secs; Authentication retries: 3
<-- Output omitted for brevity -->

Line VTY

There four Cisco IOS features under VTY configuration that deserves consideration because they provide an increased level of protection to networking devices.

SSH transport protocols

As mentioned in this post, by default, Cisco IOS still allows telnet connection when the user doesn’t disable it. To disable, please issue the command below. If you only need 5 vty lines, I suggest disabling the remaining vty lines.

router01(config)#line vty 0 4
router01(config-line)#transport input ssh
router01(config)#line vty ?
  <0-98>  First Line number
router01(config)#line vty 5 98
router01(config-line)#transport input none

SSH ACL

Creating and applying ACL to SSH is best practice, so I decided to cover it here, even though this is considered very basic security.

router01(config)#access-list 1 permit 172.16.0.0 0.0.0.63
router01(config)#access-list 1 permit 192.168.100.0 0.0.0.255
router01(config)#line vty 0 4
router01(config-line)#access-class 1 in

Session timeout

I think this is one of the controversial settings that require some discussions with the networking team. The STIG recommends to set it to 10 minutes or less. By default, Cisco IOS uses 10 minutes for this setting. Please feel free to change it to something else that follows your security policy or suggested setting by the networking team.

router01#sh run all | sec line vty
line vty 0 4
 motd-banner
 exec-banner
 exec-timeout 10 0
<-- Output omitted for brevity -->
router01(config)#line vty 0 4
router01(config-line)#exec-timeout ?
  <0-35791>  Timeout in minutes
router01(config-line)#exec-timeout 5 ?
  <0-2147483>  Timeout in seconds
router01(config-line)#exec-timeout 5 0

Final Words

All of the configurations covered here are what I’d say minimum security standard for all Cisco IOS devices. My advice for my fellow network engineers looking to secure network devices against management plane attacks must consider including this in their configuration template. Though, this blog post is just a small part of protecting the management plane. That said, I urge my fellow network engineers to research more about other settings that protect the management plane.

Are you ready to improve your network security?

Let us answer more questions by contacting us. We’re here to listen and provide solutions that are right for you.

ENGAGE US

NetworkJutsu provides networking and network security consulting services for startups, a more established small and medium-sized business (SMB), or large business throughout the San Francisco Bay Area.

Want to learn more about securing Cisco IOS?

CCNP Security Secure 642-637 Official Cert Guide

Disclosure

NetworkJutsu.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Migrated FreeRADIUS with Google Authenticator to a Docker container

07/16/2017 By Andrew Roderos 4 Comments

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

The number of virtual machines in my two-node ESXi cluster is growing and my 32GB RAM Intel NUC ESXi build will be out of memory soon if I don’t make changes. That said, I had to find a way to cut down my RAM usage to squeeze more out of this build. I don’t want to spend a couple of thousand dollars on another build. The ESXi build that I am looking at is Supermicro X10SDV-TLN4F-O which is a combination of motherboard, Intel Xeon D-1541, and 128GB ECC RDIMM RAM, an expensive ESXi build. Yes, I could buy a used server on eBay for less, but I don’t want those servers because they are too bulky and loud.

Update: FreeRADIUS 3.0 with Two-Factor Authentication using Google Authenticator

Enter Docker

What is Docker? Docker is an open-source software platform that allows users to package software into containers, allowing them to be portable among different operating systems (Windows, Linux, and macOS).

Here’s a ten-minute video that further explains what Docker is. If you want to watch an hour long video, here’s one from Docker, Inc.

Currently, I have three VMs running Ubuntu server edition for FreeRADIUS and tac_plus (TACACS+ daemon). On top of that, I was planning to set up another VM for Pi-hole (running it as a Docker container now). Sure, I could easily install it on one of the existing VMs that I have, but I want separation. With Docker, I could easily have all the separation I want but with fewer system resources and efficient use of it.

My base VM for Ubuntu server has the following assigned resources: 256MB RAM, 1 x vCPU, and 8GB of disk space. Depending on what I want to do with the new VM, I could change the resources assigned to it. If I assign it with too little of RAM, then the VM will use the disk for additional memory. Swapping is not ideal, so I usually add more RAM, which means there will be some free RAM just waiting to get used.

With Docker, I could assign 1GB of RAM to my Ubuntu VM with Docker installed and not worry about the efficient use of it. I know that eventually, the system will use the resources as I continue to add more containers. If the VM begins to swap, I could easily add more RAM.

Another advantage of Docker is the speed of spinning up new containers. With VMs, I need to clone the base image, create the VMX file, turn it on, etc. These processes would take several minutes. With Docker, I could write a one-line Dockerfile to create the Docker image and start the container. Starting up the container takes less than one second compared to the minutes spent on processes that I have to do when creating VMs.

Docker Installation

If you’re a returning visitor, you probably already know that I use Ubuntu. With that said, the Docker image will use Ubuntu as the OS. The installation could be a one-liner, but I wanted to install the newest version. Docker has the how-to guide, so just follow that if you want. Though, I will still list all of the things I did since I skipped a step or so.

$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common -y
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce -y
$ docker --version
Docker version 17.06.0-ce, build 02c1d87

Docker Compose Installation

In this next section, we will install Docker Compose. While this is optional, I like the Docker compose because it makes it easier for me to run multiple containers in one command.

$ sudo -i
# curl -L https://github.com/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
# exit
$ docker-compose --version
docker-compose version 1.14.0, build c7bdf9e

FreeRADIUS Docker Image

There are plenty of FreeRADIUS Docker images on Docker Hub, but I wanted to learn how to create one on my own. Having said that, I read several websites, including Docker’s documentation page, to get an idea on how to create my own image. It took me several tries to get my FreeRADIUS Docker image working, since I am, after all, a Docker newbie.

Writing Dockerfile

When I was ready to write my Dockerfile, one question that I had was where do I put it. For testing, I decided to create a directory in my home directory and put any files related to this Docker image. I then switched to the new directory and created my Dockerfile there. In the future, I will still create a new directory just for the sake of separation. Though, it doesn’t really matter where you put the Dockerfile.

$ mkdir radius
$ cd radius
$ vi Dockerfile

Once I have VIM running, I started writing my Dockerfile. At first, I only started with few lines since I haven’t used the Ubuntu Docker image. I wanted to make sure that I could run all the commands I need to put in the Dockerfile. Once everything worked in the container, I started to write the rest. Here’s the complete Dockerfile that I wrote.

# Use Base Ubuntu image
FROM ubuntu:16.04
# Author of this Dockerfile
MAINTAINER NetworkJutsu <networkjutsu.com>
# Update & upgrades
RUN apt-get update && apt-get dist-upgrade -y
# Install FreeRADIUS and Google Authenticator
RUN apt-get install freeradius libpam-google-authenticator -y
# Add user to container with home directory
RUN useradd -m -d /home/networkjutsu -s /bin/bash networkjutsu
# Add password to networkjutsu account.
# Obviously, you wouldn't want to do this in production.
# Go to the container and add the password there then commit the changes to the container.
RUN echo "networkjutsu:letsmakemypasswordgreatagain" | chpasswd
# Edit /etc/pam.d/radiusd file
RUN sed -i 's/@include/#@include/g' /etc/pam.d/radiusd
RUN echo "auth requisite pam_google_authenticator.so forward_pass secret=/etc/freeradius/networkjutsu/.google_authenticator user=freerad" >> /etc/pam.d/radiusd
RUN echo "auth required pam_unix.so use_first_pass" >> /etc/pam.d/radiusd
# Edit /etc/freeradius/users file
RUN sed -i '1s/^/# Instruct FreeRADIUS to use PAM to authenticate users\n/' /etc/freeradius/users
RUN sed -i '2s/^/DEFAULT Auth-Type := PAM\n/' /etc/freeradius/users
# Copy existing /etc/freeradius/sites-enabled/default file to container
COPY default /etc/freeradius/sites-enabled/default
# Copy existing /etc/freeradius/clients.conf file to container
COPY clients.conf /etc/freeradius/clients.conf
# Copy existing .google_authenticator file to container
COPY .google_authenticator /home/networkjutsu
# Create a folder in /etc/freeradius equal to the user name
RUN mkdir /etc/freeradius/networkjutsu
# Copy .google_authenticator file to /etc/freeradius/networkjutsu
RUN cp /home/networkjutsu/.google_authenticator /etc/freeradius/networkjutsu
# Change owner to freerad
RUN chown freerad:freerad /etc/freeradius/networkjutsu && chown freerad:freerad /etc/freeradius/networkjutsu/.google_authenticator
# Expose the port
EXPOSE 1812/udp 1813/udp 18120/udp
# Run FreeRADIUS
CMD freeradius -f

The lines where I instructed Docker engine to copy existing FreeRADIUS files, those files are based on the configuration covered in my past blog posts. If you’re curious about the config files, please check this post and this one. I could’ve copied everything from my existing RADIUS server, but I wanted to show other ways of writing the Dockerfile and how to edit the config files.

Building Docker Image

Once done with the Dockerfile, the next step is to build the Docker image. Creating the Docker image is pretty straightforward. We just need to issue the build command, and it will create the Docker image based on the Dockerfile that we wrote. The -t flag allows us to tag the Docker image with a friendly name.

$ sudo docker build -t radius1 .

If we don’t tag the image with a friendly name, it would look like this.

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS               NAMES
bb3ad23725a6        9ea220058853        "/bin/sh -c 'apt-g..."   32 minutes ago      Exited (100) 32 minutes ago                       adoring_poitras

If there are errors in the Dockerfile, the image will not get built. The Docker engine is good about telling the user where it failed. Here’s an example where I took some lines out of the Dockerfile.

networkjutsu@ubuntu:~$ sudo docker build -t radius1 .
Sending build context to Docker daemon  27.65kB
Step 1/10 : RUN apt-get install freeradius libpam-google-authenticator -y
Please provide a source image with `from` prior to run
networkjutsu@ubuntu:~$ sudo docker build -t radius .
Sending build context to Docker daemon  27.65kB
Step 1/12 : FROM ubuntu:16.04
<-- Output omitted for brevity -->
Step 2/12 : MAINTAINER Network Jutsu <networkjutsu.com>
<-- Output omitted for brevity -->
Step 3/12 : RUN apt-get install freeradius libpam-google-authenticator -y
<-- Output omitted for brevity -->
E: Unable to locate package freeradius
E: Unable to locate package libpam-google-authenticator
The command '/bin/sh -c apt-get install freeradius libpam-google-authenticator -y' returned a non-zero code: 100
networkjutsu@ubuntu:~$

If there are no errors, it should look something like below. The image created here is from a modified Dockerfile where I excluded the COPY commands because I do not have those files in this VM.

networkjutsu@ubuntu:~$ sudo docker build -t radius1 .
Sending build context to Docker daemon  27.65kB
Step 1/13 : FROM ubuntu:16.04
<-- Output omitted for brevity -->
Step 2/13 : MAINTAINER Network Jutsu <networkjutsu.com>
<-- Output omitted for brevity -->
Step 3/13 : RUN apt-get update && apt-get dist-upgrade -y
<-- Output omitted for brevity -->
Step 4/13 : RUN apt-get install freeradius libpam-google-authenticator -y
<-- Output omitted for brevity -->
Step 5/13 : RUN useradd -m -d /home/networkjutsu -s /bin/bash networkjutsu
<-- Output omitted for brevity -->
Step 6/13 : RUN echo "networkjutsu:letsmakemypasswordgreatagain" | chpasswd
<-- Output omitted for brevity -->Removing intermediate container 356f78c72b6c
Step 7/13 : RUN sed -i 's/@include/#@include/g' /etc/pam.d/radiusd
<-- Output omitted for brevity -->
Step 8/13 : RUN echo "auth requisite pam_google_authenticator.so forward_pass secret=/etc/freeradius/networkjutsu/.google_authenticator user=freerad" >> /etc/pam.d/radiusd
<-- Output omitted for brevity -->Removing intermediate container a1baec16ec31
Step 9/13 : RUN echo "auth required pam_unix.so use_first_pass" >> /etc/pam.d/radiusd
<-- Output omitted for brevity -->
Step 10/13 : RUN sed -i '1s/^/# Instruct FreeRADIUS to use PAM to authenticate users\n/' /etc/freeradius/users
<-- Output omitted for brevity -->
Step 11/13 : RUN sed -i '2s/^/DEFAULT Auth-Type := PAM\n/' /etc/freeradius/users
<-- Output omitted for brevity -->
Step 12/13 : EXPOSE 1812/udp 1813/udp 18120/udp
<-- Output omitted for brevity -->
Step 13/13 : CMD freeradius -f
<-- Output omitted for brevity -->
Successfully built c227ded15dcd
Successfully tagged radius:latest
networkjutsu@ubuntu:~$

Verification

To see the Docker images in our system, issue the command below. Notice that there is an Ubuntu image. This is the result of the FROM ubuntu:16.04 line from our Dockerfile.

$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
radius1             latest              c227ded15dcd        27 minutes ago      246MB
ubuntu              16.04               d355ed3537e9        3 weeks ago         119MB

Docker Compose

We’re now ready to run the Docker image. We could issue the docker run command, however, I like running the Docker image using Docker Compose. In this section, we’re going to write what we need for our docker-compose.yml file to run the Docker image. The YML file doesn’t need to be in the radius directory. In my case, I just put my file in my home directory. Remember though, when you run the docker-compose command, it will look for the YML file. Be sure to run the command in the directory where you stored the YML file.

$ vi docker-compose.yml
version: "3"
services:
  radius1:
    container_name: radius1
    image: radius1
    ports:
    - "192.168.0.100:1812:1812/udp"
    - "192.168.0.100:1813:1813/udp"
    - "192.168.0.100:18120:18120/udp"
    environment:
    - VIRTUAL_HOST=radius1.networkjutsu.lan
    restart: always
    volumes:
    - /etc/timezone:/etc/timezone:ro
    - /etc/localtime:/etc/localtime:ro
  radius2:
    container_name: radius2
    image: radius2
    ports:
    - "192.168.0.101:1812:1812/udp"
    - "192.168.0.101:1813:1813/udp"
    - "192.168.0.101:18120:18120/udp"
    environment:
    - VIRTUAL_HOST=radius2.networkjutsu.lan
    restart: always
    volumes:
    - /etc/timezone:/etc/timezone:ro
    - /etc/localtime:/etc/localtime:ro

Ports

For this section, I included an IP address. By default, the container will use the host’s IP address. If one wants to use the default IP address, then the line would look like – “1812:1812/udp”. In this case, I wanted to use a different IP address than the host. This will allow me to create another Docker container using the same ports. Since the host doesn’t have this particular IP address assigned to it, we need to set up the host machine to have another IP address (IP aliasing). Editing the network interface config means that we want the changes to be persistent even after a reboot. I think I don’t need the other lines in the alias section since it will use the main interface configs. However, I still included it in the config just in case.

$ sudo vi /etc/network/interfaces
# Host machine
auto ens160
iface ens160 inet static
address 192.168.0.200
netmask 255.255.255.0
network 192.168.0.200
broadcast 192.168.0.255
gateway 192.168.0.1
dns-nameserver 192.168.200.53
dns-search networkjutsu.lan
# First IP alias
# IP address for radius1
auto ens160:0
iface ens160:0 inet static
address 192.168.0.100
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.1
dns-nameserver 192.168.200.53
dns-search networkjutsu.lan
# Second IP alias
# IP address for raduius2
auto ens160:1
iface ens160:1 inet static
address 192.168.0.101
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.0.1
dns-nameserver 192.168.200.53
dns-search networkjutsu.lan
$ sudo service networking restart

Volumes

As I was verifying everything in my FreeRADIUS Docker container, I noticed that the time was incorrect even after setting the environment with the right time zone. During my search, I came across a thread that talks about how to set the time zone correctly. There are several ways of doing it, but I settled on this way. With this config, the container syncs with the host machine’s time. Having said that, the host needs to sync with NTP servers. Having correct time is important because my Google Authenticator is TOTP-based.

Starting the container

Once done with the YML file, we’re now ready to run our image with docker-compose command. The -d flag instructs Docker engine to run the container(s) as a daemon.

$ sudo docker-compose up -d
$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
2edac8f51819        radius              "/bin/sh -c 'freer..."   39 seconds ago      Up 38 seconds       192.168.0.100:1812-1813->1812-1813/udp, 192.168.0.100:18120->18120/udp   radius

Stopping the container

If for whatever reason, you want to stop the container, you can issue the docker stop command.

$ sudo docker stop 2edac8f51819
2edac8f51819

Final Words

My FreeRADIUS Docker image is by no means perfect. I am still a Docker newbie, so I am pretty sure if a Docker expert looks at my Dockerfile there will be some comments. But, I’ve tested this already with my PA-200, and it worked perfectly.

With Docker, it will allow me to turn off multiple VMs running on my ESXi host. On top of that, I will now be able to spin up new services quickly without going through the processes that I use to create a new VM with Ubuntu as the OS.

Are you ready to improve your network security?

Let us answer more questions by contacting us. We’re here to listen and provide solutions that are right for you.

ENGAGE US

You might also like to read

FreeRADIUS 3.0 with Two-Factor Authentication (2FA)
Adding Two-Factor Authentication to FreeRADIUS
Securing SSH with Google Authenticator
Adding Two-Factor Authentication to TACACS+

Disclosure

NetworkJutsu.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Adding Two-Factor Authentication to TACACS+

06/02/2017 By Andrew Roderos Leave a Comment

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email

Several months ago, I covered how to add two-factor authentication (2FA) to FreeRADIUS using Google Authenticator. Today, I will cover the TACACS+ version of it.

Related: What is multi-factor authentication (MFA)?

I’ve written a blog post on how to build tac_plus server using Ubuntu. The guide was written in 2011, while it’s an old blog post, the instructions are still valid using Ubuntu Server 16.04. Please use that guide on how to build one, then use this guide to add multi-factor authentication (MFA) to TACACS+.

Related: Deploying TACACS+ on a Docker container

Installing Google Authenticator PAM

It is super easy to install Google Authenticator on Ubuntu. Below is the command we need to install Google Authenticator PAM on Ubuntu.

$ sudo apt-get install libpam-google-authenticator -y

Configure tac_plus

As mentioned earlier, the instructions in my old blog post are still valid. We’re going to use only some of them in this post for the purpose of demonstration only.

By default, the /etc/tacacs+/tac_plus.conf file looks like this:

accounting file = /var/log/tac_plus.acct
key = testing123
user = DEFAULT {
       login = PAM
       service = ppp protocol = ip {}
}

Let’s change the key and user information fields to look something like this:

accounting file = /var/log/tac_plus.acct
key = tacacskey1234
user = tacacsuser {
        member = Administrators
}
group = Administrators {
        default service = permit
        login = PAM
        enable = file /etc/passwd
}

Restart TACACS+ daemon

Since we made a change to our tac_plus config file, we need to restart the service for our changes to take effect. Issue the command below.

$ sudo /etc/init.d/tacacs_plus restart
[ ok ] Restarting tacacs_plus (via systemctl): tacacs_plus.service.

An alternative command is shown below.

$ sudo service tacacs+ restart

Generating Google Authenticator Secret Key

This step is covered in my old blog post so head over there and skip to the generating the secret key section. Alternatively, we could use the same secret key(s) from another system with Google Authenticator. However, this is not the recommended practice.

To get the secret key from another system, just copy and paste the ~/.google_authenticator file of each user, like the one below.

tacacsuser@tacplus:~$ more .google_authenticator
UXQLCMOLT2QLSMVE
" RATE_LIMIT 3 30 1436015893
" DISALLOW_REUSE 39787632
" TOTP_AUTH
55312114
13740459
80118802
81859009
79311140

If you copy and paste it to a file, make sure that the permission is set to read only.

tacacsuser@tacplus:~$ ls -l .google_authenticator
-rw-rw-r-- 1 tacacsuser tacacsuser 129 May 29 17:54 .google_authenticator
tacacsuser@tacplus:~$ chmod 400 .google_authenticator
tacacsuser@tacplus:~$ ls -l .google_authenticator
-r-------- 1 tacacsuser tacacsuser 129 May 29 17:54 .google_authenticator

Configuring TACACS+ PAM

Since we instructed tac_plus to use PAM, we now need to create a file called /etc/pam.d/tac_plus, so PAM knows what to do. The file should look like:

$ more /etc/pam.d/tac_plus
auth requisite pam_google_authenticator.so forward_pass
auth required pam_unix.so use_first_pass

IOS configuration

Before we can verify that our tac_plus config is working, let’s configure a CSR1000V router running IOS-XE.

R1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#aaa new-model
R1(config)#aaa authentication login default group tacacs+ enable
R1(config)#aaa authentication enable default group tacacs+ enable
R1(config)#aaa session-id common
R1(config)#tacacs-server host 192.168.250.250
 Warning: The cli will be deprecated soon
 'tacacs-server host 192.168.250.250'
 Please move to 'tacacs server <name>' CLI
R1(config)#tacacs-server directed-request
R1(config)#tacacs-server key tacacskey1234
R1(config)#end
R1#

While the configuration above still works, it is a good idea to move towards the new way of doing things. Here’s the new way of configuring TACACS+:

R1#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
R1(config)#aaa new-model
R1(config)#aaa authentication login default group tacacs+ enable
R1(config)#aaa authentication enable default group tacacs+ enable
R1(config)#aaa session-id common
R1(config)#tacacs server tac_plus
R1(config-server-tacacs)# address ipv4 192.168.250.250
R1(config-server-tacacs)# key tacacskey1234
R1(config-server-tacacs)#end
R1#

Verification

This CSR1000V router is using version 15.4(2)S image. The output may vary depending on what platform and the IOS version.

$ ssh tacacsuser@192.168.250.250
Password & verification code:
R1>en
Password:
R1#

For completeness sake, I will list the passwords entered in the example above. The tacacsuser account is a valid account on the Ubuntu server running TACACS+ daemon. For example, the tacacsuser account has a password of tacacsuserpassword1234. Next, the verification code is the six-digit number displayed on Google Authenticator app. For example, the six-digit number is 567 890. With this example, the user will enter tacacsuserpassword1234567890 in the password & verification prompt.

For entering the privileged EXEC mode, we’ll again use tacacsuser’s password. If we look at the tac_plus config file, the enable = file /etc/passwd is what we defined.

Final Words

I am quite biased towards TACACS+. One of the reasons why is because of the command authorization piece. TACACS+ authentication and authorization are completely separate. That said, we could assign different command authorization level for the user or group.

With RADIUS, it combines authentication and authorization. Once the user authenticates successfully, the access-accept packet sent by RADIUS server to the device contain authorization information as well. If we configure the device similar to the example here, then the user will have full access.

To overcome RADIUS’ drawback, we could configure the device to use a local enable secret. This password is then shared only with the necessary user(s) or group(s). The issue with this approach is that the password is then a shared password. A lot of information security professionals do not like shared passwords because it is insecure.

Having said all that, I think it’s better to use TACACS+, especially with the Cisco-centric environment. While a lot of vendors support TACACS+, there might be some limitations on the authorization piece.

Are you ready to improve your network security?

Let us answer more questions by contacting us. We’re here to listen and provide solutions that are right for you.

ENGAGE US

You might also like to read

How to build tac_plus server
TACACS+ (tac_plus daemon) ACL
How to configure AAA on Cisco router/switches
Enabling AAA on Cisco ASA
Deploying TACACS+ on a Docker container

Disclosure

NetworkJutsu.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.

  • Share on Twitter Share on Twitter
  • Share on Facebook Share on Facebook
  • Share on LinkedIn Share on LinkedIn
  • Share on Reddit Share on Reddit
  • Share via Email Share via Email
  • « Go to Previous Page
  • Go to page 1
  • Go to page 2
  • Go to page 3
  • Go to page 4
  • Interim pages omitted …
  • Go to page 6
  • Go to Next Page »

Footer

WORK WITH US

Schedule a free consultation now!

LET’S TALK

Copyright © 2011–2023 · NetworkJutsu · All Rights Reserved · Privacy Policy · Terms of Use