k8s RBAC & 인증 이해 (k8s in action 12장)

Sian·2022년 4월 30일
0

회사에서 Role과 RBAC을 이해하며 기능을 구현해야 하는 일이 있었는데, 프론트는 막상 기능을 구현하더라도 화면을 만들기 때문에 내부적으로 이 기능이 어떻게 설계되었는지 모르는 경우가 많다.
하지만 그렇게 껍데기만 만들다보면 실제로 기획이 어디가 비어있는지, API를 어떻게 써야하는지 조금씩 빈 구멍이 생기기 때문에 이렇게 실제로 쓰진 않더라도 구현에 대해 이해하는 것이 좋은 것 같다.
그에 따라 쿠버네티스 인 액션 12장을 공부하고, 아래와 같이 요약 정리를 남긴다.

목차

  • 인증에 대한 이해
  • 서비스어카운트란 무엇이며 사용하는 이유
  • 역할 기반 액세스 제어(RBAC) 플러그인 이해
  • 롤과 롤바인딩 사용
  • 클러스터롤과 클러스터롤바인딩 사용
  • 디폴트 롤과 바인딩 이해

1. 인증 이해

  • API 서버가 요청을 받음
  • 인증 플러그인 목록 거치며 요청 전달
  • 각각의 인증 플러그인이 요청 검사하여 보낸 사람이 누구인지 밝혀내려 시도
  • 요청에서 해당 정보를 처음 추출한 플러그인은 사용자 이름, 사용자 ID와 클라이언트가 속한 그룹을 API 서버 코어에 반환
  • API 서버는 나머지 인증 플러그인 호출 중지하고 계속 인가 단계 진행

클라이언트의 인증서, HTTP 헤더로 전달된 인증 토큰, 기본 HTTP 인증 등을 통해 클라이언트의 아이덴티티를 얻음

1-1. 사용자와 그룹

인증 플러그인은 인증된 사용자의 이름과 그룹을 반환(저장하지 않음)하고 이를 사용해 사용자가 작업을 수행할 권한이 있는 지 여부 확인

사용자

  • 실제 사람(사용자) → SSO와 같은 외부 시스템에 의해 관리, 사용자 관리하는 리소스는 없기 때문에 API 서버를 통해 사용자 관리할 수 없음
  • 파드(파드 내부의 애플리케이션) → 클러스터에 서비스어카운트 리소스로 생성되고 저장(서비스 어카운트 메커니즘)

그룹

  • 사용자/서비스어카운트는 하나 이상의 그룹에 속할 수 있음
  • 개별 사용자에게 권한을 부여하지 않고 한 번에 여러 사용자에게 권한을 부여하는 데 사용
  • 빌트인 그룹
    • system:unauthenticated → 어떤 인증 플러그인에서도 클라이언트를 인증할 수 없는 요청에 사용
    • system:authenticated → 성공적으로 인증된 사용자에게 자동으로 할당
    • system:serviceaccounts → 시스템의 모든 서비스어카운트를 포함
    • system:serviceaccounts: → 특정 네임스페이스의 모든 서비스어카운트 포함

1-2. 서비스어카운트

모든 파드는 파드에서 실행 중인 애플리케이션의 아이덴티티를

나타내는 서비스어카운트와 연계되어 있음

앞선 8장에서 등장한 /var/run/secrets/kubernetes.io/serviceaccount/token(토큰 파일) 파일은 서비스어카운트의 인증 토큰을 갖고 있음

  • 애플리케이션이 이 토큰을 사용해 API 서버에 접속하면 인증 플러그인이 서비스어카운트를 인증하고 서비스어카운트의 사용자 이름을 API 서버 코어로 전달함

(서비스 어카운트의 사용자 이름 형식 → system:serviceaccount::)

  • API 서버는 설정된 인가 플러그인에 사용자 이름을 전달하며, 이 인가 플러그인은 애플리케이션이 수행하려는 작업을 서비스어카운트에서 수행할 수 있는지 결정
  • 서비스어카운트는 파드 내부에서 실행되는 애플리케이션이 API 서버에 자신을 인증하는 방법에 지나지 않음

서비스어카운트 리소스

서비스어카운트는 개별 네임스페이스로 범위가 지정되며 각 네임스페이스마다 default 서비스어카운트가 자동으로 생성됨

(현재 네임스페이스는 default만 가지고 있고, 필요한 경우 추가 가능)

각 파드는 딱 하나의 서비스와 연계되지만 여러 파드가 같은 서비스어카운트 사용 가능 (같은 네임스페이스꺼만)

서비스어카운트와 인가의 연계

  • 파드 매니페스트에 서비스어카운트의 이름을 지정해 파드에 서비스어카운트를 할당할 수 있고, 명시적으로 할당하지 않으면 파드는 네임스페이스에 있는 default 서비스어카운트 사용
  • 파드에 서로 다른 서비스어카운트를 할당하면 각 파드가 액세스할 수 있는 리소스 제어 가능
  • API 서버가 인증 토큰이 있는 요청을 수신하면, API 서버는 토큰을 사용해 요청을 보낸 클라이언트를 인증한 다음 관련 서비스어카운트가 요청된 작업을 수행할 수 있는지 여부 결정(API 서버는 클러스터 관리자가 구성한 시스템 전체의 인가 플러그인에서 정보를 얻음)
  • 사용 가능한 인가 플러그인 중 하나는 RBAC 플러그인

1-3. 서비스어카운트 생성

파드에 default 서비스어카운트를 사용하지 않고 서비스어카운트를 생성하는 이유 → 클러스터 보안

  • 클러스터의 메타데이터를 읽을 필요가 없는 파드는 클러스터에 배포된 리소스를 검색하거나 수정할 수 없는 제한된 계정으로 실행해야 함
  • 리소스의 메타데이터를 검색해야 하는 파드는 해당 오브젝트의 메타데이터만 읽을 수 있는 서비스어카운트로 실행해야 함
  • 오브젝트를 수정해야 하는 파드는 API 오브젝트를 수정할 수 있는 고유한 서비스어카운트로 실행해야 함

생성하기

describe를 통해 서비스어카운트 검사하기

Image pull secrets: 이 필드의 값은 이 서비스어카운트를 사용하는 파드에 자동으로 추가됨

Mountable secrets: 마운트 가능한 시크릿이 강제화된 경우 이 서비스 어카운트를 사용하는 파드만 해당 시크릿을 마운트 할 수 있음

Tokens: 인증 토큰이며 첫 번째 토큰이 컨테이너에 마운트됨 (배열로 들어올 수 있는건가..?)

사용자 정의 sa의 sercret을 검사함

(위의 token은 jwt 토큰이라고 함..)

서비스어카운트의 마운트 가능한 시크릿(Mountable Secrets)

파드가 서비스어카운트의 Mountable Secret 목록에 있는 시크릿만 마운트하도록 파드의 서비스어카운트를 설정 가능

이 기능을 사용하려면 서비스어카운트가 kubernetes.io/enforce-mountable-secrets=”true”. 어노테이션을 포함하고 있어야 함

서비스어카운트의 이미지 풀 시크릿 이해

이미지 풀 시크릿은 프라이빗 이미지 리포지터리에서 컨테이너 이미지를 가져오는 데 필요한 자격증명을 갖고 있는 시크릿

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
imagePullSecrets:
- name: my-dockerhub-secret

위와 같이 작성한다.

마운트 가능한 시크릿과 달리 이미지 풀 시크릿은 각각의 파드가 어떤 이미지 풀 시크릿을 사용할 수 있는지를 결정하는 것이 아니라 서비스어카운트를 사용해 모든 파드에 특정 이미지 풀 시크릿을 자동으로 추가하기 때문에 서비스어카운트에 이미지 풀 시크릿을 추가하면 각 파드에 개별적으로 추가할 필요가 없음

1-4. 파드에 서비스어카운트 할당

파드 정의의 spec.serviceAccountName 필드에서 서비스어카운트 이름 설정

파드를 만들 때 파드의 서비스어카운트를 설정해야 함. 나중에 변경 불가능

사용자 정의 서비스어카운트를 사용하는 파드 생성

apiVersion: v1
kind: Pod
metadata:
  name: curl-custom-sa
spec:
  serviceAccountName: foo // default 대신 foo 사용
  containers:
  - name: main
    image: tutum/curl
    command: ["sleep", "9999999"]
  - name: ambassador
    image: luksa/kubectl-proxy:1.6.2

파드 생성 후 파드의 컨테이너에 마운트된 토큰을 위와 같이 확인할 수 있음

위의 토큰을 사용해 API 서버와 통신할 수 있음

2. 역할 기반 액세스 제어로 클러스터 보안

RBAC은 권한이 없는 사용자가 클러스터 상태를 보거나 수정하지 못하게 하여 보안을 강화한다.

디폴트 서비스어카운트는 추가 권한을 부여하지 않는 한 클러스터 상태를 볼 수 없으며 어떤 식으로든 수정할 수 없다.

(RBAC 외에도 속성 기반, 웹훅 플러그인 등등의 여러 인가 플러그인이 있으나 RBAC이 표준)

2-1. RBAC 인가 플러그인 소개

API 서버는 REST 인터페이스를 제공하므로 사용자는 서버에 HTTP 요청을 보내 액션을 수행하고, 요청에 자격증명을 포함시킨다.

액션 이해하기

동사는 클라이언트가 수행한 HTTP 메서드에 매핑되고, 명사(파드, 서비스, 시크릿)는 쿠버네티스 리소스와 매핑됨

RBAC 규칙 적용 가능 범위

  • 전체 리소스 유형에 보안 권한을 적용
  • 특정 리소스 인스턴스에도 적용 가능하며 나중에 리소스가 아닌 URL 경로(non-resource URL path)
    • API 서버가 노출하는 모든 경로가 리소스를 매핑하는 것이 아니기 때문(ex. 서버의 상태 정보를 갖는 /healthz)

RBAC 플러그인 이해

사용자가 액션을 수행할 수 있는지 여부를 결정하는 핵심 요소로 사용자 롤을 사용

주체는 하나 이상의 롤과 연계되어 있으며 각 롤은 특정 리소스에 특정 동사 수행 가능

사용자에게 여러 롤이 있는 경우 롤에서 허용하는 모든 작업 수행 가능

2-2. RBAC 리소스 소개

RBAC 인가 규칙은 네 개의 리소스로 구성되며 두 개의 그룹으로 분류 가능

  • 롤과 클러스터롤: 리소스에 수행할 수 있는 동사 지정
  • 롤바인딩과 클러스터롤바인딩: 위의 롤을 특정 사용자, 그룹, 또는 서비스어카운트에 바인딩
  • 롤과 롤바인딩 → 네임스페이스가 지정된 리소스
  • 클러스터롤과 클러스터롤 바인딩 → 네임스페이스를 지정하지 않는 클러스터 수준의 리소스

minikube delete 후 다시 start

네임스페이스 생성과 파드 실행

네임스페이스 생성

파드 실행

파드에서 서비스 목록을 나열해보려 했으나, default 서비스어카운트를 사용하기 때문에 리소스를 나열할 수 없음

2-3. 롤과 롤바인딩 사용

아래와 같이 롤을 정의한다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: foo
  name: service-reader
rules:
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["services"]

리소스를 지정할 때는 복수형을 사용해야 함

롤 정의에서는 각 규칙 내에 나열된 리소스의 apiGroup을 지정해야 함.

여러 API 그룹에 속한 리소스에 관한 액세스를 허용하는 경우 여러 규칙을 사용함

롤 생성하기

yaml 말고도 아래와 같은 명령어로도 롤을 생성할 수 있음

서비스어카운트에 롤을 바인딩하기

foo 네임스페이스의 default 서비스어카운트에 service-reader 롤을 바인딩하는 롤바인딩을 만듦

롤은 수행할 수 있는 액션을 정의하지만 누가 수행할 수 있는지는 지정하지 않기 때문에 주체(사용자, 서비스 어카운트 혹은 그룹)에 바인딩함

(--serviceaccount, --user, --group 인수를 통해 원하는 주체에게 바인딩 가능)

롤바인딩은 항상 하나의 롤을 참조하지만 여러 주체에 롤을 바인딩할 수 있음

rolebinding 후엔 403 에러가 뜨지 않고 서비스가 잘 나열됨

롤바인딩에서 다른 네임스페이스의 서비스어카운트 포함하기

kubectl edit rolebinding test -n foo

위와 같이 bar serviceaccount도 추가한다.

bar 네임스페이스에서 실행되는 파드의 내부에서 foo 네임스페이스의 서비스를 나열 가능

요약

네임스페이스 foo에 롤바인딩이 있으며 이는 service-reader 롤을 참조하고 foo와 bar 네임스페이스 모두에서 default 서비스어카운트를 바인딩함

2-4. 클러스터롤과 클러스터롤바인딩 사용하기

어떤 리소스(ex. 노드, 퍼시스턴트볼륨, 네임스페이스..)는 전혀 네임스페이스를 지정하지 않고 API 서버는 리소스를 나타내지 않는 일부 URL 경로(ex. /healthz)를 노출하는데, 일반적인 롤로는 이런 리소스나 리소스가 아닌 URL에 관한 액세스 권한을 부여할 수 없음 → 클러스터롤의 등장

클러스터롤

  • 네임스페이스가 지정되지 않은 리소스나 리소스가 아닌 URL에 액세스를 허용하는 클러스터 수준의 리소스
  • 각각의 네임스페이스에 동일한 롤 재정의 필요 없이 개별 네임스페이스에 바인드해서 공통적인 롤로 사용 가능

클러스터 수준 리소스에 액세스 허용

위의 명령은 아래의 yaml과 같다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pv-reader
rules:
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["persistentvolumes"]

파드가 퍼시스턴트볼륨을 나열하도록 허용한다.

현재는 role이 바인딩되어있지 않아 나열할 수 없음

이렇게 해도 나열할 수 없음..

롤바인딩을 생성하고 클러스터롤을 참조해서 네임스페이스가 지정된 리소스에 액세스하게 할 수 있지만(이전의 서비스 나열 예제처럼..) 클러스터 수준 리소스에는 동일한 방식을 사용할 수 없음

클러스터 수준 리소스에 액세스 권한을 부여하려면 항상 클러스터롤바인딩을 사용해야 함

리소스가 아닌 URL에 액세스 허용하기

API 서버는 리소스가 아닌 URL도 노출하며, 이 URL에 관한 액세스 권한도 명시적으로 부여해야 함

일반적으로 이는 system:discovery 클러스터롤/클러스터롤바인딩을 통해 자동으로 수행됨

이 클러스터롤이 리소스 대신 URL을 참조하는 것을 알 수 있음

리소스가 아닌 URL의 경우 create나 update 대신 post, put, patch가 사용됨

클러스터 수준 리소스와 마찬가지로 리소스가 아닌 URL의 클러스터롤은 클러스터롤바인딩으로 바인딩되어야 함

클러스터롤바인딩은 system:discovery 클러스터롤을 참조

모든 사용자 (인증된 사용자/인증되지 않은 사용자)를 이 클러스터롤에 바인딩함

(-k로 우회했는데도 403..)

특정 네임스페이스의 리소스에 액세스 권한을 부여하기 위해 클러스터롤 사용하기

클러스터롤은 항상 클러스터롤바인딩과 바인딩될 필요는 없고, 네임스페이스를 갖는 일반적인 롤바인딩과 바인딩될 수도 있음

view라는 clusterrole에 있는 규칙

ConfigMaps, Endpoints, PersistentVolumeClaims 등 네임스페이스가 지정된 리소스를 가져오고 나열하고 볼 수 있음

클러스터롤은 클러스러롤바인딩과 롤바인딩 중 어디에 바인드되느냐에 따라 달라짐(둘 중 하나만 바인딩 가능)

  • 클러스터롤 생성 → 클러스터롤 참조: 바인딩에 나열된 주체는 모든 네임스페이스에 있는 지정된 리소스 볼 수 있음
  • 롤바인딩 생성 → 클러스터롤 참조: 바인딩에 나열된 주체가 롤바인딩의 네임스페이스에 있는 리소스만 볼 수 있음

clusterrolebinding을 만들어 파드의 서비스어카운트에 바인딩하면 파드가 foo 네임스페이스에 있는 파드 나열 가능

foo 네임스페이스말고 bar 네임스페이스의 파드도 나열 가능

이제 rolebinding으로 교체한다.

다른 네임스페이스

해당 네임스페이스는 가능하나 다른 네임스페이스나 전체 네임스페이스는 조회 불가능

롤, 클러스터롤, 롤바인딩과 클러스터롤바인딩 조합 요약

2-5. 디폴트 클러스터롤과 클러스터롤바인딩의 이해

쿠버네티스는 디폴트 롤과 바인딩을 제공

가장 중요한 롤은 view, edit, admin과 cluster-admin 클러스터롤

view 클러스터롤

리소스에 읽기 전용 액세스 허용하기

롤, 롤바인딩과 시크릿을 제외한 거의 모든 리소스 읽을 수 있음

시크릿을 읽지 못하게 하여 권한 상승 방지

edit 클러스터롤

네임스페이스 내의 리소스 수정, 시크릿 수정 등 가능

but 롤, 롤바인딩을 보거나 수정하는 것 허용하지 않음(권한 상승 방지)

admin 클러스터롤

네임스페이스에 제어 권한 허용하기

네임스페이스에서 롤과 롤바인딩 보고 수정 가능

그 밖의 디폴트 클러스터롤

  • system: 접두사로 시작하는 클러스터롤 → 쿠버네티스의 구성요소에서 사용. 매칭되는 클러스터롤바인딩이 있으며 이를 시스템 구성요소가 인증하는 사용자에게 바인딩함 (system:kube-scheduler, system:node 등등)
  • system:controller → 컨트롤러 매니저는 하나의 파드로 실행되지만 내부에서 실행되는 각 컨트롤러는 별도의 클러스터롤과 클러스터롤바인딩 사용 가능

2-6. 인가 권한을 현명하게 부여하기

각 파드에 특정 서비스어카운트 생성

각 파드를 위한 특정 서비스어카운트를 생성한 다음 롤바인딩으로 맞춤형 롤(or 클러스터롤)과 연계하는 것이 바람직함

클러스터롤바인딩으로 파드에서 다른 네임스페이스의 리소스에 접근할 수 있기 때문에 클러스터롤바인딩으로 하면 안됨

애플리케이션이 탈취될 가능성을 염두에 두기

항상 서비스어카운트에 제한을 둬야 함

3. 요약

  • API 서버의 클라이언트는 휴먼 사용자와 파드에서 실행되는 애플리케이션이 모두 포함
  • 파드의 애플리케이션은 서비스어카운트와 연계되어 있음
  • 사용자와 서비스어카운트 모두 그룹과 연계되어 있음
  • 기본적으로 파드는 각 네임스페이스에 자동으로 생성되는 default 서비스어카운트에서 실행
  • 추가적인 서비스어카운트는 수동으로 생성하고 파드와 연계시킬 수 있음
  • 서비스어카운트는 특정 파드에 제한된 시크릿 목록만 마운트할 수 있도록 구성할 수 있음
  • 서비스어카운트는 이미지 풀 시크릿을 파드에 첨부하는 데도 사용할 수 있으므로 모든 파드에 시크릿을 저장할 필요가 없음
  • 롤과 클러스터롤은 어떤 리소스에 어떤 작업을 수행할 지 정의
  • 롤바인딩과 클러스터롤바인딩은 롤과 클러스터롤을 사용자, 그룹, 서비스어카운트에 바인딩함
  • 각 클러스터에는 디폴트 클러스터롤과 클러스터롤바인딩이 제공됨

Reference
쿠버네티스 인 액션 12장

profile
https://sian-log-siyeons.vercel.app/ 이 곳으로 이전하였습니다.

0개의 댓글