대상 OS: Ubuntu Server 24.04 LTS
운영 서버에서 “root로만 가능한 작업”을 최소화하면, 사고가 터졌을 때 피해 범위가 줄어듭니다.
그런데 현실은 애매합니다. 웹 서버가 80/443 같은 저포트를 열어야 하고, ping 같은 네트워크 진단도 특권이 필요할 때가 있죠.
그래서 많은 팀이 그냥 서비스를 root로 띄우거나, sudo 권한을 넓게 주고 넘어갑니다.
하지만 Linux Capabilities를 쓰면 ‘필요한 특권만’ 프로세스에 조각처럼 부여할 수 있습니다.
이 글은 Ubuntu 24.04에서 capabilities를 이용해 root 없이 저포트 바인딩/제한된 관리 기능을 제공하는 방법을, setcap 방식과 systemd의 AmbientCapabilities 방식으로 비교하고 안전하게 운영하는 체크리스트까지 정리합니다.
---
1) Capabilities가 풀어주는 문제(왜 필요한가)
1) 서비스/에이전트를 root로 실행하지 않고도 저포트(1~1023)를 열 수 있다
2) sudoers를 넓게 열지 않고도 특정 기능만 허용할 수 있다
3) 침해 시 “권한 상승의 폭”을 줄이고, audit/검증 포인트를 명확히 만든다
Capabilities는 전통적인 root 권한을 여러 조각(CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN 등)으로 쪼갠 것입니다.
핵심은 “무엇을 주는지 정확히 알고, 최소만 주는 것”입니다.
---
2) setcap vs systemd AmbientCapabilities: 무엇을 쓸까
1) setcap(파일 기반)
- 장점: 바이너리에 capability를 영구적으로 부여, systemd 없이도 동작
- 단점: 바이너리가 교체/업데이트되면 cap이 사라지거나 예상이 바뀔 수 있음
2) systemd AmbientCapabilities(유닛 기반)
- 장점: 서비스 단위로 정책화, 배포/롤백/감사가 쉬움
- 단점: systemd 환경에 의존, 설정 실수 시 서비스가 기동 실패
운영 서버에서는 보통 “systemd 서비스는 AmbientCapabilities”, 단발성 툴은 setcap을 고려하는 흐름이 깔끔합니다.
---
3) 현재 프로세스가 어떤 cap을 쓰는지 감 잡기
1) cap 도구 설치
sudo apt update
sudo apt -y install libcap2-bin
2) 바이너리에 부여된 cap 확인
getcap -r /usr/bin /usr/sbin 2>/dev/null | head -n 40
3) 실행 중인 프로세스의 cap 확인(관찰용)
ps -eo pid,comm --sort=pid | head -n 20
(프로세스 cap는 /proc에서 확인 가능하지만 출력이 길어지는 편이라, 이 글에서는 “정책을 어떻게 주는가”에 집중합니다.)
---
4) 실전 1: 저포트(80/443) 바인딩을 root 없이 허용하기
가장 흔한 요구는 “비 root로 80/443 열기”입니다.
# 4-1) setcap으로 CAP_NET_BIND_SERVICE 부여
1) 예시로 커스텀 웹 바이너리(/usr/local/bin/myweb)가 있다고 가정
sudo install -m 0755 /path/to/myweb /usr/local/bin/myweb
2) 저포트 바인딩 capability 부여
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/myweb
3) 확인
getcap /usr/local/bin/myweb
이제 myweb은 root가 아니어도 80/443에 bind할 수 있습니다.
운영 주의
- 바이너리를 다시 복사/교체하면 cap이 사라질 수 있습니다.
- 배포 파이프라인에서 “배포 후 setcap 재적용”이 필요할 수 있습니다.
# 4-2) systemd 서비스에 AmbientCapabilities로 부여(권장)
1) myweb을 systemd로 관리한다고 가정하고 override를 만듭니다.
sudo systemctl edit myweb.service
2) 아래 내용을 추가
[Service]
User=myweb
Group=myweb
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
3) 적용 및 확인
sudo systemctl daemon-reload
sudo systemctl restart myweb.service
sudo systemctl status myweb.service --no-pager
포인트
- `AmbientCapabilities`는 프로세스에 cap을 “주입”합니다.
- `CapabilityBoundingSet`으로 상한선을 같이 걸어, 다른 cap이 들어오지 않게 합니다.
- `NoNewPrivileges=true`는 권한 상승 경로를 줄이는 안전장치로 자주 같이 씁니다.
---
5) 실전 2: ping 같은 네트워크 진단을 ‘필요한 범위’로만
전통적으로 ping은 setuid root였고, 지금도 환경에 따라 권한 이슈가 생깁니다.
Capabilities로 최소 권한을 주는 쪽이 더 안전한 경우가 있습니다.
1) ping 바이너리 상태 확인
ls -la /usr/bin/ping
getcap /usr/bin/ping 2>/dev/null || true
2) 필요 시 cap 확인/조정(환경에 따라 다름)
sudo setcap 'cap_net_raw=+ep' /usr/bin/ping
getcap /usr/bin/ping
주의
- CAP_NET_RAW는 raw socket을 열 수 있어 공격면이 있습니다.
- 서버에서 ping이 꼭 필요하지 않다면, 오히려 ping 사용을 제한하는 것도 선택지입니다.
---
6) 위험한 CAP을 알아야 한다(특히 CAP_SYS_ADMIN)
Capabilities는 ‘작게 나눈 root’입니다.
특히 다음은 운영에서 매우 조심해야 합니다.
1) CAP_SYS_ADMIN
- 커널에서 “거의 root”에 가까운 광범위 권한으로 취급되는 경우가 많습니다.
- 가능하면 절대 주지 않는 방향을 우선 고려하세요.
2) CAP_DAC_OVERRIDE / CAP_DAC_READ_SEARCH
- 파일 권한(퍼미션)을 우회할 수 있어, 정보 유출과 직결됩니다.
3) CAP_SYS_PTRACE
- 다른 프로세스 메모리를 들여다볼 수 있어 시크릿 탈취로 이어질 수 있습니다.
4) CAP_NET_ADMIN
- 네트워크 설정을 바꿀 수 있어 트래픽 가로채기/우회 경로가 생길 수 있습니다.
cap을 준다는 건 “이 기능이 뚫려도 괜찮은가?”를 먼저 묻는 것입니다.
---
7) 운영 체크리스트: 사고를 줄이는 적용 방식
1) cap은 ‘최소 1개’부터 시작하고, 늘려야 할 이유가 생길 때만 확장한다
2) systemd라면 반드시 BoundingSet과 NoNewPrivileges를 같이 고려한다
3) 서비스 계정을 분리하고(전용 User/Group), 파일 권한도 최소화한다
4) 배포 파이프라인에 “cap 유지/검증” 단계를 넣는다
getcap /usr/local/bin/myweb || true
5) 변경 이력을 남긴다
- systemd drop-in은 git으로 관리
- setcap 적용은 배포 스크립트/문서로 명시
---
8) 트러블슈팅: 서비스가 안 뜰 때 자주 보는 것
1) systemd 로그 확인
sudo journalctl -u myweb.service -n 200 --no-pager
2) 유닛에 설정된 cap 확인
systemctl show myweb.service -p AmbientCapabilities -p CapabilityBoundingSet -p NoNewPrivileges
3) 바이너리에 파일 기반 cap이 남아 충돌/혼선을 만드는지 확인
getcap /usr/local/bin/myweb 2>/dev/null || true
4) 저포트 바인딩은 되는데, 다른 권한(파일/디렉터리)에서 실패하는 경우
- cap은 네트워크 바인딩만 해결해줄 뿐, 로그 디렉터리 쓰기 권한 같은 건 별도입니다.
ls -la /var/log | head -n 30
---
마무리
Ubuntu 24.04에서 Linux Capabilities는 “root로 실행”과 “권한 없이 포기” 사이의 좋은 중간지점입니다.
저포트 바인딩처럼 현실적인 요구를 만족하면서도, root 권한을 통째로 주지 않게 해줍니다.
가장 중요한 원칙은 단순합니다.
- 필요한 cap만
- 서비스 단위로 정책화(systemd)
- BoundingSet과 NoNewPrivileges로 상한을 고정
이렇게 하면 보안과 운영 편의성을 동시에 올릴 수 있습니다.