0. 사전지식
쿠버네티스를 운영 환경에 도입하려면 반드시 신경 써야 할 것이 보안(Security)이다. 아무나 클러스터에 접근해서 리소스를 마음대로 삭제할 수 있다면 잠롯된 설계라는걸 모두가 알 것이다. 그래서 쿠버네티스는 인증(Authentication), 인가(Authorization), Admission Control, 그리고 API 서버 보안 통신 등을 통해 보안을 강화하고 있다.
1. API Server
1.1. API 서버의 핵심 역할
쿠버네티스에서 모든 요청은 결국 API Server를 통해 이루어진다. 사용자가 kubectl 명령어를 실행하면 API Server가 해당 요청을 받아서 ectd에 저장하고, 다른 컴포넌트에 전달하여 클러스터 상태를 바꿔준다. 즉, API Server는 클러스터의 관문이자 중앙 컨트롤 타워이다.

1.2. 주요 기능
| 기능 | 설명 |
| 🔗 REST API 제공 | 클러스터에 리소스를 생성, 조회, 수정, 삭제하는 창구 |
| ✅ 인증 (Authentication) | 누가 접근했는지를 확인 |
| 🔐 인가 (Authorization) | 이 사용자가 어떤 작업을 할 수 있는지 결정 |
| 🛂 어드미션 컨트롤 | 리소스 생성 전에 정책에 맞는지 검사 |
| 💾 상태 저장 | 클러스터 상태를 etcd에 저장 |
2. API 접근 제어
[흐름]
① 인증(Authentication): 이 사람 누구야? → 사용자 계정 확인
② 인가(Authorization): 이 사람 뭐까지 해도 돼? → 권한(RBAC) 확인
③ 정책 검사(Admission Control): 정책 위반 아닌가? → 최종 허용 여부
2.1. 인증(Authentication): 누가 요청했는가?
쿠버네티스에서는 여러 방식으로 사용자 인증을 지원한다.
2.1.1 주요 인증 방식 비교
| 인증 방식 | 설명 |
| 🔑 클라이언트 인증서 (X.509) | 인증 기관(CA)이 서명한 인증서를 통해 사용자 인증 |
| 🔐 정적 토큰 / 비밀번호 | 사전에 정의한 고정된 토큰/비밀번호 사용 |
| 🚀 부트스트랩 토큰 | 클러스터 초기 설정(kubeadm)에서 사용 |
| 🧪 서비스 어카운트 (Service Account) | Pod 내부에서 자동으로 주어지는 인증 토큰 |
| 🌐 OpenID Connect (OIDC) | 구글, Okta 등 외부 인증 시스템 연동 |
2.1.2. 사용자 계정 vs 서비스 계정
쿠버네티스에서 클러스터에 접근하는 주체(신분)는 크게 두 가지로 구분된다. 즉, 사람이 직접 kubectl 명령어를 입력하는 경우와, 앱(Pod)이 자동으로 쿠버네티스 API를 호출하는 경우는 역할도 다르고, 보안 제어 방식도 다르기 때문에 별도의 계정 체계로 나뉘어 있다.
[1] 사용자 계정 (User Account)
사람이 직접 클러스터에 접근할 때 사용하는 계정이며 개발자, 운영자, DevOps 엔지니어 등이 실질적인 주체이다., kubectl apply, kubectl get pod 같은 명령어를 CLI에서 실행하는 사람들을 의미한다. 클러스터에 사용자 계정(User Account)는 리소스로 존재하지 않는다.
[2] 서비스 계정 (Service Account)
Pod 내부에서 자동으로 부여받는 쿠버네티스 전용 계정이다. 즉, 앱(Pod)이 내부에서 쿠버네티스 API를 호출"할 때 사용하는 인증 수단이며 주체는 실행 중인 앱(Pod)이다. Pod가 쿠버네티스 API 서버에 접근할 수 있도록 인증 정보(토큰)를 자동 주입해주는 목적으로 사용된다. 네임스페이스 단위로 존재 (default 계정 자동 생성)하며 자동으로 토큰이/var/run/secrets/kubernetes.io/serviceaccount 경로에 마운트된다. RBAC을 통해 권한이 제어된다.
[실무 예시]
[1] Job이 ConfigMap을 읽기 위해 API 서버 접근
[2] 컨트롤러(Pod)가 다른 리소스 생성/수정
[3] Helm, ArgoCD, Jenkins 등이 동작 시 필요한 접근 권한
2.1.3. 인증(Authentication) 동작 과정

쿠버네티스는 기본적으로 CA 기반 인증 체계를 따르며, 클라이언트와 서버는 Public Key/Private Key로 암호화를 주고받는다.

Q. 근데 지금까지 위와 관련된 설정 없이도 잘 수행됐는데요?
A. 그것은 kube config에 위의 내용을 미리 작성해놨기 가능했던 것입니다.만약 kube config에 미리 설정을 하지 않았다면 `kubectl get pod`라는 간단한 명령어 조차도 `kubectl get pod --server k8s-master --client-key admin.key --client-certificate admin.crt --certificate-authority ca.crt`처럼 작성해야 합니다.
2.2. 인가 (Authorization) : 무엇을 할 수 있는가?
인증이 "누구인지" 확인하는 과정이라면, 인가는 "무엇을 할 수 있는가"를 결정한다. 쿠버네티스에서 인가 방식은 여러가지가 있지만, 가장 널리 쓰이고 공식적으로도 추천하는 방식은 바로 RBAC이다. RBAC은 “역할 기반 접근 제어”로, 누가(사용자) → 어떤 역할(Roles) → 어떤 리소스를 다룰 수 있는지 정의한다. RBAC과 관련된 객체로는 Role과 RoleBinding이 있는데, 해당 객체에 대해 알아보자.
[1] Role: 권한 정의
Role은 특정 네임스페이스(namespace) 내에서만 동작하며 "어떤 리소스를 어떤 방식으로 다룰 수 있는지" 정의한다.Role은 단독으로 사용되지 않으며 RoleBinding이 반드시 필요하다.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-ex
#namespace:
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods","services","secrets","pods/exec", "serviceaccounts"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
[1] get: 조회
[2] list: 목록 조회
[3] watch: 변경 감지
[4] create: 생성
[5] update: 수정
[6] patch: 부분 수정
[7] delete: 삭제
[2] RoleBinding: 역할 연결
정의된 Role을 사용자, 그룹, 또는 다른 서비스 계정에 연결하는 역할을 한다. RoleBindnig을 하지 않으면 권한 부여가 불가능하기 때문에 Role은 아무 의미가 없어진다.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
#namespace:
name: ex-role-binding
subjects:
- kind: User 또는 ServiceAccount
name: default
#namespace:
roleRef:
kind: Role
name: ex-role
apiGroup: rbac.authorization.k8s.io
[1] subjects: 권한을 부여할 대상
[2] roleRef: 어떤 Role에 연결할지 정의
3. 실습: 사용자 계정(User Account) 인증 및 인가 실습
쿠버네티스에서 “k8s-01”이라는 사용자에게 인증서 발급하고, 그 사용자에게 권한(Role)을 주는 실습을 수행해보자.
3.1. 개인 키(Private Key) 및 인증 요청(CSR) 생성
[1] 디렉터리 준비
mkdir ~/k8s-auth && cd ~/k8s-auth
[2] 개인 키(Private Key) 생성
openssl genrsa -out k8s01.key 2048
[3] 인증 요청(CSR) 생성
openssl req -new -key k8s01.key -out k8s01.csr
🔑 사용자 인증을 위한 개인 키(k8s01.key)와 인증서 요청 파일(k8s01.csr)을 생성한다.
3.2. CSR 내용 확인 및 인코딩
[1] CSR 리소스 생성 (Base64 인코딩 필수)
base64 인코딩은 CSR을 쿠버네티스 리소스(YAML)에 삽입할 때 필요하다.
cat k8s01.csr | base64 -w 0
3.3. Kubernetes CSR 리소스 생성
[1] CSR 매니페스트 작성
mkdir manifest
cd manifest
vi ~/k8s-auth/manifest/k8s-csr.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: k8s01
spec:
groups:
- system:authenticated
request: <위에서 인코딩한 값>
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
[1] request: 방금 만든 CSR을 base64로 인코딩한 문자열로 넣는다.
[2] signerName: kube-apiserver가 클라이언트 인증서 발급자로 동작한다.
[3] usages: 인증서 용도 → client auth는 API 서버 인증용이다.
[2] CSR 리소스 생성 및 승인
kubectl apply -f k8s-csr.yaml
kubectl certificate approve k8s01
kubectl get csr k8s01 -o yaml
[3] 인증서 추출
# 발급된 인증서를 저장
echo "<status.certificate의 값>" | base64 -d > k8s01-auth.crt
인증서 서명이 완료되면 .status.certificate 필드에 base64로 인코딩된 인증서가 생기는데, 이를 디코딩하여 k8s01-auth.crt 파일로 저장한다.
3.4. kubeconfig에 사용자 등록
인증서 기반 사용자 계정 k8s-01를 kubeconfig에 등록한다. 이제 이 사용자로 쿠버네티스 API를 사용할 수 있게 되지만, 아직까지는 권한이 없기 때문에 아무 것도 못한다.
kubectl config set-credentials k8s-01 \
--client-key=k8s01.key \
--client-certificate=k8s01-auth.crt \
--embed-certs
kubectl get pod --as=k8s-01 # 에러 발생할 수도 있음 → 권한 없음

3.5. 권한 부여: 인가(Authorization)
Role 및 RoleBinding 생성한다. (네임스페이스 범위)
[1] 새 폴더 생성 후 Role 작성
cd ~/k8s-auth
mkdir ua
cd ua
vi k8s01-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: role-dev
rules:
- apiGroups: ["", "apps"]
resources: ["pods", "deployments"]
verbs: ["get", "list"]
[1] Role: 특정 네임스페이스(default) 내에서만 유효하다.
[2] 위 Role은 pods, deployments를 get, list만 허용한다.
[2] RoleBinding 생성
이 사용자(k8s-01)에게 role-dev 권한을 연결한다.
vi k8s01-role-binding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rolebinding-dev
namespace: default
subjects:
- kind: User
name: k8s-01
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: role-dev
apiGroup: rbac.authorization.k8s.io
3.6. 권한 테스트
kubectl apply -f k8s01-role.yaml
kubectl apply -f k8s01-role-binding.yaml
[1] --as: 해당 요청을 특정 사용자로 수행하는 플래그
[2] get pod는 Role에 있으므로 성공
📌 Role은 권한 정의, RoleBinding은 사용자에 권한 연결
3.7. ClusterRole + ClusterRoleBinding
[1] ClusterRole 생성
vi k8s01-cluster-role.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-role-dev
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
ClusterRole은 모든 namespace에서 리소스를 제어할 수 있게한다.
[2] ClusterRoleBinding 생성
vi k8s01-cluster-role-binding.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cluster-rolebinding-dev
subjects:
- kind: User
name: k8s-01
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-role-dev
apiGroup: rbac.authorization.k8s.io
k8s-01 사용자에게 Cluster 전체에 대한 권한을 부여한다.
[3] 최종 확인
kubectl get ns --as=k8s-01
이제는 namespace 조회가 정상 동작해야 한다.
4. 실습: 서비스 계정(Service Account) 인증 및 인가 실습
4.1. Service Account 설정
[1] Service Account 생성
cd ~/k8s-auth/sa
vi k8s02-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: k8s-02
namespace: k8s02
kubectl apply -f .
kubectl get sa -n k8s02
4.2. Secret 생성 (ServiceAccount용 토큰 발급)
k8s-02 계정용 토큰 자동 생성하고, Kubernetes가 이 Secret에 토큰을 채워준다.
vi k8s02-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: k8s02-secret
namespace: k8s02
annotations:
kubernetes.io/service-account.name: k8s-02
type: kubernetes.io/service-account-token
kubectl apply -f k8s02-secret.yaml
kubectl get secret -n k8s02
kubectl describe secret k8s02-secret -n k8s02
📌주의: Secret에 토큰이 자동으로 생성되기까지 10~20초 걸릴 수 있음.
4.3. kubeconfig에 사용자 등록 및 context 생성
[1] 사용자 등록
ServiceAccount 토큰을 이용해 kubectl 명령에서 인증 가능하도록 등록한다.
kubectl config set-credentials k8s-02 --token=<복사한 secret 토큰>
[2] context 연결
k8s-02 유저가 사용할 네임스페이스와 클러스터 지정한다. 이렇게 context를 등록하면 kubectl config use-context k8s02로 전환 가능하다.
kubectl create ns k8s02
kubectl config set-context k8s02 --cluster=kubernetes --namespace=k8s02 --user=k8s-02
4.4. RBAC 권한 부여 (Role + RoleBinding)
[1] Role 정의
k8s02 네임스페이스 내에서 Pod, Deployment를 조회할 수 있는 권한을 부여한다.
vi k8s02-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: k8s02-role
namespace: k8s02
rules:
- apiGroups: ["", "apps"]
resources: ["pods", "deployments"]
verbs: ["get", "list"]
[2] RoleBinding 정의
k8s-02 ServiceAccount에게 위 Role 권한 부여한다.
vi k8s02-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: k8s02-role-binding
namespace: k8s02
subjects:
- kind: ServiceAccount
name: k8s-02
namespace: k8s02
roleRef:
kind: Role
name: k8s02-role
apiGroup: rbac.authorization.k8s.io
kubectl apply -f k8s02-role.yaml
kubectl apply -f k8s02-role-binding.yaml
4.5. 해당 ServiceAccount를 사용하는 Pod 배포
spec.serviceAccountName을 통해 이 Pod가 k8s-02 계정을 사용하도록 설정
vi k8s02-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s02-deployment
labels:
app: k8s02-deployment
spec:
replicas: 3
selector:
matchLabels:
app: k8s-deployment
template:
metadata:
labels:
app: k8s-deployment
spec:
serviceAccountName: k8s-02
containers:
- name: k8s-deployment-container
image: nginx:latest
ports:
- containerPort: 80
kubectl apply -f k8s02-deployment.yaml -n k8s02
4.6. 권한 확인 및 테스트
k8s02 context에서는 k8s-02 계정의 권한만으로 동작한다. 만약 Cluster-level 리소스 접근이 필요하면 ClusterRole 및 ClusterRoleBinding 사용이 필요하다.
kubectl config use-context k8s02
kubectl get deploy
📌 정리: 전체 흐름 요약
| 1 | ServiceAccount 생성 (k8s-02) |
| 2 | Secret 생성하여 토큰 발급 |
| 3 | kubectl 사용자 등록 및 context 생성 |
| 4 | Role 및 RoleBinding 생성으로 권한 부여 |
| 5 | 해당 ServiceAccount를 사용하는 Pod 배포 |
| 6 | context 전환 후 권한 테스트 |
SA, Role, RoleBinding의 리소스가 다른 ns이면 문제가 발생!
'Kubernetes > Ops' 카테고리의 다른 글
| [17] Helm (0) | 2025.06.17 |
|---|---|
| [16] Kubernetes Autoscailing (0) | 2025.06.17 |
| [15] Kubernetes Deployment Strategy (0) | 2025.06.16 |
| [14] Kubernetes Scheduler (0) | 2025.06.16 |
| [2] Kubernetes 환경 구축 (0) | 2025.06.12 |
