Service Account
쿠버네티스를 공부하면서 가장 어렵게 느꼈던 부분 중 하나는 보안과 계정 관리였습니다.
실제로 쿠버네티스 보안 전문 자격인 CKS(Certified Kubernetes Security Specialist)가 별도의 자격으로 운영될 만큼, 쿠버네티스의 보안 영역은 높은 수준의 이해와 실무 역량을 요구합니다.
특히 ServiceAccount, RBAC, 인증(Authentication)과 인가(Authorization) 등 여러 개념이 서로 유기적으로 연결되어 있어, 처음 접할 때는 전체 구조를 이해하기가 쉽지 않습니다.
[root@ocp-bastion ~]# cat /etc/group
root:x:0:ocp-dev,exemone
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:
mem:x:8:
kmem:x:9:
wheel:x:10:exemone
cdrom:x:11:
[root@ocp-bastion ~]# cat /etc/passwd clear
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
흔히 시스템 인프라 엔지니어들은 서버 시스템의 계정 관리 방식에 익숙합니다. 오랫동안 사용자 계정을 생성하고, 각 계정에 필요한 권한을 부여하는 전통적인 계정 / 인증 / 인가 체계를 기반으로 시스템을 관리해왔습니다.
쿠버네티스 역시 기본적인 보안 원리는 비슷하지만, 계정과 권한을 보다 세분화하여 관리합니다. 특히 쿠버네티스에서는 사용 주체를 User와 ServiceAccount로 구분하고, 인증(Authentication)과 인가(Authorization)를 분리하여 관리합니다. 또한 RBAC을 통해 각 계정이 어떤 리소스에 어떤 작업을 수행할 수 있는지를 세밀하게 제어합니다.

Linux에서는 어떤 프로세스가 실행될 때 반드시 특정 사용자 권한으로 동작합니다.
사용자 계정이 있고, 각 프로세스는 특정 UID/GID를 기반으로 파일이나 프로세스에 접근할 수 있는 권한을 가집니다.
Kubernetes에서도 이와 유사한 계정과 권한 관리 개념이 필요합니다. 다만 Kubernetes에서는 Pod가 단순히 Linux의 파일이나 디렉터리에 접근하는 것을 넘어, Kubernetes API Server에 접근하여 다양한 리소스를 조회하거나 제어해야 하는 경우가 있습니다.
이때 Pod는 API Server에 "나는 누구인가"를 증명할 신원이 필요합니다. 그리고 Pod와 같은 애플리케이션에 이러한 신원을 부여하기 위해 사용하는 것이 바로 ServiceAccount입니다.
사실 이렇게 이야기하면 이해하기가 쉽지가 않습니다. 실무적으로 찾아가보겠습니다.
[root@ocp-bastion ~]# kubectl get po -A
NAMESPACE NAME
chaos-demo backend-was-5457bdb96b-zlkfs
chaos-demo kafka-5f7955f857-vmsw6
chaos-demo mysql-5b59db698b-cw2kt
chaos-demo oracle-54d4885cb6-jgmsv
chaos-demo postgres-85d4dbbc88-7p6br
겉으로 보면 root 사용자가 Kubernetes의 Pod 정보를 조회한 것처럼 보입니다. 하지만 Kubernetes API Server는 일반적으로
"이 명령어를 Linux의 root가 실행했는가?"를 기준으로 권한을 판단하지 않습니다.
kubectl은 단순히 Kubernetes API Server에 요청을 전달하는 클라이언트입니다. 실제로 API Server가 확인하는 것은 kubectl이 요청할 때 함께 전달한 Kubernetes 인증 정보입니다.
kubectl은 일반적으로 kubeconfig 파일에 설정되어 있는 인증 정보를 사용합니다.
[root@ocp-bastion ~]# kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.0.10:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
namespace: default
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://192.168.0.10:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
namespace: default
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
위 결과를 보면 Linux의 root 계정으로 kubectl을 실행하더라도, 실제 Kubernetes API Server 인증에는 kubeconfig에 설정된 kubernetes-admin 사용자 정보가 사용되는 것을 확인할 수 있습니다. 즉, Linux 사용자 계정과 Kubernetes의 인증 주체는 서로 별개의 개념입니다.
해당 설정 정보는
Client
Certificate
Token OIDC 인증 정보
Exec Plugin을 통한 인증 정보를 담고 있습니다.

Linux의 root 계정에서 별도의 설정이 없다면 일반적으로 다음과 같은 경로의 kubeconfig를 사용할 수 있으며, 별도의 설정이 없다면 /root/.kube/config 경로 내에 실제 데이터를 적재하게 됩니다.
리눅스 시스템 엔지니어는 서버에 접속한 뒤, 작업을 수행하기 전에 현재 어떤 사용자 계정으로 로그인되어 있는지 확인하는 경우가 많습니다. 일반적으로 id 또는 whoami 명령어를 사용하여 현재 로그인한 사용자와 UID/GID, 소속 그룹 등의 계정 정보를 확인합니다.
Kubernetes에서도 이와 유사하게 현재 어떤 인증 주체와 컨텍스트를 기준으로 클러스터에 접근하고 있는지 확인하는 과정이 필요합니다. 다만 Kubernetes에서는 Linux 계정과 달리 kubectl이 사용하는 kubeconfig의 Context와 인증 정보를 기준으로 API Server에 접근합니다.
kubectl config current-context
kubectl config view --minify
kubectl auth whoami
Default Service Account
Pod에 serviceAccountName을 명시적으로 지정하지 않더라도 Pod는 정상적으로 생성되고 실행됩니다.
그 이유는 Kubernetes가 각 Namespace에 default라는 이름의 ServiceAccount를 기본으로 생성하며, 별도의 ServiceAccount가 지정되지 않은 Pod에는 해당 Namespace의 default ServiceAccount가 자동으로 할당되기 때문입니다.
Pod를 생성하면
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
containers:
- name: test
image: nginx
실제로는 다음과 같은 ServiceAccount를 사용하게 됩니다.
serviceAccountName: default
kubectl get pod test -o yaml
kubectl get pod test \
-o jsonpath='{.spec.serviceAccountName}'
default
운영 환경에서는 워크로드별로 별도의 ServiceAccount를 만들어 사용하는 것이 일반적으로 더 안전합니다.
아! 그렇다면 여기서 한 가지 중요한 점을 알 수 있습니다.
Kubernetes에서 접근에 대한 인증 / 인가 및 권한 판단은 Linux 시스템의 사용자 권한을 기준으로 하는 것이 아니라, Kubernetes API Server에 전달된 요청의 인증 주체와 해당 주체에 부여된 권한을 기준으로 이루어진다는 것입니다.
실무에서는 어떻게 쓰지?
앞서 살펴본 것처럼 Kubernetes에서 Pod가 API Server에 접근하려면 자신이 누구인지 증명할 수 있는 인증 정보가 필요합니다. 이때 Pod에 할당된 ServiceAccount의 토큰이 인증 수단으로 사용될 수 있습니다.
그런데 여기서 실무적으로 중요한 문제가 하나 있습니다.
"모든 Pod가 Kubernetes API Server에 접근해야 하는 것은 아닙니다."
예를 들어 Nginx가 단순히 웹 요청을 처리하거나, PostgreSQL이 데이터베이스 역할만 수행한다면 해당 애플리케이션이 Kubernetes API를 직접 호출할 이유가 없는 경우가 대부분입니다. 그럼에도 기본 설정에서는 Pod에 ServiceAccount가 할당되고, ServiceAccount의 인증 정보가 Pod 내부에 자동으로 제공될 수 있습니다.
automountServiceAccountToken: false
일반적으로 ServiceAccount 토큰이 자동 마운트된 Pod에서는 /var/run/secrets/kubernetes.io/serviceaccount/ 경로를 통해 관련 인증 정보를 확인할 수 있습니다.
내부에는 다음과 같은 파일이 존재합니다.
ca.crt
namespace
token
특히 token은 Pod가 Kubernetes API Server에 자신을 인증할 때 사용할 수 있는 중요한 인증 정보입니다.

만약 애플리케이션에 취약점이 존재해 공격자가 컨테이너 내부에서 임의의 명령을 실행할 수 있게 되었다고 가정해보겠습니다. Pod 내부에 ServiceAccount 토큰이 존재한다면 공격자는 해당 토큰을 획득하여 Kubernetes API Server에 요청을 시도할 수 있습니다.
물론 토큰을 가지고 있다고 해서 무조건 모든 Kubernetes 리소스에 접근할 수 있는 것은 아닙니다. 실제로 수행할 수 있는 작업은 해당 ServiceAccount에 부여된 RBAC 권한에 의해 제한됩니다.
하지만 보안 관점에서는 애초에 Kubernetes API를 사용할 필요가 없는 Pod에 API 인증정보를 제공하지 않는 것이 더 안전합니다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
serviceAccountName: nginx-sa
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx:latest
nginx-sa라는 파드를 생성하고, serviceaccount nginx-sa를 바인딩 하였습니다.
automount 옵션은 비활성화 하였습니다.
그렇다면 API Server에 접근해야 하는 Pod는?
여기서부터 실무적인 판단이 필요합니다.
예를 들어 Kubernetes 모니터링 Agent나 Operator, Controller처럼 다음과 같은 Kubernetes 리소스를 지속적으로 조회해야 하는 애플리케이션이 있다고 가정해보겠습니다.
Pods
Nodes
Namespaces
Deployments
DaemonSets
StatefulSets
Events
...
이러한 애플리케이션은 Kubernetes API Server와 통신해야 하므로 인증정보가 필요합니다.
단순하게 다음 설정만 적용하면, 기존에 자동 마운트된 ServiceAccount Token을 이용하던 애플리케이션은 API Server에 인증하지 못하면서 기존 수집 기능이 동작하지 않을 수 있습니다.
실제 현장에서는 보안 담당자가 Kubernetes의 내부 구조와 동작 원리까지 모두 깊이 이해하고 관리하기는 쉽지 않습니다. 많은 경우 상위 기관이나 보안 가이드라인에서 제시하는 보안 기준과 점검 항목을 바탕으로 설정을 확인하고, 미흡한 항목에 대해 조치를 요청하는 방식으로 관리가 이루어집니다.
automount 설정이 false인데 API 인증이 필요할 수 있습니다.
spec:
serviceAccountName: k8s-agent
automountServiceAccountToken: false
containers:
- name: k8s-agent
volumeMounts:
- name: kube-api-token
mountPath: /var/run/secrets/exem-k8s-agent
readOnly: true
volumes:
- name: kube-api-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
그럴 땐 필요한 ServiceAccount Token을 Projected Volume으로 명시적으로 제공하는 방식을 고려할 수 있습니다.
이렇게 하면 Kubernetes가 기본 ServiceAccount 인증정보를 자동으로 마운트하도록 두는 대신, API 접근이 필요한 워크로드에 필요한 토큰을 명시적으로 제공하는 구조를 구성할 수 있습니다.
다만 기존 애플리케이션이 기본 ServiceAccount 경로를 이용하는 in-cluster 인증 방식을 사용하고 있다면, 토큰의 마운트 위치나 CA 정보 등 애플리케이션의 인증 방식까지 함께 검토해야 합니다. 따라서 단순히 YAML 한 줄을 true → false로 변경하는 문제로 접근해서는 안 됩니다.
저는 인프라 엔지니어이지만, 정보보안기사 자격을 취득할 만큼 보안 분야에도 꾸준히 관심을 가지고 있습니다. Kubernetes의 보안 구조를 공부하다 보면 단순히 기술적인 개념을 이해하는 것을 넘어, "보안팀에서는 이러한 요소들을 어떤 관점에서 바라보고 관리할까?"라는 생각을 하게 되기도 합니다.
다음 장에서는 Kubernetes 권한 관리의 핵심인 RBAC(Role-Based Access Control)을 살펴보고, 보안의 기본 원칙인 최소 권한을 어떻게 구성하고 관리하는지 알아보도록 하겠습니다.
'쿠버네티스' 카테고리의 다른 글
| 쿠버네티스 StorageClass란?|Dynamic Provisioning과 동적 PV 생성 원리 (0) | 2026.08.18 |
|---|---|
| 쿠버네티스 PV·PVC란?|Volume과 PersistentVolume 차이 쉽게 이해하기 (0) | 2026.08.14 |
| Kubernetes Gateway API란?|Ingress와 차이·Gateway·HTTPRoute 구조 (0) | 2026.08.03 |
| 쿠버네티스 LoadBalancer Service란?|외부 IP와 트래픽 유입 원리 (0) | 2026.08.03 |
| 쿠버네티스 Ingress Controller란?|Ingress와 Controller 역할·구현체 비교 (0) | 2026.08.03 |