sudo
and
op
at least once.
sudo
interface
to op
via sudop
In a sensitive production environment where escalated privilege
must be allowed for multiple projects managed by multiple teams,
an administrator will want a tool that allows very specific and
auditable access to be given to each project managed in a scalable
way. A tool that can be used meet this need is op
.
However, there is a significant user base that is already familiar
with and user automation written for sudo
.
Unfortunately, sudo
is lacking in its ability
to strictly specify rules, harder to scale to many projects, and much
harder to audit than op
.
With sudop
, it is possible to provide a
sudo
interface to customers while still
managing the rules in op
. Only a little bit
of glue in the op
rule-base is needed as
a hint sudop
for it to map a sudo
rule that allows the execution
of only a single file or range of files with a full path on the command
line to an op
rule.
The user calls sudop
in place of sudo.
Either the user's path is modified to find a symlink to
sudop
before sudo
itself,
or the sudo
binary is simply replaced with
a symlink to sudo
. The sudo
options that can be translated to op
are honored. Options that are not relevant
to an op
rule, such as listing default sudo
permissions, are silently ignored. Wherever possible, the output of
sudop
is made to match sudo
.
sudop
does not do any privilege escalation on its own.
If a command is successfully mapped to an op
rule,
op
is simply exec
ed as
the calling user with the arguments specified by the mapping followed by the
arguments specified by the user.
The exit code of sudop
is the exit code of op
unless
the mapping itself failed.
If the -b
option
is specified, op
is double forked instead and success
is always returned.
The mapping data sudop
uses is stored in the
op
access configuration files in
/usr/local/lib/op
alongside the real op
rules.
These access files are not world readable for good reason, so
sudop
itself
needs privilege escalation to lookup the rule mappings.
A support script, sudomap
is provided and installed in
/usr/local/libexec/sudop
.
An op
rule must be installed just to
allow sudop
to run this script as
the right user (see below).
When a user passes a command to sudop
, the
sudomap
rule is called with the command the
user specified, but not any of the arguments. sudomap
uses mk
to scan all of
the .cf
files in the current working
directory for mk
rules with
the name Sudop
.
If a pattern in the submarker matches the command the user specifies,
the mk
rule is executed as a shell command, and
the output is returned to sudop
.
Note that executing a Sudop
mk
rule is not the same as executing an
op
rule.
The Sudop
mk
rules
should only return rule mapping information to sudop
.
Generally, the command executed by mk
rule will only
be an echo
statement, however
much more sophisticated mapping is possible.
If specified by the user when calling sudop
,
the options -u
and -g
are
also passed to sudomap
. When these options are given,
the environment variables USER
and
GROUP
are defined when mk
is executed. These can be used to setup the -u
and
-g
options to op.
Note that the -f
option is also particularly useful
when combined with the %s
mk
expander (see below).
The output line from sudomap
is captured by
sudop
and passed as-is as arguments to op.
If sudomap
does not return any output, it is
assumed the mapping has failed, and a sudop
exits with
a failure.
If the user calls sudop
with the
-l
option, this option is passed to
sudomap
with no other arguments.
sudomap
will then have mk
execute every Sudop
mk
rule with a submarker of -list
.
The combined output of all those executions in translated into
a list of possible commands for the user.
Both /usr/local/bin
and
/usr/bin
will be searched for these tools.
op
version 2.27 or latersudo
version 1.6.7 or latermk
version 5.8 or later
By default, the sudop
script itself is installed under
it's own name in /usr/local/bin
.
If sudo
is not installed or you simply want
users to be able to choose the alternate interface, you
can make a symlink from /usr/local/bin/sudo
to
/usr/local/bin/sudop
.
Any user that has /usr/local/bin
in their path before
a path to a real copy of sudo
will use the
sudop
interface instead.
There is a
mk
rule on the sudop
Makefile
, NukeSudo
,
that will replace any copy of sudo
in
/usr/local/bin
with
a symlink to sudop
. This should override
sudo
in favor of
sudop
for all the users on the system.
mk -m NukeSudo -droot@host Makefile
op
rule needs to
be created that runs sudomap
as a user that can
read the access files, usually root. The op
rule
itself must be named sudomap
, and it will be
called transparently by sudop
.
A user should never need to run it directly, but any user that is to be
allowed to run sudop
needs to be able to run the rule.
The current working directory of the rule must be where rule mappings are
stored, which should be the op
access file directory.
This example rule should work for almost all cases.
sudomap /usr/local/libexec/sudop/sudomap $* ; uid=root dir=/usr/local/lib/op users=.*
op
rulessudo
command to be mapped, there must be
a corresponding mk
rule in one of
the op access files with the marker Sudop
.
The submarker in the parenthesis that follow should be an absolute path that
matches a specific command to be mapped a single op
rule. If a range of sudo
commands need to be mapped
to a single op
rule, then the submarker should be an
asterisk and an embedded mk
mapfile should be used to
match the commands by regular expression (see example below).
When run, the mk
rule that matches the command
must output a single line that includes the name of
the op
rule to run in place of
the sudo
command. The mk
rule
must not run the op
itself. Any extra options to
op
can be specified by placing them before
the name of the op
rule in the output line.
This is especially useful for op
's
-f
and -s
options.
Generally, a Sudop
mk
rule
takes the following form and only an echo
statement
will be executed.
# $Sudop(command): echo "op_options op_rule"
When a range of commands must be handled by a rule, an embedded
mk
mapfile should be used to match the given command to
a regular expression. Multiple matches may be placed in
a single embedded mapfile.
# $Sudop(*): %|"# "%J echo "%<%j>" # %s command_regexp op_options op_rule # %s command_regexp op_options op_rule # $Sudop(*): %j%^
-list
, to
support sudop
's -l
option.
Support for a particular sudo
command or command
pattern can be advertised to the user by
adding a Sudop(-list)
mk
rule.
Each one of these mk
rules will result in a line of
output in the user's list. The mk
must
produce one line of output consists of two fields separated by a colon,
a list of users and the sudo
-like command glob pattern.
A Sudop(-list)
mk
rule
should take the following form and only consist of
an echo
statement.
# $Sudop(-list): echo "user:command_glob"
Allow any user in the trusted
group to run
tcpdump
as root
.
Limit the options so that -w
can only specify a
file under /tmp/tcpdumps
to prevent the user
from writing on sensitive files as root. Notice that a
sudo
argument glob can't match the
-w
option to tcpdump specifically, so we do
the best we can and just tell the user any option is
acceptable when they list the rule.
# $Sudop(/usr/sbin/tcpdump): echo "tcpdump" # $Sudop(-list): echo "root:/usr/sbin/tcpdump *" tcpdump /usr/sbin/tcpdump $* ; $*=^([^-]|-[^w]|-w/tmp/tcpdumps/) uid=root groups=^trusted$
Only execute a start script with no options. Run only as
user myapp
. Allow only users in
group myappdev
.
# $Sudop(/opt/myapp/libexec/start): echo "myapp-start" # $Sudop(-list): echo "myapp:/opt/myapp/libexec/start" myapp-start /opt/myapp/libexec/start ; uid=myapp groups=^myappdev$
Execute anything in the application's libexec
directory with any options.
We pass the full command path the user specified to
op
's -f
so that an
arbitrary executable can be run. However, the allowed path of
the command is restricted by a regular expression in
the op
rule.
We use the mapfile feature of mk
to
match the command in the submarker against a regular expression.
# $Sudop(*): %|"# "%J echo "%<%j>" # %s ^/opt/myapp/libexec/ -f \"%s\" myapp # $Sudop(*): %j%^ # $Sudop(-list): echo "myapp:/opt/myapp/libexec/* *" myapp $f $* ; %f.path=^/opt/myapp/libexec/ uid=myapp groups=^myappdev$
Allow the user to run a status command as any application installed under
/opt
. Do not allow the command to be run as
root
. With the listing rule, we tell the user
they can run the command as any user with the sudo
keyword ALL
as there is no specific list of
users. We decline to tell them they can't run the command as root.
# $Sudop(*): %|"# "%J echo "%<%j>" # %s ^/opt/[^/]+/libexec/status -f \"%s\" -u \"$USER\" appstatus # $Sudop(*): %j%^ appstatus $f ; %f.path=^/opt/[^/]+/libexec/status !u=^root$ uid=%u groups=^myappdev$
We can put multiple mappings in the same mapfile. Also note that we can create
as many Sudop(*)
rules with embedded mapfiles as
we want. Each is tested until the fist mapping that matches is used.
# $Sudop(*): %|"# "%J echo "%<%j>" # %s ^/opt/[^/]+/libexec/status$ -f \"%s\" -u \"$USER\" appstatus # %s ^/opt/foo(bar|baz|qux)/scripts/restart$ -f \"%s\" foorestart # $Sudop(*): %j%^ # $Sudop(-list): echo "ALL:/opt/*/libexec/status" # $Sudop(-list): echo "ALL:/opt/foo*/scripts/restart" appstatus $f ; %f.path=^/opt/[^/]+/libexec/status !u=^root$ uid=%u groups=^myappdev$ foorestart $f ; %f.path=^/opt/foo(bar|baz|qux)/scripts/restart uid=%f groups=^foodev$
-l
sudo
- Run the command as a specific user, if allowed.sudop
- Run the command as a specific user, if allowed.-l
sudo
- List allowed commands for the user.sudop
- List all sudop
mappings in the same format as sudo
.-b
sudo
- Run the command in the background.sudop
- Run the command in the background.-h
sudo
- Print sudo
usage.sudop
- Print sudo
usage.-V
sudo
- Print sudo
version number.sudop
- Print sudop
and op
version number.-H
sudo
- Set the environment variable HOME
the the target user's home directory instead of the callin user.sudop
- An op rule specififies how environment variables are to be handled, not the user.-s
sudo
- Run the shell in the environment variable SHELL
, if specified, or
else the default shell specified in the user's account.sudop
- An op rule specififies how environment variables are to be handled and whether the user's shell is to be used.-P
sudo
- Preserve the calling user's groups when setting the egid.sudop
- An op
rule initializes the groups of the target user.-v
sudo
- Update authorization timestamp.sudop
- Not relevant. op
doesn't use authorization timestamps.-K
sudo
- Reset a user's authorization timestamp.sudop
- Not relevant. op
doesn't use authorization timestamps.-K
sudo
- Remove a user's authorization timestamp.sudop
- Not relevant. op
doesn't use authorization timestamps.-L
sudo
- Describe possible options to Defaults
in sudoers
.sudop
- Not relevant.-S
sudo
- Read the password from standard in instead of the controlling tty.sudop
- Not relevant. An op
rule does not require a password-p
sudo
- Change the password prompt.sudop
- Not relevant. An op
rule does not require a password-a
sudo
- Select the type of authentication to use.sudop
- The op
configuration determines authentication.-c
sudo
- Set resource limitations for the command by associating it with a login class.sudop
- The op
rule specifies any resource limitations.-r
sudo
- SELinux security context role to use.sudop
- Not supported.-r
sudo
- SELinux security context type to use.sudop
- Not supported.$Id: sudop.html,v 1.12 2012/03/29 21:18:41 ksb Exp $