[Daily morning study] Kubernetes Admission Controller์ OPA(Open Policy Agent)
#daily morning study
Admission Controller๋
Kubernetes API ์๋ฒ๋ก ๋ค์ด์ค๋ ์์ฒญ์ ์ธ์ฆ(Authentication) โ ์ธ๊ฐ(Authorization) โ Admission ์์๋ก ์ฒ๋ฆฌ๋๋ค.
Admission Controller๋ ์ด ์ธ ๋ฒ์งธ ๋จ๊ณ์์ ๋์ํ๋ฉฐ, ์ค๋ธ์ ํธ๊ฐ ํด๋ฌ์คํฐ์ ์ค์ ๋ก ๋ฐ์๋๊ธฐ ์ ์ ์์ฒญ์ ๊ฐ๋ก์ฑ์ ๊ฒ์ฆํ๊ฑฐ๋ ๋ณ๊ฒฝํ๋ ํ๋ฌ๊ทธ์ธ์ด๋ค.
kubectl apply โ API Server โ Authn โ Authz โ [Admission] โ etcd ์ ์ฅ
๋ ๊ฐ์ง ํ์ ์ด ์๋ค.
| ํ์ | ์ญํ |
|---|---|
| Mutating Admission | ์์ฒญ์ ์์ (์: ๊ธฐ๋ณธ๊ฐ ์ฃผ์ , ์ฌ์ด๋์นด ์๋ ์ถ๊ฐ) |
| Validating Admission | ์์ฒญ์ ๊ฒ์ฆ ํ ํ์ฉ ๋๋ ๊ฑฐ๋ถ |
Mutating์ด ๋จผ์ ์คํ๋ ํ Validating์ด ์คํ๋๋ค.
๋นํธ์ธ Admission Controller
Kubernetes์๋ ๊ธฐ๋ณธ์ผ๋ก ๋ด์ฅ๋ Admission Controller๋ค์ด ์๋ค.
- NamespaceLifecycle: ์ญ์ ์ค์ธ ๋ค์์คํ์ด์ค์ ๋ฆฌ์์ค ์์ฑ ๊ธ์ง
- LimitRanger: ๋ฆฌ์์ค ์์ฒญ/์ ํ ๊ธฐ๋ณธ๊ฐ ์ ์ฉ
- ServiceAccount: ํ๋์ ์๋น์ค ๊ณ์ ์๋ ๋ง์ดํธ
- ResourceQuota: ๋ค์์คํ์ด์ค๋ณ ๋ฆฌ์์ค ์ด๋ ์ ํ
- PodSecurity: Pod Security Standards ์ ์ฉ (PSP ๋์ฒด)
- MutatingAdmissionWebhook: ์ธ๋ถ ์นํ ํธ์ถ (๋ณ๊ฒฝ)
- ValidatingAdmissionWebhook: ์ธ๋ถ ์นํ ํธ์ถ (๊ฒ์ฆ)
Webhook ๊ธฐ๋ฐ Admission Controller
๋นํธ์ธ์ผ๋ก๋ ๋ณต์กํ ์ ์ฑ ํํ์ ํ๊ณ๊ฐ ์๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Kubernetes๋ ์ธ๋ถ HTTP ์๋ฒ๋ก ์์ฒญ์ ์์ํ๋ Webhook ๋ฐฉ์์ ์ง์ํ๋ค.
๋์ ํ๋ฆ
kubectl apply
โ
API Server
โ
MutatingAdmissionWebhook ์ค์ ํ์ธ
โ
์ธ๋ถ ์นํ
์๋ฒ๋ก AdmissionReview ์ ์ก (HTTP POST)
โ
์นํ
์๋ฒ: ํ์ฉ(allow) / ๊ฑฐ๋ถ(deny) / ํจ์น(patch) ์๋ต
โ
ValidatingAdmissionWebhook ์ค์ ํ์ธ
โ
์ต์ข
๊ฒฐ์
MutatingWebhookConfiguration ์์
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: my-mutating-webhook
webhooks:
- name: inject-sidecar.example.com
clientConfig:
service:
name: webhook-service
namespace: webhook-system
path: "/mutate"
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
sideEffects: None
failurePolicy: Fail # ์นํ
์คํจ ์ ์์ฒญ ๊ฑฐ๋ถ
OPA(Open Policy Agent)๋
OPA๋ ์ ์ฑ (Policy)์ ์ฝ๋๋ก ํํํ๊ณ ์งํํ๋ ๋ฒ์ฉ ์ ์ฑ ์์ง์ด๋ค. ์ฟ ๋ฒ๋คํฐ์ค์ ์ข ์๋์ง ์์ผ๋ฉฐ ์๋น์ค ๋ฉ์, API ๊ฒ์ดํธ์จ์ด, ๋ง์ดํฌ๋ก์๋น์ค ๋ฑ ๋ค์ํ ํ๊ฒฝ์์ ํ์ฉ๋๋ค.
ํต์ฌ ๊ตฌ์ฑ์์
| ๊ตฌ์ฑ์์ | ์ค๋ช |
|---|---|
| Rego | OPA ์ ์ฉ ์ ์ฑ ์ธ์ด |
| Policy | Rego๋ก ์์ฑ๋ ๊ท์น ์งํฉ |
| Input | ํ๊ฐ ๋์ ๋ฐ์ดํฐ (JSON) |
| Data | ์ ์ฑ ํ๋จ์ ์ฐธ๊ณ ํ๋ ์ธ๋ถ ๋ฐ์ดํฐ |
Rego ์ธ์ด ๊ธฐ์ด
Rego๋ ์ ์ธํ ์ฟผ๋ฆฌ ์ธ์ด๋ค. deny ๊ท์น์ด ํ๋๋ผ๋ ์ฐธ์ด๋ฉด ์์ฒญ์ด ๊ฑฐ๋ถ๋๋ค.
package kubernetes.admission
# ํน๊ถ ์ปจํ
์ด๋ ๊ธ์ง
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("์ปจํ
์ด๋ '%v'์ privileged ๋ชจ๋๊ฐ ํ์ฉ๋์ง ์์ต๋๋ค", [container.name])
}
# latest ํ๊ทธ ์ด๋ฏธ์ง ๊ธ์ง
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("์ปจํ
์ด๋ '%v'์ ':latest' ํ๊ทธ ์ด๋ฏธ์ง๋ ์ฌ์ฉํ ์ ์์ต๋๋ค", [container.name])
}
Gatekeeper: OPA์ Kubernetes ํตํฉ
Gatekeeper๋ OPA๋ฅผ Kubernetes Admission Controller๋ก ํตํฉํ๋ ํ๋ก์ ํธ๋ค. CRD(Custom Resource Definition) ๊ธฐ๋ฐ์ผ๋ก ์ ์ฑ ์ ์ ์ธ์ ์ผ๋ก ๊ด๋ฆฌํ๋ค.
์ฃผ์ CRD
| CRD | ์ญํ |
|---|---|
| ConstraintTemplate | Rego ์ ์ฑ ์ ์ ๋ฐ CRD ์์ฑ |
| Constraint | ์ค์ ์ ์ฑ ์ธ์คํด์ค (๋์ ๋ฆฌ์์ค ์ง์ ) |
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}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("ํ์ ๋ ์ด๋ธ์ด ์์ต๋๋ค: %v", [missing])
}
Constraint ์์ (์ ์ฑ ์ ์ฉ)
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["production"]
parameters:
labels: ["team", "app"]
์ด ์ค์ ์ผ๋ก production ๋ค์์คํ์ด์ค์ ๋ชจ๋ ํ๋๋ team๊ณผ app ๋ ์ด๋ธ์ด ์์ผ๋ฉด ๋ฐฐํฌ๊ฐ ๊ฑฐ๋ถ๋๋ค.
Gatekeeper Audit ๊ธฐ๋ฅ
Gatekeeper๋ ์๋ก ๋ค์ด์ค๋ ์์ฒญ๋ง ๊ฒ์ฆํ๋ ๊ฒ ์๋๋ผ, ์ด๋ฏธ ํด๋ฌ์คํฐ์ ์กด์ฌํ๋ ๋ฆฌ์์ค๊ฐ ์ ์ฑ ์ ์๋ฐํ๋์ง๋ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฐ์ฌ(Audit)ํ๋ค.
# ์ ์ฑ
์๋ฐ ํํฉ ํ์ธ
kubectl get constraint pod-must-have-team-label -o yaml
# ์๋ฐ ๋ชฉ๋ก์ .status.violations ํ๋์ ํ์๋จ
status:
violations:
- enforcementAction: deny
kind: Pod
name: legacy-pod
namespace: production
message: "ํ์ ๋ ์ด๋ธ์ด ์์ต๋๋ค: {\"team\"}"
enforcementAction ์ค์
์ค์ ์ด์ ํ๊ฒฝ์์ ์ ์ ์ฑ
์ ๋ฐ๋ก deny๋ก ์ ์ฉํ๋ฉด ๊ธฐ์กด ์ํฌ๋ก๋์ ์ํฅ์ ์ค ์ ์๋ค. ์ ์ง์ ์ ์ฉ์ ์ํ ์ต์
์ด ์๋ค.
| enforcementAction | ๋์ |
|---|---|
deny | ์ ์ฑ ์๋ฐ ์ ์์ฒญ ๊ฑฐ๋ถ |
warn | ๊ฒฝ๊ณ ๋ฐํ, ์์ฒญ์ ํ์ฉ (k8s 1.19+) |
dryrun | ๊ฐ์ฌ๋ง ์ํ, ์ค์ ๊ฑฐ๋ถ ์์ |
spec:
enforcementAction: warn # ๋จผ์ warn์ผ๋ก ์ํฅ๋ ํ์
Admission Controller ์ค๊ณ ์ ๊ณ ๋ ค์ฌํญ
failurePolicy
์นํ ์๋ฒ๊ฐ ์๋ตํ์ง ์์ ๋์ ๋์์ ๊ฒฐ์ ํ๋ค.
failurePolicy: Fail # ์นํ
์คํจ โ ์์ฒญ ๊ฑฐ๋ถ (๋ณด์ ์ฐ์ )
failurePolicy: Ignore # ์นํ
์คํจ โ ์์ฒญ ํ์ฉ (๊ฐ์ฉ์ฑ ์ฐ์ )
ํ๋ก๋์
์์๋ Fail์ด ๊ธฐ๋ณธ์ด์ง๋ง, ์นํ
์๋ฒ ์์ฒด์ ๊ณ ๊ฐ์ฉ์ฑ(HA)์ ๋ฐ๋์ ํ๋ณดํด์ผ ํ๋ค.
namespaceSelector
์นํ
์ ์ฉ ๋์ ๋ค์์คํ์ด์ค๋ฅผ ๋ ์ด๋ธ๋ก ํํฐ๋งํ๋ค. ์์คํ
๋ค์์คํ์ด์ค(kube-system)๋ ์ ์ฑ
์ ์ฉ์์ ์ ์ธํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
namespaceSelector:
matchExpressions:
- key: admission-control
operator: In
values: ["enabled"]
์ฑ๋ฅ ์ํฅ
๋ชจ๋ API ์์ฒญ์ด ์นํ
์ ๊ฑฐ์น๋ฏ๋ก ์นํ
์๋ต ์ง์ฐ์ด ํด๋ฌ์คํฐ ์ ์ฒด์ ์ํฅ์ ์ค๋ค. timeoutSeconds๋ฅผ ํฉ๋ฆฌ์ ์ผ๋ก ์ค์ ํ๊ณ ์นํ
์๋ฒ ์๋ต ์๊ฐ์ ๋ชจ๋ํฐ๋งํด์ผ ํ๋ค.
OPA vs Kyverno ๋น๊ต
Kyverno๋ Kubernetes ์ ์ฉ์ผ๋ก ์ค๊ณ๋ ๋ ๋ค๋ฅธ ์ ์ฑ ์์ง์ด๋ค.
| ํญ๋ชฉ | OPA/Gatekeeper | Kyverno |
|---|---|---|
| ์ ์ฑ ์ธ์ด | Rego (๋ฒ์ฉ, ํ์ต ๊ณก์ ๋์) | YAML (k8s ๋ค์ดํฐ๋ธ) |
| ์ ์ฉ ๋ฒ์ | k8s ์ธ ๋ค์ํ ํ๊ฒฝ ๊ฐ๋ฅ | k8s ์ ์ฉ |
| Mutate ์ง์ | ์ ํ์ | ๊ฐ๋ ฅํ Mutate ์ง์ |
| Generate ์ง์ | ๋ฏธ์ง์ | ConfigMap/Secret ์๋ ์์ฑ ์ง์ |
| ๋์ ๋์ด๋ | ์๋์ ์ผ๋ก ๋์ | ์๋์ ์ผ๋ก ๋ฎ์ |
๋จ์ํ k8s ์ ์ฑ ๊ด๋ฆฌ๋ผ๋ฉด Kyverno๊ฐ ์ง์ ์ฅ๋ฒฝ์ด ๋ฎ๊ณ , ๋ฉํฐ ํ๋ซํผ ์ ์ฑ ํตํฉ์ด ํ์ํ๋ค๋ฉด OPA๊ฐ ์ ํฉํ๋ค.
์ ๋ฆฌ
- Admission Controller๋ k8s ๋ฆฌ์์ค๊ฐ etcd์ ์ ์ฅ๋๊ธฐ ์ ์์ฒญ์ ๊ฐ๋ก์ฑ ๊ฒ์ฆ/๋ณ๊ฒฝํ๋ค
- Webhook ๋ฐฉ์์ผ๋ก ์ธ๋ถ ์ ์ฑ ์๋ฒ์ ์ฐ๋ํ ์ ์๋ค
- OPA๋ Rego ์ธ์ด๋ก ์ ์ฑ ์ ํํํ๋ ๋ฒ์ฉ ์์ง์ด๋ฉฐ, Gatekeeper๋ฅผ ํตํด k8s์ ํตํฉ๋๋ค
- ConstraintTemplate โ Constraint ๊ตฌ์กฐ๋ก ์ ์ฑ ์ ์ ์ธ์ ์ผ๋ก ๊ด๋ฆฌํ๋ค
- Audit ๊ธฐ๋ฅ์ผ๋ก ๊ธฐ์กด ๋ฆฌ์์ค์ ์ ์ฑ ์๋ฐ๋ ๊ฐ์งํ ์ ์๋ค
enforcementAction: warn/dryrun์ผ๋ก ์ ์ง์ ์ ์ฑ ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค