개발놀이터

쿠버네티스 이론 : 인증, 인가 본문

배포/kubernetes

쿠버네티스 이론 : 인증, 인가

마늘냄새폴폴 2024. 9. 7. 19:18

쿠버네티스는 쿠버네티스와 관련된 명령어를 사용할 때 마스터 노드에 존재하는 API Server를 지나가게 되어있습니다. 

 

하지만 어떤 곳에서든 kubectl같은 명령어를 사용할 수 있다면 이는 보안적으로 좋지 못하겠죠?

 

이번 포스팅에선 쿠버네티스가 어떤 인증 체계를 가지고 있으며 어떻게 권한에 접근하게 하는지에 대해서 공부한 내용을 정리해보도록 하겠습니다. 

 

Kubernetes API Server

쿠버네티스의 API Server에 접근하기 위해서는 HTTPS로 접근해서 인증서가 존재하는 경우에만 접근하게 할 수 도 있고, 마스터 노드에서 사용할 수 있는 kubectl에 프록시를 연결해서 HTTP로 연결하는 방법도 있습니다. 만약 쿠버네티스 클러스터를 여러개 운영하고 있다면 모든 쿠버네티스 API Server에 접근할 수 있도록 설정파일을 만드는 방법도 있죠. 

 

또한, 파드에서도 kubectl과 같은 명령어를 사용할 수 있는데 파드에서 네임스페이스가 나눠져 있는 경우 API Server에 네임스페이스별로 접근할 수도 있고 접근하지 못할 수도 있습니다. 

 

이렇듯 쿠버네티스는 API Server에 접근할 때 사용자의 관점인 User Account와 파드와 같은 오브젝트 관점인 Service Account를 제공합니다. 

 

이때, 어떤 사용자가 API Server에 접근할 수 있을지를 정하는 Authentication이 있고, 사용이 가능하다면 어디까지 사용할 수 있는지에 대한 권한을 부여할 수 있는 Authorization이 있습니다. 

 

이뿐만 아니라 예를 들어서 쿠버네티스 관리자가 볼륨을 생성할 때 최대 용량을 10기가로 설정해놓으면 10기가를 넘는 용량을 스토리지로 만들 때 생성할 수 없도록 제한할 수 있는 Admission Control이 있습니다. 

 

다음 섹션에선 Admission Control을 제외한 Authentication과 Authorization에 대해서 정리해보았습니다. 

 

Authentication

Authentication (이하 인증) 은 API Server에 어떤 사용자가, 어떤 서비스를 이용 가능할지 쿠버네티스에게 알려주는 용도입니다. 

 

API Server에 접근하는 상황을 HTTPS, kubectl proxy, kubeconfig, Service Account 이렇게 네 가지 상황으로 나누어 자세히 알아보도록 하겠습니다. 

 

API Server에 HTTPS로 접근

API Server에 접근하는 첫 번째 방법은 인증서를 이용한 HTTPS로서 쿠버네티스는 맨 처음 클러스터가 만들어지면 6443포트로 API Server를 열어둡니다. 이 포트로 접근해 API Server에 인증 받기 위해선 kubeconfig에 적혀있는 클라이언트 개인키와 인증서를 모두 가지고 있어야합니다. 

 

kubeconfig란 쿠버네티스가 구동될 때 이 파일을 기반으로 동작하는데 그 때 인증기관의 인증서와 개인키, 인증서를 모두 가지고 있습니다. 

 

인증 순서에 대해서 잠깐 짚고 넘어가자면 

  • 인증기관의 개인키 : 인증 요청서인 csr파일이 있으면 바로 인증서로 바꿔줍니다. 
  • 클라이언트 개인키 : 인증 요청서인 client csr이 있으면 인증기관의 개인키와 인증기관의 인증서와 인증요청서를 가지고 클라이언트 인증서를 만들어줍니다. 

 

이렇게 만들어진 클라이언트 인증서와 클라이언트 개인키가 kubeconfig에 등록되게 되고 이 인증서와 개인키를 사용자가 들고 API Server에 접근하면 사용자가 인증되고 API Server에 자유롭게 접근할 수 있습니다. 

 

우리가 기본적으로 kubectl을 설치하면 이때 만들어진 kubeconfig를 그대로 복사해서 설치가 되기 때문에 우리는 별다른 설정 없이 바로 kubectl을 사용할 수 있는 것입니다. 

 

kubectl proxy로 API Server에 접근

kubectl proxy로 API Server로 접근하는 것은 사실 보안적으로 문제가 있을 수 있기 때문에 많이 사용되지 않고 권장하는 방식도 아닙니다. 

 

때문에 간단하게만 짚고 넘어가도록 하겠습니다. 

 

kubectl을 설치할 때 kubeconfig에 프록시 설정 (host, port)을 해두면 사용자가 인증서 없이 곧바로 kubectl로 접근할 수 있습니다. 

 

이 방법은 외부망으로 연결되어 있으면 굉장히 위험하고 내부망으로 연결해도 보안상 좋지 않기 때문에 잘 사용되지 않습니다. 

 

kubeconfig로 멀티 클러스터 연결

만약 멀티 클러스터를 이용하는 경우, 사용자의 kubectl을 설치할 때 여러개의 kubeconfig를 이용해서 접근할 수 있습니다. 

 

kubeconfig에는 클러스터의 정보와 유저의 정보, 그리고 이 클러스터와 유저를 이어주는 컨텍스트가 존재합니다. 

 

클러스터엔 클러스터 이름, 접근 정보 (URL등), 그리고 인증기관의 인증서가 존재합니다. 유저엔 유저이름, 유저의 개인키, 유저의 인증서가 존재하죠. 마지막으로 컨텍스트엔 컨텍스트이름, 클러스터이름, 유저이름 이렇게 적혀있어서 어떤 유저가 어떤 클러스터와 연결되어있는지 알 수 있습니다. 

 

이런 여러개의 컨텍스트를 가지고 있다면 유저는 kubectl을 사용할 때 kubectl config 명령어를 이용해서 클러스터에 접근하고 API Server에도 접근할 수 있는 것입니다. 

 

Service Account에서 API Server에 접근

마지막으로 파드와 같은 서비스들이 API Server에 접근하는 것입니다. 

 

네임스페이스를 만드렉 되면 default라는 이름의 Service Account가 자동으로 생성됩니다. 이 Service Account는 자체적인 Secret을 가지고 있으며 여기에는 인증기관의 인증서가 들어있고 토큰이 들어있습니다. 

 

만약 파드가 이 네임스페이스에 생성되면 파드가 Service Account에 연결되고 이 파드는 API Server에 접근할 수 있는 것입니다. 

 

 

Authorization

쿠버네티스에서 Authorization (이하 인가)에서 가장 많이 쓰이는 것이 RBAC입니다. RBAC란 Role Based Access Control의 약자로 역할을 기반으로 접근을 통제하는 것입니다. 

 

쿠버네티스는 클러스터단위로 관리된느 Node, PV, Namespace같은 것들이 있고, 네임스페이스 단위로 관리되는 Pod, Svc같은 것들이 있습니다. 간단하게는 클러스터 자원과 네임스페이스 자원으로 나눌 수 있습니다. 

 

즉, 파드가 클러스터 자원에 접근하기 위해서 네임스페이스를 만들면 Service Account가 만들어지고 이 Service Account (이하 SA)에 역할을 연결하면 됩니다. 

 

네임스페이스 자원에 대한 인가를 위해서는 역할을 생성하고 이를 SA와 연결하면 되는데 이 가운데 RoleBinding이라는 친구가 이둘을 연결해줍니다. 

 

먼저 자원에 대한 인가를 위해 Role을 만들고 RoleBinding을 이용해서 SA와 연결하면 이 네임스페이스에 들어와있는 파드와 서비스에게 이 역할이 부여되고 네임스페이스 자원을 사용할 수 있습니다. 

 

만약 SA가 클러스터 자원에 접근하고 싶은 경우 ClusterRole과 ClusterRoleBinding을 이용해서 똑같이 바인딩해주면 됩니다. 

 

그냥 Role과 RoleBinding이랑 다른 점은 클러스터 자원을 각각 다르게 지정해줄 수 있다는 것입니다. 즉, Node나 PV, Namespace를 직접 지정해서 역할을 부여해줄 수 있습니다.

 

굉장히 객체지향적이야..

만약 네임스페이스 내부의 자원들이 클러스터 자원에 접근하기를 원하지 않고 네임스페이스 내부 자원만 사용하고 싶으면 어떻게 할까요? 

 

그럴 때는 RoleBinding과 Role을 SA로 연결하지 않고 바로 ClusterRole과 연결하면 해당 네임스페이스의 자원만 접근이 가능합니다. 

 

왜 이렇게 하는걸까요? 이렇게 하면 그냥 Role을 연결하는 것과 뭐가 다르죠? 

 

만약 모든 네임스페이스에서 Role을 관리해야한다면 Role이 조금 변경되면 모든 네임스페이스에 연결된 모든 Role을 변경해줘야하고 그런 경우 매우 관리하기가 힘들기 때문에 ClusterRole을 RoleBinding과 연결해서 해당 네임스페이스는 클러스터 자원과 연결될 수 없다는 것을 쿠버네티스에게 알려주는 것입니다. 

 

Role, RoleBinding의 디테일

Role, RoleBinding을 조금 더 디테일하게 보면, Role에는 어떤 API그룹을 허용할 것인지 정하는 apiGroups가 있고, 어떤 자원을 허용할 것인지에 대한 resources가 있습니다. 또한, 어떤 역할을 수행할 것인지에 대한 verbs가 있습니다. 

 

만약 Job에 대한 Batch작업을 조회할 수 있는 읽기 권한을 부여한다고 가정하면 

 

apiGroups: [batch]

resources: [jobs]

verbs: [get, list]

 

이렇게 설정하면 됩니다. 이 부분에 대한 더 자세한 내용은 쿠버네티스 실습 : 인증, 인가 포스팅에서 다루도록 하겠습니다. 

 

RoleBinding은 roleRef와 subjects가 있고 roleRef에는 어떤 Role을 지정할지 Role의 이름을 적으면 되고, subjects에도 SA를 적으면 SA와 Role이 연결됩니다. 

 

만약 어떤 네임스페이스에서 모든 클러스터 자원에 접근하기를 원한다면 ClusterRole을 등록하고 

 

apiGroups: [""]

resources: [""]

verbs: ["*"]

 

이렇게 설정하고 ClusterRoleBinding에서 roleRef에 ClusterRole을 등록하고 subjects에 SA를 등록하면 됩니다. 

 

 

마치며

인증과 인가 부분도 흥미롭게 공부했습니다. 하지만 인가 부분을 공부할 때 조금 의아했던 것이 쿠버네티스의 철학입니다. 

 

Role과 SA를 바로 연결하는게 아니라 RoleBinding을 통해서 연결하는게 뭔가 어디서 봤다 싶었는데 파드와 서비스를 연결하는게 비슷하더라구요. 

 

파드와 서비스도 곧장 둘이 연결되는게 아니라 Endpoint라는 오브젝트를 통해서 연결이 되던 것이 Role과 SA를 바로 연결하지 않고 RoleBinding이라는 오브젝트로 연결하는것과 동일했습니다. 

 

조금 느낌이 다르긴 하지만 멀티클러스터링에서의 인증에서도 kubeconfig내부에서 컨텍스트로 클러스터와 유저를 엮은 것과 비슷하기도 합니다. 

 

이것이 한두개면 그러려니 하겠는데 거의 대부분의 연결이 이런 방식으로 이루어져있어서 이게 쿠버네티스가 추구하는 철학과 관련된 것인가 하는 느낌이 들었습니다. 

 

조금씩 더 공부하면서 확신을 가지게 되겠지만 우선은 이대로 궁금증만 남기고 마무리지으려합니다. 

 

이번에도 긴 글 읽어주셔서 감사합니다. 오늘도 즐거운 하루 되세요!