본문 바로가기
MLOps/Doker & Kubernetes

Udemy CKA 강의 정리 165: Service Accounts

by 공부하는 무니 2023. 1. 19.
반응형

해당 내용은 Udemy의 Certified Kubernetes Administrator (CKA) with Practice Tests 강의를 공부한 내용입니다. 내용을 그대로 번역하기보다는, 제가 이해하기 쉬운 대로 수정한 부분들이 있습니다.

⚠️ 영어 독해가 많이 부족합니다. 틀린 내용이 있으면 알려주시면 감사하겠습니다.


이번 강의에서는 쿠버네티스의 서비스 계정에 대해 이야기하겠습니다. 서비스 계정의 개념은 authentication, authorization, role-based access controls등과 같은 Kubernetes의 다른 보안 관련 개념과 연결됩니다.

그러나 이는 CKAD 커리큘럼의 일부로 'how to work with service accounts'만 알면 됩니다. 지금 수강하고 있는 CKA 대비 코스에는 보안의 다른 개념을 다루는 자세한 섹션이 있습니다.

Kubernetes에는 사용자 계정과 서비스 계정이라는 두 가지 유형의 계정이 있습니다. 이미 알고 계시겠지만 사용자 계정은 사람이 사용하고 서비스 계정은 기계가 사용합니다.

사용자 계정은 관리 작업을 수행하기 위해 클러스터에 액세스하는 관리자 또는 애플리케이션을 배포하기 위해 클러스터에 액세스하는 개발자 등을 위한 것입니다. 서비스 계정은 Kubernetes 클러스터와 상호 작용하기 위해 애플리케이션에서 사용하는 계정입니다. 예를 들어 Prometheus와 같은 모니터링 애플리케이션은 서비스 계정을 사용하여 성능 메트릭을 위해 Kubernetes API를 가져옵니다. Jenkins와 같은 자동화된 빌드 tool은 서비스 계정을 사용하여 Kubernetes 클러스터에 애플리케이션을 배포합니다.

예를 들어 보겠습니다. 저는 "My Kubernetes Dashboard"라는 간단한 Kubernetes 대시보드 애플리케이션을 구축했습니다. Python으로 구축된 간단한 애플리케이션이며 배포 시 Kubernetes API에 요청을 전송하여 Kubernetes 클러스터의 파드 목록을 검색하고 웹페이지에 표시하는 것이 전부입니다. 내 애플리케이션이 Kubernetes API를 쿼리하려면 인증을 받아야 합니다. 이를 위해 서비스 계정을 사용합니다.

서비스 계정을 생성하려면 kubectl create serviceaccount 커맨드를 실행한 다음 계정 이름(이 경우에는 dashboard-sa)을 입력합니다. kubectl에서 서비스 계정을 보려면 kubectl get serviceaccount 커맨드를 사용하세요. 그러면 모든 서비스 계정이 조회됩니다.

서비스 계정이 생성되면 토큰도 자동으로 생성됩니다. 서비스 계정 토큰은 Kubernetes API에 인증하는 동안 외부 애플리케이션에서 사용해야 하는 것입니다. 그러나 토큰은 secret 오브젝트로 저장됩니다. 지금은 dashboard-sa-token-kbbdm이라는 이름입니다.

따라서 서비스 계정을 만들 때 먼저 서비스 계정 오브젝트를 만든 다음, 서비스 계정에 대한 토큰을 생성합니다. 그런 다음 secret 오브젝트를 만들고 secret 오브젝트 내부에 해당 토큰을 저장합니다. 그리고 secret 오브젝트가 서비스 계정에 연결됩니다. 토큰을 보려면 kubectl describe secret 커맨드를 실행하여 secret 오브젝트를 봅니다.

이 토큰은 Kubernetes API에 대한 risk call을 수행하는 동안 인증 전달자 토큰authentication bearer token으로 사용할 수 있습니다.

예를 들어 curl을 사용하는 이 간단한 예에서 Kubernetes API에 대한 risk call을 수행하는 동안 bearer token을 인증 헤더로 제공할 수 있습니다. My Kubernetes Dashboard 애플리케이션의 경우엔 토큰을 복사하여 토큰 필드에 붙여넣어 대시보드 애플리케이션을 인증합니다.

이렇게 해서 새로운 서비스 계정을 생성하고 사용합니다. 서비스 계정을 생성하고, 롤 기반 액세스 제어 메커니즘을 사용하여 올바른 권한을 할당할 수 있지만, 이는 이 과정의 범위를 벗어납니다. 서비스 계정 토큰을 내보내고 이를 사용하여 Kubernetes API에 인증하도록 타사 애플리케이션을 구성할 수도 있습니다.

하지만 타사 애플리케이션이 Kubernetes 클러스터 자체에서 호스팅된다면 어떨까요? 예를 들어 Kubernetes 클러스터 자체에 배포된 My Kubernetes Dashboard 애플리케이션 또는 Prometheus 애플리케이션을 가질 수 있습니다. 이 경우 서비스 계정 토큰을 내보내고 이를 사용하도록 타사 애플리케이션을 구성하는 이 전체 프로세스는, 서비스 토큰 암호를 타사 애플리케이션을 호스팅하는 파드 내부의 볼륨으로 자동 마운트하여 간단하게 만들 수 있습니다.

이렇게 하면 Kubernetes API에 액세스하기 위한 토큰이 이미 파드 내부에 배치되어 애플리케이션에서 쉽게 읽을 수 있습니다. 수동으로 제공할 필요가 없습니다.

돌아가서 서비스 계정 목록을 보면 이미 존재하는 default 서비스 계정이 있음을 알 수 있습니다. Kubernetes의 모든 네임스페이스에 대해 default라는 서비스 계정이 자동으로 생성됩니다. 각 네임스페이스에는 고유한 default 서비스 계정이 있습니다. 파드가 생성될 때마다 default 서비스 계정과 해당 토큰이 볼륨 마운트로 해당 파드에 자동으로 마운트됩니다. 예를 들어 my-kubernetes-dashboard 이미지를 사용하여 파드를 생성하는 간단한 파드 definition 파일이 있습니다.

definition 파일에 secret 또는 볼륨 마운트를 지정하지 않았습니다. 그러나 파드가 생성되고, kubectl describe pod 커맨드를 실행하여 파드의 세부 정보를 보면 default 토큰이라는 시크릿에서 자동으로 볼륨이 생성되는 것을 볼 수 있습니다. secret 토큰은 var/run/secrets/kubernetes.io/serviceaccount 위치에 마운트됩니다. 따라서 Pod 내부에서 ls 커맨드를 실행하여 디렉토리의 콘텐츠를 조회하면 secret이 세 개의 개별 파일로 마운트된 것을 볼 수 있습니다.

실제 토큰이 있는 파일은 token이라는 파일입니다. 해당 파일의 내용을 보면 Kubernetes API에 액세스하는 데 사용되는 토큰이 표시됩니다.

이제 default 서비스 계정은 매우 제한적이라는 점을 기억하세요. default Kubernetes API 쿼리를 실행할 수 있는 권한만 있습니다. 방금 만든 것과 같은 다른 서비스 계정을 사용하려면 서비스 계정을 포함하도록 파드 definition 파일을 수정하고 새 서비스 계정의 이름을 지정합니다. 기존 파드의 서비스 계정은 편집할 수 없습니다. 파드를 삭제하고 다시 생성해야 합니다. 그러나 deployment의 경우 파드 definition 파일을 변경하면 배포에 대한 새 롤아웃이 자동으로 트리거되므로 서비스 계정을 사용할 수 있습니다. 따라서 배포는 올바른 서비스 계정으로 새 파드를 삭제하고 다시 생성하는 작업을 처리합니다. 

이제 Pod 세부 정보를 보면 새 서비스 계정이 사용되고 있음을 알 수 있습니다.

명시적으로 지정하지 않은 경우 Kubernetes는 자동으로 default 서비스 계정을 마운트합니다. pod의 spec섹션에서 자동 마운트 서비스 계정 토큰 필드를 false로 설정하여 서비스 계정을 자동으로 마운트하지 않도록 선택할 수 있습니다.

이제 릴리스 버전 1.22와 1.24에서 변경된 서비스 계정, 암호 및 토큰의 작동 방식의 몇 가지 사항에 대해 설명하겠습니다. 이전에 설명한 것처럼 모든 네임스페이스에는 default 서비스 계정이 있고 해당 서비스 계정에는 연결된 토큰이 있는 secret 오브젝트가 있습니다. 파드가 생성되면 자동으로 서비스 계정을 파드에 연결하고 토큰을 파드 내의 잘 알려진 위치에 마운트합니다. 이 경우 var/run/secrets/kubernetes.io/serviceaccount 아래에 있습니다. 이렇게 하면 파드 내에서 실행되고 해당 프로세스가 Kubernetes API를 쿼리할 수 있도록 하는 프로세스에 토큰에 액세스할 수 있습니다.

이제 파드 내부 디렉토리의 컨텐츠를 나열하면 세 개의 별도 파일로 마운트된 시크릿을 볼 수 있습니다. 실제 토큰이 있는 파일은 token이라는 파일입니다. 따라서 해당 파일의 내용을 조회하면 Kubernetes API에 액세스하는 데 사용되는 토큰이 표시됩니다. 이 내용은 동일하게 전에 논의한 내용입니다.

이제 방금 본 토큰을 가지고 아래 커맨드를 사용하여 이 토큰을 디코딩하거나,

jwt.io라는 JWT 웹 사이트에 이 토큰을 복사하여 붙여넣을 수 있습니다. 여기 오른쪽의 페이로드 섹션에 정의된 만료 날짜가 없음을 알 수 있습니다. 따라서 만료 날짜가 설정되지 않은 토큰입니다.

따라서 bound서비스 계정 토큰을 생성하기 위한 Kubernetes 개선 제안에서 발췌한 아래 내용 부분은 이러한 형태의 JWT에 일부 보안 및 확장성 관련 문제가 있다고 설명합니다.

따라서 JWT의 현재 구현은 어떤 청중에게도 제한되지 않으며 시간 제한도 없습니다. 방금 본 것처럼 토큰에는 만료 날짜가 없습니다. 따라서 JWT는 서비스 계정이 존재하는 한 유효합니다. 또한 각 JWT에는 서비스 계정별로 별도의 secret 오브젝트가 필요하므로 확장성 문제가 발생합니다. 마찬가지로 버전 1.22에서 토큰 요청 API는 API를 통해 보다 안전하고 확장 가능한 Kubernetes 서비스 계정 토큰을 프로비저닝하기 위한 메커니즘을 도입하는 것을 목표로 하는 Kubernetes 개선 제안 1205의 일부로 도입되었습니다. 따라서 토큰 요청 API에 의해 생성된 토큰은 대상 제한, 시간 제한 및 오브젝트 제한이므로 더 안전합니다. 이제 버전 1.22부터 새 파드가 생성되면 더 이상 서비스 계정(방금 본 secret 토큰)에 의존하지 않습니다. 대신 파드가 생성될 때 serviceaccount admission controllerㅡ에서 토큰 요청 API를 통해 lifetime이 정의된 토큰이 생성됩니다. 그런 다음 이 토큰은 파드에 프로젝션된 볼륨으로 마운트됩니다.

그래서 예전에는 여기 이 공간을 보면 서비스 계정의 일부인 secret이 secret 오브젝트로 마운트되는 것으로 보였지만 지금은 보시다시피 토큰 컨트롤러 API와 실제로 통신하는 프로젝션된 볼륨입니다. 토큰 요청 API 및 파드에 대한 토큰을 가져옵니다.

이제 버전 1.24를 살펴봅시다. 쿠버네티스 개선 제안 2799의 일부로 보안 기반 서비스 계정 토큰의 감소를 다루는 또 다른 개선이 이루어졌습니다. 과거에는 서비스 계정이 생성될 때 만료가 없고 대상에 구속되지 않는 토큰으로 secret을 자동으로 생성했습니다. 그런 다음 해당 서비스 계정을 사용하는 모든 파드에 볼륨으로 자동 마운트되었으며 이것이 방금 본 것입니다. 하지만 버전 1. 22에서 변경된 대로 파드에 대한 secret 오브젝트의 자동 마운트가 변경되었으며 대신 토큰 요청 API로 이동되었습니다. 버전 1. 24부터는 서비스 계정을 생성할 때 더 이상 secret 또는 토큰을 secret로 자동 생성하지 않도록 변경되었습니다. 따라서 필요한 경우 해당 서비스 계정에 대한 토큰을 생성하기 위해 kubectl create token 커맨드 다음에 서비스 계정의 이름을 실행해야 합니다. 그러면 해당 토큰이 화면에 인쇄됩니다.

이제 해당 토큰을 복사한 다음 이 토큰을 디코딩하려고 하면 이번에는 만료 날짜가 정의되어 있음을 알 수 있습니다. 그리고 시간 제한을 지정하지 않은 경우 일반적으로 커맨드를 실행한 시간부터 1시간입니다. 커맨드에 추가 옵션을 전달하여 토큰 만료를 늘릴 수도 있습니다.

이제 버전 1.24에서 만료되지 않는 토큰을 사용하여 이전 방식으로 secret을 생성하려는 경우, 유형이 kubernetes.io/service-account-token으로 설정된 secret 오브젝트를 생성하여 계속 수행할 수 있습니다. 다음과 같이 메타데이터 섹션의 annotations 내에 지정된 이름이 서비스 계정의 이름입니다.

이것이 secret 오브젝트가 해당 특정 서비스 계정과 연결되는 방식입니다. 따라서 이 작업을 수행할 때 먼저 서비스 계정을 생성했는지 확인한 다음 secret 오브젝트를 생성하세요. 그렇지 않으면 secret 오브젝트가 생성되지 않습니다. 따라서 이것은 secret 오브젝트에 만료되지 않는 토큰을 생성하고 해당 서비스 계정과 연결합니다.

서비스 계정 토큰 secret에 대한 Kubernetes 공식문서에서는 정말로 그렇게 하고 싶은지 확인해야 한다고 말합니다. 토큰을 얻기 위해 토큰 요청 API를 사용할 수 없는 경우에만 서비스 계정 토큰 secret을 생성해야 한다고 말합니다. 그래서 그것은 우리가 방금 이야기한 kubectl create token 커맨드를 실행하거나, 해당 토큰을 생성하기 위해 토큰 요청 API와 통신하거나, 버전 1.22 이후 파드에서 발생하는 자동화된 토큰 생성입니다. 또한 non-expiring token credential을 유지하는 보안 노출이 허용되는 경우에만 서비스 계정 토큰 요청을 생성해야 합니다. 서비스 계정 토큰 secret 오브젝트를 사용하는 대신 토큰 요청 API를 사용하는 것이 좋습니다. 만료가 없는 서비스 계정 토큰 secret과 달리 더 안전하고 라이프타임이 제한되어 있기 때문입니다.

이러한 변경 사항에 대해 자세히 알아보려면 여기에 나열된 Kubernetes 개선 제안과 서비스 계정 및 암호에 대한 설명서 페이지를 참조하세요. 

 

반응형

댓글