Chapter 10

보안: ServiceAccount와 RBAC

  • 10.1 쿠버네티스의 권한 인증 체계
  • 10.2 ServiceAccount
  • 10.3 롤과 클러스터 롤 (RBAC)
  • 10.4 kubeconfig 파일
  • 10.5 x509 인증서 인증

누가 어떤 리소스에 접근할 수 있는지를 제어하지 않으면 프로덕션 환경에서 사고가 터져. 쿠버네티스는 이를 위해 ServiceAccount, RBAC, 인증서 기반 인증 같은 메커니즘을 제공해.

쿠버네티스 API 서버에 요청을 보내면 세 단계를 거쳐:

  1. 인증(Authentication): "너 누구야?" — 요청자의 신원을 확인
  2. 인가(Authorization): "너 이거 할 수 있어?" — 해당 작업을 수행할 권한이 있는지 확인
  3. 어드미션 컨트롤(Admission Control): "이 요청 내용이 정책에 맞아?" — 요청의 내용을 검증하고 변경

인증 방법은 여러 가지야:

  • x509 클라이언트 인증서: kubeconfig에서 가장 흔히 쓰는 방식
  • Bearer Token: ServiceAccount의 토큰
  • OIDC(OpenID Connect): 외부 인증 서비스(Google, GitHub 등) 연동
  • Webhook Token: 외부 서비스에 인증을 위임

인가 방법 중 현재 표준은 **RBAC(Role-Based Access Control)**이야. "이 사용자는 이 역할을 가지고 있고, 이 역할은 이런 권한이 있다"를 정의하는 방식이지.

ServiceAccount는 파드가 API 서버에 접근할 때 사용하는 계정이야. 사람이 아닌 **프로세스(파드)**를 위한 계정이라고 보면 돼. 모든 네임스페이스에는 default ServiceAccount가 자동으로 생성되고, 별도 설정 없이 파드를 만들면 이 default ServiceAccount가 할당돼.

kubectl create serviceaccount my-sa
kubectl get serviceaccounts
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: default

파드에 ServiceAccount를 지정할 때:

spec:
  serviceAccountName: my-sa
  containers:
    - name: app
      image: my-app

파드 안에서 ServiceAccount의 토큰은 /var/run/secrets/kubernetes.io/serviceaccount/ 경로에 자동으로 마운트돼. 이 토큰으로 API 서버에 인증할 수 있어. 쿠버네티스 1.24부터는 ServiceAccount에 자동으로 시크릿(토큰)이 생성되지 않아. 대신 TokenRequest API를 통해 시간 제한이 있는 토큰이 자동 발급되고 파드에 주입되는데, 보안이 더 강화된 거지.

RBAC는 네 가지 오브젝트로 구성돼:

  • Role: 특정 네임스페이스 내에서의 권한을 정의
  • ClusterRole: 클러스터 전체 범위의 권한을 정의
  • RoleBinding: Role을 사용자/ServiceAccount에 연결
  • ClusterRoleBinding: ClusterRole을 사용자/ServiceAccount에 연결
# 특정 네임스페이스에서 파드를 읽을 수 있는 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
# Role을 ServiceAccount에 연결
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: dev
subjects:
  - kind: ServiceAccount
    name: my-sa
    namespace: dev
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Role은 네임스페이스 범위야. 해당 네임스페이스 내의 리소스에만 적용돼. ClusterRole은 클러스터 범위라서 네임스페이스에 속하지 않는 리소스(노드, PV 등)나 모든 네임스페이스의 리소스에 접근할 때 사용하지.

# 클러스터 전체에서 노드 정보를 읽을 수 있는 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list"]

verbs에 사용할 수 있는 값들은 get, list, watch, create, update, patch, delete이고, *를 쓰면 모든 동작을 허용해.

실무에서는 **최소 권한 원칙(Principle of Least Privilege)**을 따라야 해. 필요한 리소스에 필요한 동작만 허용하는 Role을 만들어서 부여하는 거지. cluster-admin 같은 전체 관리자 권한을 남발하면 보안 사고의 원인이 돼.

kubectl이 어떤 클러스터에 어떤 사용자로 접근할지를 정의하는 설정 파일이 kubeconfig야. 기본 경로는 ~/.kube/config이고, 세 가지 요소로 구성돼:

  • clusters: 접근할 쿠버네티스 클러스터 정보 (API 서버 주소, CA 인증서)
  • users: 인증 정보 (클라이언트 인증서, 토큰 등)
  • contexts: cluster + user + namespace의 조합. "이 클러스터에 이 사용자로 이 네임스페이스에서 작업하겠다"는 설정
apiVersion: v1
kind: Config
clusters:
  - cluster:
      server: https://192.168.1.100:6443
      certificate-authority-data: LS0tLS1...
    name: my-cluster
users:
  - name: admin
    user:
      client-certificate-data: LS0tLS1...
      client-key-data: LS0tLS1...
contexts:
  - context:
      cluster: my-cluster
      user: admin
      namespace: default
    name: my-context
current-context: my-context
kubectl config get-contexts          # 컨텍스트 목록
kubectl config use-context my-context  # 컨텍스트 전환
kubectl config current-context       # 현재 컨텍스트 확인

여러 클러스터를 관리할 때 컨텍스트 전환으로 간편하게 오갈 수 있어. kubectx 같은 도구를 쓰면 더 편하지.

쿠버네티스에서 가장 기본적인 사용자 인증 방식은 x509 클라이언트 인증서야. kubeadm으로 클러스터를 설치하면 자동으로 CA(Certificate Authority)가 생성되고, 이 CA로 서명된 인증서를 가진 사용자만 API 서버에 접근할 수 있어.

새로운 사용자를 추가하는 흐름은 이래:

  1. 개인 키 생성: openssl genrsa -out user.key 2048
  2. CSR(Certificate Signing Request) 생성: openssl req -new -key user.key -out user.csr -subj "/CN=username/O=groupname"
  3. 쿠버네티스 CSR 오브젝트 생성: CSR을 base64 인코딩해서 쿠버네티스에 제출
  4. CSR 승인: kubectl certificate approve user-csr
  5. 인증서 추출: 승인된 인증서를 kubeconfig에 등록

CSR의 **CN(Common Name)**이 사용자 이름이 되고, **O(Organization)**가 그룹이 돼. RoleBinding에서 이 이름이나 그룹에 Role을 바인딩하면 되지.

이 과정이 꽤 번거로운데, 대규모 조직에서는 OIDC 연동으로 기존 인증 시스템(LDAP, Google Workspace 등)과 통합하는 게 더 현실적이야.


정리

10장 읽고 기억할 거 세 가지:

  1. API 서버 접근은 인증 → 인가 → 어드미션 컨트롤 순서로 처리된다. RBAC가 인가의 표준.
  2. ServiceAccount는 파드용 계정이고, Role/ClusterRole로 권한을 부여한다. 최소 권한 원칙을 지켜서 필요한 권한만 부여해야 함.
  3. kubeconfig로 클러스터/사용자/네임스페이스 조합을 관리한다. 여러 클러스터를 오갈 때 컨텍스트 전환을 사용.