Search
Duplicate

Authentication & Authorization

Created By
Status
예정
Type
Created
2022/12/13 23:24
Last Edited Time
2022/12/13 23:24
Last Edited By
Date
Week
8
쿠버네티스 접근제어에는 크게 3단계가 있습니다.
Authentication: 해당 클라이언트가 쿠버네티스의 사용자가 맞는지 검증
Authorization: 해당 사용자가 해당 기능을 실행할 권할을 가지는지
Admission Control: 인증과 권한확인 이후에 추가적으로 요청 내용에 대한 검증이나 요청 내용을 강제로 변경할 때 사용합니다.
Authorization 단계는 말그대로 사용자가 특정 작업을 수행할 때 어떤 권한이 있는지를 확인하는 단계입니다. 반대로 Admission Control은 권한이 있는 사용자에 한해서 관리자(Admin)가 추가로 특정 행동을 제한(validate) 혹은 변경(mutate)하는 작업입니다.
쿠버네티스 접근제어 방식을 하나의 예를 들어서 설명해봅시다.
예를 들어 여러분들이 kubectl get pod -A라는 명령으로 모든 네임스페이스의 파드 리스트를 확인하는 경우,
먼저 명령을 내린 머신에 있는 kubernetes config파일(기본적으로 $HOME/.kube/config파일)에서 현재 사용자가 누구인지를 찾습니다.
kubectl config view라는 명령으로 보면 현재 컨텍스트의 현재 유저를 볼 수 있습니다.
그 유저를 기본인증, X.509 인증서 기반 인증, OAuth 연동 인증, WebHook 연동 인증, 프락시 서버 연동 인증 중 하나의 방법으로 인증 합니다.
인증이 성공하면 유저가 kubectl get pod -A라는 명령을 수행할 권한이 있는지 클러스터 롤 바인딩/ 롤 바인딩을 검사 합니다.
인증과 인가까지 통과한 요청은 어드미션 컨트롤러의 뮤테이팅Mutating 어드미션Admission과 밸리데이팅Validating 어드미션Admission 과정까지 통과해야 합니다.
예를 들어 뮤테이팅 어드미션에서 무조건 현재 네임스페이스의 파드 리스트만 리턴 하도록 요청을 변형 하였다면 전체 네임스페이스의 파드를 볼 수 있는 권한이 있더라도 현재 네임스페이스의 파드 리스트만 리턴 됩니다.
밸리데이팅 어드미션에서 ‘Guest’그룹의 사용자는 파드 리스트를 못 보게 정의 하였고 현재 사용자가 ‘Guest’그룹에 속한다면 최종적으로 요청은 거부 됩니다.
쿠버네티스에 대한 요청이 처리되는 전체 과정을 그림으로 표현하면 아래와 같습니다.

인증 (Authentication)

kubectl 명령으로 kubernetes의 API Server 모듈에 접근하기 위해서는 인증(Authentication) 과정을 통과해야 합니다.
kuberentes 설치 이후 아무런 인증 처리 없이 kubectl 명령을 정상적으로 사용할 수 있었던 이유는, 설치 이후에 사용자가 설정하지 않았어도 이미 kubectl 설정에 인증서가 사용되고 있었기 때문입니다.
kubectl을 사용해서 kubernetes API Seerver 모듈에 접근할 수 있는 기본 포트 : 6443
6443 포트는 기본적으로 TLS 인증이 적용되어 있습니다. 일반적인 https 인증은 접근하는 클라이언트에서 인증서가 필요 없지만, Kubernetes Api Server 모듈에 열려 있는 6443 Port에 접근하기 위해서는 Api Server에서 가지고 있는 인증서에서 검증 가능한 유효한 인증서를 가지고 접근해야 통신이 가능합니다.

1. Kubernetes에 인증을 요청할 수 있는 사용자의 종류

쿠버네티스는 계정 체계를 관리함에 있어서 사람이 사용하는 사용자 어카운트와, 시스템이 사용하는 서비스 어카운트 두가지 개념을 제공합니다.

사용자 어카운트(User Account)

사용자 어카운트는 우리가 일반적으로 생각하는 사용자 아이디의 개념입니다.
쿠버네티스는 자체적으로 사용자 계정을 관리하고 이를 인증(Authenticate)하는 시스템을 가지고 있지 않습니다. 반드시 별도의 외부 계정 시스템을 사용해야 하며, 계정 시스템 연동을 위해서 OAuth나 Webhook가 같은 계정 연동 방식을 지원합니다.
구글 계정(Google Account), 오픈스택의 키스톤(keystone), LDAP 등의 인증 시스템과 연동이 가능합니다.
파일에 유저명과 비밀번호를 저장해 두고 사용하는 것도 가능하고, openssl로 인증서 만들어서 해당 인증서 계정으로 접근하는 것도 가능합니다.
추가적으로 User를 그룹화해서 사용하는 User Group 개념도 있습니다.
ex) User Account로 Pod 생성
Pod를 생성할 때 yaml 파일로 pod 생성을 명시하고 kubectl 명령으로 Pod를 생성하는 경우 User Account로 생성되는 원리입니다.

서비스 어카운트(Service Account)

서비스 어카운트가 다소 낮설 수 있는데, 예를 들어 클라이언트가 쿠버네티스 API를 호출하거나, 콘솔이나 기타 클라이언트가 쿠버네티스 API를 접근하고자 할때, 이는 실제 사람인 사용자가 아니라 시스템이 됩니다. 그래서, 쿠버네티스에서는 이를 일반 사용자와 분리해서 관리하는데, 이를 서비스 어카운트 (service account)라고 합니다.
ex) Service Account로 Pod 생성
Pod를 생성할 때 yaml 파일로 Deployment와 같은 Controller로 생성할 경우 Deployment가 Pod를 관리하고 생성하기 때문에 Service Account를 사용해서 생성되는 원리입니다.
아래 그림과 같이 우리는 몰랐지만 kubernetes 에는 이미 각종 Controller에 해당하는 Service Account 계정들이 존재해서, 해당 Controller로 Pod를 생성할 때 Controller와 일치하는 Service Account를 사용해서 생성하고 있습니다.

2. 인증 방법

그러면 계정이 있을때, 이 계정을 이용해서 쿠버네티스의 API에 어떻게 접근을 할까? 쿠버네티스는 사용자 인증을 위해서 여러가지 메커니즘을 제공합니다. 용도에 따라서 다양한 인증 방식을 선택해서 사용할 수 있습니다.
Basic HTTP Auth
Access token via HTTP Header
Client cert
Custom made

Basic HTTP Auth

Basic HTTP Auth는 HTTP 요청에 사용자 아이디와 비밀번호를 실어 보내서 인증하는 방식인데, 아이디와 비밀번호가 네트워크를 통해서 매번 전송되기 때문에 그다지 권장하지 않는 방법입니다.

Access token via HTTP Header

Access token via HTTP Header는 일반적인 REST API 인증에 많이 사용되는 방식인데, 사용자 인증 후에, 사용자에 부여된 API TOKEN을 HTTP Header에 실어서 보내는 방식입니다.
2.1 Bearer Token을 사용한 인증
HTTP 프로토콜이 제공하는 인증 방법인 HTTP Authentication 방법 중 하나로 HTTP Header를 통해 인증 정보를 서버에게 전달하는 방법입니다.
Kubernetes Master Node의 API Server 모듈도 결국 웹서버와 똑같이 동작하기 때문에 API Server 모듈도 HTTP Authentication 설정을 적용할 수 있습니다.
HTTP Authentication을 사용하기 위해서는 HTTP Header에 "Authorzation " <type><credentials>" 필드가 있어야 합니다.
type : 인증 방식 선언
credentials : 사용자 인증 정보
kubernetes는 이러한  HTTP Authentication 방식 Type에 Bearer를 지원하고 있습니다.
서비스 어카운트의 경우에는 인증 토큰 정보를 secret에 저장을 합니다. 이 토큰 문자열을 가지고, HTTP 헤더에 “Authorization: Bearer {토큰문자열}로 넣고 호출하면 이 토큰을 이용해서 쿠버네티스는 API 호출에 대한 인증을 수행합니다.
$ kubectl describe -n kube-system sa admin
Name: admin Namespace: kube-system Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: admin-token-t4z6p Tokens: admin-token-t4z6p Events: <none>
YAML
복사
$kubectl describe -n kube-system secret admin
Name: admin-token-t4z6p Namespace: kube-system Labels: <none> Annotations: kubernetes.io/service-account.name: admin kubernetes.io/service-account.uid: c48a... Type: kubernetes.io/service-account-token Data ==== namespace: 11 bytes token: eyJhbGciOiJSUzI...
YAML
복사
간단한 스크립트를 통해서 API를 호출하는 것을 테스트 해봅시다.
APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ") 명령을 수행하면 환경 변수 APISERVER에 현재 쿠버네티스 클러스터의 API SERVER IP가 저장됩니다.
다음 APISERVER의 주소를 알았으니 curl $APISERVER/api
명령을 이용해서 HTTP GET의 /api를 호출해봅시다.
$ APISERVER=$(kubectl config view | grep server | cut -f 2- -d ":" | tr -d " ") $ curl $APISERVER/api curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
Bash
복사
호출을 하면 SSL 인증서에 대한 인증 에러가 발생합니다. 이는 API를 호출할때 인증에 필요한 정보를 기재하지 않았기 때문에, 디폴트로 Client cert를 이용한 인증을 시도하게 되고, 인증서를 지정하지 않았기 때문에 에러가 나게 되는것입니다.
그러면 인증 정보를 제대로 지정하기 위해서 서비스 어카운트 default의 토큰을 얻어서 호출해보도록 하자.
다음 스크립트는 서비스 어카운트 default의 secret에서 토큰을 추출해서 저장하는 스크립트이다.
TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t')
$ TOKEN=$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d '\t') $ echo $TOKEN eyJhbGciOiJSUzI1NiI... $ curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure { "kind": "Status", "apiVersion": "v1", "metadata": {}, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 }%
Bash
복사
저의 경우 bearer token을 이용한 인증이 불가능하도록 설정되어있어 해당 방식을 사용하지 못하지만, 원래의 경우 아래처럼 성공하는 모습을 볼 수 있습니다.
이러한 Bearer Token 인증 방식은 굉장히 허술한 면이 많아서 이를 보완하고자 Kubernetes에서 Bearer Token을 전송할 때 주로 JWT (Json Web Token)를 사용합니다.
JWT (Json Web Token) 이란?
JSON Web Token의 약자로,
일반적으로 HTTP API 서버를 만들 때에 인증 방법으로 사용.
서버는 사용자가 로그인할 때 고유한 Token을 생성하고,
이를 사용자에게 알려주어 사용자가 다른 API를 사용할 때에 헤더에
이 Token을 넣으면, 자신이라는 것을 증명할 수 있게 하는 것.
Json 형태로 Token을 정의.
[JWT는 3가지 파트로 구분됨]
1. Header : 토큰 형식 와 암호화 알고리즘을 선언
2. Payload : 전송하려는 데이터를 JSON 형식으로 기입
3. Signature : Header와 Payload의 변조 가능성을 검증
각 파트는 Base64로 인코딩 되어서 " . " 로 구분되어 있음
JWT는 보안 기술이 아닌 인증 기술에 해당함

Client Certification

Client cert는 클라이언트의 식별을 인증서 (Certification)을 이용해서 인증하는 방식입니다. 한국으로 보자면 인터넷 뱅킹의 공인 인증서와 같은 방식으로 생각하면 된다. 보안성은 가장 높으나, 인증서 관리에 추가적인 노력이 필요합니다.
2.2 Client Certification - TLS
쿠버네티스는 apiserver와 통신하기 위해서 사용하는 기본 인증 방법으로 TLS(Transport Layer Security)인증을 사용합니다. TLS는 통신할때의 오고가는 패킷을 암호화하는 일반적인 방법입니다. 보통 HTTPS용 웹서버를 설정할때 보면 서버측에만 인증서를 설정하면 보안통신이 가능합니다. 하지만 TLS 인증은 서버 뿐만이 아니라 클라이언트가 유효한지를 검증하는 기능도 가지고 있습니다. 그러기 위해서 apiserver쪽에는 있는 인증서와 매치되는 클라이언트 인증서를 가지고 접속을 시도하면 됩니다.
apiVersion: v1 clusters: - cluster: certificate-authority-data: DATA+OMITTED server: https:/ name: toast-csi-test-v1 contexts: - context: cluster: toast-csi-test-v1 user: admin name: default current-context: default kind: Config preferences: {} users: - name: admin user: client-certificate-data: REDACTED client-key-data: REDACTED
YAML
복사
contexts 부분을 보면 context는 실제로 어떤 cluster에 접근하기위해 필요한 user가 누구인지를 연결해 주고 있습니다. 그리고 여기에는 생략되어 있지만 context에는 namespace까지 지정할 수 있어서 default 네임스페이스가 아닌 특정 네임스페이스에 대한 작업을 편하게 할 수도 있게 해줍니다.
cluster 다음에는 하단의 Users를 보겠습니다. 여러명의 user를 명시해 두고 사용하는 것이 가능합니다. 여기서는 TLS인증을 사용하는 유저이기 때문에 client-certificate-data와 client-key-data를 사용합니다. 실제로는 더 긴 문자열이 오지만 여기서는 생략 시켰습니다.

Webhook 인증

kubernetes에서 Webhook 이벤트를 사용하는 임의의 인증 방법을 연동하여 인증을 받을 수도 있습니다.
webhook (웹훅)이란?
서버에서 어떠한 작업이 수행되었을 때 해당 작업이 수행되었음을 HTTP POST로 알리는 개념.
Webhook을 구현한 웹 애플리케이션은, 특정 작업이 수행될 때 URL에 대해 POST방식으로 요청을 생성.
이때, url(콜백 url)은 웹 애플리케이션을 사용하는 유저가 자신의 URL을 지정할 수 있음
kubernetes는 이러한 webhook 기능을 별도의 인증서버와 연동하여 webhook 인증 기능을 제공합니다.
webhook을 통해 LDAP, Basic Authentication Server 등등 을 자유롭게 연동하여 사용할 수 있습니다.

권한 관리 (Authorization)

ABAC (Attribute-Based Access Control)
속성 기반의 권한 관리
ABAC 방식은 권한에 대한 내용을 파일로 관리하기 때문에 권한을 변경하려면 직접 마스터 노드에 들어가서 파일을 변경하고 api server를 재시작해주어야 하기 때문에 번거로워 잘 사용하지 않습니다.
RBAC (Role-Based Access Control)
역할 기반 권한 관리
kubernetes는 기본적으로 안전한 Cluster 구성을 위해 RBAC을 사용합니다.
종류로는 Role과 RoleBinding, ClusterRole과 ClusterRoleBinding 이 있습니다.
RBAC (Role based access control) 권한 구조를 도식화 해보면 다음과 같이 표현할 수 있습니다.
사용자의 계정은 개개별 사용자인 user, 그리고 그 사용자들의 그룹은 user group, 마지막으로 시스템의 계정을 정의하는 service account로 정의됩니다.
권한은 Role이라는 개념으로 정의가 되는데, 이 Role에는 각각의 리소스에 대한 권한이 정의된다. 예를 들어 pod 정보에대한 create/list/delete등을 정의할 수 있다.
이렇게 정의된 Role은 계정과 RoleBinding 이라는 정의를 통해서, 계정과 연결이 된다.
예제를 살펴봅시다.
Role
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: kkj-role # 해당 Role의 이름 namespace: kkj-ns # Role 이 적용될 namespace 설정 # (role 규칙은 모두 해당 namespace에 적용되고 해당 namespace 만 사용 가능) # 해당 namespace는 미리 생성되어있어야 함 rules: # 권한 부여 - apiGroups: ["", "extensions", "apps"] # 사용할 API를 명시함 # 일반 yaml 파일에서 apiVersion을 명시하는데 # 그 version 그룹에 대한 권한을 설정하는 부분 # 예) apps/v1 의 apps, batch/v1 의 batch, extenstions/v1beta의 extensions 등등 resources: ["deployments", "pods", "replicasets"] # pod, deployment, service 등 어떤 자원에 접근이 가능한지 설정 verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 어떤 동작이 가능한지 설정 # 참고 ["*"] 설정 시 모든 권한 획득
YAML
복사
Role Binding
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: kkj-rb namespace: kkj-ns # 적용 대상 namespace 설정 subjects: - kind: User # 사용자를 설정 [User, Group, ServiceAccout] 가 올 수 있음 name: kkj # 상위 User 종류에 해당하는 name을 넣어줌 #해당 user는 상위 kind 종류와 동일해야 하고 기존에 생성되어있어야 함 apiGroup: "" roleRef: # 해당 사용자에게 어떤 Role를 적용할지 설정 kind: Role name: kkj-role # RoleBinding에 적용될 Role name을 넣어줌 apiGroup: rbac.authorization.k8s.io
YAML
복사
그림으로 표현하면 다음과 같습니다.

Cluster Role

Role은 적용 범위에 따라 Cluster Role과 일반 Role로 분리 됩니다.
Role의 경우 특정 네임스페이스 내의 리소스에 대한 권한을 정의할 수 있다.
반면 ClusterRole의 경우, Cluster 전체에 걸쳐서 권한을 정의할 수 있다는 차이가 있습니다.
또한 ClusterRole의 경우에는 여러 네임스페이스에 걸쳐 있는 nodes 와 같은 리소스스나 /heathz와 같이 리소스 타입이 아닌 자원에 대해서도 권한을 정의할 수 있다.
Role과 ClusterRole은 각각 RoleBinding과 ClusterRoleBinding 을 통해서 사용자에게 적용된다.

Predefined Role

쿠버네티스에는 편의를 위해서 미리 정해진 롤이 있습니다.
Default ClusterRole
Default ClusterRoleBinding
Description
cluster-admin
system:masters group
쿠버네티스 클러스터에 대해서 수퍼사용자 권한을 부여한다. ClusterRoleBinding을 이용해서 롤을 연결할 경우에는 모든 네임스페이스와 모든 리소스에 대한 권한을 부여한다. RoleBinding을 이용하여 롤을 부여하는 경우에는 해당 네임 스페이스에 있는 리소스에 대한 모든 컨트롤 권한을 부여한다.
admin
None
관리자 권한의 억세스를제공한다. RoleBinding을 이용한 경우에는 해당 네임스페이스에 대한 대부분의 리소스에 대한 억세스를 제공한다.  새로운 롤을 정의하고 RoleBinding을 정의하는 권한을 포함하지만, resource quota에 대한 조정 기능은 가지지 않는다.
edit
None
네임스페이스내의 객체를 읽고 쓰는 기능은 가지지만, role이나 rolebinding을 쓰거나 수정하는 역할은 제외된다.
view
None
해당 네임스페이스내의 객체에 대한 읽기기능을 갔는다. role이나 rolebinding을 조회하는 권한은 가지고 있지 않다.
미리 정해진 롤에 대한 자세한 정보는  https://kubernetes.io/docs/reference/access-authn-authz/rbac/
를 참고하기 바랍니다.
[참고]