Back in 2011, I wrote how to configure tac_plus (TACACS+ daemon) on an Ubuntu server. Then two years ago, I wrote a post about adding two-factor authentication (2FA) to TACACS+. Today, I’m going to talk about deploying TACACS+ on a Docker container.
While I’ve written migrating FreeRADIUS with 2FA to a Docker container post in the past, I’d still consider myself a newbie. I don’t deal with Docker daily to be well-versed.
Since I’m still a newbie, I make mistakes writing a
Dockerfile and sometimes get stuck when the container keeps restarting. Part of the problem is I’m still learning Linux even though I’ve been using it for many years.
Another part is I have yet to sit down and read a book about Docker, like this one. The book has a high rating on Amazon and seems like a good buy if you’re trying to learn it.
Yes, I could download someone else’s Docker container. However, I don’t like doing that. When I write the
Dockerfile from scratch, it forces me to learn both Docker and Linux.
Before we can deploy a TACACS+ container, we need to install the Docker software. Docker’s documentation has the steps on how to do it on your preferred OS. For this tutorial, I’m using the Ubuntu Server 18.04 as my OS of choice.
andrew@networkjutsu:~$ sudo apt-get update andrew@networkjutsu:~$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common -y andrew@networkjutsu:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - andrew@networkjutsu:~$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" andrew@networkjutsu:~$ sudo apt-get install docker-ce docker-ce-cli containerd.io -y andrew@networkjutsu:~$ sudo apt autoremove -y andrew@networkjutsu:~$ docker --version Docker version 19.03.4, build 9013bf583a
Alternatively, we can install the Docker version that Ubuntu is using in their repo. Installing from Ubuntu’s repo is the easiest way to install Docker.
andrew@networkjutsu:~$ sudo apt install docker.io -y Reading package lists... Done Building dependency tree Reading state information... Done <-- Output omitted for brevity --> andrew@networkjutsu:~$ docker --version Docker version 18.09.7, build 2d0083d
Docker Compose installation
I like to use the
docker-compose command to run multiple containers in one syntax. That said, I have that installed on my Ubuntu server. This step is optional, but I highly recommend using it. If you have a different OS, then visit this page.
andrew@networkjutsu:~$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose andrew@networkjutsu$ sudo chmod +x /usr/local/bin/docker-compose andrew@networkjutsu$ docker-compose --version docker-compose version 1.24.1, build 4667896b
I like to separate my files for each Docker containers that I want to deploy. That said, I create a new directory for each of them.
andrew@networkjutsu:~$ mkdir tacacs
Once I’ve created the directory, it’s time to write the
Dockerfile. Since I’m more familiar with VIM than any other text editor on Linux, that’s what I use. Please feel free to use your favorite Linux text editor.
andrew@networkjutsu:~$ vi tacacs/Dockerfile
Once VIM is running, we can now write the contents of our
Dockerfile. Here’s a sample of my TACACSC+
# Use Base Ubuntu image FROM ubuntu:18.04 # Author of this Dockerfile MAINTAINER Andrew Roderos <andrewroderos.com> # Update & upgrades RUN apt-get update && apt-get upgrade -y # Install tacacs+ and Google Authenticator RUN apt-get install tacacs+ libpam-google-authenticator -y # Clear local repo RUN apt-get clean # Create a user with home directory RUN useradd -m -d /home/andrew -s /bin/bash andrew # Add password to andrew account RUN echo "andrew:makemypasswordgreatagain" | chpasswd # Copy Google secret key from host's volume to tacacs+ container COPY .google_authenticator /home/andrew # Change file owner RUN chown andrew:andrew /home/andrew/.google_authenticator # Copy tac_plus configuration file from host to the container COPY tac_plus.conf /etc/tacacs+/tac_plus.conf # Add tac_plus PAM RUN touch /etc/pam.d/tac_plus RUN echo auth requisite pam_google_authenticator.so forward_pass >> /etc/pam.d/tac_plus RUN echo auth required pam_unix.so use_first_pass >> /etc/pam.d/tac_plus # Run tac_plus as foreground process and use /etc/tacacas+/tac_plus.conf as the config file CMD ["tac_plus", "-G", "-C", "/etc/tacacs+/tac_plus.conf"]
Before we can build the TACACS+ Docker container, we need to do some preliminary steps. As you can see from the
Dockerfile, it will copy some files that I already have in the current directory. Without these files, the
docker build command will error out.
Google Authenticator secret key
The first file we need is the
.google_authenticator file. This file contains all the necessary parameters for our TOTP (Time-based One Time Password).
Since I use Google Authenticator at home, I just copied my existing file for this lab. If you don’t have one, you may want to generate one from another host. I covered the generation of the secret key in this post.
Once you’ve generated the secret key, we can now copy the
.google_authenticator file in the home directory. Please copy it to the tacacs directory.
andrew@networkjutsu:~$ cp .google_authenticator tacacs
TACACS+ configuration file
The next file we need is the
tac_plus.conf file. This file gets generated when you install tac_plus software. Since I’ve covered this topic before, I already have a configuration file that I can use. If you don’t have one, then you can use my configuration files from here and here.
If you do create this from scratch, make sure the owner and permissions are the same as the one below.
andrew@networkjutsu:~/tacacs$ ls -l tac_plus.conf -rw------- 1 root root 3108 Nov 4 18:43 tac_plus.conf
Depending on how you create the file, the owner and permissions are different. For example, I created the
tac_plus.conf file using a non-root account.
andrew@networkjutsu:~/tacacs$ ls -l tac_plus.conf -rw-rw-r-- 1 networkjutsu networkjutsu 3108 Nov 4 20:41 tac_plus.conf
There are multiple options to fix this minor issue. One option is by deleting the file and recreating it using the
andrew@networkjutsu:~/tacacs$ rm tac_plus.conf andrew@networkjutsu:~/tacacs$ sudo vi tac_plus.conf andrew@networkjutsu:~/tacacs$ sudo chmod 600 tac_plus.conf andrew@networkjutsu:~/tacacs$ ls -l tac_plus.conf -rw------- 1 root root 3108 Nov 4 20:44 tac_plus.conf
Another option is adding some lines to the
Dockerfile to change the owner and permissions. Add the following lines after the
COPY tac_plus.conf /etc/tacacs+/tac_plus.conf line.
# Change owner from andrew to root RUN chown root:root /etc/tacacs+/tac_plus.conf # Change permission to root only access RUN chmod 600 /etc/tacacs+/tac_plus.conf
Creating a Docker image
Once done with the preliminary steps, we can now create our TACACS+ Docker image. Creating a Docker image is pretty straightforward. All we need to do is issue the command below.
andrew@networkjutsu:~/tacacs$ docker build -t tacacs . Sending build context to Docker daemon 8.192kB Step 1/14 : FROM ubuntu:18.04 ---> 452a96d81c30 Step 2/14 : MAINTAINER Andrew Roderos <andrewroderos.com> ---> Using cache ---> 1c717e03db89 <-- Output omitted for brevity -->
Once the building process is done, you can verify that the Docker image is ready by issuing the command below.
andrew@networkjutsu:~/tacacs$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE tacacs latest 32a7bc92b24a 2 minutes ago 205MB radius latest c558d1437285 33 hours ago 248MB
We’re now ready to run the Docker image. If you prefer to use
docker run syntax, then feel free to use that one. I happen to like to use the
docker-compose command when starting up Docker containers. That said, we need to edit my existing
docker-compose.yml file before we can run the Docker container.
andrew@networkjutsu:~/tacacs$ vi ../docker-compose.yml
The file should look like the one below.
andrew@networkjutsu:~/tacacs$ cat ../docker-compose.yml version: "3" services: radius: container_name: radius image: radius ports: - "192.168.200.51:1812:1812/udp" - "192.168.200.51:1813:1813/udp" - "192.168.200.51:18120:18120/udp" environment: - VIRTUAL_HOST=radius.networkjutsu.local restart: always volumes: - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro tacacs: container_name: tacacs image: tacacs ports: - "192.168.200.49:49:49/tcp" environment: - VIRTUAL_HOST=tacacs.networkjutsu.local restart: always volumes: - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro
Now, we’re ready to run our TACACS+ Docker container.
andrew@networkjutsu:~$ docker-compose up -d Creating tacacs ... radius is up-to-date Creating tacacs ... done andrew@networkjutsu:~/tacacs$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1a6eb28498d6 tacacs "tac_plus -G -C /etc…" 14 seconds ago Up 13 seconds 192.168.200.49:49->49/tcp tacacs 946d992dddb5 radius "freeradius -f" 17 hours ago Up 17 hours 192.168.200.51:1812-1813->1812-1813/udp, 192.168.200.51:18120->18120/udp radius
If the status says Restarting, then that means there’s something wrong with the
tac_plus.conf file or
Dockerfile. You might have to spend some time troubleshooting if your config isn’t the same as mine.
Note: The instructions covered here are not recommended for production use since it’s running the container as root.
Once the Docker container is running, then we’re now ready to verify if our TACACS+ is working as expected. This step assumes that you already have an IOS device with a TACACS+ configuration. If you need a sample configuration, please check out my post.
R1 con0 is now available Press RETURN to get started. User Access Verification Username: andrew Password & verification code: makemypasswordgreatagain468792 R1>en Password: makemypasswordgreatagain R1#
Note: The example above was done using the CSR 1000v and may not represent what the prompt would look like on regular IOS-based devices.
OS-level virtualization, such as Docker, offers a lot of advantages over server virtualization. One of the benefits of OS-level virtualization is that it consumes fewer system resources compared to VMs. It is the major reason why I run containers for my FreeRADIUS and TACACS+ services.
Additionally, if done right, it’s faster for me to deploy something on Docker than provisioning new VMs. Though, with the mistakes I’ve done in the past, I am sure I could’ve provisioned new VMs a lot faster.
Just because everyone is doing Docker containers, doesn’t mean you should follow suit. Make sure to weigh in the pros and cons of running services, such as TACACS+, on Docker.
You might like to read
AndrewRoderos.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.