Sudo는 시스템 관리자가 사용자나 사용자 그룹에게 다른 사용자로 명령을 실행하는 능력을 줄 수 있도록 하는 유틸리티다. 다시 말해, 다른 사용자의 비밀번호를 몰라도 명령 권한을 위임할 수 있다. 이 프로세스는 /etc/sudoers 파일에 sudo 항목을 만드는 루트 사용자에 의해 수행된다. 이 파일은 visudo 명령을 사용하여 편집된다. 권한을 위임할 때, 책임을 넘겨받는 다른 사용자는 신의성실의 원칙에 입각하여 그 책임을 이행해야 한다. 여기서는 근거 없는 믿음은 버리자. Sudo는 순수하게 사용자가 루트 권한으로 어떤 명령을 실행하도록 허용하기 위해서만 사용되는 것은 아니다. Sudo는 다른 사용자가 애플리케이션 사용자/소유자로서 어떤 애플리케이션이나 시스템 명령을 실행하도록 위임을 받을 수 있도록 하는 데 주로 사용된다. 현재 sudo가 시스템에 설치되어 있다면, 그것이 기존의 sudoers 파일을 덮어쓰지는 않을 것이다. 그러나 늘 그렇듯이, /etc/sudoers의 백업 사본을 만들고 업그레이드 지시사항을 잘 읽어보자.
최신 버전의 sudo를 다운로드한다.
이 데모를 위해, 필자는 sudo 버전 1.7.2를 사용했다. AIX® 5.3을 실행 중이라면, 최신 gcc 버전인 4.0.0을 가지고 있어야 한다.
# export LIBPATH=/usr/lib # ./configure --with-aixauth # make # make install |
설치된 버전을 확인하고 현재의 설치 구성뿐 아니라 빌드 옵션을 보려면 루트 권한으로 다음 명령을 사용한다.
# sudo -V Sudo version 1.7.2 Sudoers path: /etc/sudoers Authentication methods: 'aixauth' < rest of output truncated> |
기본적으로,
- sudo는 /usr/local/bin에 위치한다. 이를 이용해 다른 사용자로 명령을 실행한다.
- visudo는 /usr/local/sbin에 위치한다. 이를 이용해 sudoers 파일을 편집한다.
- 기존에 sudoers 파일이 존재하지 않는 경우에는 /etc에 위치한다. 이 파일에는 sudo 항목들이 들어 있다.
(흔히 sudoers라고만 알려진) /etc/sudoers 파일에서는 누가 sudo를 사용하여 무엇을 실행할 수 있을지 결정한다. 루트 사용자나 루트 권한을 가진 사용자가 이런 항목을 실행한다. Sudo 항목의 가장 기본적인 형태는 다음과 같다.
<사용자> <호스트> = <사용자의 별명> <필요한 비밀번호> < 실행할 명령> |
사용자가 실행할 수 있는 명령과 sudo에서 지정되는 다른 제한조건을 보려면 사용자로서 다음을 실행한다.
sudo -l |
Sudo 명령을 실행할 때 일반적인 형식은 다음과 같다.
sudo -u < 명령을 실행할 사용자> <실행할 명령> |
Sudo로 실행되는 모든 명령은 /etc/syslog.conf 파일의 항목을 사용하여 /var/adm/messages에 syslog를 통해 로그로 기록된다.
*.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 파일을 더 효율적으로 관리할 수 있게 만드는 것이 관리적 관점에서 합당한 일이다. 이런 목표를 달성하기 위한 두 가지 방법이나, 최소한 마련해두면 좋을 표준을 살펴보자. 정적 항목이 많이 있다면(즉, sudo가 있는 모든 시스템에서 같은 명령이 실행됨), include 지시문을 사용하여 이런 방법이나 표준을 별개의 sudoers 파일에 적용한다.
개별 사용자에 대한 항목이 많아도 항목을 추가하거나 수정할 때 시간이 많이 소요될 수 있다. 사용자 항목이 많을 때는 이들 항목을 그룹으로 분류하는 것이 좋은 방법이다. 그룹을 사용하면 말 그대로 사용자들을 함께 그룹화할 수 있고, 그런 그룹은 유효한 AIX 그룹이다.
이제 이 두 가지 방법을 좀 더 면밀하게 살펴보자.
대기업 환경 내에서는 sudoers 파일을 계속 유지보수하는 것이 중요하면서도 정기적으로 꼭 수행해야 하는 태스크이다. 이런 귀찮고 번잡한 일을 좀 더 쉽게 처리하기 위한 해결책이 바로 sudoers 파일을 재구성하는 방법이다. 이를 수행하는 한 가지 방법은 정적 또는 재사용 가능한 항목을 추출하는 것으로, 이때 모든 상자에서 같은 명령이 실행된다. 감사/보안 또는 storix 백업이나 일반적인 성능 보고서와 같이, sudo와 함께 포함 지시문을 사용할 수 있다. 그러면 기본 sudoers 파일에 로컬 항목이 포함될 수 있고, 포함 파일에서는 그런 항목들이 정적이므로 편집이 거의 필요 없다. Visudo를 호출하면 visudo에서 포함 항목을 발견할 때 sudoers를 스캔한다. 그 파일을 스캔한 다음에는 기본 sudoers로 돌아와서 스캔을 계속한다. 실제로 이와 같이 작동한다. 기본 sudoers 파일에서 visudo를 종료하면 포함 파일로 이동하게 되고 여기서 파일을 편집할 수 있다. 포함을 종료하면 AIX 프롬프트로 돌아온다. 포함 파일을 두 개 이상 가질 수도 있겠지만, 두 개 이상 필요할 이유가 없다.
보조 sudoers 파일을 sudo_static.<호스트 이름>이라고 하자. 이 데모의 예제에서 필자가 사용하는 호스트 이름은 rs6000이다. 기본 sudoers 파일에서 다음과 같은 항목을 만든다.
#include /etc/sudo_static.rs6000 |
그 다음, /etc/sudo_static.rs6000 파일에 몇몇 항목을 추가한다. Sudoers 지시문 또는 스탠자를 모두 넣을 필요는 없다. 이 파일에 꼭 필요하지 않은 항목이 있는 경우, 그런 항목은 포함하지 않는다. 예를 들어, 필자의 포함 파일에는 다음 텍스트만 있고 더 이상의 내용은 없다.
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에서 포함 sudoers 파일을 편집하려면 Enter를 클릭하라고 알려준다. 파일을 편집했으면 sudo가 기본 파일에서와 같이 구문 오류(있는 경우)를 표시한다. 또는 포함 파일을 직접 편집하려면
visudo -f /etc/sudo_static.rs6000 |
을 사용한다.
유효한 AIX 그룹에 속한 사용자가 sudoers에 포함될 수 있으며, 이로써 사용자당 적은 항목 수로 sudoers 파일을 더욱 효율적으로 관리할 수 있게 된다. 그룹을 포함하도록 sudoers 항목을 재구성할 때, 어떤 명령에 대해 sudo만 사용하도록 허용되는 사용자를 포함하기 위해 AIX에서 새 그룹을 작성해야 할 수도 있다. 그룹을 사용하려면 간단히 항목의 접두부로 '%'를 사용한다. 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 명령이 실행된 이후로 얼마나 오래 지났는지 확인하기 위해 시간 티켓을 사용하는 기능이 있다. 이 시간 동안 사용자는 비밀번호, 즉 사용자 자신의 비밀번호를 입력하라는 메시지를 받지 않고 명령을 다시 실행할 수 있다. 이 시간이 종료된 후에는 사용자가 명령을 다시 실행하려면 비밀번호를 다시 입력하라는 메시지를 받게 된다. 사용자가 정확한 비밀번호를 입력하면 명령이 실행되고 티켓이 다시 설정된 후, 시간 측정이 처음부터 다시 시작된다. 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
Start|start)
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
;;
Stop|stop)
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에서 다른 환경 변수도 제거하고 있다는 사실을 알게 되면, sudo에서 Defaults env_keep += 지시문으로 그런 변수를 그대로 유지하도록 sudoers에서 변수 이름을 지정할 수 있다. 예를 들어, sudo가 필자가 sudo로 작성한 스크립트 중 하나에서 DSTAGE_SUP 및 DSTAGE_META 애플리케이션 변수를 제거하고 있었다고 해보자. 이 변수들을 유지하려면 sudoers에 다음 항목을 넣으면 되었을 것이다.
Defaults env_keep += "DSTAGE_SUP" Defaults env_keep += "DSTAGE_META" |
필자가 변수 값이 아니라 변수 이름을 지정한다고 했던 사실을 상기하자. 변수 값은 다음과 같이 이미 필자의 스크립트에 포함되어 있다.
export DSTAGE_SUP=/opt/dstage/dsengine; export DSTAGE_META=/opt/dstage/db2 |
이제 sudo 스크립트를 실행하면 위의 환경 변수들은 유지된다.
Sudoers 내부의 기본 PATH는 secure_path 지시문을 사용하여 적용할 수 있다. 이 지시문에서는 사용자가 sudo 명령을 실행할 때 2진 코드와 명령을 찾아볼 위치를 지정한다. 이 옵션을 선택하면 사용자가 sudo 명령을 실행하는 특정 영역을 잠그기 위한 시도가 분명히 이루어지므로, 좋은 방법이라 할 수 있다. Sudoers에서 다음 지시문을 사용하여 검색 디렉토리로 보안 PATH를 지정한다.
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/opt/freeware/bin:/usr/sbin" |
사용자에 대해 어떤 명령을 제한하기 위한 제한사항을 둘 수 있다. "alpha," "bravo" 및 "charlie"라는 구성원이 있는 dataex라는 그룹이 있다고 가정하자. 그 그룹은 sudo 명령인 /usr/local/bin/mis_ext *를 실행하도록 허용되었으며, 여기서 별표는 스크립트로 전달되는 많은 매개변수를 나타낸다. 하지만, 매개변수가 import인 경우 사용자 "charlie"는 그 스크립트를 실행할 수 없다. 논리 연산자 NOT '!'을 사용하면 이런 유형의 조건을 충족시킬 수 있다. 다음은 sudoers에서 조건을 충족시키는 방법을 나타낸 것이다.
%dataex rs6000 = (dbmis) NOPASSWD: /usr/local/bin/mis_ext * charlie rs6000 = (dbmis) NOPASSWD: !/usr/local/bin/mis_ext import |
논리 연산자 NOT 항목은 비제한 항목 뒤에 온다는 점에 주의한다. 같은 행에서 다양한 조건부 NOT 항목을 적용할 수 있으며, 다음과 같이 쉼표로 구분하기만 하면 된다.
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 명령을 롤아웃하려면 루트 사용자로서 ssh 스크립트를 사용하는 것이 가장 좋은 방법이고, 비밀번호를 입력하지 않고 로그인하려면 호스트 간에 키가 교환되었어야 한다. 이 방법을 설명한 예제를 하나 살펴보자. 지리적으로 떨어져 있는 원격 시스템에서 디스크 또는 메모리와 같이 어떤 하드웨어 문제가 생기는 경우, IBM®의 엔지니어가 현장에 파견되어 문제가 생긴 하드웨어를 교체해 줄 것이다. 이때, 엔지니어가 태스크 수행을 위해 루트 비밀번호를 요구하는 일이 있을 것이다. 이럴 때를 대비하여 마련해두면 좋을 한 가지 절차는 엔지니어가 sudo를 사용해야 하는 루트에 대한 액세스 권한을 얻도록 하는 것이다. 엔지니어가 현장을 방문하기 전에 비밀번호를 알려주는 것이 유리할 것이다. 목록 2는 이 구성을 롤아웃할 수 있는 한 가지 방법을 나타낸 것이다. 목록 2를 더 자세히 살펴보고, 푸시 아웃하는 호스트 목록을 포함한 for 루프를 사용한다. (하지만, 일반적으로 이런 호스트는 텍스트 파일에 있을 것이므로 while 루프를 사용하여 읽어들인다.) 'here' 문서 메소드를 사용하여 sudoers의 백업 사본을 만들면 다음과 같이 sudoers에 항목이 하나 추가된다.
# -- ibmeng sudo root ibmeng host1 = (root) NOPASSWD:ALL |
그 다음, 사용자 "ibmeng"이 생성되고 chpasswd를 사용하여 그 사용자에 대한 비밀번호가 설정된다. 이 데모에서는 ibmpw가 비밀번호이다. 그런 다음, 루트에 대한 sudo를 실행하는 방법을 사용자에게 알려주는 메시지가 프로파일에 추가된다. 그러면 엔지니어가 로그인할 때 다음 메시지가 표시된다.
IBM Engineer, to access root account type: sudo -u root su - |
물론, 방문 후 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의 기능을 충분히 이해할 수 있어야 한다.
교육
-
AIX와 UNIX에서는 AIX 시스템 관리의 모든 측면과 관련된 풍부한 정보를 접할 수 있다.
-
developerWorks 기술 행사 및 웹 캐스트를 통해
최신 정보를 얻을 수 있다.
제품 및 기술 얻기
- sudo에 대해 자세히 알아보고 다운로드할 수 있다.
-
IBM 제품 평가판을
다운로드하거나 IBM SOA Sandbox의
온라인 시험판을 살펴보고 DB2®, Lotus®, Rational®, Tivoli® 및
WebSphere®의 애플리케이션 개발 도구 및 미들웨어 제품을 사용해 볼 수 있다.
토론
-
developerWorks 포럼 & 블로그를 통해 developerWorks 커뮤니티에 참여하자.
-
다음과 같은 AIX 및 UNIX 포럼에 참여하자.
- AIX Forum
- AIX Forum for developers
- Cluster Systems Management
- IBM Support Assistant Forum
- Performance Tools Forum
- PowerVM Forum
- 기타 AIX and UNIX Forums
