파일 · 권한 · 사용자 관리 42 / 50 · Part 5. 권한 상승과 Linux 보안
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정analyst)
기초편 연계: 「리눅스 시스템 기초」 19. sudo와 su
41편에서 sudo가 sudoers 규칙에 따라 명령을 허용한다고 했다. 이번 글에서는 그 규칙 파일 /etc/sudoers를 다룬다.
두 가지가 핵심이다. 첫째, sudoers 문법 — "누가, 어디서, 누구로, 어떤 명령을" 실행할 수 있는지 정의하는 형식. 둘째, visudo — sudoers를 편집할 때 반드시 써야 하는 도구다. sudoers에 문법 오류가 있으면 sudo 전체가 동작하지 않아 root 접근을 잃을 수 있는데, visudo는 저장 전에 문법을 검사해 이 사고를 막는다.
최소 권한 원칙에 따라 특정 명령만 허용 하는 규칙을 실습으로 작성한다.
사용자 호스트=(실행계정:실행그룹) [옵션:] 명령
| 요소 | 의미 | 예 |
|---|---|---|
| 사용자 | 누구에게 (%는 그룹) | deploy, %webops |
| 호스트 | 어느 호스트에서 | ALL |
| 실행계정 | 누구 권한으로 | (root), (ALL) |
| 옵션 | NOPASSWD: 등 | NOPASSWD: |
| 명령 | 허용 명령(전체 경로) | /usr/bin/systemctl restart httpd |
예:
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart httpd
%webops ALL=(root) /usr/bin/journalctl
개별 규칙은 /etc/sudoers를 직접 고치기보다 /etc/sudoers.d/ 아래 파일로 분리하는 것이 관리하기 좋다. 파일 권한은 440이어야 한다.
sudoers 편집은 반드시 visudo 로 한다. visudo는:
visudo -c는 검사만, visudo -c -f 파일은 특정 파일을 검사한다.

sudo가 실행되면 /etc/sudoers와 /etc/sudoers.d/*를 위에서부터 읽어, 실행자·명령에 맞는 마지막 일치 규칙 을 적용한다. 그래서 규칙 순서가 중요하다.
visudo가 필수인 이유는 sudoers의 특성 때문이다. 이 파일에 문법 오류가 하나라도 있으면 sudo가 파일 전체를 거부해 아무도 sudo를 쓸 수 없게 된다. root 비밀번호를 설정하지 않은 시스템(Ubuntu 기본)에서는 이것이 곧 관리 권한 완전 상실 이다. visudo는 저장 직전 검사로 이 치명적 사고를 예방한다.
최소 권한 설계의 핵심은 (ALL) ALL을 피하고 필요한 명령만 전체 경로로 지정하는 것이다. 단, 명령 경로만 제한한다고 안전한 것은 아니다. 허용한 명령이 셸 탈출이나 파일 읽기가 가능하면 권한 상승으로 이어진다(43편).
root 권한 실습.
deploy사용자와webops그룹에 제한된 sudo 규칙을 부여했다.
# 1) sudoers.d 규칙 확인
cat /etc/sudoers.d/deploy
# 2) 문법 검사 (정상)
visudo -c -f /etc/sudoers.d/deploy
# 3) 잘못된 문법은 저장 거부 (NOPASWD 오타)
echo 'baduser ALL=(ALL) NOPASWD: ALL' > /tmp/badsudoers
visudo -c -f /tmp/badsudoers
# 4) deploy 의 권한 확인
sudo -l -U deploy

텍스트 원본(실제 출력):
[root@rocky9-lab ~]# echo "=== sudoers 문법: 사용자 호스트=(실행계정) 명령 ==="
=== sudoers 문법: 사용자 호스트=(실행계정) 명령 ===
[root@rocky9-lab ~]# cat /etc/sudoers.d/deploy
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart httpd, /usr/bin/systemctl status httpd
%webops ALL=(root) /usr/bin/journalctl
[root@rocky9-lab ~]# echo "=== visudo -c : 문법 검사 ==="
=== visudo -c : 문법 검사 ===
[root@rocky9-lab ~]# visudo -c -f /etc/sudoers.d/deploy
/etc/sudoers.d/deploy: parsed OK
[root@rocky9-lab ~]# echo "=== 잘못된 문법은 저장 거부 (시뮬레이션) ==="
=== 잘못된 문법은 저장 거부 (시뮬레이션) ===
[root@rocky9-lab ~]# echo 'baduser ALL=(ALL) NOPASWD: ALL' > /tmp/badsudoers
[root@rocky9-lab ~]# visudo -c -f /tmp/badsudoers 2>&1 || echo "→ visudo 가 오류를 잡아냄"
/tmp/badsudoers:1:31: syntax error
baduser ALL=(ALL) NOPASWD: ALL
^
→ visudo 가 오류를 잡아냄
[root@rocky9-lab ~]# echo "=== deploy 의 권한 확인 ==="
=== deploy 의 권한 확인 ===
[root@rocky9-lab ~]# sudo -l -U deploy 2>/dev/null | tail -4
User deploy may run the following commands on rocky9-lab:
(root) NOPASSWD: /usr/bin/systemctl restart httpd, /usr/bin/systemctl status httpd
(root) /usr/bin/journalctl
| 출력 | 해석 |
|---|---|
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart httpd, ... status httpd | deploy는 httpd 재시작·상태만 비밀번호 없이 |
%webops ALL=(root) /usr/bin/journalctl | webops 그룹은 journalctl(비밀번호 필요) |
visudo -c -f deploy → parsed OK | 문법 정상 |
badsudoers:1:31: syntax error | NOPASWD 오타를 위치까지 지목 |
→ visudo 가 오류를 잡아냄 | 저장 전 검사로 사고 예방 |
sudo -l -U deploy → 허용 명령 목록 | deploy가 실제로 쓸 수 있는 명령 확인 |
syntax error가 위치(1:31)와 ^ 표시로 정확히 지목된 것이 핵심이다. visudo 없이 직접 편집해 이 오타를 저장했다면 sudo 전체가 멈췄을 것이다.
| 원칙 | 방법 |
|---|---|
| 최소 권한 | (ALL) ALL 대신 필요한 명령만 전체 경로 |
| 명령 제한의 한계 | 허용 명령이 셸 탈출 가능하면 무의미(43편) |
| secure_path | sudo 실행 시 PATH 고정(secure_path)으로 PATH 하이재킹 방지(04편) |
| NOPASSWD 신중 | 자동화에 필요한 최소 명령만. 범용 명령 금지 |
| sudoers.d 권한 | 440, root 소유 |
| 정기 검토 | sudo -l -U user로 사용자별 권한 감사 |
위험 패턴: user ALL=(ALL) NOPASSWD: ALL은 비밀번호 없이 모든 것을 허용하는 사실상 무제한 root다. 이런 규칙이 있는지 점검한다.
[점검] sudoers 전체 규칙 감사
sudo -l -U <user> # 사용자별 권한
grep -rvE '^#|^$' /etc/sudoers /etc/sudoers.d/ # 규칙 나열
visudo -c # 문법 무결성
↓
[이상] NOPASSWD: ALL / 셸·에디터·인터프리터 허용 / 광범위 와일드카드
↓
[Evidence] sudoers 파일 ctime, 변경 주체(로그), 규칙 추가 시각
↓
[Detection] /etc/sudoers.d/ 파일 추가·변경을 FIM 으로 감시
↓
[Response] 과도한 규칙 축소, 무단 규칙 제거, 경위 조사
| 관점 | 내용 |
|---|---|
| IOC | 공격자가 /etc/sudoers.d/에 자기 규칙 파일을 추가하는 것은 흔한 지속성 기법 |
| Detection | sudoers.d 디렉터리 변경을 FIM으로 실시간 감시 |
| 감사 | 사용자별 sudo -l을 주기적으로 검토(48편) |
| 실수 | 결과 | 예방 |
|---|---|---|
| sudoers 직접 편집 | 문법 오류로 sudo 잠김 | 반드시 visudo |
(ALL) ALL 남발 | 사실상 무제한 root | 필요한 명령만 |
| 명령 경로만 제한하고 안심 | 셸 탈출로 우회(43편) | 안전한 명령만 허용 |
| sudoers.d 권한 644 | 무시되거나 경고 | 440 |
| secure_path 미설정 | PATH 하이재킹 | Defaults secure_path |
[ ] sudoers 문법(사용자 호스트=(실행계정) 명령)을 해석했다
[ ] visudo -c 로 문법을 검사했다
[ ] 오타가 저장 거부되는 것을 확인했다
[ ] sudoers.d 로 규칙을 분리했다
[ ] sudo -l -U 로 사용자 권한을 감사했다
[ ] NOPASSWD: ALL 이 왜 위험한지 설명할 수 있다
visudo — 문법 오류를 저장 전에 잡아 sudo 잠김 사고를 막는다.(ALL) ALL 대신 필요한 명령만 전체 경로로 지정한다./etc/sudoers.d/(권한 440)로 분리 관리한다.다음 글 「43. sudo 잘못된 설정과 권한 상승」 에서는 NOPASSWD로 허용된 find 하나가 어떻게 완전한 root 권한으로 이어지는지(GTFOBins) 실제로 재현한다. "특정 명령만 허용"이 왜 안전을 보장하지 못하는지 확인한다.