[LINUX] Since sudo is that, try switching to doas

First summary

It's been long, so I'll summarize it first.

--I stopped using sudo and switched to doas --doas has the necessary and sufficient functions, and the setting is simpler than sudo. --doas was originally from the OpenBSD project and is reliable in terms of security --Install with pkg on FreeBSD --Install from source on Linux (article introduces examples on Debian / Ubuntu, CentOS) --The source scale of doas is much smaller than that of sudo

Recently, I see the fact that there are people who do not know man and make, so I have described it a little roundabout, including usage examples around that.

This article is almost the same as the content of "from sudo to doas" published in the January 2020 issue of Software Design magazine, rather than the original manuscript itself. When I revealed the story, I originally wrote it with the intention of publishing it on Qiita, but the truth is that Software Design picked up the fact that I wrote too much and the volume became an article in a magazine. .. </ small>

sudo command

The sudo command is so widespread that it is essential for system management in UNIX-like operating systems.

Originally, the su command is provided as standard in UNIX, and it is also available in various BSD and Linux distributions. su is a command that the user needs to temporarily gain root privileges, and when executed, the shell of the root environment starts, but the root password is required to gain privileges. You can get any user rights that are not root, but you will need the password of the user who wants to get those rights. In other words, su requires the password of the user who has the authority to use it from now on.

If you have one server and the administrator is still the user, su is fine when using privileges. Now consider the case where you have multiple servers and each has a common root password, and you need to give a particular user the privileges of a particular server only. In order to use su, if the root password remains the same for all servers, the user will be able to obtain privileges on another server, so it is necessary to take measures such as setting the root password for only that server. Become. If you set this kind of thing on multiple servers, you will eventually need to change the root password or prepare a privileged user other than root.

sudo solves the above problem by using your own password as the password needed to gain privileges. Of course, it is a problem if everyone can get the privilege with their own password, so it is possible to limit the users with the configuration file and also limit the commands that can be used with the privilege. It also comes with a dedicated command called visudo to edit the config file.

I personally find sudo useful in the following three points.

--You can get privileges with your own password and limit the commands that can be used when privileged. If necessary, you can set it to gain privileges without a password. --By specifying the command name after sudo, only that command can be executed with privilege, which is convenient when only one command requires privilege. --Once you enter the password with sudo, you can omit entering the password if you use sudo within a certain period of time, which is very convenient when you work continuously with privileges.

To add a little bit about the second item, you can execute only one command with privileges by specifying an argument with su, but the parameter specification is complicated and the usability is improved to sudo.

sudo vulnerability issue

Commands that handle privileges, such as sudo, tend to have vulnerability issues. Most recently (mid-October 2019), sudo vulnerabilities have been talked about. The vulnerability was that users with sudo-enabled settings could gain privileges beyond the configuration limits.

sudo is an old command that has a history of about 30 years, and I have been using it since the early 90's, but since then I have seen reports of sudo vulnerabilities from time to time. Although sudo has a lot of management functions and can be set up conveniently, there are many functions that are certainly convenient but rarely used in practice. It is very difficult to read the setting manual and understand all the functions, and I personally use it while thinking "I don't need such functions ..." [^ 1].

[^ 1]: To be honest, I don't understand all the functions of sudo.

When I saw this report of sudo vulnerability, I thought, "Is it vulnerable to sudo again?", But I remembered that recent OpenBSD has doas as a standard command. If it's my usage, the function up to sudo is completely unnecessary, so I took this opportunity to introduce doas.

doas command

Similar to sudo, doas also gains privileges using its own password. The difference is that it's very limited in functionality compared to sudo, and this is the bare minimum you'll need. For example, sudo can manage multiple users and commands by grouping them by using commands and user aliases, but doas does not have any convenient functions for such management. However, at a glance, it seems that doas will not be a problem in my range of use, and I think that this is enough for many range of use.

As mentioned above, doas is one of the commands born from the OpenBSD project. OpenBSD is a very security-focused operating system, and OpenSSH, a typical implementation of SSH that is now commonplace, is also a product of the OpenBSD project. In that respect, doas born from OpenBSD can be said to be reliable in terms of security. [^ 2].

[^ 2]: Don't get me wrong because I don't trust sudo

install doas

FreeBSD

I usually use FreeBSD as my main environment, so I thought that doas would already be in ports, and as expected, it was in security / doas and pkg also existed. Then install doas pkg.

$ sudo pkg install doas
Updating FreeBSD repository catalogue...
----- (Omission) -----
New packages to be INSTALLED:
	doas: 6.2

Number of packages to be installed: 1

Proceed with this action? [y/N]: y
[1/1] Installing doas-6.2...
[1/1] Extracting doas-6.2: 100%
=====
Message from doas-6.2:

--
To use doas,

/usr/local/etc/doas.conf

must be created. Refer to doas.conf(5) for further details.
----- (The following is omitted) -----

doas.conf settings

After the installation is complete, the next step is to set up doas. As you can see from the installation message, the settings are written in /usr/local/etc/doas.conf. Since the package does not prepare files that are the basis for editing doas.conf, it is necessary to set from scratch, but it is not difficult. Actually, this is not the first time I have set doas, and I have experience setting and using it with OpenBSD in the past. However, at that time, I only wrote one line of the minimum settings for doas.

Whatever the case, it's important to check the manual when setting up a new command. Use the man command to see how to configure doas.conf.

$ man doas.conf
DOAS.CONF(5)              FreeBSD File Formats Manual             DOAS.CONF(5)

NAME
     doas.conf - doas configuration file

SYNOPSIS
     /usr/local/etc/doas.conf

DESCRIPTION
     The doas(1) utility executes commands as other users according to the
     rules in the doas.conf configuration file.

     The rules have the following format:

           permit|deny [options] identity [as target] [cmd command [args ...]]

     Rules consist of the following parts:

     permit|deny  The action to be taken if this rule matches.
----- (The following is omitted) -----

As you can see, in doas.conf, one rule is described per line, and although it is described in the latter half,'' acts as an escape, which is a relatively familiar specification. There is a setting example in the latter half of man, but even if it is included, the whole is short enough to beat, and you can see that there are very few setting items compared to sudoers which is a sudo setting file. For example, there are only four options keywords: nopass, keepenv, sentenv, and persist.

Normally, each line is a permit followed by the required options, and the identity is set to the user name or group name. To specify a group name, add: at the beginning of the group name, such as: wheel. As mentioned above, the manual also contains setting examples, so it is a good idea to refer to them.

Since doas does not have a dedicated command for editing the configuration file like visudo in sudo, prepare /usr/local/etc/doas.conf with a familiar editor such as vi, vim, nano. The following example provides a single line of doas.conf.

$ sudo vi /usr/local/etc/doas.conf
----- (doas.Editing conf) -----
$ ls -l /usr/local/etc/doas.conf
-rw-r--r--  1 root  wheel  64 Oct 21 18:11 /usr/local/etc/doas.conf
$ cat /usr/local/etc/doas.conf 
permit nopass minmin
$

As in this example, doas.conf permissions should be set to 644, owned by root, or 640 or 600 as needed. Since the author usually uses minmin for the user name, it is shown as an example here.

In the settings, the nopass option is added to options so that any command can be executed with privileges without a password. ** I do not recommend this because there is a risk of setting without a password with the nopass option **. This is just my personal server setting, and other servers use the nopass option or not.

As I wrote at the beginning, sudo has the ability to skip password entry for a while (15 minutes by default) once sudo is run and used repeatedly, and doas also has a persist option that provides similar functionality. It seems that it is prepared, but it is stated that it can be used only with OpenBSD.

    persist  After the user successfully authenticates, do not
             ask for a password again for some time. Works on
             OpenBSD only, persist is not available on Linux or
             FreeBSD.

In sudo, visudo checks the syntax of sudores after editing and warns that there is an error and can edit again without exiting, but in doas.conf it may use an ordinary editor and it is set at the time of such editing You cannot confirm the mistake. Instead, doas itself has the ability to check the config file with the -C option.

$ doas -C /usr/local/etc/doas.conf
$

If there is an error, an error message will be displayed, so you can see that doas.conf can be described without any problem here.

If you make a mistake in doas.conf, there is a risk that doas cannot be executed, so if you are editing an existing doas.conf, it is safer to follow the steps below.

$ cp /usr/local/etc/doas.conf /tmp ← Once/doas in tmp.Copy conf
$ vi /tmp/doas.conf                 ← doas.Editing conf
<Make the necessary edits>
$ doas -C /tmp/doas.conf ← Confirmation of settings after editing
$ doas install -m 644 /tmp/doas.conf /usr/local/etc  ← doas.Update conf
$

You can look up doas options with man doas, but I'll list them briefly.

--- a: Specify the doas authentication method described in /etc/login.conf --- C file name: Check the syntax with the specified file as the doas configuration file --- n: Specify when using non-interactive (such as when using doas on a remote server via ssh). --- s: Launch the user's shell --- u Username: Get the privileges of the specified user (default is root) ---: Interpret what is specified after that as an execution command and an argument

The id command is the best way to see if doas works.

$ doas id
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
$ 

As you can see, the uid is 0, that is, you can execute the id command with root privileges and you have the privilege.

Environment variables when using doas

Personally, the most important thing is how to handle the environment variable PATH when using doas. For example, if you have commands for personal use in ~ / bin in your home directory and you want to use the same for system administration work, those commands simply cannot be used if the PATH changes. Even when you switch to privilege with doas, it is convenient if you can take over the PATH that you normally set.

First, let's check what happens to the PATH with the env command.

$ doas env | fgrep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$

By default under the doas environment, it becomes such a PATH and you can see that your PATH is not inherited. For the purpose of inheriting the personal PATH, it seemed that I should use the keepenv option at a glance, so I set it and tried it.

$ cat /usr/local/etc/doas.conf 
permit nopass keepenv minmin
$ doas env | fgrep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ 

There is no change in PATH. So take a closer look at keepenv in doas.conf.

    keepenv  The user's environment is maintained.  The default
             is to reset the environment, except for the
             variables DISPLAY and TERM.
             ----- (Omission) -----
             Note: The target user's PATH variable can be set at
             compile time by adjusting the GLOBAL_PATH variable
             in doas's Makefile. By default, the target user's
             path will be set to
             "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:"

As you can see from the last Note: section, the PATH for privileged users in doas is set to the one specified at compile time.

** In general, inheriting the environment variable PATH as is a privilege poses a security risk **. So the default PATH when running doas is like this, but it's okay for the administrator to take over his PATH if needed. After checking, I found that I should explicitly specify it with the setenv option to inherit the user's PATH.

$ cat /usr/local/etc/doas.conf 
permit nopass keepenv setenv { PATH } minmin
$ doas env | fgrep PATH
PATH=/home/minmin/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/sbin:/usr/sbin
$ 

After all, doas.conf on my personal server was set up with two lines as follows.

$ cat /usr/local/etc/doas.conf
permit nopass setenv { PATH } minmin
permit nopass keepenv root
$

Even if you are a root user, when you use doas, if there is no setting, execution of doas will be refused, so the second line is a setting to avoid it.

In the description of man, the user's HOME variable can be read so that it can be inherited by keepenv, but when I tried it, it seems that it is not so, and if you want to inherit the HOME variable, you need to explicitly specify it with setenv. In my case, it doesn't matter because I don't use the desktop environment on FreeBSD, but when using the desktop environment, it seems that the application may crash if the environment variables are not inherited properly.

doas execution record

When you run doas, it will be recorded in /var/log/auth.log for FreeBSD (same for sudo). You also need privileges to see auth.log, so use doas to check.

$ doas id
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
$ doas tail -2 /var/log/auth.log
Oct 28 23:11:17 fbsdsvr doas: minmin ran command id as root from /home/minmin
Oct 28 23:11:37 fbsdsvr doas: minmin ran command tail -2 /var/log/auth.log as root from /home/minmin
$ 

Note that limiting the tail to only -2 and two lines only prevents the display of extra things to make this sample, and there is no further meaning.

Linux edition

I noticed that doas can be used on Linux because there is a Linux string in the persist option of the manual quoted in the previous section, and I actually introduced it to Linux. There are various distributions of Linux, but here I'm trying it on Debian / Ubuntu and CentOS.

Get doas source

Since doas is not a command known to everyone at the moment like sudo, there are no packages for Linux as far as I can see. In order to install doas, you need to prepare the source and compile and install it.

The source is included in the OpenBSD source tree because doas itself is part of OpenBSD. However, even if you bring only the doas part from the OpenBSD source, there are things that are insufficient as it is, and compiling on other OS will not be smooth. Therefore, what is packaged at the source level so that it can be compiled on other OS such as Linux is published on Github.

https://github.com/slicer69/doas/

First, extract this source locally with git clone.

$ git clone https://github.com/slicer69/doas.git
----- (Omission) -----
$ cd doas
$ ls -F
LICENSE   README.md  doas.1  doas.conf.5  env.c
Makefile  compat/    doas.c  doas.h       parse.y
$

As you can see from the list of files, doas is written in C.

Compiling and installing doas (Debian / Ubuntu edition)

According to the README.md, on Linux you can compile with make and install with make install, so there seems to be nothing difficult. So let's compile it right away. I've tried the following on Debian, but I've confirmed that Ubuntu can do exactly the same.

In order to compile C programs on Debian, the build-essential package, which is the development environment, is required, so first install build-essential.

$ sudo apt update
----- (Omission) -----
$ sudo apt -y install build-essential
----- (Omission) -----
$ 

Of course, if you have already prepared the development environment, you can omit this work.

Let's actually compile it.

$ make
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o doas.o doas.c
doas.c:48:31: fatal error: security/pam_appl.h:There is no such file or directory
 #include <security/pam_appl.h>
                               ^
compilation terminated.
<Built-in>:target'doas.o'Failed with the recipe
make: *** [doas.o]Error 1
$

If the header file pam_appl.h is not found, an error will occur and compilation will stop. If you look it up, pam_appl.h is what you need to create a program that uses PAM. In fact, README.md stated that libpam0g-dev is required (README.md should be read carefully ^^;).

$ sudo apt -y install libpam0g-dev

Let's take a second look and compile it again.

$ make
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o doas.o doas.c
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o env.o env.c
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o compat/execvpe.o compat/execvpe.c
compat/execvpe.c: In function ‘execvpe’:
compat/execvpe.c:61:5: warning: nonnull argument ‘name’ compared to NULL [-Wnonnull-compare]
  if ( (! name) || (*name == '\0') ){
     ^
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o compat/reallocarray.o compat/reallocarray.c
yacc parse.y
make: yacc:The command was not found
Makefile:54:target'y.tab.o'Failed with the recipe
make: *** [y.tab.o]Error 127
$

Without the yacc command, I got an error and the compilation ended, and I noticed that build-essential didn't include yacc (that's right). Debian allows you to choose a package from several yacc implementations, but here we will install the Berkeley version of yacc byacc and compile it again. Even if you install bison instead of byacc, you can compile it on Debian / Ubuntu as it is.

$ sudo apt -y install byacc
----- (Omission) -----
$ make
yacc parse.y
cc -include compat/compat.h -Icompat -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -c y.tab.c
----- (Omission) -----
cc -o doas doas.o env.o compat/execvpe.o compat/reallocarray.o y.tab.o compat/closefrom.o compat/errc.o compat/getprogname.o compat/setprogname.o compat/strlcat.o compat/strlcpy.o compat/strtonum.o compat/verrc.o -lpam -lpam_misc
$ 

Now that the compilation is complete, it's time to install.

$ sudo make install
mkdir -p /usr/local/bin
cp doas /usr/local/bin/
chmod 4755 /usr/local/bin/doas
mkdir -p /usr/local/man/man1
cp doas.1 /usr/local/man/man1/
mkdir -p /usr/local/man/man5
cp doas.conf.5 /usr/local/man/man5/
$

As you can see from the command executed, the files actually installed by make install are shown in the following table.

File File contents
/usr/local/bin/doas program body of doas
/usr/local/man/man1/doas.1 doas command itself man file
/usr/local/man/man5/doas.conf.5 doas.conf man file

With this number of files, it's not difficult to manage even unpackaged programs. If you need to uninstall doas in the future, just delete these three files and the doas config file /usr/local/etc/doas.conf.

After installing doas, prepare doas.conf, but here I prepared the same one set in FreeBSD in / usr / local / etc.

In Debian, the execution of doas is recorded in /var/log/auth.log as in FreeBSD, but when options are specified for the command to be executed, it is explicitly separated from the command due to the option analysis library. It seems that you need to specify "-" to indicate.

$ doas id
uid=0(root) gid=0(root) groups=0(root)
$ doas tail -2 /var/log/auth.log
doas: invalid option -- '2'← ‘2’ is treated as an option of doas itself and an error occurs
usage: doas [-ns] [-a style] [-C config] [-u user] command [args]
$ doas -- tail -2 /var/log/auth.log
Oct 30 23:50:25 idmdemo0 doas: minmin ran command id as root from /home/minmin
Oct 30 23:50:35 idmdemo0 doas: minmin ran command tail -2 /var/log/auth.log as root from /home/minmin

Compiling and installing doas (CentOS)

I also tried compiling and installing doas on CentOS.

If you do not prepare the PAM header file and yacc, the same problem as Debian will occur, so I installed it with gcc and make required for C compilation. The PAM development environment uses the pam-devel package, and yacc uses the byacc package.

$ sudo yum install gcc make pam-devel byacc
----- (Omission) -----
$ make
cc -Wall -O2 -DUSE_PAM -DDOAS_CONF=\"/usr/local/etc/doas.conf\"  -D_GNU_SOURCE -include compat/compat.h -Icompat  -c -o doas.o doas.c
----- (Omission) -----
cc -o doas doas.o env.o compat/execvpe.o compat/reallocarray.o y.tab.o compat/closefrom.o compat/errc.o compat/getprogname.o compat/setprogname.o compat/strlcat.o compat/strlcpy.o compat/strtonum.o compat/verrc.o -lpam -lpam_misc
$ sudo make install
----- (Omission) -----
$ 

There is no difference in the installed files from Debian.

In case of CentOS, if bison is already installed, there is no need to install byacc newly, and you can compile by starting make with make YACC ='bison -y'.

Set doas.conf as in the OS already introduced, and check the operation of doas with the id command. In case of CentOS, the execution record of doas is / var / log / secure.

$ doas id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
$ doas -- tail -2 /var/log/secure
Oct 30 23:56:56 centos0 doas: minmin ran command id as root from /home/minmin
Oct 30 23:57:15 centos0 doas: minmin ran command tail -2 /var/log/secure as root from /home/minmin

Compare the size of the source with doas and sudo

Since the source of doas was expanded locally, I thought about this time and simply compared the scale of the source with sudo by the number of lines.

Source size of sudo

sudo is counted with the latest sudo-1.8.28p1.tar.gz at the time of writing this article.

$ tar xf sudo-1.8.28p1.tar.gz
$ cd sudo-1.8.28p1
$ ls -F
ABOUT-NLS               config.h.in             ltmain.sh
ChangeLog               config.sub              m4/
INSTALL                 configure*              mkdep.pl*
INSTALL.configure       configure.ac            mkinstalldirs*
MANIFEST                doc/                    mkpkg*
Makefile.in             examples/               pathnames.h.in
NEWS                    include/                plugins/
README                  indent.pro              po/
README.LDAP             init.d/                 pp*
aclocal.m4              install-sh*             src/
autogen.sh*             lib/                    sudo.pp
config.guess            log2cl.pl*
$ 

Since sudo contains many library files in addition to the main body of sudo, I counted the C source files (* .c) and header files (* .h) under the src directory. [^ 3]

[^ 3]: I haven't confirmed whether the source of the core part of sudo is actually only this range.

$ find src -type f -name '*.[ch]' | xargs wc -l
      76 src/preload.c
     735 src/exec_monitor.c
----- (Omission) -----
     113 src/sudo_exec.h
     197 src/get_pty.c
   12612 total
$

You can see that there are about 12600 lines. By the way, when I counted all the files corresponding to *. [Ch] included in the source package, there were more than 100,000 lines, and I was honestly very surprised.

source scale of doas

On the other hand, doas has about 1200 lines as follows, and you can see that it is very small compared to sudo.

$ wc *.[chy]
     564    1716   13080 doas.c
      65     238    1673 doas.h
     230     693    4951 env.c
     343    1044    6831 parse.y
    1202    3691   26535 total
$

The libraries required for porting to a non-OpenBSD OS are under the compat directory, but even if you count all of them, the doas source package is about 3000 lines.

The smaller the source, the better, but the larger the source, the higher the risk of including defects.

After installing doas

In my case, sudo often uses the -u and -s options, but doas also allows them to use the same functionality with the same option specifications. In other words, sudo is unnecessary if there is doas in my range of use, so I uninstalled sudo from the system in the FreeBSD environment.

However, some of my own shell scripts use sudo, so I set sudo as a symbolic link to doas, including the immediate support until it is rewritten.

$ doas ln -s doas /usr/local/bin/sudo
$ ls -l /usr/local/bin/sudo
lrwxr-xr-x  1 root  wheel  4 Oct 22 10:46 /usr/local/bin/sudo -> doas
$ ls -lL /usr/local/bin/sudo
-rwsr-xr-x  1 root  wheel  28800 Oct  4 05:20 /usr/local/bin/sudo
$sudo id ← The substance of sudo from here is doas
uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
$ sudo -V ← sudo is-Option to display version in V but not in doas
doas: illegal option -- V
usage: doas [-ns] [-a style] [-C config] [-u user] command [args]
$ 

In the case of Linux, some Linux distributions may build the system on the assumption that sudo is present, so if you remove sudo from your system, doas is not exactly the same as sudo. Let's do it after understanding that there is no problem and judging that there is no problem. You don't have to force sudo to be removed.

Finally

Even if a vulnerability is discovered in sudo, there is no risk of being attacked remotely due to the nature of the command. You don't have to rush to take measures, especially if the server is used only by you or someone you can trust. In that sense, it may not be necessary to switch to doas on a server that is used privately, but personally, if you want to use the same function, you should choose a simple one. Because of this, I think it was the correct answer to introduce doas this time.

Recommended Posts

Since sudo is that, try switching to doas
[Python] tkinter Code that is likely to be reused
[Python] pandas Code that is likely to be reused
I want to say that there is data preprocessing ~