콘텐츠로 이동
Study NoteCKA

ServiceAccount — Pod의 신원

결론부터
ServiceAccount는 Pod 안의 프로그램이 Kubernetes API를 호출할 때 사용하는 신원이며, 권한은 RBAC으로 따로 부여한다.

Pod 안의 프로그램도 클러스터 정보를 읽거나 변경해야 할 때가 있다. 이 페이지에서는 프로그램에 신원을 연결하고, 토큰을 전달하며, 필요한 권한을 확인하는 과정을 살펴본다.

왜 프로그램에도 계정이 필요한가

섹션 제목: “왜 프로그램에도 계정이 필요한가”

Ingress 컨트롤러는 Ingress를 읽고, 배포 자동화 프로그램은 Deployment를 변경한다. API 서버는 이런 요청도 누가 보냈는지 알아야 권한을 판단할 수 있다. ServiceAccount는 이때 사용하는 워크로드의 계정이다. 약어는 SA이며, 네임스페이스에 속하는 Kubernetes 오브젝트다.

Pod을 다시 만들어도 같은 ServiceAccount를 지정하면 같은 신원으로 요청할 수 있다. 여러 Pod이 하나의 ServiceAccount를 공유할 수도 있다. ServiceAccount는 Pod 자체도, 권한 목록도 아니다.

구성 요소역할
ServiceAccount프로그램이 사용할 신원
Pod의 serviceAccountName이 Pod이 사용할 ServiceAccount 선택
토큰API 요청 때 그 신원을 증명하는 자격증명
RBAC그 신원에 허용할 작업 정의

아래 예제는 sa-demo 네임스페이스에서 진행한다. 먼저 계정을 만든다.

터미널 창
kubectl create namespace sa-demo
kubectl create serviceaccount deploy-bot -n sa-demo
kubectl get serviceaccounts -n sa-demo

다음을 sa-pod.yaml로 저장한다. Pod과 ServiceAccount는 같은 네임스페이스에 있어야 한다.

apiVersion: v1
kind: Pod
metadata:
name: api-client
namespace: sa-demo
spec:
serviceAccountName: deploy-bot
containers:
- name: app
image: busybox:1.37
command: ["sleep", "3600"]
터미널 창
kubectl apply -f sa-pod.yaml
kubectl get pod api-client -n sa-demo -o jsonpath='{.spec.serviceAccountName}'
# deploy-bot

이 예제의 컨테이너는 연결된 신원과 파일을 관찰하기 위해 대기한다. ServiceAccount를 붙였다고 프로그램이 자동으로 API를 호출하는 것은 아니다.

지정하지 않으면 default를 사용한다

섹션 제목: “지정하지 않으면 default를 사용한다”

각 네임스페이스에는 default ServiceAccount가 자동으로 만들어진다. Pod에서 serviceAccountName을 생략하면 **그 Pod의 네임스페이스에 있는 default**를 사용한다. 다른 네임스페이스의 같은 이름 계정은 별개의 신원이다.

앱마다 ServiceAccount를 따로 만들면 앱별로 권한을 부여하고 확인하기 쉽다. default에는 기본적으로 API 검색 등을 제외한 일반 작업 권한이 없지만, 관리자가 추가로 권한을 연결했는지는 확인해야 한다.

토큰은 어떻게 Pod에 들어오는가

섹션 제목: “토큰은 어떻게 Pod에 들어오는가”

기본 설정에서는 Kubernetes가 API 서버용 토큰과 CA 인증서, 네임스페이스 정보를 Pod의 projected 볼륨에 넣는다. projected 볼륨은 여러 출처의 데이터를 한 디렉터리에 모으는 방식이다. 토큰은 TokenRequest API로 발급되며, kubelet이 만료 전에 갱신한다. 공식 Pod 설정 문서에서 자동 마운트와 토큰 갱신 동작을 확인할 수 있다.

ServiceAccount 토큰이 projected 볼륨으로 Pod에 마운트되고 kubelet이 갱신하는 구조
터미널 창
kubectl exec api-client -n sa-demo -- ls /var/run/secrets/kubernetes.io/serviceaccount/
# ca.crt namespace token

token은 요청의 Authorization: Bearer <토큰> 헤더에 사용한다. ca.crt는 접속하는 API 서버 인증서의 검증에, namespace는 현재 네임스페이스 확인에 쓴다. Kubernetes 클라이언트 라이브러리는 이 파일들을 읽어 클러스터 내부 접속을 구성할 수 있다.

API를 쓰지 않으면 토큰 자동 마운트 끄기

섹션 제목: “API를 쓰지 않으면 토큰 자동 마운트 끄기”

일반 웹 앱처럼 Kubernetes API를 호출하지 않는 프로그램에는 토큰이 필요하지 않을 수 있다. 그런 Pod은 생성할 때 다음 필드를 넣는다. 앞 예제와 달리 토큰 파일을 자동으로 넣지 않는 설정이다.

spec:
serviceAccountName: deploy-bot
automountServiceAccountToken: false

ServiceAccount 선택과 토큰 마운트 여부는 별개다. 이 설정을 해도 Pod의 ServiceAccount는 deploy-bot이다. ServiceAccount에도 자동 마운트 설정을 둘 수 있으며, 둘 다 지정하면 Pod 설정이 우선한다.

API 서버가 이 계정을 인식하는 이름은 다음과 같다.

system:serviceaccount:sa-demo:deploy-bot
↑namespace ↑name

ServiceAccount 생성만으로 Pod 목록을 읽는 권한이 생기지는 않는다. 아래 명령은 sa-demo의 Pod 조회 권한을 정의하고, 그 권한을 deploy-bot에 연결한다. 명령은 Role과 RoleBinding을 만들고 해당 권한을 부여할 수 있는 관리자 context에서 실행한다.

터미널 창
kubectl create role pod-reader -n sa-demo --verb=get,list,watch --resource=pods
kubectl create rolebinding deploy-bot-reader -n sa-demo \
--role=pod-reader --serviceaccount=sa-demo:deploy-bot
kubectl auth can-i list pods -n sa-demo \
--as=system:serviceaccount:sa-demo:deploy-bot
# yes
kubectl auth can-i delete pods -n sa-demo \
--as=system:serviceaccount:sa-demo:deploy-bot
# no (별도 삭제 권한을 부여하지 않은 경우)

--as는 관리자가 그 신원으로 인가 결과를 확인하는 기능이며, impersonation 권한이 필요하다. Pod 안의 토큰으로 실제 로그인하거나 프로그램의 API 호출을 시험하는 명령은 아니다. Role·RoleBinding의 범위와 YAML은 RBAC에서 이어서 본다.

Pod 밖에서 일시적으로 이 신원을 사용해야 한다면 수명 있는 토큰을 요청할 수 있다.

터미널 창
kubectl create token deploy-bot -n sa-demo --duration=1h

--duration은 요청 수명이며 실제 수명은 서버 정책에 따라 달라질 수 있다. 이 명령으로 받은 토큰은 터미널에 출력되는 자격증명이므로 로그나 저장소에 남기지 않는다. 직접 발급해 복사한 토큰은 Pod의 마운트 토큰처럼 kubelet이 자동으로 갈아 끼워 주지 않는다.

  • ServiceAccount는 프로그램의 신원이고, serviceAccountName으로 Pod에 연결한다.
  • 생략하면 같은 네임스페이스의 default를 사용한다.
  • 자동 마운트되는 토큰은 수명이 있으며 kubelet이 갱신한다.
  • API를 쓰지 않는 Pod은 automountServiceAccountToken: false로 자동 마운트를 끌 수 있다.
  • 작업 권한은 RBAC으로 따로 연결하고 auth can-i로 확인한다.

실습을 마치면 이 예제에서 만든 네임스페이스를 삭제해 리소스를 정리한다.

터미널 창
kubectl delete namespace sa-demo