이 섹션의 다중 페이지 출력 화면임. 여기를 클릭하여 프린트.

이 페이지의 일반 화면으로 돌아가기.

보안

클라우드 네이티브 워크로드를 안전하게 유지하기 위한 개념

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

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

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

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

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

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

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

클라우드

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

클라우드 공급자 보안

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

클라우드 공급자 보안
IaaS 공급자 링크
Alibaba Cloud https://www.alibabacloud.com/trust-center
Amazon Web Services https://aws.amazon.com/security/
Google Cloud Platform https://cloud.google.com/security/
IBM Cloud https://www.ibm.com/cloud/security
Microsoft Azure https://docs.microsoft.com/en-us/azure/security/azure-security
Oracle Cloud Infrastructure https://www.oracle.com/security/
VMWare VSphere https://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/
쿠버네티스 인그레스를 위한 TLS https://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 - 파드 시큐리티 폴리시

기능 상태: Kubernetes v1.21 [deprecated]

파드시큐리티폴리시(PodSecurityPolicy)는 쿠버네티스 v1.21부터 더 이상 사용되지 않으며, v1.25에서 제거될 예정이다. 파드시큐리티폴리시는 파드 시큐리티 어드미션으로 대체되었다. 사용 중단에 대한 상세 사항은 파드시큐리티폴리시 사용 중단: 과거, 현재, 그리고 미래를 참조한다.

파드 시큐리티 폴리시를 사용하면 파드 생성 및 업데이트에 대한 세분화된 권한을 부여할 수 있다.

파드 시큐리티 폴리시란?

Pod Security Policy 는 파드 명세의 보안 관련 측면을 제어하는 클러스터-레벨의 리소스이다. 파드시큐리티폴리시 오브젝트는 관련 필드에 대한 기본값뿐만 아니라 시스템에 적용하기 위해 파드가 실행해야만 하는 조건 셋을 정의한다. 관리자는 다음을 제어할 수 있다.

제어 측면 필드 이름
특권을 가진(privileged) 컨테이너의 실행 privileged
호스트 네임스페이스의 사용 hostPID, hostIPC
호스트 네트워킹과 포트의 사용 hostNetwork, hostPorts
볼륨 유형의 사용 volumes
호스트 파일시스템의 사용 allowedHostPaths
특정 FlexVolume 드라이버의 허용 allowedFlexVolumes
파드 볼륨을 소유한 FSGroup 할당 fsGroup
읽기 전용 루트 파일시스템 사용 필요 readOnlyRootFilesystem
컨테이너의 사용자 및 그룹 ID runAsUser, runAsGroup, supplementalGroups
루트 특권으로의 에스컬레이션 제한 allowPrivilegeEscalation, defaultAllowPrivilegeEscalation
리눅스 기능 defaultAddCapabilities, requiredDropCapabilities, allowedCapabilities
컨테이너의 SELinux 컨텍스트 seLinux
컨테이너에 허용된 Proc 마운트 유형 allowedProcMountTypes
컨테이너가 사용하는 AppArmor 프로파일 어노테이션
컨테이너가 사용하는 seccomp 프로파일 어노테이션
컨테이너가 사용하는 sysctl 프로파일 forbiddenSysctls,allowedUnsafeSysctls

파드 시큐리티 폴리시 활성화

파드 시큐리티 폴리시 제어는 선택 사항인 어드미션 컨트롤러로 구현된다. 어드미션 컨트롤러를 활성화하면 파드시큐리티폴리시가 적용되지만, 정책을 승인하지 않고 활성화하면 클러스터에 파드가 생성되지 않는다.

파드 시큐리티 폴리시 API(policy/v1beta1/podsecuritypolicy)는 어드미션 컨트롤러와 독립적으로 활성화되므로 기존 클러스터의 경우 어드미션 컨트롤러를 활성화하기 전에 정책을 추가하고 권한을 부여하는 것이 좋다.

정책 승인

파드시큐리티폴리시 리소스가 생성되면 아무 것도 수행하지 않는다. 이를 사용하려면 요청 사용자 또는 대상 파드의 서비스 어카운트는 정책에서 use 동사를 허용하여 정책을 사용할 권한이 있어야 한다.

대부분의 쿠버네티스 파드는 사용자가 직접 만들지 않는다. 대신 일반적으로 컨트롤러 관리자를 통해 디플로이먼트, 레플리카셋, 또는 기타 템플릿 컨트롤러의 일부로 간접적으로 생성된다. 컨트롤러에 정책에 대한 접근 권한을 부여하면 해당 컨트롤러에 의해 생성된 모든 파드에 대한 접근 권한이 부여되므로 정책을 승인하는 기본 방법은 파드의 서비스 어카운트에 대한 접근 권한을 부여하는 것이다( 참고).

RBAC을 통한 방법

RBAC은 표준 쿠버네티스 권한 부여 모드이며, 정책 사용 권한을 부여하는 데 쉽게 사용할 수 있다.

먼저, Role 또는 ClusterRole은 원하는 정책을 use 하려면 접근 권한을 부여해야 한다. 접근 권한을 부여하는 규칙은 다음과 같다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: <role name>
rules:
- apiGroups: ['policy']
  resources: ['podsecuritypolicies']
  verbs:     ['use']
  resourceNames:
  - <list of policies to authorize>

그런 다음 (Cluster)Role이 승인된 사용자에게 바인딩된다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: <binding name>
roleRef:
  kind: ClusterRole
  name: <role name>
  apiGroup: rbac.authorization.k8s.io
subjects:
# 네임스페이스의 모든 서비스 어카운트 승인(권장):
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:serviceaccounts:<authorized namespace>
# 특정 서비스 어카운트 승인(권장하지 않음):
- kind: ServiceAccount
  name: <authorized service account name>
  namespace: <authorized pod namespace>
# 특정 사용자 승인(권장하지 않음):
- kind: User
  apiGroup: rbac.authorization.k8s.io
  name: <authorized user name>

RoleBinding(ClusterRoleBinding 아님)을 사용하는 경우, 바인딩과 동일한 네임스페이스에서 실행되는 파드에 대해서만 사용 권한을 부여한다. 네임스페이스에서 실행되는 모든 파드에 접근 권한을 부여하기 위해 시스템 그룹과 쌍을 이룰 수 있다.

# 네임스페이스의 모든 서비스 어카운트 승인:
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:serviceaccounts
# 또는 동일하게, 네임스페이스의 모든 승인된 사용자에게 사용 권한 부여
- kind: Group
  apiGroup: rbac.authorization.k8s.io
  name: system:authenticated

RBAC 바인딩에 대한 자세한 예는, 역할 바인딩 예제를 참고한다. 파드시큐리티폴리시 인증에 대한 전체 예제는 아래를 참고한다.

추천 예제

파드시큐리티폴리시는 새롭고 간결해진 PodSecurity 어드미션 컨트롤러로 대체되고 있다. 이 변경에 대한 상세사항은 파드시큐리티폴리시 사용 중단: 과거, 현재, 그리고 미래를 참조한다. 다음 가이드라인을 참조하여 파드시큐리티폴리시를 새로운 어드미션 컨트롤러로 쉽게 전환할 수 있다.

  1. 파드시큐리티폴리시를 파드 보안 표준에 의해 정의된 폴리시로 한정한다.

  2. system:serviceaccounts:<namespace> (여기서 <namespace>는 타겟 네임스페이스) 그룹을 사용하여 파드시큐리티폴리시를 전체 네임스페이스에만 바인드한다. 예시는 다음과 같다.

    apiVersion: rbac.authorization.k8s.io/v1
    # 이 클러스터롤바인딩(ClusterRoleBinding)을 통해 "development" 네임스페이스의 모든 파드가 기준 파드시큐리티폴리시(PSP)를 사용할 수 있다.
    kind: ClusterRoleBinding
    metadata:
      name: psp-baseline-namespaces
    roleRef:
      kind: ClusterRole
      name: psp-baseline
      apiGroup: rbac.authorization.k8s.io
    subjects:
    - kind: Group
      name: system:serviceaccounts:development
      apiGroup: rbac.authorization.k8s.io
    - kind: Group
      name: system:serviceaccounts:canary
      apiGroup: rbac.authorization.k8s.io
    

문제 해결

  • 컨트롤러 관리자는 보안 API 포트에 대해 실행되어야 하며 수퍼유저 권한이 없어야 한다. API 서버 접근 제어에 대한 자세한 내용은 쿠버네티스 API에 대한 접근 제어를 참고하길 바란다. 컨트롤러 관리자가 신뢰할 수 있는 API 포트(localhost 리스너라고도 함)를 통해 연결된 경우, 요청이 인증 및 권한 부여 모듈을 우회하고, 모든 파드시큐리티폴리시 오브젝트가 허용되며 사용자는 특권을 가진 컨테이너를 만들 수 있는 권한을 부여할 수 있다.

컨트롤러 관리자 권한 구성에 대한 자세한 내용은 컨트롤러 역할을 참고하기 바란다.

정책 순서

파드 생성 및 업데이트를 제한할 뿐만 아니라 파드 시큐리티 폴리시를 사용하여 제어하는 많은 필드에 기본값을 제공할 수도 있다. 여러 정책을 사용할 수 있는 경우 파드 시큐리티 폴리시 컨트롤러는 다음 기준에 따라 정책을 선택한다.

  1. 기본 설정을 변경하거나 파드를 변경하지 않고 파드를 있는 그대로 허용하는 파드시큐리티폴리시가 선호된다. 이러한 비-변이(non-mutating) 파드시큐리티폴리시의 순서는 중요하지 않다.
  2. 파드를 기본값으로 설정하거나 변경해야 하는 경우, 파드를 허용할 첫 번째 파드시큐리티폴리시 (이름순)가 선택된다.

예제

이 예에서는 파드시큐리티폴리시 어드미션 컨트롤러가 활성화된 클러스터가 실행 중이고 클러스터 관리자 권한이 있다고 가정한다.

설정

이 예제와 같이 네임스페이스와 서비스 어카운트를 설정한다. 이 서비스 어카운트를 사용하여 관리자가 아닌 사용자를 조정한다.

kubectl create namespace psp-example
kubectl create serviceaccount -n psp-example fake-user
kubectl create rolebinding -n psp-example fake-editor --clusterrole=edit --serviceaccount=psp-example:fake-user

어떤 사용자로 활동하고 있는지 명확하게 하고 입력 내용을 저장하려면 2개의 별칭(alias)을 만든다.

alias kubectl-admin='kubectl -n psp-example'
alias kubectl-user='kubectl --as=system:serviceaccount:psp-example:fake-user -n psp-example'

정책과 파드 생성

파일에서 예제 파드시큐리티폴리시 오브젝트를 정의한다. 이는 특권있는 파드를 만들지 못하게 하는 정책이다. 파드시큐리티폴리시 오브젝트의 이름은 유효한 DNS 서브도메인 이름이어야 한다.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: example
spec:
  privileged: false  # 특권을 가진 파드는 허용금지!
  # 나머지는 일부 필수 필드를 채운다.
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'

그리고 kubectl로 생성한다.

kubectl-admin create -f example-psp.yaml

이제 권한이 없는 사용자로서 간단한 파드를 생성해보자.

kubectl-user create -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pause
spec:
  containers:
    - name: pause
      image: k8s.gcr.io/pause
EOF

이것의 출력은 다음과 같을 것이다.

Error from server (Forbidden): error when creating "STDIN": pods "pause" is forbidden: unable to validate against any pod security policy: []

무슨 일이 일어났나? 파드시큐리티폴리시가 생성되었지만, 파드의 서비스 어카운트나 fake-user는 새 정책을 사용할 권한이 없다.

kubectl-user auth can-i use podsecuritypolicy/example
no

예제 정책에서 fake-user에게 use 동사를 부여하는 rolebinding을 생성한다.

kubectl-admin create role psp:unprivileged \
    --verb=use \
    --resource=podsecuritypolicy \
    --resource-name=example
role "psp:unprivileged" created

kubectl-admin create rolebinding fake-user:psp:unprivileged \
    --role=psp:unprivileged \
    --serviceaccount=psp-example:fake-user
rolebinding "fake-user:psp:unprivileged" created

kubectl-user auth can-i use podsecuritypolicy/example
yes

이제 파드 생성을 다시 시도하자.

kubectl-user create -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pause
spec:
  containers:
    - name: pause
      image: k8s.gcr.io/pause
EOF

이것의 출력은 다음과 같을 것이다.

pod "pause" created

예상대로 작동한다! 그러나 특권있는 파드를 만들려는 시도는 여전히 거부되어야 한다.

kubectl-user create -f- <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: privileged
spec:
  containers:
    - name: pause
      image: k8s.gcr.io/pause
      securityContext:
        privileged: true
EOF

이것의 출력은 다음과 같을 것이다.

Error from server (Forbidden): error when creating "STDIN": pods "privileged" is forbidden: unable to validate against any pod security policy: [spec.containers[0].securityContext.privileged: Invalid value: true: Privileged containers are not allowed]

계속 진행하기 전에 파드를 삭제하자.

kubectl-user delete pod pause

다른 파드를 실행

약간 다르게 다시 시도해보자.

kubectl-user create deployment pause --image=k8s.gcr.io/pause
deployment "pause" created

kubectl-user get pods
No resources found.

kubectl-user get events | head -n 2
LASTSEEN   FIRSTSEEN   COUNT     NAME              KIND         SUBOBJECT                TYPE      REASON                  SOURCE                                  MESSAGE
1m         2m          15        pause-7774d79b5   ReplicaSet                            Warning   FailedCreate            replicaset-controller                   Error creating: pods "pause-7774d79b5-" is forbidden: no providers available to validate pod request

무슨 일이 일어났나? 우리는 이미 fake-user에 대해 psp:unprivileged 역할을 바인딩했는데, Error creating: pods "pause-7774d79b5-" is forbidden: no providers available to validate pod request 오류가 발생하는 이유는 무엇인가? 그 답은 소스인 replicaset-controller에 있다. Fake-user가 디플로이먼트를 성공적으로 생성했지만(레플리카셋을 성공적으로 생성했음), 레플리카셋이 파드를 생성했을 때 podsecuritypolicy 예제를 사용할 권한이 없었다.

이 문제를 해결하려면 psp:unprivileged 역할을 파드의 서비스 어카운트에 대신 바인딩한다. 이 경우(지정하지 않았으므로) 서비스 어카운트는 default이다.

kubectl-admin create rolebinding default:psp:unprivileged \
    --role=psp:unprivileged \
    --serviceaccount=psp-example:default
rolebinding "default:psp:unprivileged" created

이제 다시 한번 해본다면 replicaset-controller가 파드를 성공적으로 생성할 것이다.

kubectl-user get pods --watch
NAME                    READY     STATUS    RESTARTS   AGE
pause-7774d79b5-qrgcb   0/1       Pending   0         1s
pause-7774d79b5-qrgcb   0/1       Pending   0         1s
pause-7774d79b5-qrgcb   0/1       ContainerCreating   0         1s
pause-7774d79b5-qrgcb   1/1       Running   0         2s

정리

네임스페이스를 삭제하여 대부분의 예제 리소스를 정리한다.

kubectl-admin delete ns psp-example
namespace "psp-example" deleted

PodSecurityPolicy 리소스는 네임스페이스에 포함되지 않으므로 별도로 정리해야 한다.

kubectl-admin delete psp example
podsecuritypolicy "example" deleted

정책 예제

다음은 파드 시큐리티 폴리시 어드미션 컨트롤러를 사용하지 않는 것과 동일하게 만들 수 있는 최소한의 제한 정책이다.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: privileged
  annotations:
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*'
spec:
  privileged: true
  allowPrivilegeEscalation: true
  allowedCapabilities:
  - '*'
  volumes:
  - '*'
  hostNetwork: true
  hostPorts:
  - min: 0
    max: 65535
  hostIPC: true
  hostPID: true
  runAsUser:
    rule: 'RunAsAny'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'

다음은 권한이 없는 사용자로서의 실행을 필요로 하고, 루트로의 에스컬레이션(escalation) 가능성을 차단하고, 여러 보안 메커니즘을 사용을 필요로 하는 제한적 정책의 예제이다.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: restricted
  annotations:
    # docker/default 는 seccomp를 위한 프로파일을 나타내지만, 특별히 도커 런타임에 묶여 있는 것은 아니다.
    seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default,runtime/default'
    apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
    apparmor.security.beta.kubernetes.io/defaultProfileName:  'runtime/default'
spec:
  privileged: false
  # 루트로의 에스컬레이션을 방지하는 데 필요하다.
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  # 기본 볼륨 유형을 허용한다.
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    # 클러스터 관리자에 의해 구성된 휘발성 CSI 드라이버와 퍼시스턴트볼륨(PersistentVolume)의 사용은 안전하다고 가정한다.
    - 'csi'
    - 'persistentVolumeClaim'
    - 'ephemeral'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    # 루트 권한없이 컨테이너를 실행해야 한다.
    rule: 'MustRunAsNonRoot'
  seLinux:
    # 이 정책은 노드가 SELinux가 아닌 AppArmor를 사용한다고 가정한다.
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'MustRunAs'
    ranges:
      # 루트 그룹을 추가하지 않는다.
      - min: 1
        max: 65535
  fsGroup:
    rule: 'MustRunAs'
    ranges:
      # 루트 그룹을 추가하지 않는다.
      - min: 1
        max: 65535
  readOnlyRootFilesystem: false

더 많은 예제는 파드 보안 표준을 본다.

정책 레퍼런스

특권을 가진

Privileged - 파드의 컨테이너가 특권 모드를 사용할 수 있는지 여부를 결정한다. 기본적으로 컨테이너는 호스트의 모든 장치에 접근할 수 없지만 "특권을 가진" 컨테이너는 호스트의 모든 장치에 접근할 수 있다. 이것은 컨테이너가 호스트에서 실행되는 프로세스와 거의 동일한 접근을 허용한다. 이것은 네트워크 스택 조작 및 장치 접근과 같은 리눅스 기능을 사용하려는 컨테이너에 유용하다.

호스트 네임스페이스

HostPID - 파드 컨테이너가 호스트 프로세스 ID 네임스페이스를 공유할 수 있는지 여부를 제어한다. ptrace와 함께 사용하면 컨테이너 외부로 권한을 에스컬레이션하는 데 사용할 수 있다(ptrace는 기본적으로 금지되어 있음).

HostIPC - 파드 컨테이너가 호스트 IPC 네임스페이스를 공유할 수 있는지 여부를 제어한다.

HostNetwork - 파드가 노드 네트워크 네임스페이스를 사용할 수 있는지 여부를 제어한다. 이렇게 하면 파드에 루프백 장치에 접근 권한을 주고, 서비스는 로컬호스트(localhost)를 리스닝할 수 있으며, 동일한 노드에 있는 다른 파드의 네트워크 활동을 스누핑(snoop)하는 데 사용할 수 있다.

HostPorts - 호스트 네트워크 네임스페이스에 허용되는 포트 범위의 목록을 제공한다. minmax를 포함하여 HostPortRange의 목록으로 정의된다. 기본값은 허용하는 호스트 포트 없음(no allowed host ports)이다.

볼륨 및 파일시스템

Volumes - 허용되는 볼륨 유형의 목록을 제공한다. 허용 가능한 값은 볼륨을 생성할 때 정의된 볼륨 소스에 따른다. 볼륨 유형의 전체 목록은 볼륨 유형들에서 참고한다. 또한 *를 사용하여 모든 볼륨 유형을 허용할 수 있다.

새 PSP에 허용되는 볼륨의 최소 권장 셋 은 다음과 같다.

  • 컨피그맵
  • 다운워드API
  • emptyDir
  • 퍼시스턴트볼륨클레임
  • 시크릿
  • 프로젝티드(projected)

FSGroup - 일부 볼륨에 적용되는 보충 그룹(supplemental group)을 제어한다.

  • MustRunAs - 하나 이상의 range를 지정해야 한다. 첫 번째 범위의 최솟값을 기본값으로 사용한다. 모든 범위에 대해 검증한다.
  • MayRunAs - 하나 이상의 range를 지정해야 한다. 기본값을 제공하지 않고 FSGroups을 설정하지 않은 상태로 둘 수 있다. FSGroups이 설정된 경우 모든 범위에 대해 유효성을 검사한다.
  • RunAsAny - 기본값은 제공되지 않는다. 어떠한 fsGroup ID의 지정도 허용한다.

AllowedHostPaths - hostPath 볼륨에서 사용할 수 있는 호스트 경로의 목록을 지정한다. 빈 목록은 사용되는 호스트 경로에 제한이 없음을 의미한다. 이는 단일 pathPrefix 필드가 있는 오브젝트 목록으로 정의되며, hostPath 볼륨은 허용된 접두사로 시작하는 경로를 마운트할 수 있으며 readOnly 필드는 읽기-전용으로 마운트 되어야 함을 나타낸다. 예를 들면 다음과 같습니다.

 allowedHostPaths:
   # 이 정책은 "/foo", "/foo/", "/foo/bar" 등을 허용하지만,
   # "/fool", "/etc/foo" 등은 허용하지 않는다.
   # "/foo/../" 는 절대 유효하지 않다.
   - pathPrefix: "/foo"
     readOnly: true # 읽기 전용 마운트만 허용

ReadOnlyRootFilesystem - 컨테이너는 읽기-전용 루트 파일시스템(즉, 쓰기 가능한 레이어 없음)으로 실행해야 한다.

FlexVolume 드라이버

flexvolume에서 사용할 수 있는 FlexVolume 드라이버의 목록을 지정한다. 빈 목록 또는 nil은 드라이버에 제한이 없음을 의미한다. volumes 필드에 flexVolume 볼륨 유형이 포함되어 있는지 확인한다. 그렇지 않으면 FlexVolume 드라이버가 허용되지 않는다.

예를 들면 다음과 같다.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: allow-flex-volumes
spec:
  # ... 다른 스펙 필드
  volumes:
    - flexVolume
  allowedFlexVolumes:
    - driver: example/lvm
    - driver: example/cifs

사용자 및 그룹

RunAsUser - 컨테이너를 실행할 사용자 ID를 제어힌다.

  • MustRunAs - 하나 이상의 range를 지정해야 한다. 첫 번째 범위의 최솟값을 기본값으로 사용한다. 모든 범위에 대해 검증한다.
  • MustRunAsNonRoot - 파드가 0이 아닌 runAsUser로 제출되거나 이미지에 USER 지시문이 정의되어 있어야 한다(숫자 UID 사용). runAsNonRoot 또는 runAsUser 설정을 지정하지 않은 파드는 runAsNonRoot=true를 설정하도록 변경되므로 컨테이너에 0이 아닌 숫자가 정의된 USER 지시문이 필요하다. 기본값은 제공되지 않는다. 이 전략에서는 allowPrivilegeEscalation=false를 설정하는 것이 좋다.
  • RunAsAny - 기본값은 제공되지 않는다. 어떠한 runAsUser의 지정도 허용한다.

RunAsGroup - 컨테이너가 실행될 기본 그룹 ID를 제어한다.

  • MustRunAs - 하나 이상의 range를 지정해야 한다. 첫 번째 범위의 최솟값을 기본값으로 사용한다. 모든 범위에 대해 검증한다.
  • MayRunAs - RunAsGroup을 지정할 필요가 없다. 그러나 RunAsGroup을 지정하면 정의된 범위에 속해야 한다.
  • RunAsAny - 기본값은 제공되지 않는다. 어떠한 runAsGroup의 지정도 허용한다.

SupplementalGroups - 컨테이너가 추가할 그룹 ID를 제어한다.

  • MustRunAs - 하나 이상의 range를 지정해야 한다. 첫 번째 범위의 최솟값을 기본값으로 사용한다. 모든 범위에 대해 검증한다.
  • MayRunAs - 하나 이상의 range를 지정해야 한다. supplementalGroups에 기본값을 제공하지 않고 설정하지 않은 상태로 둘 수 있다. supplementalGroups가 설정된 경우 모든 범위에 대해 유효성을 검증한다.
  • RunAsAny - 기본값은 제공되지 않는다. 어떠한 supplementalGroups의 지정도 허용한다.

권한 에스컬레이션

이 옵션은 allowPrivilegeEscalation 컨테이너 옵션을 제어한다. 이 bool은 컨테이너 프로세스에서 no_new_privs 플래그가 설정되는지 여부를 직접 제어한다. 이 플래그는 setuid 바이너리가 유효 사용자 ID를 변경하지 못하게 하고 파일에 추가 기능을 활성화하지 못하게 한다(예: ping 도구 사용을 못하게 함). MustRunAsNonRoot를 효과적으로 강제하려면 이 동작이 필요하다.

AllowPrivilegeEscalation - 사용자가 컨테이너의 보안 컨텍스트를 allowPrivilegeEscalation=true로 설정할 수 있는지 여부를 게이트한다. 이 기본값은 setuid 바이너리를 중단하지 않도록 허용한다. 이를 false로 설정하면 컨테이너의 하위 프로세스가 상위 프로세스보다 더 많은 권한을 얻을 수 없다.

DefaultAllowPrivilegeEscalation - allowPrivilegeEscalation 옵션의 기본값을 설정한다. 이것이 없는 기본 동작은 setuid 바이너리를 중단하지 않도록 권한 에스컬레이션을 허용하는 것이다. 해당 동작이 필요하지 않은 경우 이 필드를 사용하여 기본적으로 허용하지 않도록 설정할 수 있지만 파드는 여전히 allowPrivilegeEscalation을 명시적으로 요청할 수 있다.

기능

리눅스 기능은 전통적으로 슈퍼유저와 관련된 권한을 보다 세밀하게 분류한다. 이러한 기능 중 일부는 권한 에스컬레이션 또는 컨테이너 분류에 사용될 수 있으며 파드시큐리티폴리시에 의해 제한될 수 있다. 리눅스 기능에 대한 자세한 내용은 기능(7)을 참고하길 바란다.

다음 필드는 대문자로 표기된 기능 이름 목록을 CAP_ 접두사 없이 가져온다.

AllowedCapabilities - 컨테이너에 추가될 수 있는 기능의 목록을 제공한다. 기본적인 기능 셋은 암시적으로 허용된다. 비어있는 셋은 기본 셋을 넘어서는 추가 기능이 추가되지 않는 것을 의미한다. *는 모든 기능을 허용하는 데 사용할 수 있다.

RequiredDropCapabilities - 컨테이너에서 삭제해야 하는 기능이다. 이러한 기능은 기본 셋에서 제거되며 추가해서는 안된다. RequiredDropCapabilities에 나열된 기능은 AllowedCapabilities 또는 DefaultAddCapabilities에 포함되지 않아야 한다.

DefaultAddCapabilities - 런타임 기본값 외에 기본적으로 컨테이너에 추가되는 기능이다. 도커 런타임을 사용할 때 기본 기능 목록은 도커 문서를 참고하길 바란다.

SELinux

  • MustRunAs - seLinuxOptions을 구성해야 한다. seLinuxOptions을 기본값으로 사용한다. seLinuxOptions에 대해 유효성을 검사한다.
  • RunAsAny - 기본값은 제공되지 않는다. 어떠한 seLinuxOptions의 지정도 허용한다.

AllowedProcMountTypes

allowedProcMountTypes는 허용된 ProcMountTypes의 목록이다. 비어 있거나 nil은 DefaultProcMountType만 사용할 수 있음을 나타낸다.

DefaultProcMount는 /proc의 읽기 전용 및 마스킹(masking)된 경로에 컨테이너 런타임 기본값을 사용한다. 대부분의 컨테이너 런타임은 특수 장치나 정보가 실수로 보안에 노출되지 않도록 /proc의 특정 경로를 마스킹한다. 이것은 문자열 Default로 표시된다.

유일하게 다른 ProcMountType은 UnmaskedProcMount로, 컨테이너 런타임의 기본 마스킹 동작을 무시하고 새로 작성된 /proc 컨테이너가 수정없이 그대로 유지되도록 한다. 이 문자열은 Unmasked로 표시된다.

AppArmor

파드시큐리티폴리시의 어노테이션을 통해 제어된다. AppArmor 문서를 참고하길 바란다.

Seccomp

쿠버네티스 v1.19부터 파드나 컨테이너의 securityContext 에서 seccompProfile 필드를 사용하여 seccomp 프로파일 사용을 제어할 수 있다. 이전 버전에서는, 파드에 어노테이션을 추가하여 seccomp를 제어했다. 두 버전에서 동일한 파드시큐리티폴리시를 사용하여 이러한 필드나 어노테이션이 적용되는 방식을 적용할 수 있다.

seccomp.security.alpha.kubernetes.io/defaultProfileName - 컨테이너에 적용할 기본 seccomp 프로파일을 지정하는 어노테이션이다. 가능한 값은 다음과 같다.

  • unconfined - 대안이 제공되지 않으면 Seccomp가 컨테이너 프로세스에 적용되지 않는다(쿠버네티스의 기본값임).
  • runtime/default - 기본 컨테이너 런타임 프로파일이 사용된다.
  • docker/default - 도커 기본 seccomp 프로파일이 사용된다. 쿠버네티스 1.11 부터 사용 중단(deprecated) 되었다. 대신 runtime/default 사용을 권장한다.
  • localhost/<path> - <seccomp_root>/<path>에 있는 노드에서 파일을 프로파일로 지정한다. 여기서 <seccomp_root>는 Kubelet의 --seccomp-profile-root 플래그를 통해 정의된다. --seccomp-profile-root 플래그가 정의되어 있지 않으면, <root-dir>--root-dir 플래그로 지정된 <root-dir>/seccomp 기본 경로가 사용된다.

seccomp.security.alpha.kubernetes.io/allowedProfileNames - 파드 seccomp 어노테이션에 허용되는 값을 지정하는 어노테이션. 쉼표로 구분된 허용된 값의 목록으로 지정된다. 가능한 값은 위에 나열된 값과 모든 프로파일을 허용하는 * 이다. 이 주석이 없으면 기본값을 변경할 수 없다.

Sysctl

기본적으로 모든 안전한 sysctls가 허용된다.

  • forbiddenSysctls - 특정 sysctls를 제외한다. 목록에서 안전한 것과 안전하지 않은 sysctls의 조합을 금지할 수 있다. 모든 sysctls 설정을 금지하려면 자체적으로 *를 사용한다.
  • allowedUnsafeSysctls - forbiddenSysctls에 나열되지 않는 한 기본 목록에서 허용하지 않은 특정 sysctls를 허용한다.

Sysctl 문서를 참고하길 바란다.

다음 내용

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

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

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

Diagram of request handling steps for Kubernetes API request

전송 보안

일반적인 쿠버네티스 클러스터에서 API는 443번 포트에서 서비스한다. API 서버는 인증서를 제시한다. 이 인증서는 종종 자체 서명되기 때문에 일반적으로 사용자 머신의 $USER/.kube/config는 API 서버의 인증서에 대한 루트 인증서를 포함하며, 시스템 기본 루트 인증서 대신 사용된다. kube-up.sh을 사용하여 클러스터를 직접 생성할 때 이 인증서는 일반적으로 $USER/.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 서버 포트와 IP

이전의 논의는 (일반적인 경우) API 서버의 보안 포트로 전송되는 요청에 적용된다. API 서버는 실제로 다음과 같이 2개의 포트에서 서비스할 수 있다.

기본적으로, 쿠버네티스 API 서버는 2개의 포트에서 HTTP 서비스를 한다.

  1. 로컬호스트 포트:

    • 테스트 및 부트스트랩을 하기 위한 것이며 마스터 노드의 다른 구성요소 (스케줄러, 컨트롤러 매니저)가 API와 통신하기 위한 것이다.
    • TLS가 없다.
    • 기본 포트는 8080이다.
    • 기본 IP는 로컬호스트(localhost)이며, --insecure-bind-address 플래그를 사용하여 변경한다.
    • 요청이 인증 및 인가 모듈을 우회한다.
    • 요청이 어드미션 제어 모듈(들)에 의해 처리된다.
    • 호스트 접근 요구로부터 보호를 받는다.
  2. 보안 포트:

    • 가능한 항상 사용하는 것이 좋다.
    • TLS를 사용한다. --tls-cert-file 플래그로 인증서를 지정하고 --tls-private-key-file 플래그로 키를 지정한다.
    • 기본 포트는 6443이며, --secure-port 플래그를 사용하여 변경한다.
    • 기본 IP는 로컬호스트가 아닌 첫 번째 네트워크 인터페이스이며, --bind-address 플래그를 사용하여 변경한다.
    • 요청이 인증 및 인가 모듈에 의해 처리된다.
    • 요청이 어드미션 제어 모듈(들)에 의해 처리된다.
    • 인증 및 인가 모듈을 실행한다.

GCE(구글 컴퓨트 엔진) 및 다른 클라우드 제공자에서 kube-up.sh로 클러스터를 생성하면 API 서버는 포트 443에서 서비스한다. GCE에서는 외부 HTTPS가 API에 접근할 수 있도록 프로젝트에서 방화벽 규칙이 구성된다. 이외에 클러스터 설정 방법은 다양하다.