简介
系统管理员可以通过 sudo 实用程序让用户或组能够作为另一个用户运行命令。换句话说,可以分派命令特权,而不须要另一个用户的密码。root 用户通过在 /etc/sudoers 文件中配置 sudo 条目完成这个流程。运用 visudo 命令编辑此文件。在分派特权时,必须相信得到特权的用户会慎重地运用它。这里要澄清一个误解:sudo 不仅用于让用户作为 root 用户运行某些命令;它主要用于让另一个用户作为运用 程序用户/所有者运行运用 程序或系统命令。如果系统上当前安装了 sudo,它不会覆盖现有的 sudoers 文件。但是,一定要保留 /etc/sudoers 的备份并阅读升级说明。
安装 sudo
本文并不介绍 sudo 的基本功能,而是讨论不同的 sudo 特征。
对于本文,我运用 sudo version 1.7.2。如果您运用 AIX® 5.3,那么一定要有最新的 gcc 版本 (4.0.0)。# eXP ort LIBPATH=/usr/lib
# ./configure --with-aixauth
# make
# make install
作为 root 用户运用以下命令检查安装的版本,查看构建选项和当前安装的配置:# sudo -V
Sudo version 1.7.2
Sudoers path: /etc/sudoers
Authentication methods: 'aixauth'
< rest of output truncated>
从 1.6.9 版开始,在 sudo 执行给定的脚本或命令之前,会缩减一些系统环境变量(比如 LIBPATH)的配置。这会给在 sudo 下运行的现有命令造成疑问。但是,在大多数情况下有办法处理。
在默认情况下:
sudo 放在 /usr/local/bin 中。运用它作为另一个用户运行命令。
visudo 放在 /usr/local/sbin 中。运用它编辑 sudoers 文件。
sudoers 文件(如果还没有的话)放在 /etc 中。这个文件包含 sudo 条目。
sudoers 文件
/etc/sudoers(通常简称为 sudoers)文件控制谁可以运用 sudo 以及运用 sudo 运行什么。 root 用户或具有根特权的用户可以配置这些条目。sudoers 中 sudo 条目最基本的形式如下:<user> <host> = <user to alias> <passWord
作为某一用户运行以下命令,可以看到此用户能够运用 sudo 运行什么命令以及其他限定:sudo -l
运行 sudo 命令的一般格式为:sudo -u < user to run as> <command to run>
日志记录
通过在 /etc/syslog.conf 文件中运用以下配置,可以运用 syslog 在 /var/adm/messages 中记录通过 sudo 运行的所有命令:*.debug /var/adm/messages
但是,我认为 sudo 命令应该记录在一个单独的文件中,这样便于查看已经运行的 sudo 命令。当然,这也有助于监视失败的 sudo 活动。建立 /var/adm/sudo.log 文件,然后在 /etc/sudoers 文件中添加以下条目:Defaults logfile=/var/adm/sudo.log
Defaults !syslog
- |
现在,无论执行成功 还是失败,所有 sudo 活动都会记录在 /var/adm/sudo.log 中。
管理 sudoers
随着时间的推移,sudoers 文件中的条目会越来越多。这是因为服务器 上配置的运用 程序环境越来越多,也可能因为进一步分派当前任务以隔离责任。随着条目添加,输入 不正确会越来越多见。让 root 用户更方便地管理 sudoers 文件是有积极意义的。我们来讨论两种实现这个目标(至少建立良好的标准)的要领。如果有许多静态条目(在有 sudo 的每台机器上都运行相同的命令),那么把这些命令放在一个单独的 sudoers 文件中,这可以运用 include 指令来实现。
如果有许多用户条目,在添加或删除条目时会耗时很长。对于这种情况,好做法是对用户执行 分组。可以把用户直接分组在一起,这些组是有效的 AIX 组。
现在细致讨论这两种要领。
包含文件
在大型企业环境中,维护 sudoers 文件是一项主要且必须经常执行的任务。简化这项任务的一个处理方案是重新组织 sudoers 文件。一种做法是提取出静态或可重用的条目,它们在每台机器上都运行相同的命令。与审计/安全 或 storix 备份或一般性能报告一样,现在可以对 sudo 运用 include 指令。主 sudoers 文件可以包含本地条目,包含文件包含静态条目,所以很少须要编辑。在调用 visudo 时,它会扫描 sudoers。当看到 include 条目时,它会扫描此文件,然后返回到主 sudoers 文件继续扫描。在从主 sudoers 文件退出 visudo 时,它会进入包含文件执行 编辑。退出包含文件之后,返回到 AIX 提示。可以有多个包含文件,但是我不认为有必要这么做。
假设我们的辅助 sudoers 文件名为 sudo_static.<hostname>。在本文的示例中,运用的主机名是 rs6000。在主 sudoers 文件中,配置以下条目:#include /etc/sudo_static.rs6000
接下来,在 /etc/sudo_static.rs6000 文件中添加一些条目。不必配置所有 sudoers 指令或小节。如果这个文件包含不必要的条目,就不要包含它们。例如,我的包含文件只包含以下文本。
可以运用 %h 替代实际的主机名:#include /etc/sudo_static.%h.
我个人不运用这种要领,因为我遇到过返回的主机名包含额外字符的情况。这个疑问在 sudo 1.7.2 p1 中已经纠正了。bravo rs6000 = (root) NOPASSWD: /usr/opt/db2_08_01/adm/db2licd -end
bravo rs6000 = (root) NOPASSWD: /usr/opt/db2_08_01/adm/db2licd
bravo rs6000 = (db2inst) NOPASSWD: /home/db2inst/sqllib/adm/db2start
bravo rs6000 = (db2inst) NOPASSWD: /home/db2inst/sqllib/adm/db2stop force
在运行 visudo、保存并退出文件时,visudo 会让您按 Enter 开始编辑包含 sudoers 文件。与主文件一样,编辑此文件之后,sudo 会指出语法不正确(如果有的话)。另外,可以运用 visudo -f /etc/sudo_static.rs6000
直接编辑包含文件。
运用组
属于有效的 AIX 组的用户可以包含在 sudoers 中,这样针对单一用户的条目更少,sudoers 文件更容易管理。在运用组重新组织 sudoers 条目时,可能须要在 AIX 中建立一个新的组,其中只包含允许运用 sudo 运行某些命令的用户。要想运用组,只需在条目前面加上前缀 ‘%’。假设您有 devops 和 devuat 组,其中包含以下用户:
# lsgroup -f -a users devops
devops:
users=joex,delta,charlie,tstgn
# lsgroup -f -a users devuat
devuat:
users=zebra,spsys,charlie
允许 devops 组作为 dbdftst 运行 /usr/local/bin/data_ext.sh 命令。
允许 devuat 组作为 dbukuat 运行命令 /usr/local/bin/data_mvup.sh 和 /usr/local/bin/data_rep.sh。
可以配置以下 sudoers 条目:%devops rs6000 = (dbdftst) NOPASSWD: /usr/local/bin/data_ext.sh
%devuat rs6000 = (dbukuat) /usr/local/bin/data_mvup.sh
%devuat rs6000 = (dbukuat) /usr/local/bin/data_rep.sh
留心,对于前面的条目,devops 组中的用户在执行 /usr/local/bin/data_ext.sh 时不会提示他们输入密码。但是,会提示 devuat 组中的用户输入密码。用户 “charlie” 是这两个组(devops 和 devuat)的成员,所以他可以执行以上所有命令。
对 sudo 运用超时
sudo 的一个特征运用时间票据判断自从最后一次运行 sudo 命令以来已经过了多长时间。在指定的时间段内,用户可以重新运行命令而不会提示输入密码(此用户自己的密码)。超过这段时间之后,用户必须再次输入密码才能重新运行命令。如果用户提供了正确的密码,就执行命令,票据复位,计时重新开始。如果在 sudoers 中此用户的条目中有 NOPASSWD,票据特征是无效的。默认的超时是 5 分钟。如果希望修改默认值,只需在 sudoers 中添加一个条目。例如,可以运用以下条目把用户 “bravo” 运行任何命令的超时值配置为 20 分钟:
Defaults:bravo timestamp_timeout=20
作为用户运用以下命令销毁票据:$ sudo -k
销毁票据之后,在运行 sudo 命令时会再次提示用户输入密码。
请不要配置所有用户的超时值,因为这会造成疑问,尤其是在运行花费时间比较长的作业集合时。在 timestamp_timeout 变量中运用 -1 值可以禁用这个特征。时间票据是 /var/run/sudo 中包含用户名的目录条目。
变量
正如前面提到的,sudo 会缩减系统变量,这可能有危险。可以运用 sudo -V 检查哪些变量保持不变,哪些变量会被缩减。输出显示保持不变和缩减的变量列表。缩减 LIBPATH 显然很不方便。有两个处理要领 —— 编写一个包装器脚本或在命令行上指定环境。先看一下包装器脚本处理方案,假设您的一个运用 程序会停止或启动 DB2® 实例。可以编写一个脚本来保持变量不变。在 清单 1. rc.db2 中,运用以下代码访问实例配置文件,进而导出各个 LIBPATH 和 DB2 环境变量,这会保持环境变量不变: . /home/$inst/sqllib/db2profile
sudoers 中执行此脚本的条目如下,它们不会缩减任何系统环境变量:bravo rs6000 = (dbinst4) NOPASSWD: /home/dbinst4/sqllib/adm/db2start
bravo rs6000 = (dbinst4) NOPASSWD: /home/dbinst4/sqllib/adm/db2stop force
bravo rs6000 = (dbinst4) NOPASSWD: /usr/local/bin/rc.db2 stop db2inst4
bravo rs6000 = (dbinst4) NOPASSWD: /usr/local/bin/rc.db2 start db2inst4
在这个示例中,用户 “bravo” 可以作为用户 “dbinst4” 执行以上命令。通常,这个用户会运行:sudo -u dbinst4 /usr/local/bin/rc.db2 stop db2inst4
sudo -u dbinst4 /usr/local/bin/rc.db2 start db2inst4
清单 1. rc.db2
#!/bin/sh
# rc.db2
# stop/start db2 instances
# check to see if db2 inst is runningdb2_running(){state=`ps -ef grep db2sysc
grep -v grep awk '$1=="'${inst}'" { print $1 }'`
if [ "$state" = "" ]
then
return 1
else
return 0
fi}
usage ()
{
echo "`basename $0` start stop <instance>"
}
# stop db2
stop_db2 ()
{
echo "stopping db2 instance as user $inst"
if [ -f /home/$inst/sqllib/db2profile ]; then
. /home/$inst/sqllib/db2profile
else
echo "Cannot source DB2..exiting"
exit 1
fi
/home/$inst/sqllib/adm/db2stop force
}
# start db2
start_db2 ()
{
echo "starting db2 instance as user $inst"
if [ -f /home/$inst/sqllib/db2profile ]; then
. /home/$inst/sqllib/db2profile
else
echo "Cannot source DB2..exiting"
exit 1
fi
/home/$inst/sqllib/adm/db2start
}
# check we get 2 params
if [ $# != 2 ]
then
usage
exit 1
fi
inst=$2
case "$1" in
Startstart)
if db2_running
then
echo "db2 instance $inst appears to be already running"
exit 0
else
echo " instance not running as user $inst..attempting to start it"
start_db2 $inst
fi
;;
Stopstop)
if db2_running
then
echo "instance running as $inst..attempting to stop it"
stop_db2 $inst
else
echo "db2 instance $inst appears to be not running anyway"
exit 0
fi
;;
*) usage
;;
esac
保留系统环境变量的另一种要领是在 sudoers 中运用 Defaults !env_reset 指令:Defaults !env_reset
然后,在命令行上指定环境变量名和值:$ sudo LIBPATH=″/usr/lib:/opt/db2_09_05/lib64″ -u delta /usr/local/bin/datapmp
如果没有配置 !env_reset 条目,那么在试图运行命令时会从 sudo 收到以下不正确:sudo: sorry, you are not allowed to set the following environment variables: LIBPATH
如果发觉 sudo 还会缩减其他环境变量,那么可以在 sudoers 中指定变量名(运用 Defaults env_keep += 指令),让 sudo 保持这些变量不变。例如,假设对于我的一个运用 sudo 的脚本,sudo 会缩减运用 程序变量 DSTAGE_SUP 和 DSTAGE_META。为了保留这些变量,可以在 sudoers 中配置以下条目:Defaults env_keep += "DSTAGE_SUP"
Defaults env_keep += "DSTAGE_META"
留心,我指定了变量名,但是没有指定变量值。值已经包含在我的脚本中,比如:exp ort DSTAGE_SUP=/opt/dstage/dsengine; exp ort DSTAGE_META=/opt/dstage/db2
现在,在执行这个脚本时,这两个环境变量会保持不变。
保卫 sudo 路径
可以运用 secure_path 指令修改 sudoers 中默认的 PATH。这个指令指定当用户执行 sudo 命令时在什么地点寻找二进制代码和命令。这个选项的目的显然是要限定用户运行 sudo 命令的范围,这是一种好做法。在 sudoers 中运用以下指令,指定安全 PATH 及其搜索 目录:
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/opt/freeware/bin:/usr/sbin"
实施限定
可以对用户能够运行的命令实施限定。假设有一个名为 dataex 的组,其成员是 “alpha”、“bravo” 和 “charlie”。现在,已经允许这个组运行 sudo 命令 /usr/local/bin/mis_ext *,这里的星号代表传递给脚本的许多参数。但是,如果参数是 import,就不允许用户 “charlie” 执行此脚本。可以运用逻辑否 '!' 操作符配置这种条件。下面是在 sudoers 中的实现要领: %dataex rs6000 = (dbmis) NOPASSWD: /usr/local/bin/mis_ext *
charlie rs6000 = (dbmis) NOPASSWD: !/usr/local/bin/mis_ext import
在 visudo 中时,不要以为保存 sudo 条目就会让修改生效;不会的。必须退出 visudo,修改才会生效。
留心,逻辑否操作符条目出现在无限定的条目后面。可以在同一行上运用 多个逻辑否条目;只需以逗号分隔它们,比如:charlie rs6000 = (dbmis) NOPASSWD: /usr/local/bin/aut_pmp *
charlie rs6000 = (dbmis) NOPASSWD: !/usr/local/bin/aut_pmp create,
!/usr/local/bin/aut_pmp delete, !/usr/local/bin/aut_pmp amend
提交 sudo 命令
在企业环境中,把 sudo 命令提交给远程主机最好是作为 root 用户运用 ssh 脚本来完成,对于无密码登录,还应该在主机之间交换密钥。我们来看一个示例。对于地理上远程的机器,如果遇到某种硬件疑问(硬盘或内存),IBM® 工程师会到现场更换发生故障的硬件。在这种情况下,他们须要有 root 密码才能完成工作。一种实现要领是让工程师必须运用 sudo 访问 root 用户。在工程师访问站点之前告诉他们密码是有优点的。清单 2 演示提交这种配置的一种要领。仔细看看 清单 2,这里运用一个 for 循环包含要提交配置的主机列表。(但是,一般情况下,把这些主机名放在一个文本文件中并运用 while 循环读取它们。)运用 ‘here’ 文档要领建立 sudoers 的备份,然后在 sudoers 中添加下面的条目:
# -- ibmeng sudo root
ibmeng host1 = (root) NOPASSWD:ALL
接下来,建立用户 “ibmeng”,运用 chpasswd 配置此用户的密码。在这个示例中,密码是 ibmpw。然后在此用户的配置文件中添加一条消息,告诉用户如何 运用 sudo 访问 root 用户。因此,在工程师登录时,他会看到以下消息:IBM Engineer, to Access
当然,在工程师离开之后,应该锁住 ibmeng 账户。
清单 2. dis_ibm
#!/bin/sh # dis_ibm dest_hosts='host1 host2 host3 host4' for host in $dest_hosts do echo "doing [$host]" $ssh -T -t -l root $host<<'mayday' host=`hostname` cp /etc/sudoers /etc/sudoers.bak if [ $? != 0 ] then echo "error: unable to cp sudoers file" exit 1 fi echo "# -- ibmeng sudo root/nibmeng $host = (root) NOPASSWD:ALL">>/etc/sudoers mkuser su=false ibmeng if [ $? = 0 ] then echo "ibmeng:ibmpw" chpasswd -c else echo "error: unable to create user ibmeng and or passwd" exit 1 fi chuser gecos='IBM engineer acc' ibmeng if [ -f /home/ibmeng/.profile ] then echo "echo /"IBM Engineer, to access root account type: sudo -u root su -"/" >>/home/ibmeng/.profile fi mayday done
结束语
sudo 允许您控制谁可以作为谁运行什么命令。但是,必须充分理解 sudoers 的特征,才能完全了解它的影响和责任。