Home 모던 리눅스 교과서 4. 접근 제어
Post
Cancel

모던 리눅스 교과서 4. 접근 제어

기본 개요

리소스와 소유권

  • 리눅스는 다중 사용자 운영체제로 유닉스로부터 사용자 개념을 물려받았다.
  • 각 사용자 계정은 실행 파일, 파일, 장치, 기타 리눅스 자산에 접근할 수 있는 사용자 ID와 연결된다.

    사용자

  • 프로세스를 실행하고 파일을 소유한다. 프로세스는 커널이 메인 메모리에 로드해 실행하는 일종의 프로그램이다.

    파일

  • 소유자가 존재한다. 기본적으로는 파일을 만든 사용자가 파일을 소유한다.

    프로세스

  • 의사소통과 지속성을 위해 파일을 사용한다. 사용자도 파일을 간접적으로 사용하기도 하지만 그러려면 프로세스를 통해야 한다.

    샌드박스

  • 샌드박스라는 용어의 정의는 다소 모호해서, 제일(jail)에서 컨테이너, 가상머신에 이르기까지 커널이나 사용자 영역에서 관리할 수 있는 다양한 방법을 가리킬 수 있다.
  • 일반적으로 샌드박스에서 실행되는 항목이 있다면 감시 메커니즘은 샌드박스 프로세스와 호스팅 환경 간에 어느정도 격리를 시행한다.
  • 뒷부분에서 더 자세히 언급한다.

접근 제어 유형

  • 개념적으로 다양한 접근 제어 유형이 있으나 리눅스 관점에서 가장 중요하고 관련성이 높은 두 가지는 임의 접근 제어(discretionary)와 강제 접근 제어(mandatory) 이다.
  • 임의 접근 제어(DAC): 사용자의 신분을 기반으로 리소스에 대한 접근을 제한할 수 있다. 여기서 임의라 함은 특정 권한을 가진 사용자가 이를 다른 사용자에게 전달할수 있음을 의미한다.
  • 강제 접근 제어(MAC) : 보안 수준을 나타내는 계층 모델을 기반으로 한다. 사용자에게는 허용 등급이 할당되고 리소스에는 보안 레이블이 할당된다. 사용자는 자신의 허용 등급 이하로 설정된 리소스에만 접근할 수 있다.
    • 관리자가 모든 권한을 설정하여 엄격하고 배타적으로 접근을 제어한다. 즉, 사용자는 리소스를 소유하고 있어도 권한을 스스로 설정할 수 없다.
  • SE 리눅스가 가장 잘 알려진 리눅스용 강제 접근 제어 구현 모듈이다.
  • 우분투에서는 앱 아머(App Armor)가 널리 쓰인다.

사용자

  • 리눅스에서는 목적 또는 의도적인 사용 관점에서 사용자 계정을 두 가지 유형으로 구분한다.
    • 시스템 사용자 또는 시스템 계정 : 일반적으로 프로그램(daemon)은 이런 유형의 계정을 사용하여 백그라운드 프로세스를 실행한다.
    • 일반 사용자 : 일반적으로 셸을 통해 리눅스를 대화식으로 사용하는 인간 사용자 유형
  • 리눅스는 UID를 통해 사용자를 식별하며, 사용자는 GID를 통해 식별 되나는 하나 이상의 그룹에 속한다.
  • root 라고 하는 UID 0를 사진 특별한 사용자는 제한이 적용되지 않는다.
  • 일반적인 경우 root 사용자로 작업하는 것은 피해야 한다.
    • 권한이 너무 많기 때문에 시스템을 파괴하기 쉽다.
  • 각각의 리눅스 배포판 마다 UID 범위를 관리하는 방법을 결정하는 고유한 방법이 존재한다.
  • 예를 들어 systemd 기반 배보판에는 아래와 같은 규칙이 있다
    • UID 0 : root 사용자
    • UID 1~999 : 시스템 사용자에게 지정됨
    • UID 65534 : nobody 사용자.
    • 나머지 UID : 일반 사용자

로컬에서 사용자 관리하기

  • 첫 번째 옵션은 사용자를 로컬에서 관리하는 것이다.
  • 즉, 시스템에 로컬로 저장된 정보만 사용되며 사용자 관련 정보는 시스템 네트워크에서 공유되지 않는다.
  • 리눅스는 파일 기반 인터페이스를 사용하여 사용자 관리를 구현한다.

|목적|파일| |—|—| |사용자 데이터베이스|/etc/passwd| |그룹 데이터베이스|/etc/group| |사용자 비밀번호|/etc/shadow| |그룹 비밀번호|/etc/gshadow|

  • /etc/passwd 에는 아래와 같은 내용이 저장되어 있다
    1
    2
    3
    4
    5
    6
    
    root:x:0:0:root:/root:/usr/local/bin/fish
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    sync:x:4:65534:sync:/bin:/bin/sync
    games:x:5:60:games:/usr/games:/usr/sbin/nologin
    
  • 보다시피 왼쪽에서부터 사용자 이름, 사용자의 비밀 번호(x는 비밀번호가 /etc/shadow에 저장됨을 의미), UID, GID, 이름 또는 전화번호, 사용자의 홈 디렉터리, 사용할 로그인 셸 이다.

중앙집중식 사용자 관리

  • 전문적인 설정으로 사용자를 관리해야 하는 시스템이나 서버가 둘 이상인 경우, 로컬에서 사용자를 관리하는 방식은 구식이다.
  • 이런 경우 중앙에서 사용자를 관리하지만 하나의 특정 시스템에 로컬로 적용할 수 있는 관리 방식이 필요하다.
  • 요구 사항과 예산에 따라 사용 가능한 몇 가지 접근 방식이 있다.
    • 디렉터리 기반 : LDAP는 수십년된 프로토콜 제품군으로 현재 IETF에서 공식화되어 있으며, IP를 통해 분산 디렉터리에 접근하고 유지 관리하는 방법을 정의힌다.
      • 예를 들어 Keycloak 같은 프로젝트를 이용해 LDAP 서버를 직접 실행할 수도 있고, 애저 액티브 디렉터리(Azure Active Directory)같은 클라우드 공급자의 제품을 사용할 수도 있다.
    • 네트워크 이용 : 커버로스(Kerberos)를 사용하면 네트워크로 사용자를 인증할 수 있다.
    • 구성 관리 시스템 사용 : Ansible, Chef, Puppet, SaltStack 등의 시스템들을 사용에 여러 컴퓨터에서 일관되게 사용자를 생성할 수 있다.

권한

파일 권한

  • 파일 권한은 ‘리소스에 접근’한다는 리눅스 개념의 핵심이다.
    • 리눅스는 모든 것이 파일이기 때문이다.
  • 다음과 같이 좁은 범위부터 넓은 범위까지 세 가지 유형/범위의 권한이 있다
    • 사용자 : 파일 소유자
    • 그룹 : 하나 이상의 구성원
    • 나머지 : 그 밖의 모두
  • 또한 세가지 접근 유형이 존재한다.
    • 읽기(r) : 일반 파일의 경우 사용자가 파일 내용을 볼 수 있다. 디렉터리의 경우 사용자는 디렉터리에 있는 파일의 이름을 볼 수 있다.
    • 쓰기(w) : 일반 파일의 경우 사용자가 파일을 수정하고 삭제할 수 있다. 디렉터리의 경우 사용자가 디렉터리에서 파일을 만들고 이름을 바꾸고 삭제할 수 있다.
    • 실행(x) : 이 옵션을 켜면 사용자가 읽기 권한도 가지고 있는 경우 파일을 실행할 수도 있다. 디렉터리의 경우 사용자가 디렉터리의 파일 정보에 접근할 수 있도록 허용해 사실상 사용자가 디렉토리로 이동(cd)하거나 내용을 나열(ls)할 수 있게 만들어준다.
  • 그 밖의 파일 접근 속성
    • s : 실행 파일에 적용되는 setuid/setgid 권한이다. 이를 실행하는 사용자는 파일 소유자 또는 그룹의 유효한 권한을 상속 받는다.
    • t : 디렉터리에만 관련된 스티키 비트(sticky bit)이다. 이 옵션이 설정되면 해당 디렉토리/파일을 소유한 사용자가 아닌 비 root 사용자가 파일을 삭제하지 못하게 방지한다.
  • chattr 를 통해 사용할 수 있는 리눅스의 특수 설정 또한 존재한다.
  • 파일의 권한은 . rwx rwx rwx 로 출력된다. 왼쪽부터 띄어쓰기를 구분으로 파일 형식, 파일 소유자 권한, 그룹 권한, 나머지 권한이다.

  • 이러한 권한은 chmod로 변경 가능하다. 원하는 권한 설정을 명시적으로 지정하거나(예:664), 단축어를 사용할 수 있다(+x)
  • chown, chgrp를 통해 소유권을 변경할 수도 있다.

프로세스 권한

  • credentials 메뉴얼 페이지의 설명에 따르면 런타임권한과 관련된 다양한 사용자ID가 있다
    • RUID(Real UID) : 프로세스를 시작한 사용자의 UID이다. 즉 인간 사용자 관점에서의 프로세스 소유권을 나타낸다.
      • 프로세스 자체에서 getuid를 통해 RUID를 얻을 수 있으며,
      • 셸에서 stat -c "%u %g" /proc/$pid/를 통해 쿼리할 수 있다
    • EUID : 리눅스 커널은 메시지 대기열과 같은 공유 리소스에 접근 할 때 EUID(Effective user ID)를 사용해 프로세스가 갖는 권한을 결정한다.
      • 전통적인 유닉스 시스템에서는 EUID가 파일 접근에도 사용된 반면, 리눅스는 파일 접근 권한에 전용 파일 시스템 UID를 사용했었다.
      • geteuid를 통해 EUID를 얻을 수 있다
    • 저장된 SUID : 프로세스가 실제 UID와 저장된 SUID 사이에서 유효 UID를 전환함으로써 권한을 가정할 수 있을 때 사용된다.
      • 예를 들어 프로세스가 특정 네트워크 포트를 사용하도록 허용하려면 root로 실행되는 것처럼 높은 권한이 필요하다. 프로세스는 getresuid를 통해 저장된 SUID를 가져올 수 있다.
    • FUID : 리눅스 전용 ID로서 파일 접근 권한을 결정하는데 사용됐으며, 원래 파일 서버가 일반 사용자를 대행해서 동작하되 해당 사용자가 보내는 시그널로부터 프로세스를 격리하는 사용 사례를 지원하기 위해 도입됐다.
      • 프로그램은 일반적으로 일반적으로 UID를 직접 조작하지 않는다.
      • 커널은 EUID가 변경되는 시기를 추적하고 이에 따라 파일 시스템 UID를 자동으로 변경한다.
      • 기술적으로 이 UID는 커널 2.0 이후로 더 이상 필요하지 않지만 호환성을 위해 여전히 지원된다.
  • 처음에 자식 프로세스가 fork를 통해 생성되면 이는 부모의 UID 복사본을 상속한다.
  • 또한 evecve 시스템 콜 중에는 프로세스의 RUID는 보존되지만 EUID와 저장된 SUID는 변경될 수 있다.
  • 이 외에도 chroot를 비롯한 여러 샌드박스 기술같이 EUID에 영향을 끼치는 경우는 다양하다.

고급 권한 관리

캐퍼빌리티

  • 유닉스 시스템의 전통을 이어받은 리눅스에서는 root 사용자가 프로세스를 실행할 때 아무런 제한이 없다. 즉 커널은 다음 두 가지 경우만 구분한다.
    • EUID가 0인 권한 있는 프로세스는 커널 권한 검사를 후회한다.
    • EUID가 0이 아닌, 권한이 없는 프로세스에 대해서는 위에 설명한 것과 같이 커널이 권한 검사를 수행한다.
  • 캐퍼빌리티 시스템 콜이 도압되면서 이런 이분법적 세계관이 바뀌었다.
  • 전통적으로 root와 관련댔던 권한은 이제 개별 단위로 나뉘어서 스레드마다 독립적으로 할당할 수 있게 됐다.
  • 캐퍼빌리티는 일반적으로 시스템 수준의 작어벵만 관련된다.
  • 즉, 대부분의 경우 이런 캐퍼빌리티에 반드시 의존하지 않아도 된다.

    seccomp 프로필

  • 이 샌드박스 기술의 기본 개념은 seccomp라는 전용 시스템 콜을 사용하여 프로세스가 사용할 수 있는 시스템 콜을 제한할 수 있다는 것이다.
  • seccomp를 직접 관리하는 것이 불편할 수 있지만 큰 번거로움 없이 사용할 수 있는 방법도 있다.
    • 예를 들어 컨테이너와 관련해서는 도커와 쿠버네티스 모두 seccomp을 지원한다.

      접근 제어 목록(ACL)

  • 사용하면 전통적인 권한 위에 추가로 사용할 수 있는 유연한 메커니즘이 리눅스에 생긴다. ACL은 사용자의 그룹 내에 없는 사용자나 그룹에 권한을 부여할 수 있다는 점에서 전통적인 권한의 단점을 해결할 수 있다.
  • grep -i acl /boot/config* 명령을 사용해 배포판이 ACL을 지원하는지를 확인할 수 있다.
  • 파일시스템에 ACL을 사용하려면 마운트 시 acl 옵션을 사용해 활성화 해야 한다.

우수 사례

최소 권한

  • 모든 사람과 프로세스는 주어진 작업을 수행하는 데 필요한 권한만 가져야 한다는 것이다.

setuid를 피하자

  • setuid는 파괴력이 있기 때문에 공격자가 시스템을 장악하기 좋다. 따라서 setuid보다는 캐퍼빌리티를 활용하자

감사(auditing)

  • 모든 작업들을 작업을 수행한 사람과 함께 변조할 수 없는 방식으로 결과 로그에 기록해야 한다. 이러한 읽기 전용 로그를 사용해 누가 언제 무엇을 했는지 확인할 수 있다.

정리

  • 리눅스에서 실제 작업을 할 때는 사용자, 프로세스, 파일 간의 관계를 기억해야 한다.
  • 이는 리눅스와 같은 다중 사용자 운영체제에서 안전하고 무사히 작업을 수행하고 손상을 방지하기 위해 매우 중요하다.
This post is licensed under CC BY 4.0 by the author.

모던 리눅스 교과서 3. 셸과 스크립팅

모던 리눅스 교과서 5. 파일 시스템