Linux

Linux Capability 란?

Joon0464 2024. 5. 2. 22:29

리눅스에서 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