리눅스에서 Capability과 Seccomp profile는 시스템 보안 강화를 위한 중요한 메커니즘입니다. 두 기능 모두 프로세스가 운영체제와 상호작용하는 방식을 제한함으로써 보안을 향상시킬 수 있습니다. 이번 글에서는 우선 Capability에 대해 설명하도록 하겠습니다.
Capability
전통적인 Unix-like 시스템에서, root 계정(UID 0)은 모든 권한을 가지고 있습니다. 이는 매우 강력하지만, 만약 root 권한을 가진 프로세스가 취약점을 갖고 있다면 시스템은 큰 위험에 노출될 수 있습니다. 리눅스 Capabilities는 root 권한을 더 세밀하게 분할하여, 특정 권한만을 프로세스에 부여할 수 있게 합니다. 예를 들어, 네트워크 소켓을 열 수 있는 권한, 시스템 시간을 변경할 수 있는 권한 등이 있습니다. 리눅스 5.2 버전에 총 38개의 `capabilities`가 있으며 널리 사용되는 capability는 아래 표와 같습니다.
Capability | 의미 |
CAP_CHOWN | 사용자가 파일의 UID/GID를 임의로 변경할 수 있도록 허용 |
CAP_KILL | 다른 사용자에게 속한 프로세스에 신호를 보낼 수 있도록 허용 |
CAP_SETUID | UID를 변경할 수 있도록 허용 |
CAP_SETPCAP | 실행 중인 프로세스의 Capability를 설정할 수 있도록 허용 |
CAP_NET_ADMIN | 인터페이스 구성과 같은 다양한 네트워크 관련 작업을 허용 |
CAP_NET_RAM | RAW 와 PACKET 소켓의 사용을 허용 |
CAP_SYS_CHROOT | chroot 호출 허용 |
CAP_SYS_ADMIN | 파일 시스템 마운트를 포함한 시스템 관리 작업을 허용 |
CAP_SYS_PTRACE | strace를 사용하여 프로세스를 디버그할 수 있도록 허용 |
CAP_SYS_MODULE | 커널 모듈의 로딩을 허용 |
Capability는 이진 비트마스크로, 특수한 권한 집합을 나타냅니다. 각 bit는 특정권한을 의미하며, 이를 통해 프로세스에 필요한 최소한의 권한만을 정밀하게 부여할 수 있습니다.
Capability 사용 예시
CAP_NET_BIND_SERVICE capability를 사용하는 예시를 들어보겠습니다. 이 capability는 프로그램이 1024 미만의 well-known port 에서 리스닝할 수 있게 해 줍니다.
포트 80 에서 리스닝하는 golang으로 작성된 간단한 웹서버 프로그램을 통해 capability 실제 사용 예시를 살펴보겠습니다.
1) my_tcp_server.go 에 코드를 다음과 같이 작성합니다.
vi ./my_tcp_server.go
package main
import (
"net"
"log"
"fmt"
)
func main() {
ln, err := net.Listen("tcp", ":80")
if err != nil {
log.Fatal(err)
}
defer ln.Close()
// 서버 시작 메시지 추가
fmt.Println("서버가 포트 80에서 시작되었습니다.")
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
continue
}
// HTTP 응답 메시지 작성
httpResponse := "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain; charset=utf-8\r\n" +
"Content-Length: 17\r\n" +
"\r\n" +
"Hello, TCP client!\n"
conn.Write([]byte(httpResponse))
conn.Close()
}
}
2) go build 수행
$ go build my_tcp_server.go
$ ls -al my_tcp_server
-rwxr-xr-x 1 joon joon 2576489 May 2 14:57 my_tcp_server
3) 서버 실행 테스트
$ ./my_tcp_server
2024/05/02 15:14:07 listen tcp :80: bind: permission denied
해당 프로그램에 CAP_NET_BIND_SERVICE capability를 부여하지 않은 상태로 일반 사용자 권한으로는 1024번 미만의 포트에서 서비스를 시작할 수 없습니다.
하지만, 해당 프로그램에 CAP_NET_BIND_SERVICE capability를 부여하면, root 권한 없이도 포트 80에서 서비스를 제공할 수 있습니다.
4) CAP_NET_BIND_SERVICE capability 부여
$ sudo setcap 'cap_net_bind_service=+ep' ./my_tcp_server
$ getcap ./my_tcp_server
./my_tcp_server cap_net_bind_service=ep
5) 서버 실행 재시도 및 curl 접근 테스트
$ ./my_tcp_server
서버가 포트 80에서 시작되었습니다.
$ sudo netstat -nltp | grep 80
tcp6 0 0 :::80 :::* LISTEN 87600/./my_tcp_server
$ curl http://localhost
Hello, TCP client
위와 같이 permission denied에러 없이 서버가 정상적으로 실행되어 80번 포트를 통해 서비스되는 것을 볼 수 있습니다. netstat 명령어로 80번 포트가 Listen 상태인 것을 확인하고, curl을 통해 80번 포트로 요청을 보내고 리턴을 받아보면 잘 동작중인 것을 알 수 있습니다. 이렇게 이번 글을 통해 Linux Capability 설정을 알아보았으며, 다음 이어지는 글에서 Seccomp profile에 대해 살펴볼 예정입니다.
'Linux' 카테고리의 다른 글
Linux systemd 완전 정복하기 (1) | 2024.05.07 |
---|---|
Linux 부팅 프로세스 (0) | 2024.05.07 |
Linux 접근 제어 목록(ACL) 이란? (0) | 2024.05.03 |
Linux seccomp 프로필과 접근제어목록(ACL)이란? (0) | 2024.05.03 |
RUID EUID SUID 란? (0) | 2024.05.02 |