PKOS 2기 5주차 학습 스터디 - GateKeeper

Louis·2023년 4월 9일
0

PKOS 2기

목록 보기
7/7


2023년 3월 6일부터 @cloudnet study를 시작 하였다.

[24단계 실습으로 정복하는 쿠버네티스][이정훈 지음]의 책을 기본으로 학습을 한다.

운영을 하면서도 부족한 부분을 배울 수 있을 것이란 기대감과 함께 시작한 수업이나 숙제를 하지 못해서 발생하는 불상사를 경험하지 않고 5주간의 스터디를 잘 마무리 했으면 좋겠다.

5주차 스터디 내용을 정리해 본다.

5주차에는 쿠버네티스 클러스터 보안에 대한 내용을 스터디 하였다.
어느 시스템이든 보안을 생략하고 시스템을 구성하진 못한다. 그동안 국내에서도 발생한 다양한 사례들을 통해서 금전적인 손해뿐 아니라 신뢰도에 영향을 주어서 시스템 및 서비스에 대한 신뢰성 추락으로 손해를 보는 경우를 정말 많이 보게 되었다.

모든 시스템을 폐쇄망에 구성하고 운영하면 보안에 대한 부분은 조금은 부담이 덜 할 수도 있겠지만 외부와 통신을 해야 하는 환경의 경우 보안을 조금 더 신경써서 구성을 하는게 당연한 상황인듯 하다.

5주차에서 스터디를 진행 한 내용 중 파드/컨테이너 보안 컨텍스트 내용이 있었다
파드/컨테이너 컨텍스트는 리눅스 보안 및 환경을 바탕으로 파드 및 컨테이너에 할당을 해서 사용하는 다양한 설정 및 방법에 대한 내용을 인지함으로써 진행 할 수 있었다.

내가 회사에서 클러스터를 구성하고 연구원 및 개발자들이 생성하는 다양한 서비스와 리소스를 일일이 검사 할 수가 없었기에 생성을 시도 할때 기존에 설정해 둔 다양한 보안 관련 설정의 위배 여부를 확인하고 생성/실패 하도록 설정을 했던 방법에 대해서 간략하게 정리하고자 한다.

Admission Control이란?

쿠버네티스에선 간단하게 3가지 단계를 통해서 접근제어를 관리한다

  • 인증 : 시스템에 접근을 하는 사용자에 대한 인증을 하는 단계(토큰)
  • 권한 허가 : 인증을 통과한 사용자가 갖고 있는 시스템에서 어떤 행동을 수행 할 수 있는지에 대한 확인 단계
  • Adminssion Control : 인증과 권한 허가를 통과한 사용자의 요청에 대한 내용을 검토하고 보안적/정책적 문제가 없는지 확인을 하는 단계
    ex) 시스템에 허가 된 권한 내에서 수행은 가능하지만 시스템이 정한 정책에 대해서 위배되지 않는지(LimitRange, ResourceQuota)를 체크하는 단계

Admission Controller는 K8S API를 사용하여 Admission Control을 하는 주체이다.
Webhook 서버를 직접 개발하여 k8s에 올려서 사용할 수도 있고, Rego 언어를 사용하여 policy에 대한 내용을 작성하는 OPA를 사용할 수도 있다.
두 방법 모두 Admission Controller가 결과를 전달받아 validation한다.
OPA가 초기 학습비용이 조금 있긴 하지만, 학습 후에는 선언적으로(declarative) 손쉽게 validation 로직을 구현할 수 있기 때문에 이를 적용하기로 하였다.

Admission Control의 전체적인 로직은 다음과 같다.

  1. Request, Event, etc
  2. OPA에게 쿼리 or 직접 개발한 Webhook 서버로 전달
  3. OPA or Webhook 서버에서 설정한 정책에 따라 판단 후 Admission Controller에게 결과 반환
  4. Admission Controller는 반환 받은 결과에 따라 처리

OPA와 GateKeeper

OPA란?

OPA(Open Policy Agent)는 플랫폼 관리자에게 세밀한 권한 관리를 할수 있도록 지원하는 범용 정책 엔진이다
K8S 뿐만 아니라 OPA 엔진을 이용하는 모든 플랫폼에서 사용 가능하다

OPA동작

  • 요청이 들어오면 서비스는 JSON을 이용하여 OPA에 허용 여부 질의
  • 질의를 받은 OPA는 저장된 Policy를 불러와서 요청에 대한 평가를 하고 결과를 다시 JSON 형식으로 서비스에 반환

정책 설정

• OPA는 Policy를 기반으로하여 사용자 접근을 관리하기 때문에 Policy를 어떻게 작성하는지가 중요함
• Policy는 Rego라는 자체 질의언어를 이용하여 작성해야 하며, Rego 언어가 선언적으로 동작하기 때문에 해당 문법에 대한 이해 필요

OPA 실습 사이트

[튜토리얼]: https://www.openpolicyagent.org/docs/latest/kubernetes-tutorial/

[Rego Playground][https://play.openpolicyagent.org](https://play.openpolicyagent.org/)

GateKeeper

게이트키퍼는 내부적으로 OPA 엔진을 사용하는 OPA의 K8S 승인/제어를 위해 제작된 솔루션

게이트키퍼 동작

• K8S에서는 정책적인 결정을 API 서버와 분리하여 독립적으로 할 수 있게 Admission Controller Webhook (이하 웹훅) 제공
• 웹훅은 클러스터가 변경될 때 무조건 실행되며, 게이트키퍼는 웹훅을 확인하여 OPA 정책 엔진에서 정의한 대로 실행

주요기능

  • Validating Admission Control
    - 웹훅을 트릭거로 OPA와 api-server 다리 역할을 하여 정책 적용
  • Policies and Constraints
    - Rego 언어로 작성되며 정의한 요구하상을 위반하는 리소스들을 확인
  • Audit
    - 배포된 자원을 정기적으로 감사하여 Constraints에 반하는 것이 있는지 확인
  • Data Replication
    - 리소스를 복제 한 후 감사가 진행되며, 복제할 수 있도록 권한 부여 필요

GateKeeper 기본 템플릿

GateKeeper 배포

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update

$ helm install -n gatekeeper gatekeeper gatekeeper/gatekeeper
W0410 01:31:07.540467   14781 warnings.go:70] policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
W0410 01:31:20.514986   14781 warnings.go:70] policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
NAME: gatekeeper
NAMESPACE: gatekeeper
STATUS: deployed
REVISION: 1
TEST SUITE: None
  • 정상적으로 배포가 되면 다양한 리소스를 확인 할 수 있다

$ k get pods -w -owide
NAME                                             READY   STATUS    RESTARTS      AGE   IP           NODE              NOMINATED NODE   READINESS GATES
gatekeeper-audit-74769bf5b6-lsf7w                1/1     Running   2 (28s ago)   42s   10.32.0.37      <none>           <none>
gatekeeper-controller-manager-6657d79c88-44pc8   1/1     Running   0             42s   10.32.0.40      <none>           <none>
gatekeeper-controller-manager-6657d79c88-dn227   1/1     Running   0             42s   10.32.0.39     <none>           <none>
gatekeeper-controller-manager-6657d79c88-llfxc   1/1     Running   0             42s   10.32.0.38      <none>           <none>


kubectl get crd | grep gatekeeper.sh

assign.mutations.gatekeeper.sh                                   
assignmetadata.mutations.gatekeeper.sh                           
configs.config.gatekeeper.sh                                     
constraintpodstatuses.status.gatekeeper.sh                       
constrainttemplatepodstatuses.status.gatekeeper.sh               
constrainttemplates.templates.gatekeeper.sh
expansiontemplate.expansion.gatekeeper.sh
modifyset.mutations.gatekeeper.sh                                
mutatorpodstatuses.status.gatekeeper.sh                          
providers.externaldata.gatekeeper.sh                             

GateKeeper 정책 적용

  • namespace를 생성 할 때 라벨을 "Louis"라고 주지 않으면 만들어 지지 않는 정책을 적용해 보겠다.

Constraint Template

  • constraintTemplate을 사용하면 새로운 제약 조건을 선언 할 수 있다
  • 정책을 적용하는데 필요한 예상 입력 매개변수와 기본 레고를 제공할 수 있다
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("you must provide labels: %v", [missing])
        }
$ kubectl apply -f constraint-template.yaml
constrainttemplate.templates.gatekeeper.sh/k8srequiredlabels created
  • 다양한 정책들을 추가 하려면 rego: | 하단 부분에 rego 문법을 사용하여서 input, 조건, msg등을 구성하여서 배포 하면 적용 할 수 있다
  • Image pull URL 검사
    • image := input.request.object.spec.containers[i].image

      deny[msg] {
      	input.request.kind.kind == "Pod"
      
      	some container in input.request.object.spec.containers
      	not startswith(container.image, "example.git.co.kr"
      	msg := sprintf("Image '%v' comes from untrusted registry", [container.image])
      }
  • label 검사

    • not input.request.object.metadata.labels.costcenter

      deny[msg] {
      	not input.request.object.metadata.labels.costcenter
      	msg := "Every resource must have a costcenter label"
      }
  • Privileged mode 검사

    			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[_]
       }
    		```
    

Constraint

  • Constraint는 작성자가 ConstraintTemplate을 통해서 만들어진 정책을 반영하기 위해서 선언하는 선언(YAML)이라고 생각하면 된다
  • 레이블을 지정할 수 있는 객체가 있는 시스템이 있고 모든 객체에 지정 레이블이 있는지 확인하려면 다음과 같은 Constraint YAML을 작성해서 배포하면 된다.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: namespace-rule
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["louis"]
$ kubectl apply -f constraint.yaml
k8srequiredlabels.constraints.gatekeeper.sh/namespace-rule created

namespace 생성 테스트

  • Label 없이 namespace 생성
$ kubectl create ns gate-test
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [namespace-rule] you must provide labels: {"louis"}
  • Label 입력하여 생성
apiVersion: v1
kind: Namespace
metadata:
  labels:
    louis: make-true
  name: louis-test
kubectl apply -f namespace-louis.yaml
namespace/louis-test created

결론

운영하는 시스템에는 다양한 보안적 이슈가 존재할 수 있고 모든 보안적 이슈를 해결하는 솔루션을 구축한다는 것은 어려울 것이다.
쿠버네티스 환경에서 정책을 적용하고자 하는 리소스 및 영역에 gatekeeper를 통해서 비교적 쉽게 적용을 할 수 있다
이를 바탕으로 다양한 정책들을 반영하여서 혹시 모를 권한 탈취 이후에도 보안적인 이슈를 최소화 할 수 있는 환경을 구축 할 수 있길 바란다.

profile
인프라 운영하는 개발자

0개의 댓글