게이트키퍼를 사용하여 포드 보안 정책 적용


이 페이지에서는 Google Kubernetes Engine(GKE) 클러스터에 포드 수준 보안 제어를 적용하는 권장 방법을 설명합니다.

개요

게이트키퍼OPA(Open Policy Agent)를 사용하여 Kubernetes 클러스터에서 포드 생성 및 업데이트 요청을 검증하는 허용 컨트롤러입니다.

게이트키퍼를 사용하면 관리자가 제약조건을 사용하여 정책을 정의할 수 있습니다. 제약조건은 Kubernetes에서 배포 동작을 허용하거나 거부하는 조건의 집합입니다. 그런 다음 ConstraintTemplate을 사용하여 클러스터에 이러한 정책을 시행할 수 있습니다. 이 문서에서는 게이트키퍼를 사용하여 보안 정책을 시행, 테스트, 감사하도록 워크로드의 보안 기능을 제한하는 예시를 제공합니다.

게이트키퍼는 Kubernetes 포드SecurityPolicies와 동일한 기능을 강제 실행하는 것 외에도 다음을 수행할 수 있습니다.

  • 정책 출시: 점진적이고 범위가 지정된 방식으로 정책을 시행하여 워크로드가 중단되는 위험을 제한합니다.
  • 정책 변경사항 테스트 실행: 정책 영향 및 시행 전에 범위를 테스트하기 위한 메커니즘을 제공합니다.
  • 기존 정책 감사: 새로운 워크로드 및 기존 워크로드에 보안 제어 애플리케이션을 적용합니다(감사 제어).

Kubernetes 오픈소스 소프트웨어(OSS)는 Kubernetes 포드SecurityPolicies 지원을 중단하는 중이며 Google에서는 그 사용을 더 이상 권장하지 않습니다.

개념

게이트키퍼에는 관리자에게 클러스터를 제어할 수 있는 강력하고 유연한 수단을 제공하기 위한 두 가지 개념인 제약조건제약조건 템플릿이 있습니다. 두 가지 모두 개방형 정책 에이전트(OPA) 제악조건 프레임워크에서 상속된 개념입니다.

제약조건은 보안 정책을 표현하며 요구사항 및 적용 범위를 정의합니다. 제약조건 템플릿Rego로 작성된 재사용 가능한 문으로, 제약조건에 정의된 요구사항에 따라 Kubernetes 객체의 특정 필드를 평가하는 로직을 적용합니다.

예를 들어 특정 네임스페이스의 포드에 적용할 수 있는 허용 가능한 seccomp 프로필을 선언하는 제약조건과 이러한 값을 추출하고 시행을 처리하는 논리를 제공하는 유사한 제약조건 템플릿이 있을 수 있습니다.

게이트키퍼 저장소의 다음 제약조건 템플릿은 포드 사양에서 securityContext.privileged의 존재를 확인합니다.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8spspprivileged

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            c.securityContext.privileged
            msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
        }
        input_containers[c] {
            c := input.review.object.spec.containers[_]
        }
        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
        }

위의 제약조건 템플릿을 확장하기 위해 다음 제약조건은 dryrun 모드에서 이 제약조건 템플릿의 특정 시행에 대한 범위(kinds)를 정의합니다.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

게이트키퍼를 사용하면 특정 요구사항에 맞게 고유한 제약조건과 제약조건 템플릿을 만들 수 있습니다. 또한 빠른 채택과 보안 적용을 사용 설정하도록 정의된 게이트키퍼 저장소에서 제약조건 표준 설정과 제약조건 템플릿을 사용할 수 있습니다. 각 제약조건에는 예시 포드 구성도 함께 제공됩니다.

시작하기 전에

시작하기 전에 다음 태스크를 수행했는지 확인합니다.

다음 방법 중 하나를 사용하여 기본 gcloud 설정을 진행합니다.

  • gcloud init를 사용하여 기본값 설정 과정을 진행합니다.
  • gcloud config를 사용하여 프로젝트 ID, 영역, 리전을 개별적으로 설정합니다.

gcloud init 사용

One of [--zone, --region] must be supplied: Please specify location 오류가 표시되면 이 섹션을 완료합니다.

  1. gcloud init를 실행하고 다음 안내를 따르세요.

    gcloud init

    원격 서버에서 SSH를 사용하는 경우 --console-only 플래그를 사용하여 다음 명령어로 브라우저를 실행하지 못하게 할 수 있습니다.

    gcloud init --console-only
  2. 안내를 따라 gcloud에서 Google Cloud 계정을 사용하도록 승인합니다.
  3. 새 구성을 만들거나 기존 구성을 선택합니다.
  4. Google Cloud 프로젝트를 선택합니다.
  5. 영역 클러스터의 기본 Compute Engine 영역이나 리전 또는 Autopilot 클러스터의 리전을 선택합니다.

gcloud config 사용

  • 기본 프로젝트 ID를 설정합니다.
    gcloud config set project PROJECT_ID
  • 영역 클러스터를 사용하는 경우 기본 컴퓨팅 영역을 설정합니다.
    gcloud config set compute/zone COMPUTE_ZONE
  • Autopilot 또는 리전 클러스터를 사용하는 경우 기본 컴퓨팅 리전을 설정합니다.
    gcloud config set compute/region COMPUTE_REGION
  • gcloud를 최신 버전으로 업데이트합니다.
    gcloud components update

Anthos Config Management를 사용하여 클러스터에서 게이트키퍼 사용 설정

Anthos Config Management는 게이트키퍼 오픈소스 프로젝트에 빌드된 정책 엔진인 정책 컨트롤러를 제공합니다. Google은 코드형 정책, 멀티 클러스터 지원, Cloud Logging과의 통합, 구성 동기화 기능을 포함하여 확장 시 정책 시행에 관련된 공통된 문제를 해결하기 때문에 Anthos Config Management의 사용을 권장합니다.

클러스터에서 정책 컨트롤러를 사용 설정하려면 Anthos Config Management 설치 가이드를 따르세요.

제약조건 및 제약조건 템플릿 사용 설정

포드SecurityPolicy와 달리 게이트키퍼 및 제약조건 템플릿은 기존 워크로드나 새 워크로드에 부정적인 영향을 미치지 않고 설치 및 사용 설정할 수 있습니다. 따라서 적용 가능한 모든 포드 보안 제약조건 템플릿을 클러스터에 적용하는 것이 좋습니다.

또한 게이트키퍼 제약조건을 구현하여 네임스페이스 및 포드와 같은 특정 객체에 대한 제어를 적용할 수 있습니다.

제약조건 일치 문에서 포드를 정의하여 production 네임스페이스에 있는 포드로 범위를 제한하는 아래 예시를 관찰합니다.

...
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"

ConstraintConstraintTemplate 객체에 사용 가능한 옵션에 대한 자세한 내용은 Gatekeeper 사용 방법을 참조하세요.

정책 테스트

기존 클러스터에 새 정책을 도입하면 기존 워크로드 제한과 같은 부정적인 동작이 발생할 수 있습니다. 포드 보안에 게이트키퍼를 사용하는 이점 중 하나는 정책을 실제로 변경하지 않고도 테스트 실행 모드를 사용하여 정책의 효과와 영향을 테스트할 수 있다는 점입니다. 이렇게 하면 시행하지 않고도 실행 중인 클러스터에서 정책 구성을 테스트할 수 있습니다. 정책 위반은 간섭 없이 로깅 및 식별됩니다.

다음 단계에서는 개발자, 운영자 또는 관리자가 제약조건 템플릿과 제약조건을 적용하여 효율성 또는 잠재적 영향을 알아내는 방법을 보여줍니다.

  1. 게이트키퍼 구성을 적용하여 감사 및 테스트 실행 기능을 위한 데이터 복제

    kubectl create -f- <<EOF
    apiVersion: config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
      name: config
      namespace: "gatekeeper-system"
    spec:
      sync:
        syncOnly:
          - group: ""
            version: "v1"
            kind: "Namespace"
          - group: ""
            version: "v1"
            kind: "Pod"
    EOF
    
  2. 적용된 제약조건이 없는 상태에서 승격된 권한으로 워크로드를 실행합니다.

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    
  3. 위에서 언급한 k8spspprivilegedcontainer 제약조건 템플릿을 로드합니다.

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  4. 이제 이 제약조건 템플릿을 확장하는 새 제약조건을 만들어 보겠습니다. 이번에는 enforcementActiondryrun으로 설정합니다.

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  5. 게이트키퍼가 실행 중인 객체 데이터를 동기화하고 수동으로 위반 여부를 확인함으로써 제약조건의 status를 확인하여 위반이 발생했는지 확인할 수 있습니다.

    kubectl get k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container -o yaml
    
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
    ...
     name: psp-privileged-container
    ...
    spec:
     enforcementAction: dryrun
     match:
       kinds:
       - apiGroups:
         - ""
         kinds:
         - Pod
    status:
     auditTimestamp: "2019-12-15T22:19:54Z"
     byPod:
     - enforced: true
       id: gatekeeper-controller-manager-0
     violations:
     - enforcementAction: dryrun
       kind: Pod
       message: 'Privileged container is not allowed: nginx, securityContext: {"privileged":
         true}'
       name: nginx
       namespace: default
    
  6. 권한이 있는 다른 포드를 실행하여 정책이 배포와 충돌하지 않는지 확인하겠습니다.

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: privpod
      labels:
        app: privpod
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    이 새 포드가 성공적으로 배포됩니다.

  7. 이 섹션에서 만든 리소스를 삭제하려면 다음 명령어를 실행합니다.

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    kubectl delete pod/nginx
    kubectl delete pod/privpod
    

정책 시행

이제 기존 또는 새 워크로드에 영향을 주지 않고 정책의 유효성과 영향을 확인할 수 있으므로 본격 시행으로 정책을 구현해 봅시다.

다음 단계에서는 위 정책 유효성을 검사하는 데 사용된 예시를 바탕으로 개발자, 운영자 또는 관리자가 제약조건 템플릿과 제약조건을 적용하여 정책을 시행하는 방법을 보여줍니다.

  1. 앞에서 언급한 k8spspprivilegedcontainer 제약조건 템플릿을 로드합니다.

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  2. 이제 이 제약조건 템플릿을 확장하는 새 제약조건을 만들어 보겠습니다. 이번에는 enforcementAction 키를 설정하지 않습니다. 기본적으로 enforcementAction 키는 deny로 설정됩니다.

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  3. 승격된 권한을 선언하는 컨테이너를 배포하려고 시도합니다.

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    다음과 같은 오류 메시지가 표시됩니다.

    Error from server ([denied by psp-privileged-container] Privileged container is not allowed:
    nginx, securityContext: {"privileged": true}): error when creating "STDIN": admission webhook "validation.gatekeeper.sh" denied the request: [denied by psp-privileged-container]
    Privileged container is not allowed: nginx, securityContext: {"privileged": true}
    
  4. 삭제하려면 다음 명령어를 실행합니다.

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    

다음 단계

게이트키퍼는 선언적 정책을 사용하여 GKE 클러스터에서 보안을 시행하고 유효성을 검사하는 강력한 방법을 제공합니다. 게이트키퍼 사용은 보안 수준을 뛰어넘으며 관리 및 운영의 다른 측면에서 게이트키퍼를 사용할 수 있습니다.