Kubernetes 클러스터 보안을 위한 필수 RBAC 모범 사례

Kubernetes RBAC 모범 사례, 최소 권한 Role 예제, 서비스 계정 범위 지정, 그리고 더 안전한 클러스터를 위한 감사 점검 방법을 알아보세요.

Kubernetes 클러스터 보안을 위한 필수 RBAC 모범 사례

Kubernetes RBAC는 클러스터 내에서 누가 무엇을 할 수 있는지를 결정합니다. 하나의 광범위한 바인딩이 손상된 계정이 시크릿을 읽거나, 워크로드를 수정하거나, 클러스터 리소스를 장악할 수 있게 만들 수 있습니다.

이 가이드는 핵심 RBAC 객체를 설명하고, 실제 작동 예제를 보여주며, 시간이 지나도 접근 권한이 표류하지 않도록 유지하는 검토 습관을 알려줍니다.

Kubernetes RBAC 기본 이해

Kubernetes의 RBAC는 개별 사용자 또는 서비스 계정의 역할에 기반하여 Kubernetes 리소스에 대한 접근을 규제하는 인가 메커니즘입니다. 이는 중요한 방어 계층으로, 오직 인가된 엔터티만이 특정 리소스에 대해 특정 작업을 수행할 수 있도록 보장합니다.

핵심적으로 RBAC는 네 가지 주요 Kubernetes 객체 유형에 의존합니다:

  • Role: Role특정 네임스페이스 내에서 적용되는 권한 집합입니다. 이는 어떤 리소스(예: pods, deployments, services, secrets)에 대해 어떤 동작(verbs: get, list, create, update, delete 등)을 수행할 수 있는지 정의합니다. 예를 들어, Roledevelopment 네임스페이스에서 podsdeployments를 읽을 수 있는 권한을 부여할 수 있습니다.
  • ClusterRole: Role과 유사하지만, ClusterRole클러스터 전체 또는 네임스페이스가 없는 리소스(예: nodes, persistentvolumes)에 적용되는 권한을 정의합니다. ClusterRole모든 네임스페이스에 걸쳐 네임스페이스가 있는 리소스에 대한 권한도 정의할 수 있습니다. 예를 들어, ClusterRole은 클러스터의 모든 nodes를 나열할 수 있도록 허용할 수 있습니다.
  • RoleBinding: RoleBindingRole(또는 네임스페이스 범위로 적용된 ClusterRole)에 정의된 권한을 사용자, 그룹 또는 서비스 계정에 부여합니다. 이는 항상 특정 네임스페이스 내에서 작동합니다.
  • ClusterRoleBinding: ClusterRoleBindingClusterRole에 정의된 권한을 사용자, 그룹 또는 서비스 계정에 부여하며, 이러한 권한을 클러스터 전체에 적용합니다.

이러한 객체들은 함께 관리자가 강력하고 세분화된 접근 제어 시스템을 구축할 수 있게 합니다. 사용자 또는 애플리케이션(서비스 계정으로 표현됨)이 작업을 수행하려고 할 때, Kubernetes는 기존의 RoleBindingsClusterRoleBindings를 평가하여 요청된 작업이 허용되는지 결정합니다.

RBAC로 최소 권한 원칙 구현

정보 보안의 핵심 원칙은 최소 권한 원칙입니다. 사용자, 프로그램 또는 프로세스는 작업을 수행하는 데 필요한 권한만 받아야 합니다. Kubernetes에서 지나치게 허용적인 역할은 작은 침해가 클러스터 전체 문제로 확대되는 일반적인 경로입니다.

세분화된 권한 정의

RBAC 정책을 작성할 때 필요한 정확한 작업과 리소스를 고려하세요:

  • 동사(Verbs): *(모든 동사)를 부여하는 대신 정확히 필요한 작업(get, list, watch, create, update, delete, patch, exec)을 지정하세요.
  • 리소스(Resources): 리소스(pods, deployments, secrets, configmaps)를 구체적으로 지정하세요. 절대적으로 필요하고 잘 정당화된 관리 역할이 아니라면 리소스에 *를 부여하지 마세요.
  • 리소스 이름(Resource Names): secrets와 같은 매우 민감한 리소스의 경우, 리소스 유형 내에서 특정 resourceNames에 대해 get과 같은 일부 동사를 제한할 수 있습니다. listwatch는 동일한 방식으로 단일 명명된 객체로 범위가 지정되지 않으므로 목록 스타일 접근에 resourceNames에 의존하지 마세요.
  • API 그룹(API Groups): 대부분의 Kubernetes 리소스는 API 그룹(예: apps, rbac.authorization.k8s.io, 코어 리소스의 경우 "")에 속합니다. 올바른 API 그룹을 지정하여 범위를 더욱 좁히세요.

네임스페이스 범위 지정

대부분의 애플리케이션 및 개발 팀의 경우 권한은 특정 네임스페이스로 제한되어야 합니다. 이러한 분리는 한 애플리케이션 또는 팀 환경의 침해가 자동으로 클러스터 전체 접근으로 이어지지 않도록 보장합니다. 가능할 때마다 항상 ClusterRoleClusterRoleBinding보다 RoleRoleBinding을 선호하세요.

실용적인 RBAC 구현: 예제

RBAC 정책을 생성하고 바인딩하는 몇 가지 실용적인 예제를 살펴보겠습니다.

예제 1: 특정 네임스페이스에 대한 개발자 접근

개발자가 전용 네임스페이스 dev-team-a에서 배포를 관리하고 로그를 봐야 한다고 가정해 보겠습니다. 다른 네임스페이스나 클러스터 전체 리소스에 접근할 수 없어야 합니다.

먼저, dev-team-a 네임스페이스에 개발자를 위한 Role을 정의합니다:

# dev-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev-team-a
  name: dev-deployer
rules:
- apiGroups: ["apps"] # Deployments용
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "delete", "patch"]
- apiGroups: [""] # Pods 및 Pod 로그용 코어 API 그룹
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

이 역할을 적용합니다:

kubectl apply -f dev-role.yaml

다음으로, 이 Role을 특정 사용자(예: 외부 ID 공급자를 통한 [email protected]) 또는 dev-team-a 네임스페이스 내의 서비스 계정에 바인딩합니다:

# dev-role-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: dev-team-a
  name: john-dev-deployer-binding
subjects:
- kind: User
  name: [email protected] # 이름은 대소문자를 구분합니다
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: dev-deployer
  apiGroup: rbac.authorization.k8s.io

이 바인딩을 적용합니다:

kubectl apply -f dev-role-binding.yaml

이제 [email protected]dev-team-a 네임스페이스 내에서만 배포를 관리하고 로그를 볼 수 있습니다. 예를 들어 kube-system에서 시크릿을 생성하거나 모든 노드를 나열할 수 없습니다.

예제 2: 시크릿에 접근하는 애플리케이션 서비스 계정

ServiceAccount로 실행되는 애플리케이션이 자체 네임스페이스에서 특정 시크릿을 읽어야 합니다.

먼저, 서비스 계정이 있는지 확인하거나 생성합니다:

# app-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: my-app-namespace
  name: my-app-service-account

이 서비스 계정을 적용합니다:

kubectl apply -f app-sa.yaml

다음으로, 특정 시크릿 읽기를 허용하는 Role을 정의합니다:

# secret-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: my-app-namespace
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["my-app-db-credentials"]
  verbs: ["get"]

이 역할을 적용합니다:

kubectl apply -f secret-reader-role.yaml

마지막으로, 이 Rolemy-app-service-account에 바인딩합니다:

# app-secret-reader-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: my-app-namespace
  name: my-app-secret-reader-binding
subjects:
- kind: ServiceAccount
  name: my-app-service-account
  namespace: my-app-namespace
roleRef:
  kind: Role
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

이 바인딩을 적용합니다:

kubectl apply -f app-secret-reader-binding.yaml

이제 애플리케이션은 지정된 시크릿만 읽을 수 있으며 그 외에는 아무것도 할 수 없습니다.

예제 3: 클러스터 관리자 역할 (주의 필요)

클러스터 전체 관리 역할은 극히 드물게 부여해야 합니다. 다음은 모니터링 도구에 필요할 수 있는 모든 노드를 나열하는 ClusterRole의 예입니다.

# node-viewer-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-viewer
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch"]

ClusterRole을 적용합니다:

kubectl apply -f node-viewer-clusterrole.yaml

그런 다음, ClusterRoleBinding을 사용하여 모니터링 서비스 계정에 바인딩합니다:

# monitoring-node-viewer-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-node-viewer-binding
subjects:
- kind: ServiceAccount
  name: monitoring-sa
  namespace: monitoring
roleRef:
  kind: ClusterRole
  name: node-viewer
  apiGroup: rbac.authorization.k8s.io

이 바인딩을 적용합니다:

kubectl apply -f monitoring-node-viewer-binding.yaml

경고: 사람 사용자에 대한 ClusterRoleClusterRoleBinding은 매우 주의하세요. 실제 클러스터 관리자와 특정 인프라 서비스 계정으로 사용을 제한하세요.

필수 RBAC 모범 사례

이러한 모범 사례를 준수하면 클러스터의 보안 태세가 크게 향상됩니다:

  1. 최소 권한 원칙(PoLP) 적용:

    • 필요한 최소 권한만 부여하세요. 모든 권한을 신중히 검토하세요.
    • 가능하면 resourcesverbs에 와일드카드(*)를 피하세요. 사용하는 경우 정당화하고 가능한 한 좁게 범위를 지정하세요.
    • 역할에서 resourceNames를 사용하여 민감한 리소스(예: secrets)에 대한 접근을 제한하세요.
  2. 분리를 위해 네임스페이스 사용:

    • 애플리케이션과 팀을 별도의 네임스페이스로 구성하세요.
    • 이러한 네임스페이스 내에서 권한을 부여하려면 기본적으로 RoleRoleBinding을 사용하세요.
  3. ClusterRoles보다 Roles 선호:

    • 권한이 진정으로 클러스터 전체에 필요한 경우(예: 노드 관리, 사용자 정의 리소스 정의, 특정 모니터링 에이전트)에만 ClusterRoleClusterRoleBinding을 사용하세요.
    • 대부분의 애플리케이션별 권한은 네임스페이스 범위여야 합니다.
  4. 정기적으로 RBAC 정책 감사 및 검토:

    • RBAC 정책은 시간이 지남에 따라 표류할 수 있습니다. 누가 어떤 접근 권한을 가지고 있는지 정기적으로 검토하세요.
    • kubectl auth can-i와 같은 도구를 사용하여 특정 사용자/서비스 계정의 권한을 테스트하세요.
    # '[email protected]'이 'dev-team-a'에서 pods를 가져올 수 있는지 확인
    kubectl auth can-i get pods --namespace=dev-team-a [email protected]
    
    # 'monitoring-sa'가 노드를 나열할 수 있는지 확인(클러스터 전체)
    kubectl auth can-i list nodes --as=system:serviceaccount:monitoring:monitoring-sa
    
    • 포괄적인 RBAC 감사를 위해 타사 도구 또는 사용자 정의 스크립트를 고려하세요.
  5. 관리 역할 분리:

    • 개발자나 애플리케이션 서비스 계정에 cluster-admin 권한을 절대 부여하지 마세요.
    • 필요한 상승된 권한만 있는 특정 관리 ClusterRoles(예: cluster-reader, node-reader)를 생성하세요.
  6. 애플리케이션에 서비스 계정 활용:

    • 클러스터 내에서 실행되는 애플리케이션은 ServiceAccounts를 사용하여 Kubernetes API와 상호 작용해야 합니다.
    • 각 애플리케이션 또는 마이크로서비스는 이상적으로 최소 권한을 가진 자체 전용 ServiceAccount를 가져야 합니다.
    • Kubernetes API 접근이 필요하지 않은 Pod의 경우, Pod 또는 서비스 계정에서 automountServiceAccountToken: false를 설정하세요.
  7. 외부 ID 관리와 통합:

    • 사람 사용자의 경우, 인증 및 그룹 관리를 위해 Kubernetes를 외부 ID 공급자(예: OIDC, LDAP, Active Directory)와 통합하세요.
    • 더 쉬운 관리를 위해 외부 그룹을 Kubernetes RoleBindings 또는 ClusterRoleBindings에 매핑하세요.
  8. GitOps로 RBAC 관리 자동화:

    • RBAC 정책을 코드로 취급하세요. 버전 제어 저장소(Git)에 저장하세요.
    • GitOps 원칙을 사용하여 RBAC 구성을 관리 및 배포하여 일관성, 추적 가능성 및 더 쉬운 롤백을 보장하세요.
  9. 감사 로그를 통해 RBAC 이벤트 모니터링:

    • Kubernetes 감사 로깅을 활성화 및 구성하여 누가, 언제, 어떤 작업을 수행했는지 포함한 API 요청을 추적하세요.
    • 감사 로그를 정기적으로 검토하여 무단 접근 시도 또는 RBAC 관련 의심스러운 활동을 감지하세요.
  10. 정기적으로 Kubernetes 업데이트:

    • 보안 패치 및 RBAC 개선 사항을 포함한 개선 사항을 활용하려면 최신 Kubernetes 버전을 유지하세요.

일반적인 함정과 이를 피하는 방법

  • 지나치게 허용적인 와일드카드: apiGroups: ["*"], resources: ["*"] 또는 verbs: ["*"]를 부여하는 것은 주요 보안 위험입니다. 항상 명시적으로 지정하세요.
  • 기본 cluster-admin 사용: 일상적인 운영에 system:masters 그룹이나 cluster-admin ClusterRole을 사용하거나 비관리자 사용자에게 할당하지 마세요. 둘 중 하나는 클러스터에 대한 광범위한 제어권을 제공합니다.
  • automountServiceAccountToken 무시: 많은 클러스터에서 자동 마운트를 비활성화하지 않으면 Pod는 서비스 계정 토큰을 받습니다. Pod가 Kubernetes API와 상호 작용할 필요가 없는 경우, Pod 사양 또는 서비스 계정 정의에서 automountServiceAccountToken: false를 설정하여 공격 표면을 줄이세요.
  • 감사 부족: 정기적인 검토 없이 RBAC 정책은 클러스터 요구 사항이 발전함에 따라 구식이 되거나 지나치게 허용적이 될 수 있습니다. 검토 프로세스를 구현하세요.
  • RoleClusterRole 혼동: 범위를 오해하면 네임스페이스 범위 접근만 의도했을 때 클러스터 전체 접근을 부여할 수 있습니다.

핵심 요약

RBAC는 지루하고 구체적으로 유지할 때 가장 잘 작동합니다: 애플리케이션 팀을 위한 네임스페이스 역할, 좁은 서비스 계정 권한, 검토 없는 와일드카드 금지, 정기적인 kubectl auth can-i 확인. 모든 바인딩을 프로덕션 코드로 취급하세요. Kubernetes 클러스터에서는 실제로 그렇기 때문입니다.