파일 · 권한 · 사용자 관리 45 / 50 · Part 5. 권한 상승과 Linux 보안
실습 환경: Rocky Linux 9.8 · Ubuntu 24.04.5 (Docker 격리 컨테이너, 테스트 계정 analyst)
기초편 연계: 「리눅스 시스템 기초」 20. 최소 권한 원칙

1. 들어가며

지금까지 배운 권한·소유권·특수 권한·sudo·ACL은 모두 하나의 원칙을 향한다. 최소 권한 원칙(Principle of Least Privilege) 이다.

모든 주체(사용자·프로세스·서비스)는 자신의 작업에 필요한 최소한의 권한만 가져야 한다.

이 원칙이 왜 중요한가? 침해는 언제든 일어날 수 있다는 전제 위에서, 침해가 나도 피해를 그 권한 범위 안에 가두기 위해서다. 웹 서버가 root로 돌면 웹 취약점 하나가 전체 장악으로 이어지지만, 전용 계정으로 돌면 피해가 그 계정 권한으로 제한된다.

이번 글에서는 최소 권한을 실제로 구현하는 방법 — 전용 계정, 정확한 파일 권한, capability, systemd 격리 — 을 다룬다.


2. 핵심 개념

2-1. 적용 계층

계층최소 권한 수단
프로세스전용 계정, capability
파일정확한 rwx, ACL(44편)
서비스systemd(User=, ProtectSystem=)
권한 상승sudo 최소 규칙(42편)
커널 강제SELinux / AppArmor

2-2. 전용 서비스 계정

각 서비스는 전용 계정(nologin 시스템 계정)으로 실행한다. nginx는 nginx, postgres는 postgres 계정으로. 이렇게 하면 한 서비스가 침해돼도 다른 서비스·시스템은 보호된다(40편).

2-3. capability

전통적으로 "80 포트 바인딩" 같은 특권 작업은 root가 필요했다. capability 는 root의 권한을 잘게 나눠, 필요한 능력 하나만 부여할 수 있게 한다. 예를 들어 cap_net_bind_service만 주면 root 없이 낮은 포트를 열 수 있다. SUID(전체 root)보다 훨씬 안전하다.


3. 동작 원리

최소 권한 원칙 — 필요한 만큼만

최소 권한 설계의 핵심은 격리 다. /srv/app 예시를 보자.

  • bin/app: root:appgrp 750 — 실행은 appgrp가 하되, 수정은 root만. 침해된 서비스가 자기 실행 파일을 변조하지 못한다.
  • data/config.yml: appsvc:appgrp 640 — 서비스만 읽는다.
  • logs/: appsvc:appgrp 750 — 서비스만 쓴다.
  • appsvc 계정: nologin 시스템 계정 — 침해돼도 대화형 셸이 없다.

이 구성에서 웹 취약점으로 appsvc 권한을 얻은 공격자는 config를 읽고 로그를 쓸 수 있을 뿐, 실행 파일 변조·다른 서비스 접근·root 권한 획득이 막힌다. 피해가 appsvc 권한 안에 갇힌다.

capability는 이를 프로세스 수준에서 강화한다. setcap cap_net_bind_service=+ep app으로 app에 포트 바인딩 능력만 주면, app이 침해돼도 그 능력 외의 root 권한은 없다.


4. 명령어 실습

root 권한 실습. appsvc는 nologin 시스템 계정, /srv/app은 최소 권한으로 구성했다.

# 1) 서비스 전용 계정 (nologin)
id appsvc

# 2) 최소 권한 디렉터리 구조
ls -lR /srv/app

# 3) capability — root 없이 특정 권한만
cp /bin/true /tmp/netbind
setcap 'cap_net_bind_service=+ep' /tmp/netbind && getcap /tmp/netbind

# 4) 시스템에 설정된 capability 파일
getcap -r /usr/bin 2>/dev/null | head -5

5. 실행 결과

실제 실행 결과 — Rocky Linux 9.8 · root@rocky9-lab — 최소 권한 구성

텍스트 원본(실제 출력):

[root@rocky9-lab ~]# echo "=== 최소 권한 구성: 서비스 전용 계정 + 최소 파일 권한 ==="
=== 최소 권한 구성: 서비스 전용 계정 + 최소 파일 권한 ===
[root@rocky9-lab ~]# id appsvc
uid=998(appsvc) gid=1001(appgrp) groups=1001(appgrp)
[root@rocky9-lab ~]# ls -lR /srv/app
/srv/app:
total 12
drwxr-xr-x 2 root   appgrp 4096 Sep 24 15:07 bin
drwxr-xr-x 2 root   appgrp 4096 Sep 24 15:07 data
drwxr-x--- 2 appsvc appgrp 4096 Sep 24 15:07 logs

/srv/app/bin:
total 28
-rwxr-x--- 1 root appgrp 27936 Sep 24 15:07 app

/srv/app/data:
total 4
-rw-r----- 1 appsvc appgrp 11 Sep 24 15:07 config.yml

/srv/app/logs:
total 0
[root@rocky9-lab ~]# echo "=== 서비스가 root 가 아닌 appsvc 로 실행되면 침해 범위 = appsvc 권한 ==="
=== 서비스가 root 가 아닌 appsvc 로 실행되면 침해 범위 = appsvc 권한 ===
[root@rocky9-lab ~]# echo "=== capabilities: root 없이 특정 권한만 (예: 80 포트 바인딩) ==="
=== capabilities: root 없이 특정 권한만 (예: 80 포트 바인딩) ===
[root@rocky9-lab ~]# cp /bin/true /tmp/netbind; setcap 'cap_net_bind_service=+ep' /tmp/netbind 2>/dev/null && getcap /tmp/netbind
/tmp/netbind cap_net_bind_service=ep
[root@rocky9-lab ~]# echo "=== 시스템 전체 SUID 대신 capability 로 최소화 가능 ==="
=== 시스템 전체 SUID 대신 capability 로 최소화 가능 ===
[root@rocky9-lab ~]# getcap -r /usr/bin 2>/dev/null | head -5
/usr/bin/newuidmap cap_setuid=ep
/usr/bin/newgidmap cap_setgid=ep

6. 결과 해석

출력해석
uid=998(appsvc) gid=1001(appgrp) groups=1001(appgrp)시스템 UID(998), 전용 그룹만
drwxr-x--- appsvc appgrp logs로그 디렉터리는 서비스만 접근
-rwxr-x--- root appgrp app실행은 appgrp, 수정은 root만
-rw-r----- appsvc appgrp config.yml설정은 서비스만 읽기
/tmp/netbind cap_net_bind_service=eproot 없이 포트 바인딩 능력만 부여
getcap -r /usr/bin → newuidmap cap_setuid=ep 등시스템도 SUID 대신 capability로 최소화한 도구들

-rwxr-x--- root appgrp app이 핵심 설계다. 서비스는 실행만 하고 수정은 못 한다. 침해돼도 자기 코드를 바꿔 지속성을 심기 어렵다.

getcap 결과의 newuidmap·newgidmap은 실제 시스템이 최소 권한을 적용한 예다. 예전에는 SUID였을 이 도구들이 이제 필요한 capability(cap_setuid)만 갖는다.


7. 보안 관점

원칙적용
서비스는 전용 계정root 실행 금지, nologin 시스템 계정
실행/수정 분리실행 권한은 서비스, 수정은 root
데이터 최소 노출설정·비밀은 서비스만 읽기(640/600)
SUID 대신 capability필요한 능력만 부여
systemd 강화User=, ProtectSystem=strict, NoNewPrivileges=
커널 강제SELinux(Rocky)/AppArmor(Ubuntu)로 추가 격리

systemd 유닛 예:

[Service]
User=appsvc
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/srv/app/logs

이 설정은 서비스가 지정 경로 외에 쓰지 못하게 하고, 권한 상승(SUID)을 무력화한다.


8. 보안관제 관점

[설계 감사]  서비스 실행 계정 점검
   ps -eo user,comm | awk '$1=="root"'        # root 실행 서비스 검토
   systemctl show <svc> -p User -p NoNewPrivileges
     ↓
[이상]      웹·앱 서비스가 root 실행 / 서비스 계정에 광범위 권한
     ↓
[Detection] 최소 권한 위반 = 침해 시 피해 확대 요인. 사전 점검으로 완화
     ↓
[Evidence]  서비스 계정 권한, capability(getcap -r /), SUID 목록(47편)
     ↓
[Response]  전용 계정 전환, 권한 축소, systemd 강화
관점내용
사전 완화최소 권한은 탐지가 아니라 피해 축소 다. 침해를 막지 못해도 범위를 줄인다
점검root로 도는 서비스, 과도한 capability, 광범위 sudo를 감사
Defense in Depth파일 권한 + 계정 격리 + capability + SELinux를 겹친다

9. 실무에서 자주 발생하는 실수

실수결과예방
서비스를 root로 실행침해 시 전체 장악전용 계정
편의로 777·광범위 권한최소 권한 위반필요한 최소만
SUID로 특권 부여전체 root 노출capability
설정 파일을 넓게 공개비밀 노출640/600, 서비스만
systemd 격리 미사용방어 계층 부족ProtectSystem 등

10. 실습 체크리스트

[ ] 서비스 전용 nologin 계정을 확인했다
[ ] 실행/수정을 분리한 파일 권한을 확인했다
[ ] setcap 으로 capability 를 부여했다
[ ] getcap 으로 시스템의 capability 파일을 확인했다
[ ] SUID 대신 capability 가 나은 이유를 설명할 수 있다
[ ] 최소 권한이 피해 범위를 가두는 원리를 이해했다

11. 핵심 정리

  • 최소 권한 원칙: 모든 주체는 작업에 필요한 최소 권한만 가진다.
  • 목적은 침해를 막는 것이 아니라 피해를 그 권한 안에 가두는 것 이다.
  • 서비스는 전용 nologin 계정으로, 실행과 수정을 분리한다.
  • capability 로 SUID(전체 root) 대신 필요한 능력만 부여한다.
  • systemd(User=·ProtectSystem=·NoNewPrivileges=)와 SELinux/AppArmor로 겹겹이 방어한다.
  • 최소 권한은 탐지가 아니라 사전 피해 축소다.

12. 다음 편 예고

다음 글 「46. World-Writable 파일 점검」 에서는 최소 권한 위반의 대표 사례 — 누구나 쓸 수 있는(world-writable) 파일과 디렉터리 — 를 find로 탐색하고, Sticky Bit 유무로 위험을 구분하는 실전 점검 명령을 다룬다.


참고 자료


시리즈 이동

profile
코드에 숨겨진 위협을 읽고 AI로 보안의 미래를 설계합니다. 프론트엔드 개발 경험을 자산 삼아 더 견고하고 지능적인 보안 운영 시스템을 구축해 나가는 과정을 기록합니다

0개의 댓글