전권 sudo 를 꼭 필요한 명령으로
이 실습은 VM 에서 돕니다
우분투 24.04 VM 한 대입니다. root 이고 systemd 와 커널 기능이 그대로 있습니다. 실습 파드에는 capability 가 없어 이 실습이 다루는 설정을 바꿀 수 없기 때문에 VM 으로 돕니다. 처음 뜨는 데 몇 분이 걸립니다. 세션이 끝나면 VM 은 통째로 사라지므로 남기고 싶은 것은 화면에서 복사해 두세요.
목표
두 팀 계정에 편의로 준 전권 sudo 를 각자 꼭 필요한 명령으로 좁힙니다. 좁힌 뒤 필요한 일은 그대로 되고 넘치는 일은 막히는지 확인하고, sudo 사용을 로그로 남깁니다.
왜 중요한가
NOPASSWD: ALL 은 그 계정의 토큰이나 세션 하나가 곧 root 라는 뜻입니다. 자동화 계정은 비밀번호를 물어볼 수 없어서 NOPASSWD 를 받는데, 그 범위가 전권이면 그 계정으로 들어온 공격자가 아무 명령이나 root 로 실행합니다.
sudoers 에는 함정이 둘 있습니다. 하나는 마지막으로 일치하는 규칙이 이긴다는 것입니다. 좁은 규칙을 추가해도 아래에 전권 줄이 남아 있으면 소용이 없습니다. 다른 하나는 셸 탈출입니다. 페이저나 편집기를 열 수 있는 명령을 NOPASSWD 로 주면 그 안에서 셸로 빠져나가 사실상 전권이 됩니다.
단계
- 두 계정의 유효 규칙을
/root/sudo/01-before.txt에 저장합니다. - deployer 를 shopapi 재시작·상태로 좁힙니다.
- oncall 을 journalctl·reboot 로 좁힙니다.
- 허용된 일이 되는지
/root/sudo/04-allowed.txt에 확인합니다. - 넘치는 일이 막히는지
/root/sudo/05-denied.txt에 확인합니다. - sudo 사용을
/var/log/sudo.log에 남깁니다. - 남은 넓은 규칙이 없는지
/root/sudo/07-audit.txt에 확인합니다.
참고
- 규칙 파일은
visudo -f /etc/sudoers.d/90-team으로 열면 저장할 때 문법을 검사합니다. 깨진 sudoers 는 sudo 전체를 잠급니다. - 특정 계정의 유효 규칙:
sudo -l -U <계정>. 그 계정으로 명령 실행:sudo -u <계정> -- <명령>. - 흔한 실수: 좁은 규칙을 추가하면서 전권 줄을 지우지 않는 것. 아래 줄이 이깁니다.
- 명령은 절대 경로로 적습니다.
systemctl만 적으면 PATH 에 따라 다른 바이너리가 걸릴 수 있습니다.
지금 무엇이 되는지 본다
deployer 와 oncall 의 유효 sudo 규칙을 각각 뽑아 /root/sudo/01-before.txt 에 저장하세요. 두 계정이 지금 무엇이든 비밀번호 없이 할 수 있다는 것이 보여야 합니다.
특정 계정의 유효 규칙은 sudo -l -U <계정> 으로 봅니다. 파일을 읽는 것과 sudo 가 실제로 해석한 결과는 다를 수 있으니 이 명령으로 봅니다.
배포 계정은 재시작만
/etc/sudoers.d/90-team 을 고쳐 deployer 가 systemctl restart shopapi 와 systemctl status shopapi 만 비밀번호 없이 할 수 있게 하세요. 전권 줄은 없애고, visudo -c 로 문법을 확인합니다.
명령을 절대 경로와 인자까지 적으면 그 조합만 허용됩니다(/usr/bin/systemctl restart shopapi). 전권 줄이 남아 있으면 마지막에 일치하는 그 줄이 이깁니다. 파일을 직접 고치지 말고 visudo -f 로 열면 저장할 때 문법을 검사합니다.
당번 계정은 로그와 재부팅만
같은 파일에서 oncall 이 journalctl 과 /sbin/reboot 만 비밀번호 없이 할 수 있게 하세요. 전권 줄을 없애고 문법을 확인합니다.
두 명령을 쉼표로 이어 한 규칙에 적습니다. journalctl 의 경로는 command -v journalctl 로 확인하세요. 전권 줄이 하나라도 남으면 좁힌 규칙이 무의미해집니다.
필요한 일은 되는가
두 계정이 허용된 일은 그대로 되는지 확인해 /root/sudo/04-allowed.txt 에 적으세요. deployer 로 sudo systemctl restart shopapi 가 되고 서비스가 다시 떠야 하며, oncall 로 sudo journalctl -n1 이 되어야 합니다.
다른 계정으로 명령을 돌리려면 sudo -u <계정> -- <명령> 입니다(관리자가 대신 확인). 재시작 뒤 systemctl is-active shopapi 로 서비스가 살아 있는지 봅니다. 권한을 좁히다 정상 업무를 막으면 그 하드닝은 되돌려집니다.
넘치는 일은 막히는가
두 계정이 허용되지 않은 일은 막히는지 확인해 /root/sudo/05-denied.txt 에 적으세요. deployer 로 sudo cat /etc/shadow 가 거부되고, oncall 로 sudo systemctl restart shopapi 가 거부되어야 합니다. 각 줄에 명령과 denied 를 적습니다.
sudo -n -l <명령> 은 그 명령이 허용되는지 묻고, 비밀번호 없이 거부되면 0 이 아닌 값으로 끝납니다. 실제로 실행해 보지 않고도 확인할 수 있습니다.
누가 무엇을 sudo 했는지 남긴다
/etc/sudoers.d/10-logging 에 Defaults 를 두어 sudo 사용을 /var/log/sudo.log 에 남기게 하세요(logfile, log_input, log_output). 그다음 deployer 로 허용된 명령을 한 번 돌려 그 로그에 기록이 남는지 확인하세요.
Defaults logfile="..." 과 Defaults log_input, log_output 을 씁니다. iolog 는 디렉터리에 쌓이고, logfile 은 한 줄 요약입니다. 문법은 visudo 로 확인하세요.
숨은 전권이 남지 않았는가
sudoers 전체(/etc/sudoers 와 /etc/sudoers.d/*)에서 사람 계정에 붙은 NOPASSWD: ALL 이나 (ALL) ALL 같은 넓은 규칙이 더 없는지 확인해 /root/sudo/07-audit.txt 에 남기세요. 남은 넓은 규칙이 있으면 그 줄을, 없으면 clean 을 적습니다.
sudo -l -U <계정> 을 두 계정에 대해 다시 돌려 ALL 이 사라졌는지 봅니다. 파일을 grep 할 때는 %admin·%sudo 그룹 규칙과 주석도 함께 살피세요. root 와 그룹 규칙은 그대로 두되 사람 계정의 전권만 봅니다.