Skip to main content

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

· 11 min read
Jinwoong Kim

PKOS Study #5

가시다님의 Production Kubernetes Online Study (=PKOS) 2기 멤버가 되서 쿠버네티스 스터디를 진행하고 있다. 이정훈님의 집필하신 "24단계 실습으로 정복하는 쿠버네티스" 책을 기반으로 하는 스터디이며 총 (4+1)주간 진행이 되고 있고 마지막인 다섯번째 스터디 일정이 마무리 되었다.

이번 스터디 과제에서는 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와 mutatevalidategenerate 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와 같은 도구를 사용하여 정책을 조금더 적극적으로 감사하거나 차단하는 형태의 관리가 가능하다.

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