2023년 3월 6일부터 @cloudnet study를 시작 하였다.
[24단계 실습으로 정복하는 쿠버네티스][이정훈 지음]의 책을 기본으로 학습을 한다.
운영을 하면서도 부족한 부분을 배울 수 있을 것이란 기대감과 함께 시작한 수업이나 숙제를 하지 못해서 발생하는 불상사를 경험하지 않고 5주간의 스터디를 잘 마무리 했으면 좋겠다.
5주차 스터디 내용을 정리해 본다.
5주차에는 쿠버네티스 클러스터 보안에 대한 내용을 스터디 하였다.
어느 시스템이든 보안을 생략하고 시스템을 구성하진 못한다. 그동안 국내에서도 발생한 다양한 사례들을 통해서 금전적인 손해뿐 아니라 신뢰도에 영향을 주어서 시스템 및 서비스에 대한 신뢰성 추락으로 손해를 보는 경우를 정말 많이 보게 되었다.
모든 시스템을 폐쇄망에 구성하고 운영하면 보안에 대한 부분은 조금은 부담이 덜 할 수도 있겠지만 외부와 통신을 해야 하는 환경의 경우 보안을 조금 더 신경써서 구성을 하는게 당연한 상황인듯 하다.
5주차에서 스터디를 진행 한 내용 중 파드/컨테이너 보안 컨텍스트 내용이 있었다
파드/컨테이너 컨텍스트는 리눅스 보안 및 환경을 바탕으로 파드 및 컨테이너에 할당을 해서 사용하는 다양한 설정 및 방법에 대한 내용을 인지함으로써 진행 할 수 있었다.
내가 회사에서 클러스터를 구성하고 연구원 및 개발자들이 생성하는 다양한 서비스와 리소스를 일일이 검사 할 수가 없었기에 생성을 시도 할때 기존에 설정해 둔 다양한 보안 관련 설정의 위배 여부를 확인하고 생성/실패 하도록 설정을 했던 방법에 대해서 간략하게 정리하고자 한다.
쿠버네티스에선 간단하게 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의 전체적인 로직은 다음과 같다.
- Request, Event, etc
- OPA에게 쿼리 or 직접 개발한 Webhook 서버로 전달
- OPA or Webhook 서버에서 설정한 정책에 따라 판단 후 Admission Controller에게 결과 반환
- Admission Controller는 반환 받은 결과에 따라 처리
OPA(Open Policy Agent)는 플랫폼 관리자에게 세밀한 권한 관리를 할수 있도록 지원하는 범용 정책 엔진이다
K8S 뿐만 아니라 OPA 엔진을 이용하는 모든 플랫폼에서 사용 가능하다
• OPA는 Policy를 기반으로하여 사용자 접근을 관리하기 때문에 Policy를 어떻게 작성하는지가 중요함
• Policy는 Rego라는 자체 질의언어를 이용하여 작성해야 하며, Rego 언어가 선언적으로 동작하기 때문에 해당 문법에 대한 이해 필요
[튜토리얼]: https://www.openpolicyagent.org/docs/latest/kubernetes-tutorial/
[Rego Playground][https://play.openpolicyagent.org](https://play.openpolicyagent.org/)
게이트키퍼는 내부적으로 OPA 엔진을 사용하는 OPA의 K8S 승인/제어를 위해 제작된 솔루션
• K8S에서는 정책적인 결정을 API 서버와 분리하여 독립적으로 할 수 있게 Admission Controller Webhook (이하 웹훅) 제공
• 웹훅은 클러스터가 변경될 때 무조건 실행되며, 게이트키퍼는 웹훅을 확인하여 OPA 정책 엔진에서 정의한 대로 실행
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
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
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[_]
}
```
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
$ kubectl create ns gate-test
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [namespace-rule] you must provide labels: {"louis"}
apiVersion: v1
kind: Namespace
metadata:
labels:
louis: make-true
name: louis-test
kubectl apply -f namespace-louis.yaml
namespace/louis-test created
운영하는 시스템에는 다양한 보안적 이슈가 존재할 수 있고 모든 보안적 이슈를 해결하는 솔루션을 구축한다는 것은 어려울 것이다.
쿠버네티스 환경에서 정책을 적용하고자 하는 리소스 및 영역에 gatekeeper를 통해서 비교적 쉽게 적용을 할 수 있다
이를 바탕으로 다양한 정책들을 반영하여서 혹시 모를 권한 탈취 이후에도 보안적인 이슈를 최소화 할 수 있는 환경을 구축 할 수 있길 바란다.