[발표자료 다운로드] 쿠버네티스 접근 제어 — 권한 과다를 막는 위임과 감사 기준

쿠버네티스 접근 제어는 전권 역할을 그대로 나눠 주지 않고, 권한을 깎은 역할로 넘긴 뒤 그 사용을 기록으로 남기는 일이다.

목차 (Agenda)

쿠버네티스 접근 제어

발표자료 다운로드 — 누가 무엇을 할 수 있는지 정하는 접근 제어

이 자료는 CNCF Korea 쿠버네티스 보안과 거버넌스 과정 2편의 발표 슬라이드다. 1편에서 네트워크·격리·API 세 층의 경계를 나눴다면, 2편은 그 경계 안에서 누가 무엇을 할 수 있는지그 권한이 어떻게 쓰였는지를 다룬다.

결론부터 적는다. 쿠버네티스 접근 제어에서 실무가 틀리는 자리는 넷이다. 전권 역할을 그대로 넘기고, 쓰지도 않는 서비스 계정 토큰을 켜 두고, 1년짜리 인증서의 만료일을 아무도 안 보고, 감사 기록을 클러스터 안에만 둔다. 네 가지 모두 설정 한 줄로 막을 수 있는데, 막지 않으면 사고가 난 뒤에 되돌릴 방법이 없다.

아래 버튼을 누르면 슬라이드 6쪽을 PDF 한 파일로 받을 수 있다.

CNF 백서 구독하기🔔

새로운 백서가 발간되면 가장 먼저 안내드려요!

CNF가 전하는 최신 백서와 클라우드 인사이트를 가장 빠르게 만나보실 수 있습니다.

진심으로 구독 부탁드립니다 🙏

발표 영상으로 먼저 보기

슬라이드만으로는 권한이 어느 방향으로 넘어가는지 잘 보이지 않는다. 같은 내용을 발표자가 순서대로 풀어 설명한 영상을 함께 공개했다.

발표 영상은 슬라이드 순서 그대로 롤과 롤바인딩부터 감사 정책까지 이어진다.

쿠버네티스 접근 제어를 처음 설계하는 팀이라면 슬라이드와 영상을 함께 보는 편이 빠르다.

영상에서 다루는 순서는 다음과 같다.

  • 롤과 롤바인딩, 그리고 역할의 범위가 네임스페이스 하나라는 점
  • 전권 역할 대신 권한을 깎은 역할로 관리 권한을 넘기는 방법
  • 워크로드에 저절로 붙는 서비스 계정 토큰과 자동 주입 끄기
  • 기본 1년짜리 인증서가 만료되면 클러스터가 멈추는 이유
  • 감사 기록이 답해야 하는 세 가지 질문
  • 리소스마다 다르게 거는 네 가지 기록 수준

경계를 어떻게 나누는지부터 보고 싶다면 1편 쿠버네티스 보안 경계 설계 — 기본값 리스크를 차단하는 기준을 먼저 읽으면 순서가 이어진다. 클라우드 네이티브 보안 전반은 클라우드 네이티브 보안 완벽 가이드 — 4C 모델과 DevSecOps 적용법에 정리돼 있다.

쿠버네티스 보안을 처음 설계한다면

클라우드 네이티브 보안 완벽 가이드 — 4C 모델과 DevSecOps 적용법

4C 모델의 층별 통제와 DevSecOps 적용 순서를 한 번에 정리한 가이드다.

이 발표자료가 답하는 다섯 가지 질문

쿠버네티스 접근 제어를 처음 설계하는 플랫폼팀이 실제로 묻는 질문을 기준으로 슬라이드를 배치했다.

  1. 관리 권한을 팀에 넘길 때 무엇을 깎고 무엇을 남겨야 하는가
  2. 우리가 만들지 않은 서비스 계정 토큰이 왜 파드 안에 들어와 있는가
  3. 잘 돌던 클러스터가 어느 날 갑자기 막히는 이유는 무엇인가
  4. 사람과 워크로드는 각각 어떤 방식으로 클러스터에 붙어야 하는가
  5. 감사 기록은 어느 수준까지 남겨야 조사에 쓸 수 있는가

질문마다 답이 되는 슬라이드를 아래 순서대로 붙였다. 슬라이드 이미지를 누르면 크게 볼 수 있다.

롤과 롤바인딩 — 권한은 두 조각으로 붙는다

쿠버네티스 접근 제어의 기본 단위는 두 개다. Role 에 무엇을 할 수 있는지 적고, RoleBinding 으로 그 역할을 누구에게 줄지 잇는다. 그리고 이 역할이 미치는 범위는 네임스페이스 하나다. 클러스터 전체에 걸려면 클러스터 범위의 역할을 따로 만들어야 한다.

기본 관리자 역할은 무엇이든 가능

▲ 기본 관리자 역할은 무엇이든 가능 (발표자료 2쪽)

실제 운영에서 중요한 것은 방향이다. 클러스터 어드민팀은 무엇이든 할 수 있는 기본 관리자 역할을 그대로 쓰지 않는다. 권한을 깎은 역할을 따로 만들어, 노드와 공통 기반은 관리하되 서비스 구획은 조회만 하고 Secret 은 제외한다. 그리고 각 서비스 구획의 관리 권한은 프로덕트팀에 넘긴다. 그 안에서는 프로덕트팀이 스스로 결정하고 실행한다.

원칙은 한 줄이다. 권한을 가진다는 것은 동시에 책임을 진다는 뜻이다. 조직이 정한 책임과 시스템이 부여한 권한은 함께 가야 한다. 한쪽만 하면 문서상의 책임과 실제 권한이 어긋난다. 쿠버네티스 접근 제어 설계에서 이 원칙이 깨지면 뒤따르는 설정은 형식만 남는다.

주의할 점이 하나 있다. 전권 역할을 그대로 나눠 주는 것은 위임이 아니라 통제 포기다. 건물 마스터키를 복사해 나눠 주는 것과 같다. 필요한 층만 열리는 카드를 만들어 주어야 한다.

하나 더. 쿠버네티스 접근 제어는 누가 무엇을 조작할 수 있는지를 통제하고, 파드가 어떤 권한으로 실행되는지는 Pod Security Admission 의 몫이다. 둘을 하나로 보면 조작 권한만 막고 실행 권한은 열린 채 남는다.

권한 체계를 검토할 때 확인할 것은 기능의 유무가 아니라 기본값과 그 기본값을 바꿀 수 있는 사람이다. 승인 절차가 기본으로 켜져 있는지, 위험한 조작에 승인이 걸려 있는지, 그 두 설정을 누가 끌 수 있는지를 함께 본다. 설정을 끌 수 있다는 사실 자체보다 끌 사람을 정해 두지 않은 상태가 실제 위험을 만든다.

그래서 권한 설계 문서에는 역할 목록만이 아니라 예외를 허용할 사람과 그 절차가 함께 적혀야 한다. 역할은 시스템에 남지만 예외는 대화로 처리되는 경우가 많고, 그 대화는 기록으로 남지 않는다.

안전장치를 여러 겹으로 쌓아도 실행이 끝난 뒤 그 결과가 맞는지 확인하는 층은 대개 빠져 있다. 권한을 좁히는 설계와 결과를 되짚는 기록은 서로를 대신하지 못하므로, 뒤의 감사 기록까지 함께 설계해야 한 바퀴가 닫힌다.

워크로드에 저절로 붙는 서비스 계정 토큰

네임스페이스를 만들면 기본 서비스 계정(ServiceAccount)이 함께 만들어진다. 우리가 만들지 않아도 이미 존재한다. 파드에 계정을 지정하지 않아도 그 기본 계정의 토큰이 파일로 주입된다. 그 파드에 들어간 쪽은 그 토큰으로 API 를 호출할 수 있다.

아무것도 지정하지 않아도 토큰이 주입됨

▲ 아무것도 지정하지 않아도 토큰이 주입됨 (발표자료 3쪽)

쓰지도 않을 신용카드가 지갑에 저절로 들어와 있는 셈이다. 지갑을 잃어버리는 순간부터 그 카드가 문제가 된다. 그래서 API 를 부르지 않는 워크로드에서는 자동 주입을 꺼 둔다. 대부분의 애플리케이션이 여기에 해당한다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: payment-prod
spec:
  template:
    spec:
      automountServiceAccountToken: false

API 가 필요한 워크로드에는 전용 계정을 만들고 꼭 필요한 권한만 붙인다. 기본 계정에 권한을 붙이면 그 네임스페이스의 모든 파드가 그 권한을 갖게 된다. 편의를 위해 붙여 둔 클러스터가 종종 있으므로, 파드 안에 토큰 파일이 남아 있는지와 기본 계정이 아무 권한도 갖지 않는지를 함께 확인한다.

kubectl -n payment-prod exec deploy/web -- \
  ls /var/run/secrets/kubernetes.io/serviceaccount 2>/dev/null || echo "토큰 없음 — 정상"
kubectl auth can-i --list --as=system:serviceaccount:payment-prod:default -n payment-prod

만료되면 멈추는 인증서와 사람·워크로드 인증

인증서 만료로 클러스터가 통째로 멈추는 사고는 생각보다 흔하다. kubeadm 으로 만든 클러스터의 인증서는 기본 유효기간이 1년이고, API 서버와 kubelet, etcd 가 서로를 확인하는 데 쓰인다. 업그레이드를 하면 그 과정에서 갱신되므로 정기적으로 올리는 클러스터가 오히려 안전하다.

kubeadm 클러스터의 인증서는 기본 1년

▲ kubeadm 클러스터의 인증서는 기본 1년 (발표자료 4쪽)

클러스터를 새로 세우면서 인증서 구성을 함께 확인하려면 쿠버네티스(Kubernetes) 설치 가이드 — 첫 클러스터 구축의 절차를 나란히 보면 된다.

문제는 잘 돌고 있어서 손을 대지 않은 클러스터다. 딱 1년째 되는 날 API 서버가 막힌다. 서랍에 넣어 둔 여권과 같아서, 쓸 일이 없다가 공항에 가서야 만료를 알게 된다. 만료일을 알림 대상에 넣어 둔다.

kubeadm certs check-expiration

사람 계정도 방식이 갈린다. 기본 접속 설정은 클라이언트 인증서인데, 인증서는 폐기 목록이 없어 회수가 어렵다. 사람이 조직을 떠나면 접근을 끊을 수 있어야 하므로 사람은 사내 계정과 묶는 OIDC, 워크로드는 서비스 계정 토큰으로 붙이는 것이 운영에 낫다. 사람의 자격 증명을 파드 안에 넣거나 접속 설정 파일을 여럿이 돌려 쓰지 않는다.

감사 기록 — 세 질문에 답할 수 있는가

모든 변경은 API 를 지나간다. 그래서 쿠버네티스 접근 제어의 사용 이력은 감사 기록에 전부 남는다. 기록을 켜 두지 않으면 사후 조사에서 쓸 근거 자체가 없다. 가게에 CCTV 를 달지 않은 것과 같아서, 사고가 난 다음에 달아도 어제 장면은 남아 있지 않다.

요청이 어느 구성 요소를 지나는지부터 짚어 보려면 6.1 쿠버네티스 클러스터 구성 요소에서 컨트롤 플레인 구성을 확인하면 된다. 쿠버네티스 접근 제어의 사용 이력은 모두 이 경로를 지나 기록으로 남는다.

모든 변경이 API 를 지나므로 여기서 전부 남음

▲ 모든 변경이 API 를 지나므로 여기서 전부 남음 (발표자료 5쪽)

감사 로그는 클러스터 밖 저장소로 내보낸다. 안에만 두면 침해가 일어났을 때 기록도 함께 지워질 수 있다. 감사 로그를 노드 디스크에만 두면 그 노드가 죽을 때 같이 사라진다.

이 기록으로 답할 수 있어야 하는 질문은 셋이다.

  • 누가 언제 이 설정을 바꿨는가
  • 어느 계정이 비밀값을 읽었는가
  • 실패한 권한 요청이 어디서 들어왔는가

세 질문에 답할 수 없다면 기록 수준부터 다시 본다. 보관 기간은 규정이 요구하는 기간과 조사에 필요한 기간 중 긴 쪽을 쓰고, 기록을 볼 수 있는 권한도 함께 통제한다.

감사 정책 — 네 수준을 리소스마다 다르게

감사 정책은 요청마다 4가지 기록 수준 중 하나를 매기는 방식이다. 남기지 않는 None, 누가 무엇에 무엇을 했는지까지인 Metadata, 보낸 내용까지인 Request, 응답까지 전부인 RequestResponse 다.

전부 남기면 디스크가 차고 아무것도 안 남기면 사고 뒤에 볼 것이 없음

▲ 전부 남기면 디스크가 차고 아무것도 안 남기면 사고 뒤에 볼 것이 없음 (발표자료 6쪽)

여기서 실수가 두 가지 자주 나온다. 하나는 전부 RequestResponse 로 거는 것이다. 조회 요청까지 응답 본문을 통째로 남기니 하루 만에 디스크가 찬다. 반대로 아무것도 걸지 않으면 사고가 났을 때 볼 것이 없다. 집에 쌓이는 영수증과 같아서 전부 모으면 서랍이 넘치고 다 버리면 정산이 안 된다.

그래서 리소스마다 다르게 거는 것이 실무 기준이다. Secret 은 값이 기록에 남으면 안 되므로 누가 언제 읽었는지까지만, 권한 설정 변경은 무엇을 어떻게 바꿨는지 전부 남긴다.

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]
  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  - level: None
    verbs: ["get", "list", "watch"]

조회성 동작은 대체로 빼고 변경 동작 위주로 남긴다. 정책을 켜기 전에 양을 먼저 재 보면 디스크가 차는 사고를 피할 수 있다. 쿠버네티스 접근 제어의 마지막 조각은 이렇게 남긴 기록을 실제로 볼 사람과 주기를 정하는 일이다.

핵심 정리

쿠버네티스 접근 제어에서 기억할 것은 여섯 줄이다.

  • 쿠버네티스 접근 제어는 Role 과 RoleBinding 두 조각으로 붙고, 역할의 범위는 네임스페이스 하나다.
  • 전권 역할을 그대로 넘기는 것은 위임이 아니다. 권한을 깎은 역할을 만들어 넘겨야 책임이 함께 이동한다.
  • 조작 권한(RBAC)과 실행 권한(Pod Security Admission)은 다른 통제다. 하나로 보면 실행 권한이 열린 채 남는다.
  • 서비스 계정 토큰은 지정하지 않아도 주입되므로, API 를 쓰지 않는 워크로드에서는 자동 주입을 끈다.
  • kubeadm 클러스터 인증서는 기본 1년이다. 만료일을 알림 대상에 넣고, 사람은 OIDC · 워크로드는 서비스 계정으로 붙인다.
  • 감사 기록은 클러스터 밖으로 내보내고, 네 가지 기록 수준을 리소스마다 다르게 건다.

지금 클러스터에서 확인할 것

읽고 나서 바로 돌려 볼 수 있는 순서다.

쿠버네티스 접근 제어 점검은 아래 다섯 가지를 눈으로 확인하는 데서 시작한다.

  1. 기본 관리자 역할을 그대로 받은 바인딩이 있는지 확인한다.
  2. API 를 쓰지 않는 워크로드에서 서비스 계정 토큰 자동 주입을 끈다.
  3. 기본 서비스 계정에 권한이 붙어 있지 않은지 확인한다.
  4. 인증서 만료일을 알림 대상에 넣고 남은 기간을 재 본다.
  5. 감사 로그가 클러스터 밖으로 나가고 있는지, 보관 기간이 정해져 있는지 확인한다.

자주 묻는 질문

관리 권한을 팀에 넘길 때 무엇을 깎아야 하나?

기본 관리자 역할을 그대로 주지 않는다. 노드와 공통 기반 관리 권한은 클러스터 어드민팀이 갖고, 서비스 구획은 조회만 하되 Secret 은 제외한 역할을 따로 만들어 쓴다. 각 구획의 관리 권한은 프로덕트팀에 넘겨 그 안에서 스스로 결정하게 한다.

서비스 계정 토큰 자동 주입은 언제 꺼야 하나?

쿠버네티스 API 를 호출하지 않는 워크로드에서는 끈다. 대부분의 애플리케이션이 여기에 해당한다. 파드 명세에 automountServiceAccountToken 을 false 로 두고, 기본 계정에 권한이 붙어 있지 않은지도 함께 확인한다.

잘 돌던 클러스터가 갑자기 막히는 이유는 무엇인가?

kubeadm 으로 만든 클러스터의 인증서가 기본 1년이기 때문이다. 업그레이드 과정에서 갱신되므로 정기적으로 올리는 클러스터는 오히려 안전하고, 손대지 않은 클러스터가 1년째 되는 날 API 서버가 막힌다. 만료일을 알림 대상에 넣어 둔다.

감사 기록은 어느 수준까지 남겨야 하나?

리소스마다 다르게 건다. Secret 은 값이 남으면 안 되므로 Metadata 까지만, RBAC 변경은 RequestResponse 로 전부 남긴다. 조회성 요청은 대체로 빼고, 기록은 클러스터 밖 저장소로 내보내 보관 기간을 정해 둔다.

자료 다운로드

쿠버네티스 보안과 거버넌스 과정 2편의 발표 슬라이드 6쪽을 PDF 한 파일로 정리했다.

Share This Story, Choose Your Platform!

Go to Top