1 - 클라우드 네이티브 보안 개요

클라우드 네이티브 보안 관점에서 쿠버네티스 보안을 생각해보기 위한 모델

이 개요는 클라우드 네이티브 보안의 맥락에서 쿠버네티스 보안에 대한 생각의 모델을 정의한다.

클라우드 네이티브 보안의 4C

보안은 계층으로 생각할 수 있다. 클라우드 네이티브 보안의 4C는 클라우드(Cloud), 클러스터(Cluster), 컨테이너(Container)와 코드(Code)이다.

클라우드 네이티브 보안의 4C

클라우드 네이티브 보안 모델의 각 계층은 다음의 가장 바깥쪽 계층을 기반으로 한다. 코드 계층은 강력한 기본(클라우드, 클러스터, 컨테이너) 보안 계층의 이점을 제공한다. 코드 수준에서 보안을 처리하여 기본 계층의 열악한 보안 표준을 보호할 수 없다.

클라우드

여러 면에서 클라우드(또는 공동 위치 서버, 또는 기업의 데이터 센터)는 쿠버네티스 클러스터 구성을 위한 신뢰 컴퓨팅 기반(trusted computing base) 이다. 클라우드 계층이 취약하거나 취약한 방식으로 구성된 경우 이 기반 위에서 구축된 구성 요소가 안전하다는 보장은 없다. 각 클라우드 공급자는 해당 환경에서 워크로드를 안전하게 실행하기 위한 보안 권장 사항을 제시한다.

클라우드 공급자 보안

자신의 하드웨어 또는 다른 클라우드 공급자에서 쿠버네티스 클러스터를 실행 중인 경우, 보안 모범 사례는 설명서를 참고한다. 다음은 인기있는 클라우드 공급자의 보안 문서 중 일부에 대한 링크이다.

클라우드 공급자 보안
IaaS 공급자링크
Alibaba Cloudhttps://www.alibabacloud.com/trust-center
Amazon Web Serviceshttps://aws.amazon.com/security
Google Cloud Platformhttps://cloud.google.com/security
Huawei Cloudhttps://www.huaweicloud.com/securecenter/overallsafety
IBM Cloudhttps://www.ibm.com/cloud/security
Microsoft Azurehttps://docs.microsoft.com/en-us/azure/security/azure-security
Oracle Cloud Infrastructurehttps://www.oracle.com/security
VMware vSpherehttps://www.vmware.com/security/hardening-guides.html

인프라스트럭처 보안

쿠버네티스 클러스터에서 인프라 보안을 위한 제안은 다음과 같다.

인프라스트럭처 보안
쿠버네티스 인프라에서 고려할 영역추천
API 서버에 대한 네트워크 접근(컨트롤 플레인)쿠버네티스 컨트롤 플레인에 대한 모든 접근은 인터넷에서 공개적으로 허용되지 않으며 클러스터 관리에 필요한 IP 주소 집합으로 제한된 네트워크 접근 제어 목록에 의해 제어된다.
노드에 대한 네트워크 접근(노드)지정된 포트의 컨트롤 플레인에서 (네트워크 접근 제어 목록을 통한) 연결을 허용하고 NodePort와 LoadBalancer 유형의 쿠버네티스 서비스에 대한 연결을 허용하도록 노드를 구성해야 한다. 가능하면 이러한 노드가 공용 인터넷에 완전히 노출되어서는 안된다.
클라우드 공급자 API에 대한 쿠버네티스 접근각 클라우드 공급자는 쿠버네티스 컨트롤 플레인 및 노드에 서로 다른 권한 집합을 부여해야 한다. 관리해야하는 리소스에 대해 최소 권한의 원칙을 따르는 클라우드 공급자의 접근 권한을 클러스터에 구성하는 것이 가장 좋다. Kops 설명서는 IAM 정책 및 역할에 대한 정보를 제공한다.
etcd에 대한 접근etcd(쿠버네티스의 데이터 저장소)에 대한 접근은 컨트롤 플레인으로만 제한되어야 한다. 구성에 따라 TLS를 통해 etcd를 사용해야 한다. 자세한 내용은 etcd 문서에서 확인할 수 있다.
etcd 암호화가능한 한 모든 스토리지를 암호화하는 것이 좋은 방법이며, etcd는 전체 클러스터(시크릿 포함)의 상태를 유지하고 있기에 특히 디스크는 암호화되어 있어야 한다.

클러스터

쿠버네티스 보안에는 다음의 두 가지 영역이 있다.

  • 설정 가능한 클러스터 컴포넌트의 보안
  • 클러스터에서 실행되는 애플리케이션의 보안

클러스터의 컴포넌트

우발적이거나 악의적인 접근으로부터 클러스터를 보호하고, 모범 사례에 대한 정보를 채택하기 위해서는 클러스터 보안에 대한 조언을 읽고 따른다.

클러스터 내 컴포넌트(애플리케이션)

애플리케이션의 공격 영역에 따라, 보안의 특정 측면에 중점을 둘 수 있다. 예를 들어, 다른 리소스 체인에 중요한 서비스(서비스 A)와 리소스 소진 공격에 취약한 별도의 작업 부하(서비스 B)를 실행하는 경우, 서비스 B의 리소스를 제한하지 않으면 서비스 A가 손상될 위험이 높다. 다음은 쿠버네티스에서 실행되는 워크로드를 보호하기 위한 보안 문제 및 권장 사항이 나와 있는 표이다.

워크로드 보안에서 고려할 영역추천
RBAC 인증(쿠버네티스 API에 대한 접근)https://kubernetes.io/docs/reference/access-authn-authz/rbac/
인증https://kubernetes.io/ko/docs/concepts/security/controlling-access/
애플리케이션 시크릿 관리(및 유휴 상태에서의 etcd 암호화 등)https://kubernetes.io/ko/docs/concepts/configuration/secret/
https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
파드가 파드 시큐리티 폴리시를 만족하는지 확인하기https://kubernetes.io/docs/concepts/security/pod-security-standards/#policy-instantiation
서비스 품질(및 클러스터 리소스 관리)https://kubernetes.io/ko/docs/tasks/configure-pod-container/quality-service-pod/
네트워크 정책https://kubernetes.io/ko/docs/concepts/services-networking/network-policies/
쿠버네티스 인그레스를 위한 TLShttps://kubernetes.io/ko/docs/concepts/services-networking/ingress/#tls

컨테이너

컨테이너 보안은 이 가이드의 범위를 벗어난다. 다음은 일반적인 권장사항과 이 주제에 대한 링크이다.

컨테이너에서 고려할 영역추천
컨테이너 취약점 스캔 및 OS에 종속적인 보안이미지 빌드 단계의 일부로 컨테이너에 알려진 취약점이 있는지 검사해야 한다.
이미지 서명 및 시행컨테이너 이미지에 서명하여 컨테이너의 내용에 대한 신뢰 시스템을 유지한다.
권한있는 사용자의 비허용컨테이너를 구성할 때 컨테이너의 목적을 수행하는데 필요한 최소 권한을 가진 사용자를 컨테이너 내에 만드는 방법에 대해서는 설명서를 참조한다.
더 강력한 격리로 컨테이너 런타임 사용더 강력한 격리를 제공하는 컨테이너 런타임 클래스를 선택한다.

코드

애플리케이션 코드는 가장 많은 제어를 할 수 있는 주요 공격 영역 중 하나이다. 애플리케이션 코드 보안은 쿠버네티스 보안 주제를 벗어나지만, 애플리케이션 코드를 보호하기 위한 권장 사항은 다음과 같다.

코드 보안

코드 보안
코드에서 고려할 영역추천
TLS를 통한 접근코드가 TCP를 통해 통신해야 한다면, 미리 클라이언트와 TLS 핸드 셰이크를 수행한다. 몇 가지 경우를 제외하고, 전송 중인 모든 것을 암호화한다. 한 걸음 더 나아가, 서비스 간 네트워크 트래픽을 암호화하는 것이 좋다. 이것은 인증서를 가지고 있는 두 서비스의 양방향 검증을 실행하는 mTLS(상호 TLS 인증)를 통해 수행할 수 있다.
통신 포트 범위 제한이 권장사항은 당연할 수도 있지만, 가능하면 통신이나 메트릭 수집에 꼭 필요한 서비스의 포트만 노출시켜야 한다.
타사 종속성 보안애플리케이션의 타사 라이브러리를 정기적으로 스캔하여 현재 알려진 취약점이 없는지 확인하는 것이 좋다. 각 언어에는 이런 검사를 자동으로 수행하는 도구를 가지고 있다.
정적 코드 분석대부분 언어에는 잠재적으로 안전하지 않은 코딩 방법에 대해 코드 스니펫을 분석할 수 있는 방법을 제공한다. 가능한 언제든지 일반적인 보안 오류에 대해 코드베이스를 스캔할 수 있는 자동화된 도구를 사용하여 검사를 한다. 도구는 다음에서 찾을 수 있다. https://owasp.org/www-community/Source_Code_Analysis_Tools
동적 탐지 공격잘 알려진 공격 중 일부를 서비스에 테스트할 수 있는 자동화된 몇 가지 도구가 있다. 여기에는 SQL 인젝션, CSRF 및 XSS가 포함된다. 가장 널리 사용되는 동적 분석 도구는 OWASP Zed Attack 프록시이다.

다음 내용

쿠버네티스 보안 주제에 관련한 내용들을 배워보자.

2 - 파드 시큐리티 스탠다드

파드 시큐리티 스탠다드에 정의된 여러 가지 정책 레벨에 대한 세부사항

파드 시큐리티 스탠다드에서는 보안 범위를 넓게 다루기 위해 세 가지 정책을 정의한다. 이러한 정책은 점증적이며 매우 허용적인 것부터 매우 제한적인 것까지 있다. 이 가이드는 각 정책의 요구사항을 간략히 설명한다.

프로필설명
특권(Privileged)무제한 정책으로, 가장 넓은 범위의 권한 수준을 제공한다. 이 정책은 알려진 권한 상승(privilege escalations)을 허용한다.
기본(Baseline)알려진 권한 상승을 방지하는 최소한의 제한 정책이다. 기본(최소로 명시된) 파드 구성을 허용한다.
제한(Restricted)엄격히 제한된 정책으로 현재 파드 하드닝 모범 사례를 따른다.

프로필 세부사항

특권(Privileged)

특권 정책은 의도적으로 열려있으며 전적으로 제한이 없다. 이러한 종류의 정책은 권한이 있고 신뢰할 수 있는 사용자가 관리하는 시스템 및 인프라 수준의 워크로드를 대상으로 한다.

특권 정책은 제한 사항이 없는 것으로 정의한다. 기본으로 허용하는 메커니즘(예를 들면, gatekeeper)은 당연히 특권 정책일 수 있다. 반대로, 기본적으로 거부하는 메커니즘(예를 들면, 파드 시큐리티 폴리시)의 경우 특권 정책은 모든 제한 사항을 비활성화해야 한다.

기본(Baseline)

기본 정책은 알려진 권한 상승을 방지하면서 일반적인 컨테이너 워크로드에 대해 정책 채택을 쉽게 하는 것을 목표로 한다. 이 정책은 일반적인(non-critical) 애플리케이션의 운영자 및 개발자를 대상으로 한다. 아래 명시한 제어 방식은 다음과 같이 강행되거나 금지되어야 한다.

기본(Baseline) 정책 명세서
제어정책
호스트 프로세스

윈도우 파드는 호스트 프로세스 컨테이너를 실행할 권한을 제공하며, 이는 윈도우 노드에 대한 특권 접근을 가능하게 한다. 기본 정책에서의 호스트에 대한 특권 접근은 허용되지 않는다.

기능 상태: Kubernetes v1.23 [beta]

제한된 필드

  • spec.securityContext.windowsOptions.hostProcess
  • spec.containers[*].securityContext.windowsOptions.hostProcess
  • spec.initContainers[*].securityContext.windowsOptions.hostProcess
  • spec.ephemeralContainers[*].securityContext.windowsOptions.hostProcess

허용된 값

  • Undefined/nil
  • false
호스트 네임스페이스

호스트 네임스페이스 공유는 금지된다.

제한된 필드

  • spec.hostNetwork
  • spec.hostPID
  • spec.hostIPC

허용된 값

  • Undefined/nil
  • false
특권 컨테이너

특권 파드(Privileged Pods)는 대부분의 보안 메커니즘을 비활성화하므로 금지된다.

제한된 필드

  • spec.containers[*].securityContext.privileged
  • spec.initContainers[*].securityContext.privileged
  • spec.ephemeralContainers[*].securityContext.privileged

허용된 값

  • Undefined/nil
  • false
기능(Capabilities)

아래 명시되지 않은 부가 기능을 추가하는 작업은 금지된다.

제한된 필드

  • spec.containers[*].securityContext.capabilities.add
  • spec.initContainers[*].securityContext.capabilities.add
  • spec.ephemeralContainers[*].securityContext.capabilities.add

허용된 값

  • Undefined/nil
  • AUDIT_WRITE
  • CHOWN
  • DAC_OVERRIDE
  • FOWNER
  • FSETID
  • KILL
  • MKNOD
  • NET_BIND_SERVICE
  • SETFCAP
  • SETGID
  • SETPCAP
  • SETUID
  • SYS_CHROOT
호스트 경로(hostPath) 볼륨

호스트 경로 볼륨은 금지된다.

제한된 필드

  • spec.volumes[*].hostPath

허용된 값

  • Undefined/nil
호스트 포트

호스트 포트는 허용되지 않아야 하며, 또는 적어도 알려진 목록 범위내로 제한되어야 한다.

제한된 필드

  • spec.containers[*].ports[*].hostPort
  • spec.initContainers[*].ports[*].hostPort
  • spec.ephemeralContainers[*].ports[*].hostPort

허용된 값

  • Undefined/nil
  • Known list
  • 0
AppArmor

지원되는 호스트에서는, runtime/default AppArmor 프로필이 기본으로 적용된다. 기본 정책은 기본 AppArmor 프로필이 오버라이드 및 비활성화되는 것을 방지해야 하며, 또는 허용된 프로필에 한해서만 오버라이드 되도록 제한해야 한다.

제한된 필드

  • metadata.annotations["container.apparmor.security.beta.kubernetes.io/*"]

허용된 값

  • Undefined/nil
  • runtime/default
  • localhost/*
SELinux

SELinux 타입을 설정하는 것은 제한되며, 맞춤 SELinux 사용자 및 역할 옵션을 설정하는 것은 금지되어 있다.

제한된 필드

  • spec.securityContext.seLinuxOptions.type
  • spec.containers[*].securityContext.seLinuxOptions.type
  • spec.initContainers[*].securityContext.seLinuxOptions.type
  • spec.ephemeralContainers[*].securityContext.seLinuxOptions.type

허용된 값

  • Undefined/""
  • container_t
  • container_init_t
  • container_kvm_t

제한된 필드

  • spec.securityContext.seLinuxOptions.user
  • spec.containers[*].securityContext.seLinuxOptions.user
  • spec.initContainers[*].securityContext.seLinuxOptions.user
  • spec.ephemeralContainers[*].securityContext.seLinuxOptions.user
  • spec.securityContext.seLinuxOptions.role
  • spec.containers[*].securityContext.seLinuxOptions.role
  • spec.initContainers[*].securityContext.seLinuxOptions.role
  • spec.ephemeralContainers[*].securityContext.seLinuxOptions.role

허용된 값

  • Undefined/""
/proc 마운트 타입

기본 /proc 마스크는 공격 가능 영역을 최소화하기 위해 설정되고 필수이다.

제한된 필드

  • spec.containers[*].securityContext.procMount
  • spec.initContainers[*].securityContext.procMount
  • spec.ephemeralContainers[*].securityContext.procMount

허용된 값

  • Undefined/nil
  • Default
Seccomp

Seccomp 프로필은 Unconfined으로 설정하면 안된다.

제한된 필드

  • spec.securityContext.seccompProfile.type
  • spec.containers[*].securityContext.seccompProfile.type
  • spec.initContainers[*].securityContext.seccompProfile.type
  • spec.ephemeralContainers[*].securityContext.seccompProfile.type

허용된 값

  • Undefined/nil
  • RuntimeDefault
  • Localhost
Sysctls

Sysctls는 보안 메커니즘을 비활성화 시키거나 호스트에 위치한 모든 컨테이너에 영향을 미칠 수 있으며, 허용된 "안전한" 서브넷을 제외한 곳에서는 허용되지 않아야 한다. 컨테이너 또는 파드 네임스페이스에 속해 있거나, 같은 노드 내의 다른 파드 및 프로세스와 격리된 상황에서만 sysctl 사용이 안전하다고 간주한다.

제한된 필드

  • spec.securityContext.sysctls[*].name

허용된 값

  • Undefined/nil
  • kernel.shm_rmid_forced
  • net.ipv4.ip_local_port_range
  • net.ipv4.ip_unprivileged_port_start
  • net.ipv4.tcp_syncookies
  • net.ipv4.ping_group_range

제한(Restricted)

제한 정책은 일부 호환성을 희생하면서 현재 사용되고 있는 파드 하드닝 모범 사례 시행하는 것을 목표로 한다. 보안이 중요한 애플리케이션의 운영자 및 개발자는 물론 신뢰도가 낮은 사용자도 대상으로 한다. 아래에 나열된 제어 방식은 강제되거나 금지되어야 한다.

제한 정책 명세서
제어정책
기본 프로필에 해당하는 모든 요소
볼륨 타입

제한 정책은 다음과 같은 볼륨 타입만 허용한다.

제한된 필드

  • spec.volumes[*]

허용된 값

spec.volumes[*] 목록에 속한 모든 아이템은 다음 필드 중 하나를 null이 아닌 값으로 설정해야 한다.
  • spec.volumes[*].configMap
  • spec.volumes[*].csi
  • spec.volumes[*].downwardAPI
  • spec.volumes[*].emptyDir
  • spec.volumes[*].ephemeral
  • spec.volumes[*].persistentVolumeClaim
  • spec.volumes[*].projected
  • spec.volumes[*].secret
권한 상승(v1.8+)

권한 상승(예를 들어, set-user-ID 또는 set-group-ID 파일 모드를 통한)은 허용되지 않아야 한다. v1.25+에서는 리눅스 전용 정책이다.(spec.os.name != windows)

제한된 필드

  • spec.containers[*].securityContext.allowPrivilegeEscalation
  • spec.initContainers[*].securityContext.allowPrivilegeEscalation
  • spec.ephemeralContainers[*].securityContext.allowPrivilegeEscalation

허용된 값

  • false
루트가 아닌 권한으로 실행

컨테이너는 루트가 아닌 사용자 권한으로 실행되어야 한다.

제한된 필드

  • spec.securityContext.runAsNonRoot
  • spec.containers[*].securityContext.runAsNonRoot
  • spec.initContainers[*].securityContext.runAsNonRoot
  • spec.ephemeralContainers[*].securityContext.runAsNonRoot

허용된 값

  • true
pod-level에서 spec.securityContext.runAsNonRoottrue로 설정되면 컨테이너 필드는 undefined/nil로 설정될 수 있다.
루트가 아닌 사용자로 실행(v1.23+)

컨테이너에서는 runAsUser 값을 0으로 설정하지 않아야 한다.

제한된 필드

  • spec.securityContext.runAsUser
  • spec.containers[*].securityContext.runAsUser
  • spec.initContainers[*].securityContext.runAsUser
  • spec.ephemeralContainers[*].securityContext.runAsUser

허용된 값

  • any non-zero value
  • undefined/null
Seccomp(v1.19+)

Seccomp 프로필은 다음과 같은 값으로 설정되어야 한다.Unconfined 프로필 및 프로필의 absence는 금지되어 있다. v1.25+에서는 리눅스 전용 정책이다.(spec.os.name != windows)

제한된 필드

  • spec.securityContext.seccompProfile.type
  • spec.containers[*].securityContext.seccompProfile.type
  • spec.initContainers[*].securityContext.seccompProfile.type
  • spec.ephemeralContainers[*].securityContext.seccompProfile.type

허용된 값

  • RuntimeDefault
  • Localhost
pod-level의 spec.securityContext.seccompProfile.type 필드가 적절하게 설정되면, 컨테이너 필드는 undefined/nil로 설정될 수 있다. 모든 컨테이너 레벨 필드가 설정되어 있다면, pod-level 필드는 undefined/nil로 설정될 수 있다.
능력(Capabilities) (v1.22+)

컨테이너는 ALL 능력을 내려놓아야 하며, NET_BIND_SERVICE 능력을 다시 추가하기 위한 목적일 때만 허용되어야 한다. v1.25+에서는 리눅스 전용 정책이다.(spec.os.name != windows)

제한된 필드

  • spec.containers[*].securityContext.capabilities.drop
  • spec.initContainers[*].securityContext.capabilities.drop
  • spec.ephemeralContainers[*].securityContext.capabilities.drop

허용된 값

  • ALL을 포함하고 있는 모든 능력 리스트

제한된 필드

  • spec.containers[*].securityContext.capabilities.add
  • spec.initContainers[*].securityContext.capabilities.add
  • spec.ephemeralContainers[*].securityContext.capabilities.add

허용된 값

  • Undefined/nil
  • NET_BIND_SERVICE

정책 초기화

정책 초기화에서의 디커플링(Decoupling) 정책 정의는, 내재되어 있는 시행 메커니즘과 별개로 클러스터 사이의 공통된 이해와 일관된 정책 언어 사용을 가능하게끔 한다.

메커니즘이 발달함에 따라, 아래와 같이 정책별로 정의가 될 것이다. 개별 정책에 대한 시행 방식은 여기서 정의하고 있지 않는다.

파드 시큐리티 어드미션 컨트롤러

대안

쿠버네티스 환경에서 정책을 시행하기 위한 대안이 개발되고 있으며 다음은 몇 가지 예시이다.

파드 OS 필드

쿠버네티스에서는 리눅스 또는 윈도우를 실행하는 노드를 사용할 수 있다. 하나의 클러스터에 두 종류의 노드를 혼합하여 사용할 수 있다. 윈도우 환경 쿠버네티스는 리눅스 기반 워크로드와 비교하였을 때 몇 가지 제한사항 및 차별점이 있다. 구체적으로 말하자면, 대부분의 파드 securityContext 필드는 윈도우 환경에서 효과가 없다.

제한 파드의 시큐리티 스탠다드 변화

쿠버네티스 v1.25에서 나타난 또 다른 중요 변화는, 제한 파드 시큐리티가 pod.spec.os.name 필드를 사용하도록 업데이트 되었다는 것이다. 특정 OS에 특화된 일부 정책은 OS 이름에 근거하여 다른 OS에 대해서는 완화될 수 있다

특정 OS 정책 제어

spec.os.name의 값이 windows가 아닐 시에만 다음 제어 항목에 대한 제한 사항이 요구된다.

  • 권한 상승
  • Seccomp
  • Linux 기능

FAQ

왜 특권 프로필과 기본 프로필 사이의 프로필은 없는 것인가?

여기서 정의된 세 가지 프로필은 가장 높은 보안에서(제한 프로필) 가장 낮은 보안까지(특권 프로필) 명백한 선형 관계를 가지며 넓은 범위의 워크로드를 다룬다. 기본 정책을 넘는 요청 권한은 일반적으로 애플리케이션 전용에 속하므로 이러한 틈새시장에 대해서는 표준 프로필을 제공하지 않는다. 이 경우에는 항상 특권 프로필을 사용해야 한다는 주장은 아니지만, 해당 영역의 정책은 케이스 별로 정의되어야 한다는 것이다.

이외 프로필이 분명히 필요하다면 SIG Auth는 향후에 이러한 입장을 재고할 수 있다.

시큐리티 컨텍스트와 시큐리티 프로필의 차이점은 무엇인가?

시큐리티 컨텍스트는 파드 및 컨테이너를 런타임에 설정한다. 시큐리티 컨텍스트는 파드 매니페스트 내 파드 및 컨테이너 명세의 일부로 정의되고 컨테이너 런타임에 파라미터로 제공한다.

시큐리티 프로필은 컨트롤 플레인 메커니즘으로, 시큐리티 컨텍스트의 상세 설정을 비롯하여 시큐리티 컨텍스트 외부의 다른 관련된 파라미터도 적용한다. 2021년 7월부로, 파드 시큐리티 폴리시는 내장된 파드 시큐리티 어드미션 컨트롤러에 의해 대체되어 사용이 중단되었다.

샌드박스 파드는 어떠한가?

현재로서는, 파드가 샌드박스 특성을 가지는지 제어할 수 있는 API 표준이 존재하지 않는다. 샌드박스 파드는 샌드박스 런타임(예를 들면, gVisor 혹은 Kata 컨테이너)을 통해 식별할 수 있지만, 샌드박스 런타임이 무엇인지에 대한 표준 정의는 없는 상태이다.

샌드박스 워크로드가 필요로하는 보호물은 다른 워크로드와 다를 수 있다. 예를 들어, 내재된 커널과 분리된 워크로드에서는 제한된 특수 권한의 필요성이 적어진다. 이는 높아진 권한을 요구하는 워크로드가 분리될 수 있도록 허용한다.

추가적으로, 샌드박스 방식에 따라 샌드박스 워크로드에 대한 보호가 달라진다. 이와 같은 경우에는, 하나의 프로필만을 모든 샌드박스 워크로드에 대해 권장할 수 없다.

3 - 파드 시큐리티 어드미션

파드 보안을 적용할 수 있는 파드 시큐리티 어드미션 컨트롤러에 대한 개요
기능 상태: Kubernetes v1.25 [stable]

쿠버네티스 파드 시큐리티 스탠다드는 파드에 대해 서로 다른 격리 수준을 정의한다. 이러한 표준을 사용하면 파드의 동작을 명확하고 일관된 방식으로 제한하는 방법을 정의할 수 있다.

쿠버네티스는 파드 시큐리티 스탠다드를 적용하기 위해 내장된 파드 시큐리티 어드미션 컨트롤러를 제공한다. 파드 시큐리티의 제한은 파드가 생성될 때 네임스페이스 수준에서 적용된다.

내장된 파드 시큐리티 어드미션 적용

이 페이지는 쿠버네티스 v1.29에 대한 문서 일부이다. 다른 버전의 쿠버네티스를 실행 중인 경우, 해당 릴리즈에 대한 문서를 참고한다.

파드 시큐리티 수준

파드 시큐리티 어드미션은 파드의 시큐리티 컨텍스트 및 기타 관련 필드인 파드 시큐리티 스탠다드에 정의된 세가지 수준에 따라 요구사항을 적용한다: 특권(privileged), 기본(baseline) 그리고 제한(restricted). 이러한 요구사항에 대한 자세한 내용은 파드 시큐리티 스탠다드 페이지를 참고한다.

네임스페이스에 대한 파드 시큐리티 어드미션 레이블

이 기능이 활성화되거나 웹훅이 설치되면, 네임스페이스를 구성하여 각 네임스페이스에서 파드 보안에 사용할 어드미션 제어 모드를 정의할 수 있다. 쿠버네티스는 미리 정의된 파드 시큐리티 스탠다드 수준을 사용자가 네임스페이스에 정의하여 사용할 수 있도록 레이블 집합을 정의한다. 선택한 레이블은 잠재적인 위반이 감지될 경우 컨트롤 플레인이 취하는 조치를 정의한다.

파드 시큐리티 어드미션 모드
모드설명
강제(enforce)정책 위반 시 파드가 거부된다.
감사(audit)정책 위반이 감사 로그에 감사 어노테이션 이벤트로 추가되지만, 허용은 된다.
경고(warn)정책 위반이 사용자에게 드러나도록 경고를 트리거하지만, 허용은 된다.

네임스페이스는 일부 또는 모든 모드를 구성하거나, 모드마다 다른 수준을 설정할 수 있다.

각 모드에는, 사용되는 정책을 결정하는 두 개의 레이블이 존재한다.

# 모드별 단계 레이블은 모드에 적용할 정책 수준을 나타낸다.
#
# 모드(MODE)는 반드시 `강제(enforce)`, `감사(audit)` 혹은 `경고(warn)`중 하나여야 한다.
# 단계(LEVEL)는 반드시 `특권(privileged)`, `기본(baseline)`, or `제한(restricted)` 중 하나여야 한다.
pod-security.kubernetes.io/<MODE>: <LEVEL>

# 선택 사항: 특정 쿠버네티스 마이너 버전(예를 들어, v1.29)과 함께
# 제공된 버전에 정책을 고정하는 데 사용할 수 있는 모드별 버전 레이블
#
# 모드(MODE)는 반드시 `강제(enforce)`, `감사(audit)` 혹은 `경고(warn)`중 하나여야 한다.
# 버전(VERSION)은 반드시 올바른 쿠버네티스의 마이너(minor) 버전 혹은 '최신(latest)'하나여야 한다.
pod-security.kubernetes.io/<MODE>-version: <VERSION>

네임스페이스 레이블로 파드 시큐리티 스탠다드 적용하기 문서를 확인하여 사용 예시를 확인한다.

워크로드 리소스 및 파드 템플릿

파드는 디플로이먼트(Deployment)잡(Job)과 같은 워크로드 오브젝트 생성을 통해 간접적으로 생성되는 경우가 많다. 워크로드 오브젝트는 _파드 템플릿_을 정의하고 워크로드 리소스에 대한 컨트롤러는 해당 템플릿을 기반으로 파드를 생성한다. 위반을 조기에 발견할 수 있도록 감사 모드와 경고 모드가 모두 워크로드 리소스에 적용된다. 그러나 강제 모드에서는 워크로드 리소스에 적용되지 않으며, 결과가 되는 파드 오브젝트에만 적용된다.

면제 (exemptions)

지정된 네임스페이스와 관련된 정책으로 인해 금지된 파드 생성을 허용하기 위해 파드 보안 강제에서 면제 를 정의할 수 있다. 면제는 어드미션 컨트롤러 구성하기 에서 정적으로 구성할 수 있다.

면제는 명시적으로 열거해야 한다. 면제 기준을 충족하는 요청은 어드미션 컨트롤러에 의해 무시 된다. 면제 기준은 다음과 같다.

  • 사용자 이름(Usernames): 면제 인증된(혹은 사칭한) 사용자 이름을 가진 사용자의 요청은 무시된다.
  • 런타임 클래스 이름(RuntimeClassNames): 면제 런타임 클래스 이름을 지정하는 파드 및 워크로드 리소스는 무시된다.
  • 네임스페이스(Namespaces): 파드 및 워크로드 리소스는 면제 네임스페이스에서 무시된다.

다음 파드 필드에 대한 업데이트는 정책 검사에서 제외되므로, 파드 업데이트 요청이 이러한 필드만 변경하는 경우, 파드가 현재 정책 수준을 위반하더라도 거부되지 않는다.

  • seccomp 또는 AppArmor 어노테이션에 대한 변경 사항을 제외한 모든 메타데이터 업데이트.
    • seccomp.security.alpha.kubernetes.io/pod (사용 중단)
    • container.seccomp.security.alpha.kubernetes.io/* (사용 중단)
    • container.apparmor.security.beta.kubernetes.io/*
  • .spec.activeDeadlineSeconds 에 대해 유효한 업데이트
  • .spec.tolerations 에 대해 유효한 업데이트

다음 내용

4 - 파드 시큐리티 폴리시

파드시큐리티폴리시를 사용하는 것 대신, 다음 중 하나를 사용하거나 둘 다 사용하여 파드에 유사한 제한을 적용할 수 있다.

마이그레이션에 관한 설명이 필요하다면 파드시큐리티폴리시(PodSecurityPolicy)에서 빌트인 파드시큐리티어드미션컨트롤러(PodSecurity Admission Controller)로 마이그레이션을 참고한다. 이 API 제거에 대해 더 많은 정보가 필요하다면, 파드시큐리티폴리시(PodSecurityPolicy) 사용 중단: 과거, 현재, 미래를 참고한다.

쿠버네티스 v1.29 이외의 버전을 실행 중이라면, 해당 쿠버네티스 버전에 대한 문서를 확인한다.

5 - 윈도우 노드에서의 보안

이 페이지에서는 윈도우 운영 체제에서의 보안 고려 사항 및 추천 사례에 대해 기술한다.

노드의 시크릿 데이터 보호

윈도우에서는 시크릿 데이터가 노드의 로컬 스토리지에 평문으로 기록된다(리눅스는 tmpfs 또는 인메모리 파일시스템에 기록). 클러스터 운영자로서, 다음 2 가지의 추가 사항을 고려해야 한다.

  1. 파일 ACL을 사용하여 시크릿의 파일 위치를 보호한다.
  2. BitLocker를 사용하여 볼륨 수준의 암호화를 적용한다.

컨테이너 사용자

윈도우 파드 또는 컨테이너에 RunAsUsername을 설정하여 해당 컨테이너 프로세스를 실행할 사용자를 지정할 수 있다. 이는 RunAsUser와 대략적으로 동등하다.

윈도우 컨테이너는 ContainerUser와 ContainerAdministrator라는 기본 사용자 계정을 2개 제공한다. 이 두 사용자 계정이 어떻게 다른지는 마이크로소프트의 안전한 윈도우 컨테이너 문서 내의 언제 ContainerAdmin 및 ContainerUser 사용자 계정을 사용해야 하는가를 참고한다.

컨테이너 빌드 과정에서 컨테이너 이미지에 로컬 사용자를 추가할 수 있다.

그룹 관리 서비스 어카운트를 활용하여 윈도우 컨테이너를 Active Directory 사용자로 실행할 수도 있다.

파드-수준 보안 격리

리눅스 특유의 파드 보안 컨텍스트 메커니즘(예: SELinux, AppArmor, Seccomp, 또는 커스텀 POSIX 기능)은 윈도우 노드에서 지원되지 않는다.

특권을 가진(Privileged) 컨테이너는 윈도우에서 지원되지 않는다. 대신, 리눅스에서 권한 있는 컨테이너가 할 수 있는 작업 중 많은 부분을 윈도우에서 수행하기 위해 HostProcess 컨테이너를 사용할 수 있다.

6 - 쿠버네티스 API 접근 제어하기

이 페이지는 쿠버네티스 API에 대한 접근 제어의 개요를 제공한다.

사용자는 kubectl, 클라이언트 라이브러리 또는 REST 요청을 통해 API에 접근한다. 사용자와 쿠버네티스 서비스 어카운트 모두 API에 접근할 수 있다. 요청이 API에 도달하면, 다음 다이어그램에 설명된 몇 가지 단계를 거친다.

Diagram of request handling steps for Kubernetes API request

전송 보안

기본적으로 쿠버네티스 API 서버는 TLS에 의해 보호되는 첫번째 non-localhost 네트워크 인터페이스의 6443번 포트에서 수신을 대기한다. 일반적인 쿠버네티스 클러스터에서 API는 443번 포트에서 서비스한다. 포트번호는 --secure-port 플래그를 통해, 수신 대기 IP 주소는 --bind-address 플래그를 통해 변경될 수 있다.

API 서버는 인증서를 제시한다. 이러한 인증서는 사설 인증 기관(CA)에 기반하여 서명되거나, 혹은 공인 CA와 연결된 공개키 인프라스트럭처에 기반한다. 인증서와 그에 해당하는 개인키는 각각 --tls-cert-file--tls-private-key-file 플래그를 통해 지정한다.

만약 클러스터가 사설 인증 기관을 사용한다면, 해당 CA 인증서를 복사하여 클라이언트의 ~/.kube/config 안에 구성함으로써 연결을 신뢰하고 누군가 중간에 가로채지 않았음을 보장해야 한다.

클라이언트는 이 단계에서 TLS 클라이언트 인증서를 제시할 수 있다.

인증

TLS가 설정되면 HTTP 요청이 인증 단계로 넘어간다. 이는 다이어그램에 1단계로 표시되어 있다. 클러스터 생성 스크립트 또는 클러스터 관리자는 API 서버가 하나 이상의 인증기 모듈을 실행하도록 구성한다. 인증기에 대해서는 인증에서 더 자세히 서술한다.

인증 단계로 들어가는 것은 온전한 HTTP 요청이지만 일반적으로 헤더 그리고/또는 클라이언트 인증서를 검사한다.

인증 모듈은 클라이언트 인증서, 암호 및 일반 토큰, 부트스트랩 토큰, JWT 토큰(서비스 어카운트에 사용됨)을 포함한다.

여러 개의 인증 모듈을 지정할 수 있으며, 이 경우 하나의 인증 모듈이 성공할 때까지 각 모듈을 순차적으로 시도한다.

요청을 인증할 수 없는 경우 HTTP 상태 코드 401과 함께 거부된다. 이 외에는 사용자가 특정 username으로 인증되며, 이 username은 다음 단계에서 사용자의 결정에 사용할 수 있다. 일부 인증기는 사용자 그룹 관리 기능을 제공하는 반면, 이외의 인증기는 그렇지 않다.

쿠버네티스는 접근 제어 결정과 요청 기록 시 usernames를 사용하지만, user 오브젝트를 가지고 있지 않고 usernames 나 기타 사용자 정보를 오브젝트 저장소에 저장하지도 않는다.

인가

특정 사용자로부터 온 요청이 인증된 후에는 인가되어야 한다. 이는 다이어그램에 2단계로 표시되어 있다.

요청은 요청자의 username, 요청된 작업 및 해당 작업이 영향을 주는 오브젝트를 포함해야 한다. 기존 정책이 요청된 작업을 완료할 수 있는 권한이 해당 사용자에게 있다고 선언하는 경우 요청이 인가된다.

예를 들어 Bob이 아래와 같은 정책을 가지고 있다면 projectCaribou 네임스페이스에서만 파드를 읽을 수 있다.

{
    "apiVersion": "abac.authorization.kubernetes.io/v1beta1",
    "kind": "Policy",
    "spec": {
        "user": "bob",
        "namespace": "projectCaribou",
        "resource": "pods",
        "readonly": true
    }
}

Bob이 다음과 같은 요청을 하면 'projectCaribou' 네임스페이스의 오브젝트를 읽을 수 있기 때문에 요청이 인가된다.

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "projectCaribou",
      "verb": "get",
      "group": "unicorn.example.org",
      "resource": "pods"
    }
  }
}

Bob이 projectCaribou 네임스페이스에 있는 오브젝트에 쓰기(create 또는 update) 요청을 하면 그의 인가는 거부된다. 만약 Bob이 projectFish처럼 다른 네임스페이스의 오브젝트 읽기(get) 요청을 하면 그의 인가는 거부된다.

쿠버네티스 인가는 공통 REST 속성을 사용하여 기존 조직 전체 또는 클라우드 제공자 전체의 접근 제어 시스템과 상호 작용할 것을 요구한다. 이러한 제어 시스템은 쿠버네티스 API 이외의 다른 API와 상호작용할 수 있으므로 REST 형식을 사용하는 것이 중요하다.

쿠버네티스는 ABAC 모드, RBAC 모드, 웹훅 모드와 같은 여러 개의 인가 모듈을 지원한다. 관리자가 클러스터를 생성할 때 API 서버에서 사용해야 하는 인가 모듈을 구성했다. 인가 모듈이 2개 이상 구성되면 쿠버네티스가 각 모듈을 확인하고, 어느 모듈이 요청을 승인하면 요청을 진행할 수 있다. 모든 모듈이 요청을 거부하면 요청이 거부된다(HTTP 상태 코드 403).

인가 모듈을 사용한 정책 생성을 포함해 쿠버네티스 인가에 대해 더 배우려면 인가 개요를 참조한다.

어드미션 제어

어드미션 제어 모듈은 요청을 수정하거나 거부할 수 있는 소프트웨어 모듈이다. 인가 모듈에서 사용할 수 있는 속성 외에도 어드미션 제어 모듈은 생성되거나 수정된 오브젝트 내용에 접근할 수 있다.

어드미션 컨트롤러는 오브젝트를 생성, 수정, 삭제 또는 (프록시에) 연결하는 요청에 따라 작동한다. 어드미션 컨트롤러는 단순히 오브젝트를 읽는 요청에는 작동하지 않는다. 여러 개의 어드미션 컨트롤러가 구성되면 순서대로 호출된다.

이는 다이어그램에 3단계로 표시되어 있다.

인증 및 인가 모듈과 달리, 어드미션 제어 모듈이 거부되면 요청은 즉시 거부된다.

어드미션 제어 모듈은 오브젝트를 거부하는 것 외에도 필드의 복잡한 기본값을 설정할 수 있다.

사용 가능한 어드미션 제어 모듈은 여기에 서술되어 있다.

요청이 모든 어드미션 제어 모듈을 통과하면 유효성 검사 루틴을 사용하여 해당 API 오브젝트를 검증한 후 오브젝트 저장소에 기록(4단계)된다.

감사(Auditing)

쿠버네티스 감사는 클러스터에서 발생하는 일들의 순서를 문서로 기록하여, 보안과 관련되어 있고 시간 순서로 정리된 기록을 제공한다. 클러스터는 사용자, 쿠버네티스 API를 사용하는 애플리케이션, 그리고 컨트롤 플레인 자신이 생성한 활동을 감사한다.

더 많은 정보는 감사를 참고한다.

다음 내용

인증 및 인가 그리고 API 접근 제어에 대한 추가적인 문서는 아래에서 찾을 수 있다.

또한, 다음 사항을 익힐 수 있다.

  • 파드가 API 크리덴셜(credential)을 얻기 위해 시크릿(Secret) 을 사용하는 방법.

7 - 역할 기반 접근 제어 (RBAC) 모범 사례

클러스터 운영자를 위한 모범 RBAC 설정 규칙 및 사례

쿠버네티스 RBAC는 클러스터 사용자 및 워크로드가 자신의 역할을 수행하기 위해 필요한 자원에 대해서만 접근 권한을 가지도록 보장하는 핵심 보안 제어 방식이다. 클러스터 관리자가 클러스터 사용자 권한을 설정할 시에는, 보안 사고로 이어지는 과도한 접근 권한 부여의 위험을 줄이기 위해 권한 에스컬레이션 발생 가능성에 대해 이해하는 것이 중요하다.

여기서 제공하는 모범 사례는 RBAC 문서 와 함께 읽는 것을 권장한다.

보편적인 모범 사례

최소 권한

이상적으로는, 최소의 RBAC 권한만이 사용자 및 서비스 어카운트에 부여되어야 한다. 작업에 명시적으로 필요한 권한만 사용되어야 한다. 각 클러스터마다 경우가 다르겠지만, 여기서 적용해 볼 수 있는 보편적 규칙은 다음과 같다.

  • 권한은 가능하면 네임스페이스 레벨에서 부여한다. 클러스터롤바인딩 대신 롤바인딩을 사용하여 특정 네임스페이스 내에서만 사용자에게 권한을 부여한다.
  • 와일드카드(wildcard)를 사용한 권한 지정을 할 시에는, 특히 모든 리소스에 대해서는 가능하면 지양한다. 쿠버네티스는 확장성을 지니는 시스템이기 때문에, 와일드카드를 이용한 권한 지정은 현재 클러스터에 있는 모든 오브젝트 타입뿐만 아니라 모든 오브젝트 타입에 대해서도 권한을 부여하게 된다.
  • 운영자는 cluster-admin 계정이 필수로 요구되지 않을시에는 사용을 지양한다. 적은 권한을 가진 계정과 가장 (impersonation) 권한을 혼합하여 사용하면 클러스터 자원을 실수로 수정하는 일을 방지할 수 있다.
  • system:masters 그룹에 사용자 추가를 지양한다. 해당 그룹의 멤버는 누구나 모든 RBAC 권한 체크를 우회할 수 있으며 롤바인딩과 클러스터 롤바인딩을 통한 권한 회수가 불가능한 슈퍼유저 (superuser) 권한을 가지게 된다. 추가적으로 클러스터가 권한 웹훅을 사용할 시에는, 그룹의 멤버가 해당 웹훅도 우회할 수 있다. (그룹의 멤버인 사용자가 전송하는 요청은 웹훅에 전달되지 않는다.)

특권 토큰 분배 최소화

이상적인 상황에서는, 강력한 권한이 부여된 서비스 어카운트를 파드에게 지정해서는 안된다. (예를 들어, 권한 에스컬레이션 위험에 명시된 모든 권한) 워크로드가 강력한 권한을 요구하는 상황에서는 다음과 같은 사례를 고려해 보자.

  • 강력한 권한을 가진 파드를 실행하는 노드의 수를 제한한다. 컨테이너 이스케이프의 영향 범위를 최소화하기 위해, 실행되고 있는 모든 데몬셋은 최소의 권한만을 가지도록 한다.
  • 강력한 권한을 가진 파드를 신뢰되지 못하거나 외부로 노출된 파드와 함께 실행하는 것을 지양한다. 신뢰되지 못하거나 신뢰성이 적은 파드와 함께 실행되는 것을 방지하기 위해 테인트와 톨러레이션, 노드 어피니티, 혹은 파드 안티-어피니티를 사용해 보는 것도 고려해 보자. 신뢰성이 적은 파드가 제한된 파드 시큐리티 스탠다드에 부합하지 않을 시에는 더욱 조심해야 한다.

하드닝 (Hardening)

모든 클러스터에서 요구되지 않더라도, 쿠버네티스에서는 기본으로 제공하는 권한이 있다. 기본으로 부여되는 RBAC 권리에 대한 검토를 통해 보안 하드닝을 할 수 있다. 보편적으로는 system: 계정에 부여되는 권한을 수정하는 것은 지양한다. 클러스터 권한을 하드닝할 수 있는 방법은 다음과 같다.

  • system:unauthenticated 그룹의 바인딩은 누구에게나 네트워크 레벨에서 API 서버와 통신할 수 있는 권한을 부여하므로, 바인딩을 검토해 보고 가능하면 제거한다.
  • automountServiceAccountToken: false를 설정함으로써, 서비스 어카운트 토큰의 자동 마운트 사용을 지양한다. 더 자세한 내용은 기본 서비스 어카운트 토큰 사용법을 참고한다. 파드에서 위와 같은 설정을 하게 된다면, 서비스 어카운트 설정을 덮어쓰게 되며 서비스 어카운트 토큰을 요구하는 워크로드는 여전히 마운트가 가능하다.

주기적 검토

중복된 항목 및 권한 에스컬레이션에 대비하여, 쿠버네티스 RBAC 설정을 주기적으로 검토하는 일은 중요하다. 만일 공격자가 삭제된 사용자와 같은 이름으로 사용자 계정을 생성할 수 있다면, 삭제된 사용자의 모든 권한, 특히 해당 사용자에게 부여되었던 권한까지도 자동으로 상속받을 수 있게 된다.

쿠버네티스 RBAC - 권한 에스컬레이션 위험

쿠버네티스 RBAC 중, 부여받을 시 사용자 또는 서비스 어카운트가 권한 에스컬레이션을 통해 클러스터 밖의 시스템까지 영향을 미칠 수 있게끔 하는 권한이 몇 가지 존재한다.

해당 섹션은 클러스터 운영자가 실수로 클러스터에 의도되지 않은 접근 권한을 부여하지 않도록 하기 위해 신경 써야 할 부분에 대한 시야를 제공하는 것이 목적이다.

시크릿 나열

시크릿에 대해 get 권한을 부여하는 행위는 사용자에게 해당 내용에 대한 열람을 허용하는 일이라는 것은 명확히 알려져 있다. listwatch 권한 또한 사용자가 시크릿의 내용을 열람할 수 있는 권한을 부여한다는 것을 알고 지나가는 것이 중요하다. 예를 들어 리스트 응답이 반환되면 (예를 들어, kubectl get secrets -A -o yaml을 통해), 해당 응답에는 모든 시크릿의 내용이 포함되어 있다.

워크로드 생성

네임스페이스에 워크로드(파드 혹은 파드를 관리하는 워크로드 리소스)를 생성할 수 있는 권한은 파드에 마운트할 수 있는 시크릿, 컨피그맵 그리고 퍼시스턴트볼륨(PersistentVolume)과 같은 해당 네임스페이스의 다른 많은 리소스에 대한 액세스 권한을 암묵적으로 부여한다. 또한 파드는 모든 서비스어카운트로 실행할 수 있기 때문에, 워크로드 생성 권한을 부여하면 해당 네임스페이스에 있는 모든 서비스어카운트의 API 액세스 수준도 암묵적으로 부여된다.

특권 파드 실행 권한을 가지는 사용자는 해당 노드에 대한 권한을 부여받을 수 있으며, 더 나아가 권한을 상승시킬 수 있는 가능성도 존재한다. 특정 사용자 혹은, 적절히 안정 및 격리 된 파드를 생성할 수 있는 자격을 가진 다른 주체를 완전히 신뢰하지 못하는 상황이라면, 베이스라인 혹은 제한된 파드 시큐리티 스탠다드를 사용해야 한다. 이는 파드 시큐리티 어드미션 또는 다른 (서드 파티) 매커니즘을 통해 시행할 수 있다.

이러한 이유로, 네임스페이스는 서로 다른 수준의 보안 또는 테넌시가 필요한 리소스들을 분리하는 데 사용해야 한다. 최소 권한 원칙을 따르고 권한을 가장 적게 할당하는 것이 바람직하지만, 네임스페이스 내의 경계는 약한 것으로 간주되어야 한다.

퍼시스턴트 볼륨 생성

파드시큐리티폴리시 문서에서도 언급이 되었듯이, 퍼시스턴트볼륨 생성 권한은 해당 호스트에 대한 권한 에스컬레이션으로 이어질 수 있다. 퍼시스턴트 스토리지에 대한 권한이 필요할 시에는 신뢰 가능한 관리자를 통해 퍼시스턴트볼륨을 생성하고, 제한된 권한을 가진 사용자는 퍼시스턴트볼륨클레임을 통해 해당 스토리지에 접근하는 것이 바람직하다.

노드의 proxy 하위 리소스에 대한 접근

노드 오브젝트의 하위 리소스인 프록시에 대한 접근 권한을 가지는 사용자는 Kubelet API에 대한 권한도 가지며, 이는 권한을 가지고 있는 노드에 위치한 모든 파드에서 명령어 실행 권한이 주어짐을 의미한다. 이러한 접근 권한을 통해 감시 로깅 및 어드미션 컨트롤에 대한 우회가 가능해짐으로, 해당 리소스에 대한 권한을 부여할 시에는 주의가 필요하다.

에스컬레이트 동사

사용자가 자신이 보유한 권한보다 더 많은 권한을 가진 클러스터롤을 생성하고자 할때, RBAC 시스템이 이를 막는 것이 보편적이다. 이와 관련하여, escalate 동사가 예외에 해당한다. RBAC 문서에서도 언급이 되었듯이, 해당 권한을 가진 사용자는 권한 에스컬레이션을 할 수 있다.

바인드 동사

해당 권한을 사용자에게 부여함으로써 escalate 동사와 유사하게 권한 에스컬레이션에 대한 쿠버네티스에 내장된 보호 기능을 우회할 수 있게 되며, 이는 사용자가 부여받지 않은 권한을 가진 롤에 대한 바인딩을 생성할 수 있게끔 한다.

가장 (Impersonate) 동사

사용자는 해당 동사를 통해 클러스터 내에서 다른 사용자를 가장하여 권한을 부여받을 수 있게 된다. 가장된 계정을 통해 필요 이상의 권한이 부여되지 않도록 해당 동사 부여시 주의를 기울일 필요가 있다.

CSR 및 증명서 발급

CSR API를 통해 CSR에 대한 create 권한 및 certificatesigningrequests/approval에 대한 update 권한을 가진 사용자가, 서명자가 kubernetes.io/kube-apiserver-client인 새로운 클라이언트 증명서를 생성할 수 있게 되며 이를 통해 사용자는 클러스터를 인증할 수 있게 된다. 해당 클라이언트 증명서는 임의의 이름을 가지게 되며, 이에 중복된 쿠버네티스 시스템 구성 요소도 포함 된다. 이는 권한 에스컬레이션 발생 가능성을 열어두게 된다.

토큰 요청

serviceaccounts/token에 대해 create 권한을 가지는 사용자는 기존의 서비스 어카운트에 토큰을 발급할 수 있는 토큰리퀘스트를 생성할 수 있다.

컨트롤 어드미션 웹훅

validatingwebhookconfigurations 혹은 mutatingwebhookconfigurations에 대한 제어권을 가지는 사용자는 클러스터가 승인한 모든 오브젝트를 열람할 수 있는 웹훅을 제어할 수 있으며, 변화하는 웹훅의 경우에는 승인된 오브젝트를 변화시킬 수도 있다.

쿠버네티스 RBAC - 서비스 거부 위험

객체 생성 서비스 거부

클러스터 내 오브젝트 생성 권한을 가지는 사용자는 쿠버네티스가 사용하는 etcd는 OOM 공격에 취약에서 언급 되었듯이, 서비스 거부 현상을 초래할 정도 규모의 오브젝트를 생성할 수 있다. 다중 테넌트 클러스터에서 신뢰되지 못하거나 신뢰성이 적은 사용자에게 시스템에 대해 제한된 권한이 부여된다면 해당 현상이 나타날 수 있다.

해당 문제의 완화 방안 중 하나로는, 리소스 쿼터를 사용하여 생성할 수 있는 오브젝트의 수량을 제한하는 방법이 있다.

다음 내용

  • RBAC에 대한 추가적인 정보를 얻기 위해서는 RBAC 문서를 참고한다.

8 - 쿠버네티스 시크릿 모범 사례

클러스터 운영자와 애플리케이션 개발자를 위한 모범 시크릿 관리 규칙 및 사례.

쿠버네티스에서 시크릿은 비밀번호, OAuth 토큰 및 SSH 키와 같은 민감한 정보를 저장한다.

시크릿을 사용하면 민감한 정보가 사용되는 방법을 더 잘 통제할 수 있으며, 실수로 외부에 노출되는 위험도 줄일 수 있다. 시크릿 값은 base64 문자열로 인코딩되며 기본적으로는 평문으로 저장되지만, 암호화하여 저장하도록 설정할 수도 있다.

파드는 볼륨을 마운트하거나 혹은 환경 변수를 통하는 등 다양한 방식으로 시크릿을 참조할 수 있다. 시크릿은 기밀 데이터를 다루는 용도로 적합하며, 컨피그맵은 기밀이 아닌 데이터를 다루는 용도로 적합하다.

다음 모범 사례는 클러스터 관리자와 애플리케이션 개발자 모두를 위한 것이다. 이 가이드라인을 사용하여 시크릿 오브젝트에 있는 민감한 정보의 보안을 개선하고 시크릿을 보다 효과적으로 관리할 수 있다.

클러스터 관리자

이 섹션에서는 클러스터 관리자가 클러스터의 기밀 정보 보안을 개선하는 데 사용할 수 있는 모범 사례를 제공한다.

저장된 데이터(at rest)에 암호화 구성

기본적으로 시크릿 오브젝트는 etcd에 암호화되지 않은 상태로 저장된다. 따라서 etcd의 시크릿 데이터에 암호화를 구성해야 한다. 자세한 내용은 Encrypt Secret Data at Rest를 참고한다.

시크릿에 대한 최소 권한 접근 구성

쿠버네티스 역할 기반 접근 제어 (RBAC) (RBAC)와 같은 접근 제어 메커니즘을 계획할 때, Secret 오브젝트에 대한 접근에 대해 다음 가이드라인을 고려한다. 또한 역할 기반 접근 제어 (RBAC) 모범 사례의 다른 가이드라인도 따라야 한다.

  • 컴포넌트: 가장 권한이 높은 시스템 수준의 구성 요소에 대해서만 watchlist 액세스를 제한한다. 컴포넌트의 정상 동작에 필요한 경우에만 시크릿에 대한 get 액세스를 허용한다.
  • 사람: 시크릿에 get, watch 또는 list 액세스를 제한한다. 클러스터 관리자에게만 etcd에 대한 액세스를 허용한다. 여기에는 읽기 전용 액세스가 포함된다. 특정 어노테이션을 사용하여 시크릿에 대한 액세스를 제한하는 등의 더 복잡한 액세스 제어를 수행하려면 써드파티(third-party) 권한 부여 메커니즘을 사용하는 것을 고려한다.

시크릿을 사용하는 파드를 생성할 수 있는 사용자는 해당 시크릿의 값도 볼 수 있다. 클러스터 정책에서 사용자가 시크릿을 직접 읽는 것을 허용하지 않더라도, 동일한 사용자가 시크릿을 노출하는 파드를 실행할 수 있다. 이 액세스 권한을 가진 사용자가 의도적이든 의도적이지 않든 시크릿 데이터를 노출시켜 발생할 수 있는 영향을 감지하거나 제한할 수 있다. 몇 가지 권장 사항은 다음과 같다.

  • 수명이 짧은 시크릿 사용
  • 한 사용자가 여러 비밀을 동시에 읽는 것과 같은 특정 이벤트에 대해 경고하는 감사 규칙 구현

etcd 관리 정책 개선

더 이상 사용하지 않는다면 etcd에서 사용하는 내구성 스토리지를 지우거나 파쇄하는 것을 고려한다.

여러 개의 etcd 인스턴스가 있는 경우, 인스턴스 간에 암호화된 SSL/TLS 통신을 구성하여 전송 중(in transit)인 시크릿 데이터를 보호한다.

외부 시크릿에 대한 액세스 구성

써드파티 시크릿 저장소 공급자를 사용하여 기밀 데이터를 클러스터 외부에 보관한 다음 해당 정보에 액세스하도록 파드를 구성할 수 있다. 쿠버네티스 시크릿 스토어 CSI 드라이버는 kubelet이 외부 스토어에서 시크릿을 검색하고 접근 권한을 부여한 특정 파드에 시크릿을 볼륨으로 마운트할 수 있도록 하는 데몬셋(DaemonSet)이다.

지원되는 제공자 목록은 다음을 참고한다. 시크릿 스토어 CSI 드라이버 제공자.

개발자

이 섹션은 개발자가 쿠버네티스 리소스를 구축하고 배포할 때 기밀 데이터의 보안을 개선하기 위해 사용할 수 있는 모범 사례를 제공한다.

특정 컨테이너에 시크릿 액세스 제한

파드에 여러 개의 컨테이너를 정의하고 있고 그 중 하나만 시크릿에 접근해야 하는 경우, 볼륨 마운트 또는 환경 변수 구성을 정의하여 다른 컨테이너가 해당 시크릿에 액세스하지 못하도록 한다.

읽기 후 시크릿 데이터 보호

애플리케이션은 환경 변수나 볼륨에서 기밀 정보를 읽은 후에도 그 값을 보호해야 한다. 예를 들어, 애플리케이션은 시크릿 데이터를 로그에 남기거나 신뢰할 수 없는 상대에게 전송하지 않아야 한다.

시크릿 매니페스트 공유 방지

시크릿 데이터가 base64로 인코딩된 매니페스트를 통해 시크릿을 구성하는 경우, 이 파일을 공유하거나 소스 리포지토리에 체크인하면 매니페스트를 읽을 수 있는 모든 사람이 시크릿을 사용할 수 있다는 것을 의미한다.

9 - 멀티 테넌시(multi-tenancy)

이 페이지는 클러스터 멀티 테넌시를 구현하기 위해 유효한 구성 옵션과 모범 사례에 대한 개요를 제공한다.

클러스터 공유를 통해 비용 절감 및 운영을 간편화할 수 있다. 그러나 클러스터를 공유하게 되면 보안, 공평성, 소란스러운 이웃(noisy neighbors) 관리와 같이 여러 문제 상황이 발생할 수 있다.

클러스터는 다양한 방법을 통해 공유될 수 있다. 특정 경우에는 같은 클러스터 내 서로 다른 애플리케이션이 실행될 수 있다. 또 다른 경우에는 하나의 애플리케이션에서 각 엔드유저에 대한 인스턴스가 모여 여러 인스턴스가 같은 클러스터 내에서 실행될 수 있다. 이러한 모든 종류의 공유 방법은 주로 멀티 테넌시 라는 포괄적 용어로 통칭한다.

쿠버네티스에서는 엔드 유저 또는 테넌트에 대한 정형화된 개념을 정해놓고 있지는 않지만, 다양한 테넌시 요구사항을 관리하기 위한 몇 가지 기능을 제공한다. 이에 대한 내용은 밑에서 다룬다.

유스케이스

클러스터를 공유하기 위해 고려해야 하는 첫 번째 단계는, 사용 가능한 패턴과 툴을 산정하기 위해 유스케이스를 이해하는 것이다. 일반적으로 쿠버네티스에서의 멀티 테넌시는 다양한 형태로 변형 또는 혼합이 가능하지만, 넓게는 두 가지 범주로 분류된다.

다수의 팀

흔히 사용하는 멀티 테넌시의 형태는 하나 또는 그 이상의 워크로드를 운영하는 한 조직 소속의 여러 팀이 하나의 클러스터를 공유하는 형태이다. 이러한 워크로드는 같은 클러스터 내외의 다른 워크로드와 잦은 통신이 필요하다.

이러한 시나리오에서 팀에 속한 멤버는 보통 kubectl과 같은 툴을 통해 쿠버네티스 리소스에 직접적으로 접근하거나, GitOps 컨트롤러 혹은 다른 종류의 배포 자동화 툴을 통해 간접적으로 접근한다. 대개는 다른 팀 멤버 간에 일정량의 신뢰가 형성되어 있지만, 안전하고 공평한 클러스터 공유를 위해서는 RBAC, 쿼터(quota), 네트워크 정책과 같은 쿠버네티스 정책이 필수이다.

다수의 고객

다른 주요 멀티 테넌시 형태로는 서비스형소프트웨어(SaaS) 사업자가 여러 고객의 워크로드 인스턴스를 실행하는 것과 관련이 있다. 이러한 비즈니스 모델은 많은 이들이 "SaaS 테넌시"라고 부르는 배포 스타일과 밀접한 연관이 있다. 그러나 SaaS 사업자는 다른 배포 모델을 사용할 수 있기도 하며 SaaS가 아니어도 이러한 배포 모델의 적용이 가능하기 때문에, "다중 고객 테넌시(multi-customer tenancy)"를 더 적합한 용어로 볼 수 있다.

고객은 이러한 시나리오에서 클러스터에 대한 접근 권한을 가지지 않는다. 쿠버네티스는 그들의 관점에서는 보이지 않으며, 사업자가 워크로드를 관리하기 위해서만 사용된다. 비용 최적화는 주로 중대한 관심사가 되며, 워크로드 간의 확실한 격리를 보장하기 위해 쿠버네티스 정책이 사용된다.

용어

테넌트

쿠버네티스에서의 멀티 테넌시를 논할 때는, "테넌트(tenant)"를 하나의 의미로 해석할 수 없다. 오히려 다중 팀 혹은 다중 고객 테넌시의 여부에 따라 테넌트의 정의는 달라진다.

다중 팀 사용(multi-team usage)에서의 테넌트는 일반적으로 하나의 팀을 의미하며, 이 팀은 일반적으로 서비스의 복잡도에 따라 스케일 하는 작은 양의 워크로드를 다수 배포한다. 그러나 "팀" 자체에 대한 정의도 상위 조직으로 구성될 수 있기도 하고 작은 팀으로 세분화될 수 있기 때문에 정의가 모호할 수 있다.

반대로 각 팀이 새로운 고객에 대한 전용 워크로드를 배포하게 된다면, 다중 고객 테넌시 모델을 사용한다고 볼 수 있다. 이와 같은 경우에서는, "테넌트"는 하나의 워크로드를 공유하는 사용자의 집합을 의미한다. 이는 하나의 기업만큼 큰 규모일 수도 있고, 해당 기업의 한 팀 정도의 작은 규모일수도 있다.

같은 조직이 "테넌트"에 대한 두 개의 정의를 서로 다른 맥락에서 사용할 수 있는 경우가 많다. 예를 들어, 플랫폼 팀은 다수의 내부 "고객"을 위해 보안 툴 및 데이터베이스와 같은 공유된 서비스를 제공할 수 있고, SaaS 사업자는 공유된 개발 클러스터를 다수의 팀에게 제공할 수 있다.
마지막으로, SaaS 제공자는 민감한 데이터를 다루는 고객별 워크로드와 공유된 서비스를 다루는 멀티 테넌트를 혼합하여 제공하는 하이브리드 구조도 사용이 가능하다.

공존하는 테넌시 모델을 나타내고 있는 클러스터

격리

쿠버네티스에서 멀티 테넌트 솔루션을 설계하고 빌드 하는 방법은 몇 가지가 있다. 각 방법은 격리 수준, 구현 비용, 운영 복잡도, 서비스 비용에 영향을 미치는 각자만의 상충 요소를 가지고 있다.

각 쿠버네티스 클러스터는 쿠버네티스 소프트웨어를 실행하는 컨트롤 플레인과 테넌트의 워크로드가 파드의 형태로 실행되고 있는 워커 노드로 구성된 데이터 플레인으로 구성되어 있다. 테넌트 격리는 조직의 요구사항에 따라 컨트롤 플레인 및 데이터 플레인 모두에 대해 적용할 수 있다.

제공되는 격리의 수준은 강한 격리를 의미하는 "하드(hard)" 멀티 테넌시와 약한 격리를 의미하는 "소프트(soft)" 멀티 테넌시와 같은 용어를 통해 정의한다. 특히 "하드" 멀티 테넌시는 주로 보안이나 리소스 공유 관점(예를 들어, 데이터 유출 및 DoS 공격에 대한 방어)에서 테넌트가 서로 신뢰하지 않는 상황을 설명할 때 주로 사용한다. 데이터 플레인은 일반적으로 더 큰 공격 영역을 가지고 있기 때문에, 컨트롤 플레인 격리 또한 중요하지만 데이터 플레인을 격리하는 데 있어서 "하드" 멀티 테넌시는 추가적인 주의를 요구한다.

그러나 모든 사용자에게 적용할 수 있는 하나의 정의가 없기 때문에, "하드"와 "소프트" 용어에 대한 혼동이 생길 수 있다. 오히려 요구사항에 따라 클러스터 내에서 다양한 종류의 격리를 유지할 수 있는 다양한 기법을 다루는 "하드한 정도" 혹은 "소프트한 정도"가 넓은 범위에서는 이해하기에 편하다.

극단적인 경우에는 클러스터 레벨의 공유를 모두 포기하고 각 테넌트에 대한 전용 클러스터를 할당하거나, 가상머신을 통한 보안 경계가 충분하지 않다고 판단될 시에는 전용 하드웨어에서 실행하는 것이 쉽고 적절한 방법일 수 있다. 클러스터를 생성하고 운영하는데 필요한 오버헤드를 클라우드 공급자가 맡게 되는 매니지드 쿠버네티스 클러스터에서는 이와 같은 방식을 사용하기에 더 쉬울 수 있다. 강한 테넌트 격리의 장점은 여러 클러스터를 관리하는데 필요한 비용과 복잡도와 비교하여 산정되어야 한다. 멀티 클러스터 SIG는 이러한 종류의 유스케이스를 다루는 작업을 담당한다.

이 페이지의 남은 부분에서는 공유 쿠버네티스 클러스터에서 사용되는 격리 기법을 중점적으로 다룬다. 그러나 전용 클러스터를 고려하고 있다 하더라도, 요구사항 혹은 기능에 대한 변화가 생겼을 때 공유 클러스터로 전환할 수 있는 유연성을 제공할 수 있기 때문에, 이러한 권고사항을 검토해 볼 가치가 있다.

컨트롤 플레인 격리

컨트롤 플레인 격리는 서로 다른 테넌트가 서로의 쿠버네티스 API 리소스에 대한 접근 및 영향을 미치지 못하도록 보장한다.

네임스페이스

쿠버네티스에서 네임스페이스는 하나의 클러스터 내에서 API 리소스 그룹을 격리하는 데 사용하는 기능이다. 이러한 격리는 두 가지 주요 특징을 지닌다.

  1. 네임스페이스 내의 오브젝트 이름은 폴더 내의 파일과 유사하게 다른 네임스페이스에 속한 이름과 중첩될 수 있다. 이를 통해 각 테넌트는 다른 테넌트의 활동과 무관하게 자신의 리소스에 대한 이름을 정할 수 있다.

  2. 많은 쿠버네티스 보안 정책은 네임스페이스 범위에서 사용한다. 예를 들어, RBAC 역할과 네트워크 정책은 네임스페이스 범위의 리소스이다. RBAC를 사용함으로써 사용자 및 서비스 어카운트는 하나의 네임스페이스에 대해 제한될 수 있다.

멀티 테넌트 환경에서의 각 네임스페이스는 테넌트의 워크로드를 논리적이고 구별되는 관리 단위로 분할할 수 있다. 실제로 일반적인 관습에서는 여러 워크로드가 하나의 테넌트에 의해 운영되더라도, 각 워크로드를 개별 네임스페이스로 격리한다. 이를 통해 각 워크로드는 개별 정체성을 가질 수 있으며 적절한 보안 정책을 적용 받을 수 있게끔 보장한다.

네임스페이스 격리 모델은 테넌트 워크로드를 제대로 격리 시키기 위해 몇 가지 다른 쿠버네티스 리소스, 네트워크 플러그인, 보안 모범 사례에 대한 준수가 필요하다. 이와 같이 고려해야 하는 사항은 아래에 명시되어 있다.

접근 제어

컨트롤 플레인에서의 가장 중요한 격리 방식은 인증이다. 만일 팀 또는 해당 팀의 워크로드가 서로 다른 API 리소스에 대한 접근 및 수정이 가능하다면, 다른 종류의 정책을 모두 바꾸거나 비활성화할 수 있게 되어 해당 정책이 제공하는 보호를 무효화한다. 따라서 각 테넌트가 필요로 하는 네임스페이스에 대한 적절한 최소의 권한만을 부여하는 것이 중요하다. 이는 "최소 권한의 원칙(Principle of Least Privilege)"이라고 부른다.

역할 기반 접근 제어(RBAC)는 흔히 쿠버네티스 컨트롤 플레인에서의 사용자와 워크로드에 (서비스 어카운트) 대한 인증을 시행하기 위해 사용된다. 롤(Roles)롤바인딩(RoleBindings)은 네임스페이스 레벨에서 애플리케이션의 접근 제어를 시행하기 위해 사용되는 쿠버네티스 오브젝트이다. 클러스터 레벨의 오브젝트에 대한 접근 권한을 인증하기 위해 사용되는 유사한 오브젝트도 존재하지만, 이는 멀티 테넌트 클러스터에서는 비교적 유용성이 떨어진다.

다중 팀 환경에서는, 클러스터 전범위 리소스에 대해 클러스터 운영자와 같이 특권을 가진 사용자에 의해서만 접근 또는 수정이 가능하도록 보장하기 위해 RBAC를 사용하여 테넌트의 접근을 적합한 네임스페이스로 제한해야 한다.

만일 사용자에게 필요 이상으로 권한을 부여하는 정책이 있다면, 이는 영향 받는 리소스를 포함하고 있는 네임스페이스가 더 세분화된 네임스페이스로 재구성 되어야 한다는 신호일 가능성이 높다. 네임스페이스 관리 툴을 통해 공통된 RBAC 정책을 서로 다른 네임스페이스에 적용하고 필요에 따라 세분화된 정책은 허용하며, 세분화된 네임스페이스를 간편하게 관리할 수 있다.

쿼터

쿠버네티스 워크로드는 CPU 및 메모리와 같은 노드 리소스를 소모한다. 멀티 테넌트 환경에서는, 테넌트 워크로드의 리소스 사용량을 관리하기 위해 리소스 쿼터를 사용할 수 있다. 테넌트가 쿠버네티스 API에 대한 접근 권한을 가지는 다수 팀 유스케이스의 경우에는, 테넌트가 생성할 수 있는 API 리소스(예를 들어, 파드의 개수 혹은 컨피그맵의 개수)의 개수를 리소스 쿼터를 사용하여 제한할 수 있다. 오브젝트 개수에 대한 제한은 공평성을 보장하고 같은 컨트롤 플레인을 공유하는 테넌트 간 침범이 발생하는 소란스러운 이웃 문제를 예방하기 위한 목적을 가지고 있다.

리소스 쿼터는 네임스페이스 오브젝트이다. 테넌트를 네임스페이스에 대해 매핑함으로써, 클러스터 운영자는 쿼터를 사용하여 하나의 테넌트가 클러스터의 리소스를 독점하거나 컨트롤 플레인을 압도하지 못하도록 보장할 수 있다. 네임스페이스 관리 툴은 쿼터 운영을 간편화해준다. 이에 더해 쿠버네티스 쿼터는 하나의 네임스페이스 내에서만 적용이 가능하지만, 특정 네임스페이스 관리 툴은 네임스페이스 그룹이 쿼터를 공유할 수 있도록 허용함으로써 운영자에게 내장된 쿼터에 비해 적은 수고로 더 많은 유연성을 제공한다.

쿼터는 하나의 테넌트가 자신에게 할당된 몫의 리소스 보다 많이 사용하는 것을 방지하며, 이를 통해 하나의 테넌트가 다른 테넌트의 워크로드 성능에 부정적 영향을 미치는 "소란스러운 이웃" 문제를 최소화할 수 있다.

쿠버네티스에서 네임스페이스에 대한 쿼터를 적용할 시에는 각 컨테이너에 대한 리소스 요청과 제한을 명시하도록 요구한다. 제한은 각 컨테이너가 소모할 수 있는 리소스의 양에 대한 상한선이다. 설정된 제한을 초과하여 리소스 소모를 시도하는 컨테이너는 리소스의 종류에 따라 스로틀(throttled)되거나 종료(killed)된다. 리소스 요청이 제한보다 낮게 설정되었을 시에는, 각 컨테이너가 요청한 리소스의 양은 보장되지만 워크로드 간의 영향이 있을 가능성은 존재한다.

쿼터는 네트워크 트래픽과 같이 모든 종류의 리소스 공유에 대한 보호는 할 수 없다. 노드 격리(아래에서 설명)가 이러한 문제에 대해서는 더 나은 해결책일 수 있다.

데이터 플레인 격리

데이터 플레인 격리는 다른 테넌트의 파드 및 워크로드와 충분히 격리가 이루어질 수 있도록 보장한다.

네트워크 격리

기본적으로 쿠버네티스 클러스터의 모든 파드는 서로 통신을 할 수 있도록 허용되어 있으며 모든 네트워크 트래픽은 암호화되어 있지 않다. 이는 트래픽이 실수 또는 악의적으로 의도되지 않은 목적지로 전송되거나 신뢰가 손상된(compromised) 노드 상의 워크로드에 의해 가로채지는 것과 같은 보안 취약점으로 이어질 수 있다.

파드에서 파드로의 통신은 네임스페이스 레이블 혹은 IP 주소 범위를 통해 파드 간의 통신을 제한하는 네트워크 정책에 의해 제어될 수 있다. 테넌트 간의 엄격한 네트워크 격리가 필요한 멀티 테넌트 환경에서는, 파드 간의 통신을 거부하는 기본 정책과 모든 파드가 네임 해석(name resolution)을 위해 DNS 서버를 쿼리하도록 하는 규칙을 시작에 설정하는 것을 권고한다. 이러한 기본 정책을 기반으로 하여, 네임스페이스 내에서 통신을 허용하는 관대한 규칙을 추가할 수 있다. 또한 네임스페이스 간에 트래픽을 허용해야 하는 경우 네트워크 정책 정의의 namespaceSelector 필드에 빈 레이블 셀렉터 '{}'를 사용하지 않는 것이 좋다. 이러한 방식은 요구에 따라 한 단계 더 정제할 수 있다. 이는 하나의 컨트롤 플레인 내의 파드에 대해서만 적용된다는 것을 알아두어야 한다. 서로 다른 가상의 컨트롤 플레인에 소속된 파드는 쿠버네티스 네트워킹을 통해 통신할 수 없다.

네임스페이스 관리 툴을 통해 기본 또는 공통 네트워크 정책을 간편하게 생성할 수 있다. 이에 더해, 몇 가지 툴은 클러스터 상에서 일관된 집합의 네임스페이스 레이블을 사용할 수 있게 함으로써 정책에 대한 신뢰 가능한 기반이 마련될 수 있도록 보장한다.

추가적으로, 서비스 메쉬(service mesh)는 워크로드 특징에 따른 OSI 7 계층 정책을 제공하므로 네임스페이스보다 더 고도의 네트워크 격리를 제공할 수 있다. 이러한 상위 정책은 특히 하나의 테넌트에 대한 여러 네임스페이스가 있는 경우와 같이, 네임스페이스 기반 멀티 테넌시를 더욱 쉽게 관리할 수 있도록 한다. 신뢰가 손상된(compromised) 노드가 발생했을 시에도 데이터를 보호할 수 있는 상호 간의 TLS을 통해 암호화도 제공하며 전용 또는 가상의 클러스터 사이에서도 동작한다. 그러나 관리하기에 더 복잡할 수 있으며 모든 사용자에게 적합한 방법이 아닐 수 있다.

스토리지 격리

쿠버네티스는 워크로드가 퍼시스턴트 스토리지로 사용할 수 있는 몇 가지 종류의 볼륨을 제공한다. 보안 및 데이터 격리를 위해서는 동적 볼륨 프로비저닝을 권고하며 노드 리소스를 사용하는 볼륨 타입은 피해야 한다.

스토리지 클래스는 클러스터에 제공하는 사용자 정의 "클래스"를 서비스 품질 수준(quality-of-service level), 백업 정책 혹은 클러스터 운영자에 의해 결정된 사용자 정의 정책을 기반으로 명시할 수 있도록 허용한다.

파드는 퍼시스턴트 볼륨 클레임을 통해 스토리지를 요청할 수 있다. 퍼시스턴트 볼륨 클레임은 공용 쿠버네티스 클러스터 내에서 스토리지 시스템의 부분 단위 격리를 가능하게끔 하는 네임스페이스 리소스이다. 그러나 퍼시스턴트 볼륨은 클러스터 전범위(cluster-wide)의 리소스이며 워크로드와 네임스페이스의 라이프사이클에 독립적이므로, 이를 염두에 둘 필요가 있다.

예를 들어, 각 테넌트에 대한 별도의 스토리지 클래스를 설정할 수 있으며 이를 통해 격리를 강화할 수 있다. 만일 스토리지 클래스가 공유된다면, Delete 리클레임(reclaim) 정책을 설정하여
퍼시스턴트 볼륨이 다른 네임스페이스에서 재사용되지 못하도록 보장해야 한다.

컨테이너 샌드박싱(sandboxing)

쿠버네티스 파드는 워커 노드 상에서 실행되는 하나 또는 그 이상의 컨테이너로 구성되어 있다. 컨테이너는 OS 레벨의 가상화를 활용하기 때문에 하드웨어 기반의 가상화를 활용하는 가상 머신에 비해 격리의 경계가 약하다.

공유 환경에서 애플리케이션 및 시스템 계층 상 패치되지 않은 취약점은 컨테이너 탈출(container breakout) 또는 원격 코드 실행과 같이 호스트 리소스에 대한 접근을 허용하여 공격자에 의해 악용될 수 있다. 컨텐츠 매니지먼트 시스템(CMS)과 같은 특정 애플리케이션에서는, 고객이 신뢰되지 않은 스크립트 및 코드를 업로드할 수 있는 기능이 허용될 수 있다. 어떤 경우이든, 강한 격리를 통해 워크로드를 한 단계 더 격리하고 보호하기 위한 기능은 필요하다.

샌드박싱은 공유 클러스터에서 실행되는 워크로드를 격리하는 방법을 제공한다. 일반적으로 각 파드를 가상 머신 또는 유저스페이스 커널(userspace kernel)과 같은 별도의 실행 환경에서 실행하는 것과 연관이 있다. 샌드박싱은 주로 워크로드가 악의적으로 판단되는 신뢰되지 않은 코드를 실행할 때 권고된다. 이러한 격리가 필요한 이유는 컨테이너가 공유된 커널에서 실행되기 때문이다. 컨테이너는 하위 호스트의 /sys/proc 와 같은 파일 시스템을 마운트 하기 때문에, 개별 커널을 가지는 가상 머신에서 실행되는 애플리케이션과 비교하였을 때는 보안성이 낮다. Seccomp, AppArmor, SELinux와 같은 제어를 통해 컨테이너의 보안을 강화할 수 있지만, 공유 클러스터에서 실행되고 있는 모든 워크로드에 대해 공통된 규칙을 적용하는 데는 어려움이 있다. 워크로드를 샌드박스 환경에서 실행함으로써, 공격자가 호스트의 취약점을 악용하여 호스트 시스템 및 해당 호스트에서 실행되고 있느 모든 프로세스와 파일 대한 권한을 얻을 수 있는 컨테이너 탈출로 부터 호스트를 보호할 수 있다.

가상 머신 및 유저스페이스 커널은 샌드박싱을 제공하는 대표적인 두 가지 방법이다. 다음과 같은 샌드박싱 구현이 가능하다.

  • gVisor는 컨테이너로부터 시스템 호출을 가로채 Go로 작성된 유저스페이스 커널을 통해 실행하므로, 컨테이너가 호스트 내부(underlying host)에 대한 제한적인 접근 권한만 가진다.
  • Kata 컨테이너는 OCI에 부합하는 런타임으로 가상 머신 내에서 컨테이너가 실행되도록 한다. Kata는 하드웨어 가상화를 통해, 신뢰되지 않은 코드를 실행하는 컨테이너에 대해 추가적인 보안 계층을 제공한다.

노드 격리

노드 격리는 테넌트 워크로드를 서로 격리시킬 수 있는 또 다른 기법이다. 노드 격리를 통해 하나의 노드 집합은 특정 테넌트의 파드를 전용으로 실행할 수 있으며 테넌트 파드 간의 혼합(co-mingling)은 금지되어 있다. 이러한 구성을 사용하게 되면 노드 상에서 실행되는 파드가 모두 하나의 테넌트 소유이기 때문에 소란스러운 테넌트 문제를 줄일 수 있다. 컨테이너 탈출에 성공한 공격자가 있다 하더라도, 해당 노드의 컨테이너 및 마운트 된 볼륨에 대해서만 접근 권한을 가지므로, 노드 격리를 통해 정보 유출의 위험도 비교적 감소한다.

다른 테넌트의 워크로드가 다른 노드에서 실행되고 있다 하더라도, Kubelet과 (가상 컨트롤 플레인을 사용하지 않는 한) API 서비스는 여전히 공유되고 있다는 사실을 이해하는 것은 중요하다. 능숙한 공격자는 Kubelet 또는 노드에서 실행되고 있는 다른 파드에 부여된 권한을 이용하여 클러스터 내에서 좌우로 이동하며 다른 노드에서 실행되고 있는 테넌트 워크로드에 대한 접근 권한을 얻을 수 있다. 만일 이러한 사항이 우려된다면, seccomp, AppArmor, SELinux와 같은 제어 방식을 이용하거나, 샌드박스 컨테이너 이용 또는 각 테넌트에 대한 개별 클러스터를 생성하는 방안을 검토해 보아야 한다.

노드 격리를 통해 파드가 아닌 노드 별 비용을 청구할 수 있으므로, 비용 관점에서는 샌드박스 컨테이너에 비해 이해 및 파악이 수월하다. 또한 호환성 및 성능 문제 발생 가능성이 낮으며 샌드박스 컨테이너 보다 구현도 더 쉬운 편이다. 예를 들어, 각 테넌트에 대한 노드는 대응하는 톨러레이션(toleration)을 가진 파드만 실행할 수 있도록 테인트(taint)를 통해 설정할 수 있다. 변화하는 웹훅을 통해 자동으로 톨러레이션과 노드 어피니티를 테넌트 네임스페이스에 배포된 파드에 추가하여, 해당 파드를 특정 테넌트를 위해 지정된 특정 노드의 집합에서 실행될 수 있도록 한다.

노드 격리는 파드 노드 셀렉터 또는 가상 Kubelet(Virtual Kubelet)을 통해 구현할 수 있다.

추가적인 고려 사항

해당 섹션에서는 멀티 테넌시와 연관 있는 이외의 쿠버네티스 구성 및 패턴에 대한 내용을 다룬다.

API 우선순위와 공평성

API 우선순위(priority)와 공평성(fairness)은 쿠버네티스의 기능 중 하나로, 클러스터 내 실행 중인 특정 파드에 대해 우선순위를 부여할 수 있다. 애플리케이션이 쿠버네티스 API를 호출하게 되면, API 서버는 해당 파드에 부여된 우선순위를 산정한다. 더 높은 우선순위를 가진 파드의 호출은 낮은 우선순위를 가진 파드의 호출보다 먼저 수행된다. 경합률(contention)이 높을 시에는 낮은 우선순위의 호출은 서버 리소스가 한가해질 때까지 대기하거나 해당 요청을 거부할 수 있다.

고객이 쿠버네티스 API와 상호작용하는 애플리케이션(예를 들어, 컨트롤러)을 실행하지 않은 한, SaaS 환경에서 API 우선순위와 공평성을 사용하는 일은 흔치 않을 것이다.

서비스 품질(QoS)

SaaS 애플리케이션을 실행할 시에는, 각 테넌트에게 다른 수준의 서비스 품질 티어(tier)를 제공하는 기능이 필요할 수 있다. 예를 들어, 낮은 성능 및 기능을 보장하는 무료 서비스와 특정 수준의 성능을 보장하는 유료 서비스를 제공할 수 있다. 다행히 쿠버네티스는 이러한 티어를 공유 클러스터 내에서 구현하기 위한 네트워크 QoS, 스토리지 클래스, 파드 우선순위 및 선점과 같은 몇 가지 구성들을 제공한다. 이는 각 테넌트가 지불한 비용에 적합한 서비스 품질을 제공하기 위한 목적이다. 우선 네트워크 QoS에 대해 먼저 살펴본다.

일반적으로 하나의 노드에 위치한 모든 파드는 네트워크 인터페이스를 공유한다. 네트워크 QoS 없이는, 몇 개의 파드가 가용 대역폭 중 다른 파드의 대역폭까지 소모하여 불공평한 공유를 야기할 수 있다. 쿠버네티스 대역폭 플러그인은 리눅스 tc 큐를 이용하여 파드에 비율 제한을 적용할 수 있는 쿠버네티스 리소스 구성(예를 들어, 요청/제한)을 사용 가능하게 하는 네트워킹 확장 리소스를 생성한다. 네트워크 플러그인 문서에 따르면 해당 플러그인은 아직은 실험 목적으로 사용되고 있다는 점에 대한 주의가 필요하며 프로덕션 환경에서 사용하기 전에는 철저한 테스트가 이루어져야 한다.

스토리지 서비스 품질과 같은 경우에는, 각 성능 특징을 나타내기 위해 서로 다른 스토리지 클래스 또는 프로필을 생성할 필요가 있다. 각 스토리지 프로필은 IO, 중복성, 처리량과 같이 서로 다른 워크로드에 최적화된 티어의 서비스와 묶을 수 있다. 테넌트가 자신의 워크로드에 적합한 스토리지 프로필을 적용하기 위해서는 추가적인 로직이 필요할 수 있다.

마지막으로, 파드에 우선순위 값을 부여할 수 있는 파드 우선순위와 선점이 있다. 파드 스케줄링 시에 우선순위가 높은 파드를 스케줄링하기 위한 리소스가 부족하다면, 스케줄러는 낮은 우선순위의 파드에 대한 축출을 시도한다. 공유 클러스터 내에서 다른 서비스 티어(예를 들어, 무료 및 유료)를 사용하는 테넌트를 가진 유스케이스가 있다면, 이러한 기능을 활용하여 특정 티어에 더 높은 우선순위를 부여할 수 있다.

DNS

쿠버네티스 클러스터는 네임과 IP 주소 간의 변환을 제공하기 위해 모든 서비스와 파드에서 도메인 네임 시스템(DNS) 서비스를 포함하고 있다. 기본적으로 쿠버네티스 DNS 서비스를 통해 클러스터 내 모든 네임스페이스를 조회할 수 있다.

테넌트가 파드 및 다른 쿠버네티스 리소스에 접근할 수 있거나, 더욱 강력한 격리가 필요한 멀티 테넌트 환경에서는 파드가 다른 네임스페이스의 서비스를 조회하는 것을 막는 것이 적절할 수 있다. 네임스페이스 교차 DNS 조회(cross-namespace DNS lookup)는 DNS 서비스의 보안 규칙 설정을 통해 제한할 수 있다. 예를 들어, CoreDNS(쿠버네티스 기본 DNS 서비스)는 쿠버네티스 메타데이터를 이용하여 네임스페이스 내의 파드 및 서비스에 대한 쿼리를 제한할 수 있다. 추가적인 정보는 CoreDNS 문서에 포함된 해당 사항을 설정하는 예시에서 확인할 수 있다.

테넌트 별 가상 컨트롤 플레인 모델이 사용될 시에는, 테넌트 별 DNS 서비스가 설정하거나 멀티 테넌트 DNS 서비스를 사용해야 한다. CoreDNS 사용자 맞춤 버전은 멀티 테넌트를 지원하는 하나의 예시이다.

오퍼레이터

오퍼레이터는 애플리케이션을 관리하는 쿠버네티스 컨트롤러이다. 오퍼레이터는 데이터베이스 서비스와 유사하게 애플리케이션의 여러 인스턴스를 간편하게 관리할 수 있어, 다중 소비자 (SaaS) 멀티 테넌시 유스케이스의 중요한 기반이 된다.

멀티 테넌트 환경에서 사용되는 오퍼레이터는 더욱 엄격한 가이드라인을 준수해야 한다. 다음은 오퍼레이터가 지켜야 할 사항이다.

  • 오퍼레이터가 배포된 네임스페이스뿐만 아니라, 다른 테넌트 네임스페이스에서의 리소스 생성도 지원해야 한다.
  • 스케줄링과 공평성을 보장하기 위해, 파드에 대한 리소스 요청 및 제한을 설정한다.
  • 파드에서 노드 격리 및 샌드박스 컨테이너와 같은 데이터 플레인 격리 기법을 설정할 수 있도록 지원한다.

구현

멀티 테넌시를 위해 쿠버네티스 클러스터를 공유하는 대표적인 방법은 두 가지가 있으며, 이는 네임스페이스 사용 (테넌트 별 네임스페이스) 또는 컨트롤 플레인 가상화 (테넌트 별 가상 컨트롤 플레인)이다.

두 경우 모두 데이터 플레인 격리와 API 우선순위 및 공평성과 같은 추가적인 고려 사항에 대한 관리를 권고한다.

네임스페이스 격리는 쿠버네티스에서 지원이 잘 이루어지고 있으며, 아주 적은 리소스 비용을 소모하며 서비스 간의 통신과 같은 테넌트가 상호작용하기 위한 기능을 제공한다. 그러나 설정하는 과정이 복잡하며 커스텀 리소스 데피니션 정의, 스토리지 클래스, 웹훅과 같이 네임스페이스 적용을 받지 않은 쿠버네티스 리소스에 대해서는 적용되지 않는다.

컨트롤 플레인 가상화는 더 많은 리소스 사용량과 더 어려운 테넌트 교차 공유(cross-tenant sharing)를 대가로, 네임스페이스 되지 않은 리소스에 대한 격리 기능을 제공한다. 네임스페이스 격리로는 충분하지 않으며 높은 운영 비용 (특히 온 프레미스) 또는 큰 오버헤드와 리소스 공유의 부재로 인한 전용 클러스터는 사용하지 못할 때 좋은 선택지다. 그러나, 가상 컨트롤 플레인을 사용하더라도 네임스페이스를 같이 사용하면 이익을 볼 수 있다.

두 가지의 옵션은 다음 섹션에서 상세히 다룬다.

테넌트 별 네임스페이스

이전에 언급하였듯이, 전용 클러스터 또는 가상 컨트롤 플레인을 사용하더라도 각 워크로드를 개별 네임스페이스로 격리하는 것을 고려해 보아야 한다. 이를 통해 각 워크로드는 컨피그맵 및 시크릿과 같이 자신의 리소스에만 접근할 수 있으며 각 워크로드에 대한 전용 보안 정책을 조정할 수 있다. 추가적으로, 전용 및 공유 클러스터 간 전환 혹은 서비스 메쉬와 같은 멀티 클러스터 툴을 이용할 수 있는 유연성을 제공받기 위해 각 네임스페이스 이름을 전체 클러스터 무리 사이에서도 고유하게 짓는 것이 (즉, 서로 다른 클러스터에 위치하더라도) 모범 사례이다.

반대로 워크로드 레벨이 아닌, 하나의 테넌트가 소유한 모든 워크로드에 대해 적용되는 정책도 있기 때문에 테넌트 레벨에서의 네임스페이스 적용도 장점이 있다. 그러나 이는 또 다른 문제를 제기한다. 첫 번째로 개별 워크로드에 대한 맞춤 정책을 적용하는 것이 어렵거나 불가능해지며, 두 번째로는 네임스페이스를 적용받을 하나의 "테넌시" 레벨을 정하는 것이 어려울 수 있다. 예를 들어, 하나의 조직에 부서, 팀, 하위 팀이 있다고 하면 어떤 단위에 대해 네임스페이스를 적용해야 하는가?

이러한 문제의 해결책으로, 네임스페이스를 계층으로 정리하고 특정 정책 및 리소스를 사이에서 공유할 수 있는 계층적 네임스페이스 컨트롤러(HNC)를 쿠버네티스에서 제공하고 있다. 또한 네임스페이스 레이블 관리, 네임스페이스 라이프사이클, 관리 위임, 관련된 네임스페이스 사이에서 리소스 쿼터 공유와 같은 이점도 있다. 이러한 기능은 다중 팀 및 다중 고객 시나리오에서도 유용하다.

유사한 기능을 제공하며 네임스페이스 리소스 관리를 돕는 다른 프로젝트는 다음과 같다.

다중 팀 테넌시

다중 고객 테넌시

정책 엔진

정책 엔진은 테넌트 구성을 생성하고 검증하는 기능을 제공한다.

테넌트 별 가상 컨트롤 플레인

컨트롤 플레인 격리의 또 다른 형태로는 쿠버네티스 확장을 이용하여 클러스터 전범위의 API 리소스를 세분화할 수 있는, 각 테넌트에 가상 컨트롤 플레인을 제공하는 형태이다. 데이터 플레인 격리 기법을 이러한 모델과 함께 이용하여 테넌트 간의 워커 노드를 안전하게 관리할 수 있다.

가상 컨트롤 플레인 기반의 멀티 테넌시 모델은 각 테넌트에게 전용 컨트롤 플레인 요소를 제공하며 클러스터 전범위 리소스 및 애드온 서비스에 대한 완전한 제어를 부여하게 되어 네임스페이스 기반 멀티 테넌시를 확장한다. 워커 노드는 모든 테넌트 간 공유 되며, 일반적으로 테넌트에 의해 접근이 불가능한 쿠버네티스 클러스터에 의해 관리된다. 이러한 클러스터를 슈퍼 클러스터 (혹은 호스트 클러스터)라고 부른다. 테넌트의 컨트롤 플레인은 하위 컴퓨팅 리소스와 직접적으로 연결된 것이 아니기 때문에 가상 컨트롤 플레인 이라고 부른다.

가상 컨트롤 플레인은 일반적으로 쿠버네티스 API 서버, 컨트롤러 매니저, etcd 데이터 스토어로 구성되어 있다. 테넌트 컨트롤 플레인과 슈퍼 클러스터 컨트롤 플레인 간 변화를 조정하는 메타데이터 동기화 컨트롤러를 통해 슈퍼 클러스터와 상호작용한다.

하나의 API 서버를 사용하였을 때 나타나는 격리 문제는 테넌트 별 전용 컨트롤 플레인을 이용하면 해결된다. 몇 가지 예시로는, 컨트롤 플레인 내의 소란스러운 이웃 문제, 잘못된 정책 설정으로 인한 제어불능 영향 반경, 웹훅 및 CRD와 같은 클러스터 범위 오브젝트 간의 충돌이 있다. 그러므로 각 테넌트가 쿠버네티스 API 서버에 대한 접근 권한 및 완전한 클러스터 관리 기능이 필요한 경우, 가상 컨트롤 플레인 모델이 적합하다.

개선된 격리의 대가는 각 테넌트 별 가상 컨트롤 플레인을 운영하고 유지하는 비용에서 나타난다. 추가적으로, 각 테넌트 컨트롤 플레인은 노드 레벨에서의 소란스러운 이웃 문제 또는 보안 위협과 같은 데이터 플레인에서의 격리 문제를 해결하지 못한다. 이러한 문제에 대해서는 별도로 대응해야 한다.

쿠버네티스 클러스터 API - 네스티드(CAPN) 프로젝트는 가상 컨트롤 플레인 구현 방식을 제공한다.

이외의 구현 방식