

쿠버네티스 클러스터의 POD에서 클러스터 API 사용하기
Software Developer, I love code.
쿠버네티스 리소스에 대한 접근 제어하기사용자 기준으로 RoleBinding. 클러스터 내부의 리소스 접근 제어하기ServiceAccount실습. ServiceAccount를 통해 애플리케이션 배포실습2. 네임스페이스에서 라벨 조회 후 애플리케이션에 반영사용자나 서비스 계정 또는 그 그룹에 룰을 부여하기그룹생성그룹에 롤, 롤바인딩 하기서비스계정 오용하는 방법토큰 주기적 교체 방법서드파티 플러그인을 사용한 권한 부여 검증하기who-canaccess-matrixrbac-lookupRBAC 전략 구상하기
RBAC의 대상
- kubectl을 사용하는 사용자
- 서비스 접근 토큰을 통해 쿠버네티스 api를 사용하는 내부 컴포넌트
외부 사용자를 위한 인증서를 쿠버네티스에 반입한느 방법
외부 인증 시스템이 없을 때 클러스터 내 사용자를 관리하는 방법
쿠버네티스 리소스에 대한 접근 제어하기
작업을 수행하는 주체(이를테면 사용자, 시스템 계정 또는 그룹)에 권한을 설정할 수 있지만, 주체에 직접 권한을 설정하는 것은 번거로우므로,
- Role 정의
- Role에 권한을 부여
- 각 주체(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"
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는 제공된 사용자명 및 그룹 정보를 신뢰
- 사용자는 여러 그룹에 속할 수 있으며, 그룹명과 구성원은 인증 시스템이 관리
- 서비스 계정은 항상 두 개의 그룹에 속함
- 클러스터 내 모든 서비스 계정의 그룹
- 자신이 속한 네임스페이스 내 모든 서비스 계정의 그룹
- 쿠버네티스는 그룹명이 유효한지 검사하지 않음. 인증 시스템에 설정된 그룹과 롤바인딩에 작성된 그룹이 일치하도록 하는 책임은 전적으로 사용자 몫임
그룹생성
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를 사용해야 하는 애플리케이션만 사용하도록 함
- 기본 서비스 계정의 속성에서 파드에 이들 계정의 토큰이 자동으로 포함안되도록 할 수 있음
- 보안 프로파일이 충분히 성숙해지면 보안 정책에 위배되는 것이 없는지 검증하고, 어드미션 컨트롤로 새로운 애플리케이션에서도 보안 정책이 준수되도록 강제해야 함