(API Group → Authorization/RBAC → ServiceAccount/Token → Image/Runtime/Network Security → Context 도구 → CRD/Controller/Operator)
아래 내용은 자막 스크립트에서 다룬 흐름을 중심으로, 우리가 다뤘던 주제들을 한 번에 이어지도록 재구성한 정리글입니다. (중간중간 실무에서 자주 막히는 포인트만 최소한으로 덧붙였습니다.)
1) Kubernetes API와 API Group: “무엇을” 제어하는가의 지도
Kubernetes에서 우리가 하는 거의 모든 일은 결국 kube-apiserver와의 상호작용입니다.
- 버전 확인: API 서버의
/version - 파드 목록:
/api/v1/pods - 기타 리소스:
/apis/<group>/<version>/...
Kubernetes API는 목적에 따라 큰 덩어리로 나뉘는데, 이 강의에서는 “클러스터 기능을 담당하는 API”에 집중합니다.
Core Group vs Named Group
- Core Group: 네임스페이스, 파드, 서비스, ConfigMap, Secret, PV/PVC 등 “기본 리소스”가 있는 곳
- URL 경로가 보통
/api/v1형태 (그룹 이름을 명시하지 않는 특수 케이스)
- URL 경로가 보통
- Named Group: apps, networking, storage, rbac, auth 등 기능별로 체계적으로 정리된 그룹
- URL 경로가 보통
/apis/<group>/<version>
- URL 경로가 보통
리소스와 Verb(동사)
각 API 그룹 아래에 리소스가 있고, 리소스마다 가능한 동작(verb)이 있습니다.
- 예: deployments에 대해
list/get/create/update/delete/watch등
API Group 확인 방법 (실습/디버깅용)
- API 서버 루트로 접근하면(인증 필요) 사용 가능한 그룹이 나열됩니다.
- 인증 없이
curl로 때리면/version같은 일부만 되고 대부분은 막힙니다. - 그래서 kubectl proxy를 쓰면 편해집니다.
- 로컬
127.0.0.1:8001로 프록시를 띄우고, kubeconfig 자격증명으로 API 서버에 대신 요청해줍니다.
- 로컬
- 주의: kube-proxy(데이터 플레인 네트워킹)와 kubectl proxy(API 접근용 HTTP 프록시)는 전혀 다른 것
2) Authorization(인가): “누가 들어왔는지” 다음엔 “무엇을 하게 할지”
인증(Authentication)은 “누구냐”를 증명하는 단계이고,
인가(Authorization)는 “무엇을 할 수 있냐”를 결정하는 단계입니다.
클러스터에는 관리자뿐 아니라 개발자/테스터/모니터링 도구/CI-CD(Jenkins 등)도 들어오게 됩니다.
모두에게 관리자급 권한을 줄 수 없으니 인가가 필요합니다.
Kubernetes가 지원하는 대표 인가 메커니즘
- Node Authorizer
- ABAC(Attribute-Based Access Control)
- RBAC(Role-Based Access Control)
- Webhook Authorization(외부 정책 엔진, 예: OPA 등)
- AlwaysAllow / AlwaysDeny 같은 모드도 존재
여러 인가 모드의 체인 동작
API 서버의 --authorization-mode에 Node,RBAC,Webhook처럼 콤마로 여러 개를 줄 수 있고,
요청은 순서대로 평가됩니다.
- 어떤 모듈이 “승인”하면 그 시점에 끝
- 어떤 모듈이 “거부/처리 불가”하면 다음 모듈로 넘어감
3) RBAC 핵심: Role/RoleBinding (네임스페이스 범위)
RBAC는 “사용자/그룹을 권한에 직접 연결”하는 대신:
- Role(권한 규칙 묶음)을 만들고
- RoleBinding으로 사용자(또는 SA)를 Role에 연결합니다.
이게 ABAC(정책 파일 직접 편집 + API 서버 재기동)보다 관리가 훨씬 쉽습니다.
Role 정의(개념)
apiGroups: Core면[""]또는 빈 값(스크립트에서는 “코어 그룹은 비워도 된다”는 뉘앙스)resources: 예)pods,configmapsverbs: 예)get,list,create,delete- (옵션)
resourceNames: 특정 리소스 이름만 허용(예: blue/orange 파드만)
예시(개념형):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list","create","delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create"]
RoleBinding 정의(개념)
subjects: 사용자/그룹/서비스어카운트 지정roleRef: 어떤 Role(또는 ClusterRole)에 붙일지 지정
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: devuser-developer-binding
namespace: default
subjects:
- kind: User
name: dev-user
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
확인 명령(스크립트 흐름)
kubectl get role,kubectl describe role <name>kubectl get rolebinding,kubectl describe rolebinding <name>- 권한 점검:
kubectl auth can-i <verb> <resource> --as <user>- 네임스페이스도 함께 테스트 가능
4) ClusterRole/ClusterRoleBinding (클러스터 범위) + PV/PVC 정리
Role/RoleBinding은 기본적으로 네임스페이스 범위입니다.
하지만 어떤 리소스는 네임스페이스에 속하지 않습니다.
클러스터 범위 리소스 예
- Node
- PersistentVolume(PV)
- Namespace
- CertificateSigningRequest(CSR)
- ClusterRole / ClusterRoleBinding
- (등)
이런 리소스 권한을 주려면 ClusterRole + ClusterRoleBinding을 씁니다.
중요한 포인트(스크립트에도 나오는 주의)
- ClusterRole은 “클러스터 범위 리소스 전용”만은 아닙니다.
네임스페이스 리소스(pods 등) 에 대해서도 ClusterRole을 만들 수 있고,
이 경우 “모든 네임스페이스에 걸친 권한”이 됩니다.
PV/PVC가 뭐고, “어떤 클러스터”에 속하나?
- PV(PersistentVolume)
- 클러스터 범위(Cluster-scoped) 리소스
- “클러스터가 제공할 수 있는 스토리지 덩어리(볼륨)”를 미리 등록해두거나(정적 프로비저닝), StorageClass로 동적 생성되게 함
- PVC(PersistentVolumeClaim)
- 네임스페이스 범위(Namespaced) 리소스
- 파드/앱이 “이만큼의 스토리지가 필요해요”라고 요청(Claim) 하는 것
그리고 질문했던 핵심:
- PV/PVC의 바인딩은 오직 ‘그 Kubernetes 클러스터 내부’에서만 일어납니다.
- PV는 클러스터 전역 리소스
- PVC는 특정 네임스페이스의 요청
- 둘이 바인딩되면 그 관계는 그 클러스터 내부의 etcd에 저장된 상태입니다.
- “다른 클러스터의 PV를 이 클러스터 PVC가 쓴다” 같은 형태는 Kubernetes 리소스 바인딩 관점에서는 불가(클러스터가 다르면 API/etcd 자체가 다름)
5) ServiceAccount와 Token: “RBAC만 있으면 되지 않나?”의 답
스크립트의 흐름은 다음입니다.
- Kubernetes 계정은 크게 2종:
- User Account: 사람이 쓰는 계정(관리자/개발자)
- ServiceAccount(SA): 애플리케이션(기계)이 쓰는 계정(Prometheus, Jenkins 등)
RBAC vs Token: 역할이 다르다
- RBAC: “무엇을 할 수 있는지(인가)” 규칙
- Token(또는 인증서): “누구인지(인증)” 증명 수단
즉 “RBAC가 있는데 왜 토큰이 필요?”에 대한 답은:
RBAC는 인증이 끝난 ‘주체(identity)’가 전제다.
토큰/인증서는 그 주체를 증명하기 위한 인증 수단이다.
SA 토큰은 어떻게 파드에 들어오나
- 기본적으로 파드가 생성되면 기본 ServiceAccount가 연결됩니다.
- kubelet이 Projected Volume 형태로 토큰을 파드 내부에 마운트합니다.
- 경로 예:
/var/run/secrets/kubernetes.io/serviceaccount
- 경로 예:
- 애플리케이션은 그 토큰을 읽어 API 서버에 Bearer 토큰으로 요청할 수 있습니다.
토큰 자동 주입 끄기
automountServiceAccountToken: false- ServiceAccount 수준 또는 Pod 수준에서 설정 가능
“SA에 파드 생성 권한이 있고, SA가 파드에 달려 있으면 그 파드가 파드를 만들 수 있나?”
가능합니다. 파드 안의 애플리케이션이:
- 마운트된 SA 토큰을 사용해 API 서버에 인증하고
- RBAC가
pods.create를 허용한다면 - API 서버에 “파드 생성” 요청을 할 수 있습니다.
그래서 SA 권한은 최소 권한(least privilege) 로 주는 게 매우 중요합니다.
SA를 Pod에 설정 vs Deployment에 설정 차이
- 실제로 권한이 적용되는 단위는 Pod입니다.
- Deployment에 SA를 “설정”한다는 건, 정확히는 Deployment의 Pod Template(spec.template.spec.serviceAccountName) 에 넣는 것입니다.
- 결과적으로 “그 Deployment가 만들어내는 모든 Pod”에 같은 SA가 붙습니다.
6) Image Security: 프라이빗 레지스트리 이미지 가져오기
이미지는 보통 다음 규칙으로 해석됩니다.
nginx라고만 쓰면 사실상docker.io/library/nginxlibrary는 도커 공식 이미지 계정(공식 검증/관리)
- 레지스트리를 명시하면 예:
gcr.io/...,private.registry.com/...
프라이빗 레지스트리 이미지를 쓰려면 노드의 런타임이 이미지를 pull할 때 인증이 필요합니다.
Kubernetes에서는 이를 imagePullSecrets로 해결합니다.
- Docker registry 타입 Secret 생성
- Pod spec에
imagePullSecrets로 참조
개념 예시:
kubectl create secret docker-registry regcred \
--docker-server=private.registry.com \
--docker-username=USER \
--docker-password=PASS \
--docker-email=you@example.com
spec:
imagePullSecrets:
- name: regcred
여기서의 Secret은 “레지스트리 인증” 목적이고, SA 토큰과 목적이 다릅니다(혼동 포인트).
7) Security Context: Docker 보안 개념이 Kubernetes로 올라오는 지점
스크립트는 Docker 보안 기본을 먼저 다룹니다.
- 컨테이너는 VM처럼 완전 분리라기보다 커널 공유
- Namespace로 프로세스 격리
- 기본적으로 컨테이너 프로세스는 root로 실행될 수 있지만,
Docker는 Linux Capabilities로 root 권한을 “풀 권한이 아니라 제한된 권한 묶음”으로 제어합니다. --cap-add,--cap-drop,--privileged같은 옵션
Kubernetes SecurityContext 적용 원칙
- 컨테이너는 Pod 안에 들어가므로
- Pod 수준 securityContext(모든 컨테이너에 적용)
- Container 수준 securityContext(해당 컨테이너에만 적용)
- 둘 다 있으면 컨테이너 설정이 Pod 설정을 override 합니다.
예: runAsUser, capabilities.add 등
실습에서 겪은 에러 포인트(중요)
에러:
unknown field "spec.securityContext.capabilities"
이유: capabilities는 Pod-level securityContext에 둘 수 없고, Container-level securityContext에 둬야 합니다.
올바른 형태(컨테이너 아래로 이동):
spec:
containers:
- name: ubuntu
image: ubuntu
command: ["sleep","4800"]
securityContext:
capabilities:
add: ["SYS_TIME"]
8) Network Security: Ingress/Egress → NetworkPolicy
Ingress / Egress 개념
- Ingress: 들어오는 트래픽(유입)
- Egress: 나가는 트래픽(유출)
Kubernetes는 기본적으로 모든 파드가 서로 통신 가능(All Allow)인 상태로 시작합니다.
특정 파드(예: DB)를 보호하고 싶으면 NetworkPolicy를 적용합니다.
NetworkPolicy의 핵심 구조
- podSelector로 “어떤 파드에 정책을 적용할지” 선택
- policyTypes로 Ingress/Egress 중 무엇을 제어할지 지정
- ingress/egress 규칙으로 “허용할 트래픽”만 열기
DB 보호 시나리오(스크립트 핵심):
- 목표: DB 파드의 3306 포트는 API 파드에서만 접근 허용
- DB 입장에서 “API → DB”는 Ingress
그리고 중요한 문장:
- 인그레스에서 “요청”을 허용하면 그에 대한 “응답”은 별도 규칙 없이 정상 동작(상태 기반 흐름)
셀렉터 3종(From/To)
podSelector: 레이블로 파드 선택namespaceSelector: 레이블로 네임스페이스 선택ipBlock: CIDR로 외부 IP 대역 허용
그리고 규칙 조합의 논리:
- 같은
from:리스트의 여러 항목은 OR - 한 항목 안에서
podSelector+namespaceSelector같이 있으면 AND - YAML에서
-(리스트 아이템) 위치가 바뀌면 “규칙 의미”가 크게 달라질 수 있음 (스크립트가 강조한 부분)
“ingress만 적어두면 egress는 다 열려있나?”
정리만 깔끔하게 하면:
- 특정 파드가 Ingress 정책만 적용받는다면, Egress는 기본 동작(대개 허용) 그대로인 경우가 많습니다.
- 반대로
policyTypes: ["Egress"]를 적용하면 egress는 “명시 허용만 통과”로 바뀝니다(규칙 없으면 사실상 deny-all egress).
apply Conflict 에러(자주 만나는 실무/실습 문제)
에러:
object has been modified; please apply your changes to the latest version
의미:
- 내가 apply하려는 사이에 리소스가 다른 곳에서 업데이트되어 resourceVersion 충돌이 난 것
해결 패턴(안전한 순서):
- 최신을 다시 받아서 수정 후 apply
kubectl get netpol internal-policy -o yaml > policy.yaml- 수정 →
kubectl apply -f policy.yaml
- 실습 환경이면 삭제 후 재생성도 가능
kubectl delete -f policy.yaml && kubectl apply -f policy.yaml
9) kubectx / kubens, 그리고 context의 의미
실습에서는 네임스페이스/컨텍스트를 자주 바꾸는데, 프로덕션에서는 그 복잡도가 더 커집니다.
그래서 kubectx, kubens 같은 도구가 유용합니다.
kubectx: 컨텍스트 전환kubens: 네임스페이스 전환
그리고 가장 중요한 개념:
context = (cluster + user + namespace)
- cluster: 어느 API 서버(클러스터)에 붙을지
- user: 어떤 자격증명/정체성으로 붙을지
- namespace: 기본 네임스페이스(옵션)
즉 context는 “kubectl 작업 프로필”입니다.
10) CRD → Custom Controller → Operator: Kubernetes를 “도메인 플랫폼”으로 확장
CRD(CustomResourceDefinition)
- Kubernetes에 “새 리소스 타입”을 등록하는 객체
- CRD를 만들면:
kubectl apply/get/delete로 커스텀 리소스를 다룰 수 있고- 데이터는 etcd에 저장됨
- 하지만 CRD만으로는 실제 동작이 없음
- Ticket을 만들었다고 “항공권 예약 API”를 자동 호출해주지 않음
Custom Controller
- 루프로 돌면서 특정 리소스(Ticket)의 생성/수정/삭제 이벤트를 감시하고
- 외부 API 호출(예약/변경/취소)을 수행하는 코드/프로세스
구현 방식 개요(스크립트):
- Python 등으로도 만들 수 있지만 비용/구현 난도가 커질 수 있음
- Go client 생태계(shared informer, queue, cache)를 쓰면 컨트롤러를 “올바르게” 만들기 쉬움
- 샘플 컨트롤러 레포를 clone → 로직 커스터마이징 → 빌드/실행
- kubeconfig로 로컬 실행도 가능
- 보통은 Docker 이미지로 패키징해서 클러스터 안에서 Deployment로 실행
Operator(Operator Framework / OperatorHub)
- CRD + Controller(그리고 설치에 필요한 RBAC/배포 리소스)를 하나로 패키징해서 배포/관리
- etcd operator처럼 “설치”뿐 아니라 백업/복구 같은 운영 작업까지 자동화하는 운영자(사람 역할) 개념
- OperatorHub에서 다양한 오퍼레이터를 찾고, OLM 기반 설치 흐름이 소개됨
마무리: 이 글의 핵심 한 줄 요약들
- API Group: Kubernetes 기능 지도(리소스가 어디에 속하는지)
- Authorization: 인증된 주체가 “무엇을 할 수 있는지” 결정(노드/RBAC/웹훅 등)
- RBAC: Role/RoleBinding(네임스페이스), ClusterRole/ClusterRoleBinding(클러스터 범위)
- PV/PVC: PV는 클러스터 범위, PVC는 네임스페이스 범위(바인딩은 같은 클러스터 안에서만)
- ServiceAccount/Token: RBAC(인가)와 별개로 “인증 수단”이 필요하며, 파드에 토큰이 자동 마운트될 수 있음
- ImagePullSecrets: 프라이빗 레지스트리 pull 인증
- SecurityContext: runAsUser/capabilities 등 런타임 권한을 Pod/Container 수준에서 제어(컨테이너 설정이 우선)
- NetworkPolicy: 기본 All-Allow에서 “선택한 파드”만 허용 규칙 기반으로 잠그는 방식
- Context/kubectx/kubens: 멀티 클러스터/멀티 네임스페이스 운영 필수 도구
- CRD/Controller/Operator: Kubernetes를 도메인 플랫폼으로 확장(데이터만 저장하려면 CRD, 동작하려면 컨트롤러, 패키징/운영 자동화는 오퍼레이터)
'CKA' 카테고리의 다른 글
| Storage - Docker의 Storage Driver vs Volume Driver (0) | 2026.01.03 |
|---|---|
| Storage - Docker의 Storage (0) | 2026.01.03 |
| Security - Custom Controller & Operator (0) | 2026.01.02 |
| Security - Custom Resource Definition (0) | 2026.01.02 |
| Security - Context & 네임스페이스 전환을 빠르게 하는 도구 (0) | 2026.01.02 |