TestForge Blog
← 전체 포스트

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 읽기 금지 기본
ServiceAccountAPI 접근 불필요 시 토큰 마운트 비활성화

다음 편에서는 워크로드 패턴 선택을 다룹니다. Deployment, StatefulSet, DaemonSet, Job/CronJob을 언제 쓰는지 기준을 정리합니다.