Skip to main content

kyverno를 활용한 Kubernetes 정책 엔진 적용

· 6 min read
Jinwoong Kim
Technologist and Cloud Consultant

kyverno 도구를 이용해서 쿠버네티스의 정책 엔진으로 활용하여 보안을 포함한 다양한 정책을 적용하는 방법을 알아본다.

kyverno​

Kyverno는 그리스어로 "지배하다, 다스리다"의 뜻으로 쿠버네티스 네이티브로 설계된 정책 엔진(policy engine)이다. Kyverno 정책을 활용하여 쿠버네티스 리소스가 정책에 부합하는지 검사하고, 필요하면 리소스를 변경하거나 생성할 수 있다. Kyverno 구조 및 동작 방식을 간단히 정리한다.

OPA Gatekeeper는 독자적인 policy 언어인 Rego를 사용하여 policy를 정의하만 kyverno는 쿠버네티스 리소스로 관리되며 정책을 작성하는 데 새로운 언어가 필요하지 않다. OPA Gatekeeper와 유사하게 pre-defined policy library 를 제공한다.

kyverno 구조 및 동작 방식​

Kyverno는 클러스터에서 dynamic admission controller로 동작한다. Kyverno는 kube-apiserver로부터 admission HTTP callback들의 확인 또는 변경을 수신하고, 정책 수용과 요청 거절을 반환하기 위한 정책을 적용한다. 따라서 kubectl, git, kustomize와 같은 익숙한 도구들을 사용하여 정책을 관리할 수 있다.

정책을 통해 쿠버네티스 리소스의 유효성 검사, 변경, 생성, 정리를 수행할 수 있을 뿐만 아니라 OCI 이미지 공급망(supply chain) 보안을 보장한다.

Kyverno CLI는 CI/CD 파이프라인의 일부로 정책을 테스트하고 리소스를 검증하는 데 사용할 수 있다.

Pasted image 20230408005656.png

고가용성 Kyverno 설치는 여러 개의 replica를 실행할 수 있으며, 각 복제본에는 서로 다른 기능을 수행하는 여러 컨트롤러가 있다.

  • Webhook : kube-apiserver의 AdmissionReview 요청을 처리
  • Monitor : webhook에 필요한 설정을 생성하고 관리
  • PolicyController : policy 리소스를 감시하며, 설정된 스캔 간격에 따라서 백그라운드 스캔을 시작
  • GenerateController : 생성된 리소스들의 생명주기를 관리

Kyverno는 최신 버전의 manifest 또는 Helm을 사용하여 설치할 수 있다. Kyverno는 쿠버네티스 프로젝트와 동일한 지원 정책인 N-2 정책을 따르며, 세 가지 최신 마이너 릴리스가 유지된다.

YAML을 사용하여 Kyverno 설치​

단일 설치 매니페스트를 사용하여 Kyverno를 설치할 수도 있지만 프로덕션 설치로 고가용성으로 구성할 경우 헬름 차트로 해야 한다.

kubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.9.0/install.yaml

Helm을 사용하여 Kyverno 설치​

헬름을 사용하여 Kyverno를 설치하려면 먼저 Kyverno 헬름 리포지토리를 추가한다.

helm repo add kyverno https://kyverno.github.io/kyverno/

리포지토리를 업데이트 하고 차트를 검색한다.

helm repo update
helm search repo kyverno -l

고가용성을 위해 replica를 3으로 설치한다.

helm install kyverno kyverno/kyverno -n kyverno --create-namespace --set replicaCount=3

Kyverno 파드 보안 표준 정책을 설치하려면 Kyverno를 설치한 후 아래 헬름 명령어를 실행한다.

helm install kyverno-policies kyverno/kyverno-policies -n kyverno

Pasted image 20230408020119.png

정책에 대해서 조금 자세히 살펴보면, Policy는 Rule들의 집합이고, 각 rule은 하나의 match와 mutate, validate, generate resource 또는 verifyImages 중 하나로 구성된다. Policy의 종류(kind)는 클러스터 전체에 적용되는 ClusterPolicy와 namespace에 적용되는 Policy가 있다.

정책은 정의된 순서대로 적용된다. admission control에서 mutation 규칙은 validation 규칙 전에 적용되기 때문에 mutation에 의한 결과를 validation할 수 있다. 모든 mutation 규칙은 모든 정책에서 validation 규칙이 적용되기 전에 적용된다.

여러가지 정책들이 있지만 간단하게 테스트를 진행하는 조건으로 latest 태그가 달린 이미지는 배포되지 않게 하는 것을 진행해 본다.

https://kyverno.io/policies/best-practices/disallow_latest_tag/disallow_latest_tag/

latest 태그는 변경 가능하며 이미지가 변경되면 예기치 않은 오류가 발생할 수 있다. 일반적으로 애플리케이션 파드의 특정 버전에 매핑되는 변경 불가능한 태그를 사용하는 것이 좋다. 이 정책은 이미지가 태그를 지정하고 해당 태그가 latest로 호출되지 않는지 확인한다.

아래 ClusterPolicy 에서 spec.validationFailureAction는 유효성 검사 정책 규칙 실패 시 어떤 액션을 수행할지 정하는 부분이다. enforce 는 정책내의 규칙(latest 태그가 있는 파드가 배포될 경우)에 해당하는 이벤트가 발생하게 되면 강제적용되고, 기본값인 audit의 경우에는 감사로그만 생성이 된다.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
annotations:
policies.kyverno.io/title: Disallow Latest Tag
policies.kyverno.io/category: Best Practices
policies.kyverno.io/minversion: 1.6.0
policies.kyverno.io/severity: medium
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
The ':latest' tag is mutable and can lead to unexpected errors if the
image changes. A best practice is to use an immutable tag that maps to
a specific version of an application Pod. This policy validates that the image
specifies a tag and that it is not called `latest`.
spec:
validationFailureAction: enforce
background: true
rules:
- name: require-image-tag
match:
any:
- resources:
kinds:
- Pod
validate:
message: "An image tag is required."
pattern:
spec:
containers:
- image: "*:*"
- name: validate-image-tag
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Using a mutable image tag e.g. 'latest' is not allowed."
pattern:
spec:
containers:
- image: "!*:latest"

테스트로 nginx:latest 이미지를 생성하면 admission webhook 단계에서 요청을 거절하여 deployment 배포가 실패한 것을 확인할 수 있다.

$ kubectl create deployment nginx --image=nginx:latest

error: failed to create deployment: admission webhook "validate.kyverno.svc-fail" denied the request:

policy Deployment/default/nginx for resource violation:

disallow-latest-tag:
autogen-validate-image-tag: 'validation error: Using a mutable image tag e.g. ''latest''
is not allowed. rule autogen-validate-image-tag failed at path /spec/template/spec/containers/0/image/'

event를 확인해보면 다음과 같이 nginx 파드 오브젝트가 Killing 되는것을 확인할 수 있다.

$ kubectl get events -A --sort-by=.metadata.creationTimestamp --field-selector type!=Warning
NAMESPACE LAST SEEN TYPE REASON OBJECT MESSAGE
default 1m Normal Killing pod/nginx-7597c656c9-rlvnr Stopping container nginx

이번에는 정책 위반 시 audit 옵션으로 바꾸고 똑같이 배포를 진행해보면 정상적으로 배포는 진행되지만, event나 describe로 확인해보면 다음과 같이 정책 위반 Warning 메세지를 확인할 수 있다.

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m29s default-scheduler Successfully assigned default/nginx-7597c656c9-w897t to i-00b3ebc1b78f19739
Normal Pulling 2m28s kubelet Pulling image "nginx:latest"
Normal Pulled 2m21s kubelet Successfully pulled image "nginx:latest" in 6.218701714s
Normal Created 2m21s kubelet Created container nginx
Normal Started 2m21s kubelet Started container nginx
Warning PolicyViolation 118s kyverno-scan policy disallow-latest-tag/validate-image-tag fail: validation error: Using a mutable image tag e.g. 'latest' is not allowed. rule validate-image-tag failed at path /spec/containers/0/image/

예시로 이미지 태그를 제어하는 정책을 가지고 테스트를 진행하였지만, 이외에도 많은 정책들을 적용해볼 수 있다.

  • Validate : Kubernetes API Server로 들어오는 요청 중 필수 설정(예, 특정 라벨이 누락되거나, 인그레스 생성시 인증서가 누락된 경우)이 누락된 경우 차단
  • Mutate : 운영환경에서 일부 설정 오류로 인한 장애가 발생하지 않도록 예방
  • Disallow Capabilities: 정책에 나열된 Linux Capability 이외의 기능을 추가하는 것은 허용하지 않음

정리​

1.25버전 부터 Pod Security Policies(PSPs)가 deprecated 되면서 admission controller와 정책 엔진 영역에서 활용이 가능한 솔루션이 필요하게 되었는데, 스터디에서 소개해준 polaris는 깔끔한 대시보드와 정책 엔진으로서 다양한 기능들을 활용할 수 있다. polaris는 오픈소스 기준에서도 보안에 대한 취약점과 설정을 쉽게 알아내고 리포트를 뽑아내는 측면이 강하다면, kyverno는 정책을 Kubernetes 리소스로 native하게 관리할 수 있기 때문에 kubectl, git, kustomize와 같은 도구를 사용하여 정책을 조금더 적극적으로 감사하거나 차단하는 형태의 관리가 가능하다.

해당 포스팅은 현재 재직중인 회사에 관련이 없고, 개인 역량 개발을 위한 자료로 활용할 예정입니다.