사전 최소 권한
패턴

최소 권한

gabury1

프로그램과 사용자에게 일을 끝내는 데 필요한 만큼만 권한을 주기로 하는 결정입니다. 남는 권한은 미리 걷어 둡니다. 사고나 실수가 나도 망가지는 범위가 그만큼 좁아집니다.

쉽고 빠른 이해

프로그램과 사용자에게 필요한 만큼만 권한을 주고 나머지는 걷어 두는 결정입니다. 읽기만 하면 되는 프로그램에는 읽는 동작만 주고 만들거나 지우는 동작은 안 주는 식입니다.

권한을 넉넉하게 열어 두면 사고나 실수가 났을 때 망가지는 범위도 그만큼 넓어집니다. 그걸 줄이려고 씁니다.

  1. 일을 끝내는 데 필요한 만큼만 권한을 부여합니다
  2. 실제 접근 기록을 보고 안 쓰는 권한을 걷어냅니다
  3. 권한을 주는 권한(새 역할을 만들거나 남에게 나눠주는 일)은 이미 가진 권한 범위 안에서만 허용합니다

대가는 두 가지입니다. 무엇을 줘야 일이 되는지 미리 알아내는 비용이 붙고, 권한을 쪼갤수록 관리할 정책의 수가 늘어납니다.

상세

Saltzer 와 Schroeder 는 이 원칙을 이렇게 적었습니다. 시스템의 모든 프로그램과 모든 사용자는 그 일을 끝내는 데 필요한 최소한의 권한 집합으로 동작해야 한다는 것입니다.

두 사람이 든 효과는 셋입니다. 첫째는 사고나 오류에서 나올 수 있는 피해를 제한하는 것입니다. 글은 이것이 주된 효과라고 적습니다. 둘째는 특권 프로그램들 사이에 생길 수 있는 상호작용의 수를 올바른 동작에 필요한 최소로 줄이는 것입니다. 그렇게 하면 의도하지 않았거나 원치 않았거나 부적절한 특권 사용이 일어날 확률이 낮아진다고 적혀 있습니다. 셋째는 감사 범위입니다. 특권 오용과 관련된 문제가 생겼을 때 살펴봐야 할 프로그램의 수가 최소가 됩니다.

두 사람은 방화벽에도 빗댔습니다. 어떤 보호 메커니즘이 피해가 번지는 것을 막는 「방화벽」 구실을 할 수 있다면, 최소 권한 원칙은 그 방화벽을 어디에 세울지 정하는 근거를 준다는 것입니다. 원문이 방화벽에 따옴표를 붙여 썼는데, 네트워크 장비가 아니라 피해를 가두는 칸막이를 가리키는 비유입니다. 군이 쓰는 알 필요 규칙(임무에 필요한 정보만 알려주고 나머지는 감추는 규칙)이 이 원칙의 사례라고도 적었습니다.

오늘 쓰이는 통제 문장도 같은 자리를 가리킵니다. NIST(National Institute of Standards and Technology) 용어집은 최소 권한을 각 개체가 자기 기능을 수행하는 데 필요한 최소한의 시스템 자원과 인가만 부여받도록 보안 아키텍처를 설계하는 원칙이라고 정의합니다. 이 정의는 서로 다른 표준 문서 두 곳에 그대로 옮겨 실릴 만큼 자리를 잡았습니다. 용어집에는 판본이 둘 실려 있습니다. 한쪽은 「자원과 인가」 차례로 적고 NIST SP(Special Publication, 특별 간행물) 800-53 Rev. 5 를 출처로 답니다. 다른 쪽은 「인가와 자원」 차례로 적고, 개체를 다시 부르지 않은 채 기능 수행에 필요한 만큼이라고만 적으며, NIST SP 800-171r3 을 출처로 답니다. 말의 차례와 표현은 다르지만 가리키는 뜻은 같습니다 — 어느 쪽이든 그 개체가 자기 기능을 하는 데 필요한 최소한만 준다는 것입니다.

대가

무엇을 줘야 그 일이 되는지를 알아내는 일이 먼저 붙습니다. AWS(Amazon Web Services)의 IAM(Identity and Access Management) 모범 사례 문서는 정책으로 권한을 설정할 때 일을 수행하는 데 필요한 권한만 부여하라고 적습니다. 특정 조건에서 특정 자원에 취할 수 있는 동작을 정의하는 방식입니다. 그러자면 워크로드나 사용 사례에 어떤 권한이 필요한지를 탐색해야 합니다. 문서는 그 탐색 동안 넓은 권한으로 시작할 수도 있다고 적습니다. 그렇게 시작했다면 사용 사례가 무르익었을 때 부여한 권한을 줄여 최소 권한 쪽으로 나아가는 작업을 할 수 있다고 이어 적습니다. 그래서 사용 사례가 아직 굳지 않아 무엇이 필요한지 모르는 탐색 단계에서는 최소 권한 대신 넓은 권한을 먼저 여는 쪽을 고르기도 합니다. 그 선택을 하면 나중에 권한을 줄여 최소 권한 쪽으로 좁히는 일이 남습니다.

권한을 쪼갤 수 있는 단위는 시스템이 미리 정해 둔 만큼입니다. 그 단위가 굵으면 거기서 더 못 좁힙니다. 리눅스 캐퍼빌리티(root 권한을 조각조각 나눠 둔 단위 하나하나)가 그 예를 문서 안에 스스로 적어 뒀습니다. capabilities(7) 은 CAP_SYS_ADMIN 에 대해 이 캐퍼빌리티가 과적재되어 있다고(원래 다루기로 한 것보다 훨씬 많은 일이 이 한 단위에 몰려 있다고) 먼저 밝힙니다. 이 한 단위에 딸린 것이 quotactl(2) · mount(2) · umount(2) · pivot_root(2) · swapon(2) · swapoff(2) · sethostname(2) · setdomainname(2) 같은 시스템 관리 작업입니다. 프로세스 간 통신에 쓰는 자원을 조작하는 IPC_SET · IPC_RMID, 그리고 프로세스 개수 상한을 바꾸는 RLIMIT_NPROC 재정의도 같은 단위입니다. clone(2) · unshare(2) 로 새 네임스페이스를 만드는 CLONE_* 플래그를 쓰는 일도 여기 들어갑니다.

같은 문서의 커널 개발자용 주석은 더 못을 박습니다. 기존 캐퍼빌리티 검사 중 아주 큰 비율이 이 캐퍼빌리티에 묶여 있다고 적습니다. 그래서 이것을 「새로운 root」라고 불러도 무리가 아니라고 적습니다. 한쪽으로는 넓은 범위의 권한을 줍니다. 다른 쪽으로는 그 넓은 범위 때문에 많은 특권 프로그램이 바로 이 캐퍼빌리티를 요구하게 됩니다. 문서는 가능하면 CAP_SYS_ADMIN 을 고르지 말라고 적습니다. root 를 쪼갠 목록을 쓰더라도 이 단위를 받는 프로그램은 사실상 root 에 가까운 것을 받습니다.

관리할 대상도 늘어납니다. AWS 문서는 공급자가 만들어 둔 관리형 정책이 여러 공통 사용 사례에 권한을 부여한다고 적습니다. 다만 그 정책은 모든 고객이 쓰도록 열려 있는 것이라, 특정 사용 사례에는 최소 권한을 부여하지 못할 수도 있다고 덧붙입니다. 그래서 사용 사례에 맞는 고객 관리형 정책을 따로 정의해 권한을 더 줄이라고 권합니다. 최소 권한을 고른 순간, 공용 정책 몇 개로 끝나던 자리가 직접 만들고 유지하는 정책의 목록으로 바뀝니다.

이름의 출처

Jerome H. Saltzer 와 Michael D. Schroeder 가 이 이름을 붙였습니다. 두 사람이 쓴 「The Protection of Information in Computer Systems」가 원전입니다. 글에는 초청 논문이라는 표시가 붙어 있습니다. 원고는 1974년 10월 11일에 접수됐습니다. 1975년 4월 17일에 개정됐습니다. 저작권 표기는 1975년 J. H. Saltzer 입니다. 두 사람은 매사추세츠 공과대학교(MIT, Massachusetts Institute of Technology)의 Project MAC 과 전기공학·컴퓨터과학과 소속으로 이 글을 썼습니다.

이름이 붙은 자리는 이 글의 설계 원칙 목록입니다. 목록은 a)부터 h)까지 여덟 항목입니다. 여섯 번째 칸인 f) 가 Least privilege 입니다. 그 칸의 첫 문장이 곧 정의입니다. 원문은 https://web.mit.edu/Saltzer/www/publications/protection/Basic.html 에 있습니다. 표지는 https://web.mit.edu/Saltzer/www/publications/protection/ 입니다.

예시

리눅스 캐퍼빌리티의 CAP_NET_BIND_SERVICE

CAP_NET_BIND_SERVICE
       Bind a socket to Internet domain privileged ports (port numbers
       less than 1024).

이 캐퍼빌리티가 주는 것은 소켓을 인터넷 도메인의 특권 포트, 즉 1024 미만 포트 번호에 바인드하는 일 하나입니다. 그런 포트를 열어야 하는 프로세스에 root 전체 대신 이 단위 하나만 주면 됩니다. 같은 캐퍼빌리티 목록 안에 있지만 CAP_SYS_ADMIN 과 폭이 이만큼 다릅니다.

쿠버네티스의 Role

쿠버네티스 문서가 읽기 접근만 부여하는 예로 싣고 있는 Role 입니다. default 네임스페이스에 있습니다. 이 네임스페이스는 앞서 나온 리눅스 네임스페이스와는 다른, 쿠버네티스 자체의 구획입니다.

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

resources 가 대상 종류를 pod 하나로 묶습니다. verbs 가 할 수 있는 동사를 get · watch · list 셋으로 묶습니다. create 도 delete 도 이 목록에 없습니다. metadata.namespace 가 default 라서 적용 범위도 그 네임스페이스 안입니다.

PostgreSQL 의 GRANT

PostgreSQL 문서는 사용자 miriam 이 테이블 mytable 을 만든 뒤 실행하는 예로 이 세 줄을 듭니다.

SQL
GRANT SELECT ON mytable TO PUBLIC;
GRANT SELECT, UPDATE, INSERT ON mytable TO admin;
GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;

세 줄의 폭이 각각 다릅니다. 첫 줄은 모두에게 읽기만 줍니다. 둘째 줄은 admin 에게 읽기와 갱신과 삽입을 줍니다. 셋째 줄은 miriam_rw 에게 테이블 전체가 아니라 col1 열에 대해서만 읽기와 갱신을 줍니다. 권한을 좁히는 단위가 테이블에서 열까지 내려간 자리입니다.

운영

굴리는 쪽의 일은 이미 부여한 권한이 실제로 필요한 만큼인지 계속 확인하는 작업입니다. AWS 문서가 방법 셋을 적어 뒀습니다.

첫째는 정책의 소유권을 옮기는 것입니다. 공급자 관리형 정책으로 권한 부여를 시작하되, 사용 사례에 맞는 고객 관리형 정책을 정의해 권한을 더 줄이라고 적혀 있습니다.

둘째는 실제 접근 기록으로 정책을 만드는 것입니다. AWS 는 계정 안에서 일어난 접근 활동을 CloudTrail 이라는 곳에 기록해 둡니다. IAM Access Analyzer 는 그 기록을 근거로 세분화된 정책을 만들어 냅니다. AWS 문서는 이 근거 확보에서부터 운영 배포까지 이어지는 절차를 다섯 단계로 적습니다 — CloudTrail 에 기록된 접근 활동을 Access Analyzer 가 서비스와 작업 단위로 분석하고, 세분화된 정책을 만들고, 정책마다 개별로 시험한 뒤, 운영 환경에 배포합니다.

flowchart TD
    A["CloudTrail 에 기록된<br/>접근 활동"] --> B["IAM Access Analyzer 가<br/>서비스·작업 분석"]
    B --> C["세분화된 정책 생성"]
    C --> D["정책마다 개별 시험"]
    D --> E["운영 환경에 배포"]

셋째는 안 쓰는 것을 걷어내는 것입니다. IAM 은 last accessed 정보를 제공합니다. 더 이상 필요 없는 사용자 · 역할 · 권한 · 정책 · 자격 증명을 식별해 제거하는 데 씁니다. 같은 정보로 정책을 다시 다듬어 최소 권한에 더 맞추는 데도 쓴다고 적혀 있습니다. 문서는 이 일을 정기적으로 하라고 적습니다.

권한을 주는 권한을 따로 막아 두는 방법도 있습니다. 쿠버네티스의 역할 기반 접근 제어는 Role 생성과 갱신에 조건을 겁니다. 그 Role 에 담긴 권한을 이미 전부 갖고 있을 때만 만들거나 고칠 수 있습니다. 아니면 rbac.authorization.k8s.io API(Application Programming Interface) 그룹의 roles · clusterroles 리소스에 대해 escalate 동사를 명시적으로 부여받아야 합니다. 범위도 같아야 합니다. ClusterRole 이면 클러스터 전역이고 Role 이면 같은 네임스페이스나 클러스터 전역입니다. 문서가 든 예는 이렇습니다. user-1 이 클러스터 전역으로 Secret 을 나열할 능력이 없다면, 그 권한을 담은 ClusterRole 을 만들 수 없습니다.

Role 을 참조해 쓰는 RoleBinding 이라는 별도의 자원에도 같은 종류의 조건이 걸립니다. 참조하는 Role 의 권한을 같은 범위에서 이미 전부 갖고 있거나, 그 Role 에 대해 bind 동사를 인가받았을 때만 만들거나 고칠 수 있습니다.

Role·ClusterRole 을 만들거나 고치는 시도와 RoleBinding 을 만들거나 고치는 시도는 같은 모양의 갈림을 거칩니다. 다음 그림이 그 갈림입니다.

flowchart TD
    A["Role·ClusterRole·RoleBinding<br/>생성 또는 갱신 시도"] --> B{"그 안의 권한을 같은 범위에서<br/>이미 전부 갖고 있나"}
    B -->|예| C["허용"]
    B -->|아니오| D{"별도로 승인받은 동사가 있나<br/>(Role·ClusterRole: escalate,<br/>RoleBinding: bind)"}
    D -->|예| C
    D -->|아니오| E["거부"]

관련 항목

같은 목록에 있는 설계 원칙

메커니즘의 경제성 · 안전한 기본값 · 완전한 조정 · 개방 설계 · 권한 분리 · 최소 공통 메커니즘 · 심리적 수용성

권한을 둘러싼 인접 개념

권한 · 인가 · 인증과 인가 · 역할 기반 접근 제어 · 접근 제어 목록 · 캐퍼빌리티 · 권한 상승 · 보안 엔지니어링

다른 이름: least privilege · principle of least privilege · PoLP · 최소 권한 원칙