대상 OS: Rocky Linux 9
sudo는 리눅스 서버에서 “가장 많이 쓰이는 권한 상승 통로”입니다.
문제는 sudo가 편한 만큼, 규칙이 허술하면 침해 시 공격자가 곧바로 root 권한을 획득하고, 운영 중에는 사람이 실수로 위험한 명령을 실행해 장애를 내기 쉽다는 점입니다.
그래서 sudo는 ‘허용 리스트(allowlist)’로 줄이고, 누가/언제/무엇을 했는지 감사 로그를 남기고, 위험한 사용 패턴을 차단하는 방향으로 운영해야 합니다.
Rocky Linux 9에서는 sudoers의 Cmnd_Alias/Runas_Alias 등을 활용해 명령을 구조화하고, sudo 자체의 로깅 옵션과 함께 “감사 가능한 최소 권한” 체계를 만들 수 있습니다.
오늘은 실제 운영에서 자주 쓰는 형태로: 그룹 기반 허용 리스트 + 출력 로깅 + 안전장치 + 롤백까지 정리합니다.
---
# 1) 현재 상태 점검: sudo 권한이 어디서 새는지 먼저 보기
1) sudo 설치/버전 확인
sudo -V | head -n 20
2) 누가 sudo 그룹(또는 wheel)에 들어가 있는지 확인
- Rocky 계열은 보통 `wheel`이 sudo 권한을 갖습니다.
getent group wheel
getent group sudo 2>/dev/null || true
3) 현재 sudo 정책 파일 구조 확인
sudo ls -al /etc/sudoers /etc/sudoers.d
sudo visudo -c
---
# 2) 운영 원칙: ‘루트 셸’을 주지 말고 ‘업무 명령’만 주기
1) 피해야 할 규칙
- `ALL=(ALL) ALL`
- `NOPASSWD: ALL`
- `sudo su -`, `sudo bash`, `sudo sh`를 허용하는 것
2) 목표
- 서비스 운영자는 “서비스 관련 명령만”
- 네트워크 운영자는 “네트워크 관련 명령만”
- 긴급 계정은 별도 통제(접속 IP 제한, 사용 알림 등)
---
# 3) 그룹 설계: 역할 기반 sudo 그룹 만들기
1) 예시 그룹 생성
sudo groupadd -f ops-nginx
sudo groupadd -f ops-net
2) 사용자에 역할 부여
sudo usermod -aG ops-nginx <사용자1>
sudo usermod -aG ops-net <사용자2>
3) 그룹 반영 확인
id <사용자1>
id <사용자2>
---
# 4) sudoers allowlist: Cmnd_Alias로 “허용 명령 묶음” 만들기
1) /etc/sudoers.d에 파일로 관리(권장)
- 파일명은 숫자 프리픽스를 주면 우선순위를 관리하기 쉽습니다.
sudo bash -lc 'cat >/etc/sudoers.d/10-ops-allowlist <<"EOF"
# Role-based sudo allowlist (Rocky Linux 9)
# 편집 후 반드시 visudo -c로 검증할 것
Defaults use_pty
Defaults logfile="/var/log/sudo/sudo.log"
Defaults log_output,log_input
Defaults iolog_dir="/var/log/sudo-io"
Defaults iolog_mode=0600
Defaults timestamp_timeout=5
Defaults passwd_timeout=1
# 위험한 환경변수 주입 방지(기본 env_reset 유지)
Defaults env_reset
Defaults env_keep += "LANG LC_ALL"
# 명령 alias
Cmnd_Alias NGINX_SVC = /usr/bin/systemctl status nginx, /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
Cmnd_Alias JOURNAL_NGINX = /usr/bin/journalctl -u nginx, /usr/bin/journalctl -u nginx *
Cmnd_Alias NET_BASIC = /usr/sbin/ip, /usr/sbin/ss, /usr/sbin/ethtool
Cmnd_Alias FIREWALL = /usr/bin/firewall-cmd, /usr/sbin/nft
# 역할별 허용
%ops-nginx ALL=(root) NGINX_SVC, JOURNAL_NGINX
%ops-net ALL=(root) NET_BASIC, FIREWALL
# root shell 금지(명시적으로 막고 싶다면)
# Cmnd_Alias ROOT_SHELL = /usr/bin/su, /usr/bin/bash, /usr/bin/sh, /usr/bin/zsh
# %ops-nginx ALL=(root) !ROOT_SHELL
EOF'
chmod 0440 /etc/sudoers.d/10-ops-allowlist
'
2) 문법 검증(필수)
sudo visudo -c
sudo visudo -cf /etc/sudoers.d/10-ops-allowlist
설명:
- `use_pty`는 sudo 명령 실행을 pty로 강제해 로깅/감사에 유리합니다.
- `log_output,log_input`은 명령 출력/입력을 iolog로 남깁니다(용량 증가 주의).
- `logfile`로 sudo 로그를 별도 파일에 남기면 중앙수집/감사에 유리합니다.
---
# 5) 감사 로그 보관: 디렉터리 권한/로테이션
1) 로그 디렉터리 만들기
sudo install -d -m 0750 -o root -g root /var/log/sudo
sudo install -d -m 0700 -o root -g root /var/log/sudo-io
2) 로그가 쌓이는지 테스트
- ops-nginx 사용자로 로그인 후 아래 실행:
sudo -l
sudo systemctl status nginx
- 로그 확인:
sudo tail -n 50 /var/log/sudo/sudo.log
sudo ls -al /var/log/sudo-io | tail -n 20
3) 용량 관리(간단 예시)
- iolog는 빠르게 커질 수 있어 주기적으로 정리 정책이 필요합니다.
sudo du -sh /var/log/sudo-io 2>/dev/null || true
---
# 6) 안전장치: requiretty, NOPASSWD 최소화, breakglass 분리
1) requiretty는 언제 쓰나
- 예전에는 원격 자동화 차단용으로 많이 썼지만, 현대 운영(자동화/CI)에서는 장애 원인이 되기도 합니다.
- 대신 `use_pty` + allowlist + MFA/접근제어 조합이 더 현실적입니다.
(그래도 정책상 필요하면, 특정 그룹/사용자에만 제한적으로 적용하는 쪽을 권장합니다.)
2) NOPASSWD는 “정말 필요한 명령”만
- 예: 모니터링 에이전트가 `systemctl status`를 해야 한다면 그 명령만 NOPASSWD로.
sudo bash -lc 'cat >/etc/sudoers.d/20-monitor-nopasswd <<"EOF"
# Example: allow status-only without password
User_Alias MON = <모니터링계정>
Cmnd_Alias STATUS_ONLY = /usr/bin/systemctl status nginx, /usr/bin/systemctl status sshd
MON ALL=(root) NOPASSWD: STATUS_ONLY
EOF'
chmod 0440 /etc/sudoers.d/20-monitor-nopasswd
'
sudo visudo -cf /etc/sudoers.d/20-monitor-nopasswd
3) breakglass(긴급) 계정 분리
- 긴급 계정은 최소 인원, 강한 인증, 사용 시 알림, 평소 접근 차단이 핵심입니다.
- 이 글에서는 개념만 남기고, 실제 운영에서는 접근 통제(관리망/VPN)와 함께 설계하세요.
---
# 7) 운영 점검: “허용된 것만 되는지” 확인하는 테스트
1) 허용 명령 확인
sudo -l
2) 허용되지 않은 명령 시도(예: 쉘)
sudo bash -lc 'echo test' 2>/dev/null || true
3) sudo 출력 로깅이 남는지 확인
sudo tail -n 80 /var/log/sudo/sudo.log
---
# 8) 롤백(긴급 복구): sudo 잠금 사고를 피하는 절차
1) 파일 단위로 비활성화
sudo mv /etc/sudoers.d/10-ops-allowlist /etc/sudoers.d/10-ops-allowlist.disabled.$(date +%F_%H%M%S)
2) 문법 재검증
sudo visudo -c
- sudo가 완전히 잠기면 콘솔/루트 접근이 필요하므로, 변경은 반드시 별도 세션 확보 후 진행하세요.
---
# 9) 마무리 체크리스트
1) wheel 같은 “광범위 그룹”에 불필요 인원이 없는가
2) NOPASSWD가 최소 명령으로 제한되어 있는가
3) 루트 셸 허용이 없는가
4) sudo.log와 iolog 보관/로테이션이 있는가
5) breakglass 계정은 별도 통제되고 있는가