Kubernetes 개발·운영 실전 2편 — Namespace & RBAC 설계
Kubernetes 멀티 팀·멀티 환경 운영을 위한 Namespace 분리 전략과 RBAC 설계 원칙. 최소 권한 원칙을 지키면서 개발자 생산성을 높이는 실전 구성.
TestForge Team ·
Namespace와 RBAC를 먼저 설계해야 하는 이유
클러스터를 구성하면 기본적으로 default 네임스페이스만 존재합니다. 초기에는 여기에 다 올리는 경우가 많지만, 팀이 커지고 서비스가 늘어나면 이 구조는 반드시 문제를 일으킵니다.
- A팀이 잘못 실행한
kubectl delete pods --all이 B팀 서비스를 삭제 - 개발자가 프로덕션 Secret을 실수로 수정
- 어떤 팀의 워크로드가 클러스터 리소스를 독점
Namespace와 RBAC는 이 문제를 구조적으로 막는 첫 번째 방어선입니다.
1. Namespace 분리 전략
환경 기반 분리 (소규모 팀)
cluster
├── development
├── staging
└── production
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: development
team: platform
---
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: staging
---
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: production
팀 + 환경 기반 분리 (중대형 팀)
cluster
├── team-a-dev
├── team-a-prod
├── team-b-dev
├── team-b-prod
└── platform # 공통 인프라 (monitoring, ingress 등)
팀별로 네임스페이스를 분리하면 팀 간 리소스 격리와 독립 배포가 가능합니다.
서비스 기반 분리 (마이크로서비스)
cluster
├── auth-service
├── payment-service
├── notification-service
└── platform
서비스마다 별도 네임스페이스를 두면 NetworkPolicy로 서비스 간 통신을 명확히 제어할 수 있습니다.
2. ResourceQuota로 리소스 상한 설정
네임스페이스별 리소스 상한을 설정하지 않으면 특정 팀의 워크로드가 클러스터 전체를 잠식할 수 있습니다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a-dev
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
services: "10"
persistentvolumeclaims: "5"
secrets: "20"
configmaps: "20"
LimitRange로 기본값 설정
Pod에 resources를 명시하지 않으면 무제한으로 실행됩니다. LimitRange로 기본값을 강제합니다.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-a-dev
spec:
limits:
- type: Container
default:
cpu: "500m"
memory: 256Mi
defaultRequest:
cpu: "100m"
memory: 128Mi
max:
cpu: "2"
memory: 2Gi
3. RBAC 설계 원칙
RBAC는 누가(Subject) 무엇을(Verb) 어떤 리소스에(Resource) 할 수 있는지 정의합니다.
역할 계층 설계
| 역할 | 대상 | 권한 |
|---|---|---|
| cluster-admin | 플랫폼 팀 | 클러스터 전체 |
| namespace-admin | 팀 리드 | 특정 네임스페이스 전체 |
| developer | 개발자 | 읽기 + Pod 조작 + 로그 조회 |
| viewer | 외부 감사, 인턴 | 읽기 전용 |
developer Role 정의
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: team-a-dev
rules:
# 조회 권한
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "endpoints", "events"]
verbs: ["get", "list", "watch"]
# Pod 조작 (exec, 로그, 포트포워딩)
- apiGroups: [""]
resources: ["pods/exec", "pods/log", "pods/portforward"]
verbs: ["get", "create"]
# Deployment 조회 + 재시작
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["get", "list", "watch", "patch"]
# Secret은 목록만 — 내용 조회 금지
- apiGroups: [""]
resources: ["secrets"]
verbs: ["list"]
viewer Role 정의
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
namespace: team-a-dev
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["get", "list", "watch"]
RoleBinding으로 사용자에게 역할 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: team-a-dev
subjects:
- kind: User
name: alice@company.com
apiGroup: rbac.authorization.k8s.io
- kind: Group
name: team-a-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
4. ServiceAccount 최소 권한 설정
Pod가 Kubernetes API를 호출할 필요가 없다면 기본 ServiceAccount 토큰 마운트를 비활성화합니다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: team-a-dev
automountServiceAccountToken: false # API 접근 불필요 시 비활성화
API 접근이 필요한 경우 전용 ServiceAccount를 만들고 최소 권한만 부여합니다.
# ArgoCD처럼 클러스터 리소스를 관리하는 컨트롤러용
apiVersion: v1
kind: ServiceAccount
metadata:
name: resource-watcher
namespace: platform
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: resource-watcher
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: resource-watcher
subjects:
- kind: ServiceAccount
name: resource-watcher
namespace: platform
roleRef:
kind: ClusterRole
name: resource-watcher
apiGroup: rbac.authorization.k8s.io
5. RBAC 검증
# 특정 사용자의 권한 확인
kubectl auth can-i get pods --namespace team-a-dev --as alice@company.com
kubectl auth can-i delete secrets --namespace production --as alice@company.com
# 현재 내 권한 전체 확인
kubectl auth can-i --list --namespace team-a-dev
# ServiceAccount 권한 확인
kubectl auth can-i get deployments \
--as system:serviceaccount:platform:resource-watcher
6. 실전 네임스페이스 초기화 스크립트
#!/bin/bash
# init-namespace.sh <team> <env>
TEAM=$1
ENV=$2
NS="${TEAM}-${ENV}"
kubectl create namespace $NS
kubectl label namespace $NS team=$TEAM environment=$ENV
kubectl apply -f - <<EOF
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: $NS
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "30"
EOF
kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: $NS
subjects:
- kind: Group
name: ${TEAM}-developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
EOF
echo "Namespace $NS initialized."
정리
| 설계 요소 | 핵심 원칙 |
|---|---|
| Namespace | 팀 또는 환경 기준으로 분리, 기본값 정의 |
| ResourceQuota | 네임스페이스별 CPU/메모리/오브젝트 상한 |
| LimitRange | 리소스 미명시 Pod에 기본값 강제 |
| RBAC | 최소 권한, Secret 읽기 금지 기본 |
| ServiceAccount | API 접근 불필요 시 토큰 마운트 비활성화 |
다음 편에서는 워크로드 패턴 선택을 다룹니다. Deployment, StatefulSet, DaemonSet, Job/CronJob을 언제 쓰는지 기준을 정리합니다.