HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📖
공부한 책
/쿠버네티스 교과서/
17장 역할 기반 접근 제어를 이용한 리소스 보안

17장 역할 기반 접근 제어를 이용한 리소스 보안

Soo StorySoo Story쿠버네티스 클러스터의 POD에서 클러스터 API 사용하기
쿠버네티스 클러스터의 POD에서 클러스터 API 사용하기

쿠버네티스 클러스터의 POD에서 클러스터 API 사용하기

Software Developer, I love code.

Soo StorySoo Story
 
쿠버네티스 리소스에 대한 접근 제어하기사용자 기준으로 RoleBinding. 클러스터 내부의 리소스 접근 제어하기ServiceAccount실습. ServiceAccount를 통해 애플리케이션 배포실습2. 네임스페이스에서 라벨 조회 후 애플리케이션에 반영사용자나 서비스 계정 또는 그 그룹에 룰을 부여하기그룹생성그룹에 롤, 롤바인딩 하기서비스계정 오용하는 방법토큰 주기적 교체 방법서드파티 플러그인을 사용한 권한 부여 검증하기who-canaccess-matrixrbac-lookupRBAC 전략 구상하기
RBAC의 대상
  • kubectl을 사용하는 사용자
  • 서비스 접근 토큰을 통해 쿠버네티스 api를 사용하는 내부 컴포넌트
 
외부 사용자를 위한 인증서를 쿠버네티스에 반입한느 방법
외부 인증 시스템이 없을 때 클러스터 내 사용자를 관리하는 방법

쿠버네티스 리소스에 대한 접근 제어하기

작업을 수행하는 주체(이를테면 사용자, 시스템 계정 또는 그룹)에 권한을 설정할 수 있지만, 주체에 직접 권한을 설정하는 것은 번거로우므로,
  1. Role 정의
  1. Role에 권한을 부여
  1. 각 주체(Subject)에 롤바인딩(RoleBinding)으로 역할(Role)을 설정함
 
Role, RoleBinding : 네임스페이스에 속하는 리소스에 대한 권한 정의
ClusterRole, ClusterRoleBinding : 특정 네임스페이스에 속하지 않는 리소스에 대한 권한 정의
kubectl get clusterrole NAME CREATED AT admin 2024-11-03T23:10:45Z cluster-admin 2024-11-03T23:10:45Z create-approve-csr 2024-11-28T01:41:14Z edit 2024-11-03T23:10:45Z ingress-nginx 2024-11-22T08:35:21Z ingress-traefik-controller 2024-11-25T01:26:14Z kubeadm:get-nodes 2024-11-03T23:10:45Z ... kubectl get role
위의 cluster-admin role을 누가 부여받을까?
  • 쿠버네티스에는 사용자 객체가 없음
  • 또한 쿠버네티스에는 사용자 인증 절차도 없음
  • 대신 외부 아이덴티티 제공자에 의존하며 이들을 신뢰함
    • 운영환경의 클러스터는 조직의 기존 인증 시스템을 사용하도록 되어 있을 것임(액티브 디렉터리, LDAP, OpenID 커넥트..)
    • 클라우드 플랫폼은 전용 인증시스템과 쿠버네티스를 통합해놓음. AKS 는 애저 ad 계정으로 인증, EKS는 IAM 혹은 다른 방식으로
  • 실습에서는 인증서 사용. 쿠버네티스 사용자명에 대해 사용자용 클라이언트 인증서 발급 & API 서버에 요청 시, 인증서 포함

사용자 기준으로 RoleBinding.

# 새로 만든 인증서를 인증 수단으로 등록 kubectl config set-credentials reader --client-key=./user.key --client-certificate=./user.crt --embed-certs=true # 등록된 인증서를 인증 수단으로 하는 컨텍스트를 생성 kubectl config set-context reader --user=reader --cluster docker-desktop # reader@kiamol.net user 로 pod 조회 kubectl get pods --as reader@kiamol.net
  • 쿠버네티스에는 사용자 정보가 저장되지 않음
  • 사용자명을 이용 시, 실제로 찾는 것은 사용자명과 일치하는 롤바인딩
  • 사용자명이 일치하는 롤바인딩이 없다면 아무 권한이 없는 것
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: reader-view namespace: default labels: kiamol: ch17 subjects: - kind: User name: reader@kiamol.net apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io
kubectl get pods -n kube-system --as reader@kiamol.net Error from server (Forbidden): pods is forbidden: User "reader@kiamol.net" cannot list resource "pods" in API group "" in the namespace "kube-system"
default namespace에 대해서만 view 권한이 있기에, kube-system 네임스페이스의 파드 조회 불가
  • subjects.apiGroup
    • subjects.kind가 User 또는 Group 일때 apiGroup: rbac.authorization.k8s.io
    • ServiceAccount를 지정할 경우 apiGroup을 생략하거나 빈 값으로 두면 된다.
  • subjects.kind
    • User
    • Group
    • ServiceAccount

클러스터 내부의 리소스 접근 제어하기

ServiceAccount

  • 모든 네임스페이스에는 기본 서비스 계정이 자동 생성됨
    • 서비스 계정이 따로 지정되지 않은 파드는 모두 기본 서비스 계정을 사용함
  • 위에서 보았던 사용자와 마찬가지로, RoleBinding이나 ClusterRoleBinding 이 없으면 아무 권한 없음
  • 애플리케이션은 사용자에 비해 크게 제한된 권한만 있으면 되기에, 각 컴포넌트별로 전용 서비스 계정 만드는 것이 가장 좋음
    • 모든 애플리케이션이 같은 서비스 계정을 공유하면, 권한이 점점 커지게 되어 서비스 계정이 너무 강한 권한을 갖게 됨
  • 서비스 계정의 RBAC는 쿠버네티스 API 서버를 사용하는 애플리케이션(eg. 프로메테우스, 쿠버네티스 API를 통해 파드 목록 조회)의 보안을 위한 것임
kubectl apply -f namespace.yaml namespace/kiamol-ch17 created kubectl get serviceaccounts -n kiamol-ch17 NAME SECRETS AGE default 0 7s
  • /var/run/secrets/kubernetes.io/serviceaccount 경로 아래에 있는 token이 사용된 서비스 어카운트의 토큰(따로 pod 만들때 ServiceAccount를 지정해주지 않았다면 default ServiceAccount)
    • 파드 안에서 kubectl을 사용하면 해당 파드의 서비스 계정의 컨텍스트가 사용됨
  • 서비스 계정 참조 문법 : system.serviceaccount:<namespace>:<계정이름>

실습. ServiceAccount를 통해 애플리케이션 배포

apiVersion: v1 kind: ServiceAccount metadata: name: kube-explorer labels: kiamol: ch17 --- apiVersion: apps/v1 kind: Deployment metadata: name: kube-explorer labels: kiamol: ch17 spec: selector: matchLabels: app: kube-explorer template: metadata: labels: app: kube-explorer spec: serviceAccountName: kube-explorer containers: - image: kiamol/ch17-kube-explorer name: web ports: - containerPort: 80 name: http env: - name: ASPNETCORE_ENVIRONMENT value: Development --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: default-pod-reader namespace: default labels: kiamol: ch17 rules: - apiGroups: [""] #core resources: ["pods"] verbs: ["get", "list", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kube-explorer-default namespace: default labels: kiamol: ch17 subjects: - kind: ServiceAccount name: kube-explorer namespace: default roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: default-pod-reader
  • 해당 ServiceAccount는 default namespace의 파드 목록 및 파드 삭제가 가능함
  • 만약 권한이 없는 api를 호출하게 되면 파드에 마운트된 서비스 계정 토큰으로 인증 시도할 때, 403 Forbidden 오류가 발생함

실습2. 네임스페이스에서 라벨 조회 후 애플리케이션에 반영

apiVersion: v1 kind: ServiceAccount metadata: name: todo-web namespace: kiamol-ch17 --- apiVersion: apps/v1 kind: Deployment metadata: name: todo-web namespace: kiamol-ch17 spec: selector: matchLabels: app: todo-web template: metadata: labels: app: todo-web spec: serviceAccountName: todo-web initContainers: - name: configurator image: kiamol/ch17-todo-list-configurator volumeMounts: - name: shared mountPath: "/config-out" readOnly: false containers: - name: web image: kiamol/ch04-todo-list volumeMounts: - name: shared mountPath: "/app/config" readOnly: true volumes: - name: shared emptyDir: {} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ch17-reader labels: kiamol: ch17 rules: - apiGroups: [""] resources: ["namespaces"] # 네임스페이스에 대한 접근권한은 클러스터롤로 정의 resourceNames: ["kiamol-ch17"] # 하나의 네임스페이스에 대한 권한 부여 verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: todo-web-reader labels: kiamol: ch17 subjects: - kind: ServiceAccount name: todo-web namespace: kiamol-ch17 roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ch17-reader
  • 위 todo 애플리케이션에 침입하더라도 공격자가 쿠버네티스 API 를 사용하기는 어려움. 어차피 네임스페이스 정보 확인밖에 못함
  • RBAC 의 단점
    • 규칙이 적용되기 전에 대상 리소스가 먼저 존재해야 함
    • 네임스페이스 및 서비스 계정이 롤과 롤바인딩 생성 전에 존재해야 함
    • kubectl 로 배치 시, yaml 파일 이름 순서대로 실행 됨

사용자나 서비스 계정 또는 그 그룹에 룰을 부여하기

  • 롤바인딩은 그룹을 대상으로 가능함
  • 사용자와 서비스 계정 모두 그룹에 속할 수 있음
  • 사용자는 쿠버네티스 외부에서 인증받으며, 쿠버네티스 API는 제공된 사용자명 및 그룹 정보를 신뢰
    • 사용자는 여러 그룹에 속할 수 있으며, 그룹명과 구성원은 인증 시스템이 관리
  • 서비스 계정은 항상 두 개의 그룹에 속함
      1. 클러스터 내 모든 서비스 계정의 그룹
      1. 자신이 속한 네임스페이스 내 모든 서비스 계정의 그룹
  • 쿠버네티스는 그룹명이 유효한지 검사하지 않음. 인증 시스템에 설정된 그룹과 롤바인딩에 작성된 그룹이 일치하도록 하는 책임은 전적으로 사용자 몫임

그룹생성

apiVersion: v1 kind: Pod metadata: name: sre-user labels: kiamol: ch17 spec: serviceAccountName: user-cert-generator containers: - name: user-cert-generator image: kiamol/ch17-user-cert-generator env: - name: USER_NAME value: sre1 - name: GROUP value: sre - name: SET_CONTEXT value: "true" --- apiVersion: v1 kind: Pod metadata: name: test-user labels: kiamol: ch17 spec: serviceAccountName: user-cert-generator containers: - name: user-cert-generator image: kiamol/ch17-user-cert-generator env: - name: USER_NAME value: tester1 - name: GROUP value: test - name: SET_CONTEXT value: "true"

그룹에 롤, 롤바인딩 하기

apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: logs-reader labels: kiamol: ch17 rules: - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: test-logs-cluster labels: kiamol: ch17 subjects: - kind: Group name: test apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: logs-reader apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: sre-view-cluster labels: kiamol: ch17 subjects: - kind: Group name: sre apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: sre-edit-ch17 namespace: kiamol-ch17 subjects: - kind: Group name: sre apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: edit apiGroup: rbac.authorization.k8s.io

서비스계정 오용하는 방법

  • 사용자마다 서비스 계정 만들고, 이 서비스 계정의 토큰으로 kubectl 인증해서 사용하는 방법
  • 그룹의 서비스 계정 만들 수 없어, 그룹 권한 적용하려면 네임스페이스를 그룹으로 삼아 각 그룹마다 네임스페이스를 만들고 그룹의 모든 서비스 계정을 해당하는 네임스페이스로 몰아넣을 수 있음
  • 서비스 계정의 토큰을 삭제하는 방법으로 특정 사용자 권한 회수 가능함

토큰 주기적 교체 방법

  • 새 토큰 생성, 사용자에게 보내기.
  • 사용자는 기존 토큰 삭제하고 새 토큰 사용하도록 컨텍스트 변경
 

서드파티 플러그인을 사용한 권한 부여 검증하기

앞의 kubectl can-i 명령이 특정 사용자가 어떤 작업을 수행할 권한이 있는지 알아보기에는 유용하지만, 권한 부여를 검증하는 수단으로는 충분치 않음
가장 편리한 방법은 플러그인 관리자인 Krew를 사용
kubectl krew install who-can kubectl who-can get configmap todo-web-config kubectl krew install access-matrix kubectl access-matrix for pods -n default kubectl krew install rbac-lookup # sre 검색어로 RBAC 권한 주체를 검색 kubectl rbac-lookup sre

who-can

RBAC 롤을 차례로 살펴보며 지정된 권한과 일치하는 것을 찾은 후 이 롤을 부여받은 주체를 파악해서 알려줌
 

access-matrix

특정 리소스 또는 유형을 지정하면 이 대상에 대한 접근 권한이 있는 룰과 이 룰을 부여받은 주체가 누구인지 보여줌

rbac-lookup

  • RBAC 권한 주체의 검색 기능을 제공. 검색어를 입력하면 검색어와 일치하는 사용자 계정, 서비스 계정이나 그룹을 보여 주고 이들의 롤도 함께 알려줌.
  • 특정 사용자가 정당한 권한을 가지고 있는지 검증할 때 사용자 관점에서 RBAC 권한 확인하기 편리함
 

RBAC 전략 구상하기

  • RBAC를 사용하면 애플리케이션(ServiceAccount)과 외부 사용자의 권한을 동일한 방법으로 통제 가능
    • 롤과 롤바인딩이 동일하게 작용하기 때문에
  • 사용자는 별도의 신뢰할 수 있는 시스템에 사용자명 및 소속 그룹 정보를 의존하는 형태로 인증하는 것이 좋음
    • 사전 정의된 클러스터롤(view, edit, admin)을 활용하여 이들 롤을 그룹에 부여하는 것부터 시작
  • 서비스 계정은 되도록 사용하지 말되, 쿠버네티스 api를 사용해야 하는 애플리케이션만 사용하도록 함
    • 기본 서비스 계정의 속성에서 파드에 이들 계정의 토큰이 자동으로 포함안되도록 할 수 있음
  • 보안 프로파일이 충분히 성숙해지면 보안 정책에 위배되는 것이 없는지 검증하고, 어드미션 컨트롤로 새로운 애플리케이션에서도 보안 정책이 준수되도록 강제해야 함