sudo
an alternative
Don't forget to look at please.html, a rust sudo alternative.
time restricted entries
A little known feature of sudo is that you can specify NOTBEFORE
and
NOTAFTER
rules. This means, if someone should only be able to run a
command until a certain time, or not before a given time, it can be
specified using these keywords.
Maybe Alice changes her role from web developer at the end of 2019, so no longer requires the ability to run the apache scripts:
alice ALL=(ALL) NOTAFTER=20191231235959 NOPASSWD: \
/usr/sbin/apache2ctl restart, /usr/sbin/apache2ctl stop, \
/usr/sbin/apache2ctl start, /usr/sbin/apache2ctl configtest
runaway wildcards
Most of us know that the following is rather dangerous to use in a sudoers file:
*
Well, to be more specific, something like the following:
user ALL=ALL /bin/cat /var/log/messages*
As the documentation points out, that *
can expand to ANY
character, any number of times. That would permit the following:
sudo /bin/cat /var/log/messages /etc/shadow
All we had to do was match the initial command and first argument. If you rotate log files, then the chances are you use the date as the file suffix, perhaps in ISO8601 format like a good citizen.
What we'd like to describe, is something like this, the messages file with, or without the date extension followed by .gz or, in regex:
user ALL=ALL /bin/cat /var/log/messages(-\d[8].gz)?
Wouldn't it be nice if we could do this?
It just so happens, that there's a patch for this.
Once it is applied, you can use the following syntax:
user ALL=ALL /bin/cat m{/var/log/messages((.[0-9]+|-[0-9]+)(.gz)?)?}
How about more log files, using the same extension format:
user ALL=ALL /bin/cat m{/var/log/(messages|syslog|maillog|kern|user)((.[0-9]+|-[0-9]+)(.gz)?)?}
You're welcome. One thing, the command must not be a regex, visudo
checks the command part is valid.
What if you're not in a position where you can use this because you cannot deploy a source code build? Well, there is one last option. You can do something like this:
user ALL=ALL /bin/cat /var/log/messages*
user ALL=ALL !/bin/cat /var/log/messages* *
If you were to include any file following a trailing /
then you need
to add an additional exclusion to prevent path traversal (that's a word
I've not thought about since early IIS web server issues, and sometimes
I still see ..%255c..%255cwinnt/system32/cmd.exe
in log files):
user ALL=ALL /bin/cat /var/log/*
user ALL=ALL !/bin/cat /var/log/* *
user ALL=ALL !/bin/cat /var/log/*..*
This can limit the damage, but it's not as tight as a regex. Ordering matters, if you reverse the instructions, or place the first after the last, then it is possible to read /etc/shadow again.
With the above pattern matching, the last match will win, ensure you include the negative matches last.
what if we need to include two wild cards in a rule?
Remember the rules above, always put the positive match at the top, and follow it with negatives as the last match has effect.
user ALL=(www-data) /usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache* */bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache*..*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/* */maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*..*/maps/*.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/* *.db
user ALL=(www-data) !/usr/local/apache*/bin/httxt2dbm -i - -o /var/www/sites/*/maps/*..*.db
I hope you find this patch useful.
safe file edits
Imagine you're managing the configuration for a busy computer. A new user joins the company and you need to re-push the configuration file.
In pushing out the configuration file you find that the disk filled, and the configuration was left in a partial state, a line was not finished as it crossed a block boundary. As a result sudo will now fail to parse the configuration and will not allow users to elevate. That's a shame.
To avoid problems like this, use visudo
. You can use this interactive
editor to modify sudoers
or other sudoers
files with -f
:
visudo -f /etc/sudoers.d/users
This is great for interactive editing. To edit with sed
, or echo >>
,
you can do something like this (append):
export EDITOR='tee -a'
echo 'alice ALL=ALL /usr/sbin/apache2ctl' \
| visudo -f /etc/sudoers.d/alice
To filter, like with sed
, you can do the following (replace alice with
bo and remove apche2ctl:
export EDITOR='tee -a'
cat /etc/sudoers.d/bob \
| grep -v /usr/sbin/apache2ctl \
| sed -e 's/^alice/bob/g' \
| visudo -f /etc/sudoers.d/bob
visudo
will test the configuration before putting the files in place.
This is very important so that end users do not experience breakage in
their access. sudo
is very critical to the stable running of systems
whist ensuring least privilege access is maintained in place. Don't give
your users excuse to have higher access than they need, they'll likely
come running for root credentials as soon as lower access breaks,
especially if they're from a
windows background!
something with a space in the argument
If you want to permit something like the following (for when you don't
have root login on the remote machine, but can run sudo
):
sudo rsync -avP --rsync-path="sudo rsync" /source/directory user@remote:/some/where/to/copy/to
This might seem odd, but we'll get there, you could add an entry like the following in sudoers:
user ALL=ALL /usr/bin/rsync -avP --rsync-path=sudo\ rsync /source/directory user@remote:/some/where/to/copy/to
It's important to note the absence of quote marks around sudo rsync
,
and the backslash separating the two words. This is down to how the
shell unqoutes the parameters.
safely edit a file that belongs to another user
Suppose you wish to permit a user (frank) to edit files belonging to
opendkim
in /etc/opendkim/*
and /etc/opendkim.conf
, but we don't
know all their names yet:
frank ALL = (opendkim) sudoedit /etc/opendkim.conf
frank ALL = (opendkim) sudoedit /etc/opendkim/*
frank ALL = (opendkim) !sudoedit /etc/opendkim/*..*
frank ALL = (opendkim) !sudoedit /etc/opendkim/* *
Now, all frank
needs to do is:
$ sudoedit -u opendkim /etc/opendkim.conf
You could easily modify files belonging to any other user by changing the relevant bits above.
how do i use : within a chown user:group sudo rule
:
is a control character. In fact the following should be treated as
control characters: , : = \
.
character | example use |
---|---|
, | separates rules: frank ALL = (ALL) /bin/ls, /bin/cat |
: | join character for aliases |
= | used in definitions |
\ | used as an escape character |
In order to use :
within a rule, such as chown
, you may do the
following:
frank ALL = (root) /bin/chown frank\:frank -R /home/frank