본문으로 건너뛰기

CKAD 개념 노트: ServiceAccount, 접근 제어, SecurityContext

  • kubernetes
  • ckad
  • rbac
  • serviceaccount
  • securitycontext
  • security

기준: Kubernetes v1.35 (kind kindest/node:v1.35.8에서 명령어·YAML 확인)

목차

요청 흐름

kubectl / Pod
   │  (client certificate, bearer token ...)
   ▼
[1] Authentication   실패 → 401 Unauthorized
   ▼
[2] Authorization    실패 → 403 Forbidden
   ▼
[3] Admission        mutating → validating, 하나라도 거부하면 요청 전체 거부
   ▼
etcd에 저장

Authentication: 누구인가

  • 사용자 종류 두 가지
    • normal user: Kubernetes 밖에서 관리. API로 User 객체를 만들 수 없음
    • ServiceAccount: Kubernetes API가 관리, namespace에 속함
  • 방식: client certificate, bearer token, authenticating proxy 등 authentication plugin
  • 결과로 요청에 붙는 속성: username, UID, groups, extra
  • ServiceAccount의 username: system:serviceaccount:<namespace>:<name>
    • groups: system:serviceaccounts, system:serviceaccounts:<namespace>
  • 어떤 방식으로도 거부되지 않은 요청은 (anonymous 허용 시) system:anonymous / system:unauthenticated로 처리
  • 잘못된 bearer token → 401 Unauthorized

Authorization: 해도 되는가

  • 확인 속성: user, group, verb, resource, subresource, namespace, API group 등
  • HTTP method → verb 대응
HTTPverb
POSTcreate
GET, HEADget (단일), list (컬렉션), watch
PUTupdate
PATCHpatch
DELETEdelete (단일), deletecollection (컬렉션)
  • mode: Node, RBAC, ABAC, Webhook, AlwaysAllow, AlwaysDeny
  • 여러 authorizer가 있으면 순서대로 물어보고, 처음 allow/deny를 낸 쪽이 결정. 전부 “의견 없음”이면 거부
  • 기본은 deny. 허용 규칙만 있고 거부 규칙은 RBAC에 없음
  • 거부 → 403 Forbidden

Admission: 받아들여도 되는가

  • authentication·authorization을 통과한 뒤, 저장 직전에 요청을 가로채는 kube-apiserver 내장 코드
  • 두 단계: mutating(객체 수정 가능) → validating(검사만)
  • 읽기 요청(get, list, watch)은 admission을 거치지 않음
  • 켜고 끄기: kube-apiserver --enable-admission-plugins=... / --disable-admission-plugins=...
  • v1.35 기본 활성 목록 중 CKAD와 닿는 것
plugin역할
NamespaceLifecycle삭제 중이거나 없는 namespace에 객체 생성 막음
LimitRangerLimitRange 적용 (기본 requests/limits 주입, 범위 검사)
ResourceQuotanamespace 단위 총량 제한
ServiceAccountPod에 ServiceAccount·token 자동 설정
PodSecurityPod Security Standards 적용
  • “생성은 되는데 Pod가 안 뜬다”가 아니라 “생성 자체가 거부된다”면 admission 단계에서 막혔을 가능성

RBAC

API group rbac.authorization.k8s.io/v1, 객체 4종.

객체범위내용
Rolenamespace한 namespace 안의 권한 규칙
ClusterRole클러스터클러스터 범위 리소스 권한, 또는 여러 namespace에 재사용할 규칙
RoleBindingnamespaceRole 또는 ClusterRole을 subject에 연결. 효과는 그 namespace 안으로 한정
ClusterRoleBinding클러스터ClusterRole을 클러스터 전체에 연결
  • subject 종류: User, Group, ServiceAccount
  • 바인딩을 만든 뒤에는 roleRef를 바꿀 수 없음. 바꾸려면 삭제 후 재생성
  • 기본 제공 사용자용 ClusterRole: cluster-admin, admin, edit, view
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
  - apiGroups: [""] # "" = core API group
    resources: ["pods"]
    verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
  - kind: ServiceAccount
    name: my-sa
    namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

ServiceAccount

  • 사람이 아닌 계정. Pod 안의 프로세스가 API server에 접근할 때의 신원
  • namespace마다 default ServiceAccount가 자동 생성. 지워도 control plane이 다시 만듦
  • default ServiceAccount는 RBAC 기준으로 API discovery 외 권한 없음
  • Pod에 지정: spec.serviceAccountName
    • 이미 존재하는 Pod의 serviceAccountName은 수정 불가. Deployment 등은 template을 바꿔 새 Pod로 교체
    • spec.serviceAccount는 deprecated alias
  • token
    • v1.22부터 TokenRequest API로 받은 짧은 수명·자동 갱신 token을 projected volume으로 마운트
    • 경로: /var/run/secrets/kubernetes.io/serviceaccount/ (token, ca.crt, namespace)
    • 수동 발급: kubectl create token <sa> (--duration으로 수명 요청)
  • 자동 마운트 끄기: automountServiceAccountToken: false
    • ServiceAccount와 Pod 양쪽에 둘 수 있고, 둘 다 있으면 Pod 쪽이 우선
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: default
automountServiceAccountToken: false
---
apiVersion: v1
kind: Pod
metadata:
  name: api-client
  namespace: default
spec:
  serviceAccountName: my-sa
  automountServiceAccountToken: true # Pod 설정이 우선
  containers:
    - name: app
      image: busybox:1.28
      command: ["sh", "-c", "sleep 1h"]

SecurityContext

Pod·container가 노드에서 어떤 사용자·권한으로 실행되는지 정하는 설정. RBAC와 달리 API 권한과는 무관.

  • 위치
    • Pod 레벨: spec.securityContext, 모든 container에 적용
    • container 레벨: spec.containers[].securityContext
    • 둘 다 있으면 container 레벨이 덮어씀
필드Podcontainer의미
runAsUser / runAsGroupOO프로세스 UID / 기본 GID
runAsNonRootOOtrue면 UID 0으로 실행 시 kubelet이 시작 거부
seccompProfileOORuntimeDefault, Localhost, Unconfined
fsGroupOXvolume 소유 그룹
supplementalGroupsOX추가 그룹
sysctlsOXPod sysctl
capabilitiesXOLinux capability add/drop
readOnlyRootFilesystemXOroot filesystem 읽기 전용
allowPrivilegeEscalationXOsetuid 등으로 권한 상승 허용 여부 (no_new_privs)
privilegedXOprivileged 모드
  • allowPrivilegeEscalation: container가 privileged이거나 CAP_SYS_ADMIN을 가지면 항상 true
  • capability 이름은 CAP_ 접두사 없이: CAP_SYS_TIME → SYS_TIME
apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  volumes:
    - name: tmp
      emptyDir: {}
  containers:
    - name: app
      image: busybox:1.28
      command: ["sh", "-c", "sleep 1h"]
      volumeMounts:
        - name: tmp
          mountPath: /tmp # readOnlyRootFilesystem일 때 쓰기 경로
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
          add: ["NET_BIND_SERVICE"]

Pod Security Standards

Pod 보안 수준을 세 단계 정책으로 정의한 것. 강제는 PodSecurity admission controller(Pod Security Admission)가 담당.

수준내용
Privileged제한 없음. 알려진 권한 상승도 허용
Baseline알려진 권한 상승 차단. 기본(최소 지정) Pod 설정은 허용
Restricted현재 Pod hardening best practice 수준의 강한 제한

Restricted에서 요구하는 container 설정(발췌):

  • allowPrivilegeEscalation: false
  • runAsNonRoot: true, runAsUser는 0 금지
  • capabilities.drop에 ALL, add는 NET_BIND_SERVICE만
  • seccompProfile.type: RuntimeDefault 또는 Localhost (미지정·Unconfined 불가)
  • volume 종류 제한: configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret

namespace label로 적용:

apiVersion: v1
kind: Namespace
metadata:
  name: secure-ns
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
mode위반 시
enforcePod 거부
auditaudit log에 annotation 추가, 허용
warn사용자에게 경고, 허용

헷갈리는 것 비교

항목AB
401 vs 403401: authentication 실패 (누구인지 모름)403: authorization 거부 (누구인지는 알지만 권한 없음)
authorization vs admission요청 속성(user, verb, resource)만 보고 판단객체 내용(필드 값)까지 보고 수정·거부. 읽기 요청은 대상 아님
Role vs ClusterRolenamespace 범위클러스터 범위. RoleBinding으로 한 namespace에만 붙일 수도 있음
RoleBinding + ClusterRole효과는 RoleBinding의 namespace 안으로 한정ClusterRoleBinding이면 전 namespace
RBAC vs SecurityContextAPI server에 대한 권한노드에서 프로세스가 가진 권한
runAsNonRoot vs runAsUser조건 검사 (root면 실행 거부)실제 UID 지정
privileged vs capabilities사실상 호스트 수준 권한 전부필요한 capability만 골라서 add/drop
Pod vs container securityContext공통 기본값, fsGroup 등 Pod 전용 필드덮어쓰기, capabilities 등 container 전용 필드

시험 포인트

imperative 명령어

# ServiceAccount
kubectl create serviceaccount my-sa -n dev
kubectl set serviceaccount deployment/web my-sa -n dev
kubectl create token my-sa -n dev

# RBAC
kubectl create role pod-reader --verb=get,list,watch --resource=pods -n dev
kubectl create rolebinding pod-reader-binding --role=pod-reader \
  --serviceaccount=dev:my-sa -n dev
kubectl create clusterrole secret-reader --verb=get,list,watch --resource=secrets
kubectl create rolebinding view-binding --clusterrole=view \
  --serviceaccount=dev:my-sa -n dev

# 권한 확인
kubectl auth can-i list pods -n dev --as=system:serviceaccount:dev:my-sa
kubectl auth can-i --list -n dev --as=system:serviceaccount:dev:my-sa

# Pod Security Admission
kubectl label namespace secure-ns pod-security.kubernetes.io/enforce=restricted
  • SecurityContext는 imperative 플래그가 없음. kubectl run ... --dry-run=client -o yaml로 뼈대를 만든 뒤 YAML에 추가

kubectl explain

kubectl explain pod.spec.securityContext                          # Pod 레벨: runAsUser, fsGroup 등
kubectl explain pod.spec.containers.securityContext               # container 레벨: capabilities, readOnlyRootFilesystem 등
kubectl explain pod.spec.containers.securityContext.capabilities  # add, drop
kubectl explain pod.spec.automountServiceAccountToken
kubectl explain role.rules                                        # apiGroups, resources, verbs
kubectl explain rolebinding.subjects                              # kind, name, namespace

참고 문서