ข้ามไปยังเนื้อหาหลัก

Admission Webhook for K8s

1. ภาพรวม & เอกสารสำหรับ Casbin K8s-Gatekeeper

Casbin K8s-GateKeeper เป็น Kubernetes admission webhook ที่รวม Casbin เข้ากับเครื่องมือควบคุมการเข้าถึง โดยการใช้ Casbin K8s-GateKeeper คุณสามารถกำหนดกฎที่ยืดหยุ่นเพื่ออนุญาตหรือขัดขวางการดำเนินการใด ๆ บนทรัพยากร K8s โดยไม่ต้องเขียนโค้ดใด ๆ เพียงแค่บรรทัดสั่งการที่เป็น declarative configurations ของ Casbin models และ policies ซึ่งเป็นส่วนหนึ่งของภาษา ACL (Access Control List) ของ Casbin

Casbin K8s-GateKeeper ถูกพัฒนาและดูแลโดยชุมชน Casbin ที่เก็บข้อมูลของโปรเจ็กต์นี้สามารถเข้าถึงได้ที่นี่: https://github.com/casbin/k8s-gatekeeper

0.1 ตัวอย่างง่าย ๆ

ตัวอย่างเช่น คุณไม่จำเป็นต้องเขียนโค้ดใด ๆ แต่ใช้บรรทัดการกำหนดค่าต่อไปนี้เพื่อทำฟังก์ชันนี้: "ห้ามใช้ images ที่มี tags ที่ระบุไว้ใน deployments ใด ๆ":

Model:

[request_definition]
r = obj

[policy_definition]
p = obj,eft

[policy_effect]
e = !some(where (p.eft == deny))

[matchers]
m = r.obj.Request.Namespace == "default" && r.obj.Request.Resource.Resource =="deployments" && \
contain(split(accessWithWildcard(${OBJECT}.Spec.Template.Spec.Containers , "*", "Image"),":",1) , p.obj)

And Policy:

p, "1.14.1",deny

เหล่านี้เป็นภาษา ACL ของ Casbin ทั่วไป สมมติว่าคุณได้อ่านบทเกี่ยวกับพวกเขาแล้ว มันจะเข้าใจได้ง่ายมาก

Casbin K8s-Gatekeeper มีข้อดีดังต่อไปนี้:

  • ใช้งานง่าย การเขียนบรรทัด ACL ไม่กี่บรรทัดดีกว่าการเขียนโค้ดมากมาย
  • มันอนุญาตให้อัปเดตการกำหนดค่าได้ทันที คุณไม่จำเป็นต้องปิดปลั๊กอินทั้งหมดเพื่อแก้ไขการกำหนดค่า
  • มันยืดหยุ่น กฎที่ไม่จำกัดสามารถทำได้บนทรัพยากร K8s ใด ๆ ซึ่งสามารถสำรวจได้ด้วย kubectl gatekeeper
  • มันทำให้การดำเนินการของ K8s admission webhook ซึ่งซับซ้อนมาก ง่ายขึ้น คุณไม่จำเป็นต้องรู้ว่า K8s admission webhook คืออะไรหรือวิธีการเขียนโค้ดสำหรับมัน ทั้งหมดที่คุณต้องทำคือรู้ทรัพยากรที่คุณต้องการจำกัดและจากนั้นเขียน Casbin ACL ทุกคนรู้ว่า K8s มีความซับซ้อน แต่โดยการใช้ Casbin K8s-Gatekeeper คุณสามารถประหยัดเวลาได้
  • มันได้รับการดูแลโดยชุมชน Casbin ติดต่อเราได้เสมอหากคุณมีความสับสนเกี่ยวกับปลั๊กอินนี้หรือหากคุณพบปัญหาใด ๆ เมื่อลองใช้

1.1 Casbin K8s-Gatekeeper ทำงานอย่างไร?

K8s-Gatekeeper เป็น admission webhook สำหรับ K8s ที่ใช้ Casbin เพื่อใช้กฎการควบคุมการเข้าถึงที่กำหนดโดยผู้ใช้เพื่อช่วยป้องกันการดำเนินการใด ๆ บน K8s ที่ผู้ดูแลระบบไม่ต้องการ

Casbin เป็นไลบรารีควบคุมการเข้าถึงแบบเปิดที่ทรงพลังและมีประสิทธิภาพ มันให้การสนับสนุนสำหรับการบังคับใช้การอนุญาตตามโมเดลการควบคุมการเข้าถึงที่หลากหลาย สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ Casbin ดูที่ ภาพรวม

Admission webhooks ใน K8s เป็น HTTP callbacks ที่รับ 'admission requests' และทำอะไรบางอย่างกับพวกเขา โดยเฉพาะอย่างยิ่ง K8s-Gatekeeper เป็นประเภทพิเศษของ admission webhook: 'ValidatingAdmissionWebhook' ซึ่งสามารถตัดสินใจว่าจะยอมรับหรือปฏิเสธคำขอนี้หรือไม่ สำหรับคำขอการรับเข้า พวกเขาเป็น HTTP requests ที่อธิบายการดำเนินการบนทรัพยากรที่ระบุของ K8s (ตัวอย่างเช่น การสร้าง/ลบ deployment) สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ admission webhooks ดูที่ เอกสารอย่างเป็นทางการของ K8s

1.2 ตัวอย่างที่แสดงวิธีการทำงาน

ตัวอย่างเช่น เมื่อมีคนต้องการสร้าง deployment ที่มี pod ที่รัน nginx (โดยใช้ kubectl หรือ K8s clients) K8s จะสร้างคำขอการรับเข้า ซึ่ง (ถ้าแปลเป็นรูปแบบ YAML) อาจเป็นอย่างนี้:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.1
ports:
- containerPort: 80

คำขอนี้จะผ่านกระบวนการของทุก middleware ที่แสดงในรูปภาพ รวมถึง K8s-Gatekeeper ของเรา K8s-Gatekeeper สามารถตรวจจับทุก Casbin enforcers ที่เก็บไว้ใน etcd ของ K8s ซึ่งถูกสร้างและดูแลโดยผู้ใช้ (ผ่าน kubectl หรือ Go client ที่เราให้บริการ) แต่ละ enforcer ประกอบด้วย Casbin model และ Casbin policy คำขอการรับเข้าจะถูกประมวลผลโดยทุก enforcer ทีละตัว และเพียงแค่ผ่านทุก enforcers คำขอจึงจะถูกยอมรับโดย K8s-Gatekeeper นี้

(หากคุณไม่เข้าใจว่า Casbin enforcer, model หรือ policy คืออะไร ดูเอกสารนี้: เริ่มต้น)

ตัวอย่างเช่น ด้วยเหตุผลบางอย่าง ผู้ดูแลระบบต้องการห้ามการปรากฏของ image 'nginx:1.14.1' ในขณะที่อนุญาต 'nginx:1.3.1' สามารถสร้าง enforcer ที่มีกฎและนโยบายต่อไปนี้ได้ (เราจะอธิบายวิธีการสร้าง enforcer ว่าโมเดลและนโยบายเหล่านี้คืออะไร และวิธีเขียนพวกเขาในบทต่อไป)

Model:

[request_definition]
r = obj

[policy_definition]
p = obj,eft

[policy_effect]
e = !some(where (p.eft == deny))

[matchers]
m = r.obj.Request.Namespace == "default" && r.obj.Request.Resource.Resource =="deployments" && \
access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Image") == p.obj

Policy:

p, "nginx:1.13.1",allow
p, "nginx:1.14.1",deny

โดยการสร้าง enforcer ที่มีโมเดลและนโยบายด้านบน คำขอการรับเข้าก่อนหน้านี้จะถูกปฏิเสธโดย enforcer นี้ ซึ่งหมายความว่า K8s จะไม่สร้าง deployment นี้

2 ติดตั้ง K8s-gatekeeper

มีสามวิธีที่มีให้สำหรับการติดตั้ง K8s-gatekeeper: External webhook, Internal webhook และ Helm

หมายเหตุ

หมายเหตุ: วิธีเหล่านี้เพื่อให้ผู้ใช้ลองใช้ K8s-gatekeeper เท่านั้นและไม่ปลอดภัย หากคุณต้องการใช้ในสภาพแวดล้อมการผลิต โปรดตรวจสอบว่าคุณได้อ่าน บทที่ 5. การตั้งค่าขั้นสูง และทำการเปลี่ยนแปลงที่จำเป็นก่อนการติดตั้ง 2.1 Internal webhook

2.1.1 ขั้นตอนที่ 1: สร้าง image

2.1.1 Step 1: Build the image

สำหรับวิธีการ webhook ภายใน, webhook นั้นจะถูกนำมาใช้งานเป็นบริการภายใน Kubernetes เพื่อสร้างบริการและการปรับใช้ที่จำเป็น, คุณต้องสร้างภาพของ K8s-gatekeeper คุณสามารถสร้างภาพของคุณเองได้โดยการรันคำสั่งต่อไปนี้:

docker build --target webhook -t k8s-gatekeeper .

คำสั่งนี้จะสร้างภาพในเครื่องท้องถิ่นชื่อ 'k8s-gatekeeper:latest'

หมายเหตุ

หมายเหตุ: หากคุณกำลังใช้ minikube, กรุณาทำการรัน eval $(minikube -p minikube docker-env) ก่อนที่จะรัน 'docker build'

2.1.2 ขั้นตอนที่ 2: ตั้งค่าบริการและการปรับใช้สำหรับ K8s-gatekeeper

รันคำสั่งต่อไปนี้:

kubectl apply -f config/rbac.yaml
kubectl apply -f config/webhook_deployment.yaml
kubectl apply -f config/webhook_internal.yaml

สิ่งนี้จะเริ่มการทำงานของ K8s-gatekeeper, และคุณสามารถยืนยันได้โดยการรัน kubectl get pods

2.1.3 ขั้นตอนที่ 3: ติดตั้งทรัพยากร CRD สำหรับ K8s-gatekeeper

รันคำสั่งต่อไปนี้:

kubectl apply -f config/auth.casbin.org_casbinmodels.yaml 
kubectl apply -f config/auth.casbin.org_casbinpolicies.yaml

2.2 วิธีการ webhook ภายนอก

สำหรับวิธีการ webhook ภายนอก, K8s-gatekeeper จะทำงานนอก Kubernetes, และ Kubernetes จะเข้าถึง K8s-gatekeeper เหมือนกับการเข้าถึงเว็บไซต์ทั่วไป Kubernetes มีข้อกำหนดที่จำเป็นว่า webhook ที่ให้การยอมรับต้องเป็น HTTPS เพื่อวัตถุประสงค์ในการทดลองใช้ K8s-gatekeeper, เราได้จัดเตรียมชุดของใบรับรองและกุญแจส่วนตัว (แม้ว่าจะไม่ปลอดภัย) หากคุณต้องการใช้ใบรับรองของคุณเอง, กรุณาดูที่ บทที่ 5. การตั้งค่าขั้นสูง สำหรับคำแนะนำในการปรับใบรับรองและกุญแจส่วนตัว ใบรับรองที่เราจัดเตรียมมานั้นได้รับการออกให้กับ 'webhook.domain.local'

ดังนั้น, แก้ไขโฮสต์ (เช่น, /etc/hosts) และชี้ 'webhook.domain.local' ไปยังที่อยู่ IP ที่ K8s-gatekeeper กำลังทำงานอยู่ จากนั้นทำการรันคำสั่งต่อไปนี้:

2.3 ติดตั้ง K8s-gatekeeper ผ่าน Helm

go mod tidy
go mod vendor
go run cmd/webhook/main.go
kubectl apply -f config/auth.casbin.org_casbinmodels.yaml
kubectl apply -f config/auth.casbin.org_casbinpolicies.yaml
kubectl apply -f config/webhook_external.yaml

2.3.1 ขั้นตอนที่ 1: สร้างภาพ

กรุณาดูที่ บทที่ 2.1.1

2.3.2 การติดตั้ง Helm

รันคำสั่ง helm install k8sgatekeeper ./k8sgatekeeper

ทดลองใช้ K8s-gatekeeper 3.1 สร้าง Casbin Model และ Policy

คุณมีสองวิธีในการสร้างโมเดลและนโยบาย: ผ่าน kubectl หรือผ่าน go-client ที่เราจัดเตรียมไว้

3.1.1 สร้าง/อัปเดต Casbin Model และ Policy ผ่าน kubectl

ใน K8s-gatekeeper, Casbin model ถูกเก็บไว้ในทรัพยากร CRD ที่เรียกว่า 'CasbinModel'

คำจำกัดความของมันตั้งอยู่ใน config/auth.casbin.org_casbinmodels.yaml มีตัวอย่างใน example/allowed_repo/model.yaml

ให้ความสนใจกับฟิลด์ต่อไปนี้: metadata.name: ชื่อของโมเดล

  • ชื่อนี้ต้องตรงกับชื่อของอ็อบเจกต์ CasbinPolicy ที่เกี่ยวข้องกับโมเดลนี้, เพื่อให้ K8s-gatekeeper สามารถจับคู่พวกเขาและสร้าง enforcer spec.enable: หากฟิลด์นี้ถูกตั้งค่าเป็น 'false', โมเดลนี้ (รวมถึงอ็อบเจกต์ CasbinPolicy ที่เกี่ยวข้องกับโมเดลนี้) จะถูกละเลย
  • spec.modelText: สตริงที่มีข้อความของโมเดล Casbin
  • Casbin Policy ถูกเก็บไว้ในทรัพยากร CRD อื่นที่เรียกว่า 'CasbinPolicy', ซึ่งคำจำกัดความสามารถพบได้ใน config/auth.casbin.org_casbinpolicies.yaml

มีตัวอย่างใน example/allowed_repo/policy.yaml

ให้ความสนใจกับฟิลด์ต่อไปนี้: metadata.name: ชื่อของนโยบาย

  • ชื่อนี้ต้องตรงกับชื่อของอ็อบเจกต์ CasbinModel ที่เกี่ยวข้องกับนโยบายนี้, เพื่อให้ K8s-gatekeeper สามารถจับคู่พวกเขาและสร้าง enforcer spec.policyItem: สตริงที่มีข้อความของนโยบาย Casbin
  • หลังจากสร้างไฟล์ CasbinModel และ CasbinPolicy ของคุณเองแล้ว, ใช้คำสั่งต่อไปนี้เพื่อใช้งานพวกเขา:

เมื่อคู่ของ CasbinModel และ CasbinPolicy ถูกสร้างขึ้น, K8s-gatekeeper จะสามารถตรวจจับได้ภายใน 5 วินาที

kubectl apply -f <filename>

3.1.2 สร้าง/อัปเดต Casbin Model และ Policy ผ่าน go-client ที่เราจัดเตรียมไว้

เราเข้าใจว่าอาจมีสถานการณ์ที่ไม่สะดวกในการใช้ shell เพื่อทำการรันคำสั่งโดยตรงบนโหนดของคลัสเตอร์ K8s, เช่นเมื่อคุณกำลังสร้างแพลตฟอร์มคลาวด์อัตโนมัติสำหรับบริษัทของคุณ

ด้วยเหตุนี้, เราได้พัฒนา go-client เพื่อสร้างและบำรุงรักษา CasbinModel และ CasbinPolicy ไลบรารี go-client ตั้งอยู่ใน pkg/client

ใน client.go, เราจัดเตรียมฟังก์ชันเพื่อสร้างคลายเอนต์

In client.go, we provide a function to create a client.

func NewK8sGateKeeperClient(externalClient bool) (*K8sGateKeeperClient, error) 

พารามิเตอร์ externalClient กำหนดว่า K8s-gatekeeper กำลังทำงานภายในคลัสเตอร์ K8s หรือไม่

ใน model.go, เรามีฟังก์ชันต่างๆ เพื่อสร้าง, ลบ และแก้ไข CasbinModel คุณสามารถหาวิธีการใช้งาน interfaces เหล่านี้ได้ใน model_test.go

ใน policy.go, เรามีฟังก์ชันต่างๆ เพื่อสร้าง, ลบ และแก้ไข CasbiPolicy คุณสามารถหาวิธีการใช้งาน interfaces เหล่านี้ได้ใน policy_test.go

3.1.2 ลองดูว่า K8s-gatekeeper ทำงานได้หรือไม่

สมมติว่าคุณได้สร้างโมเดลและนโยบายที่ถูกต้องแล้วใน example/allowed_repo ตอนนี้ลองใช้คำสั่งต่อไปนี้:

kubectl apply -f example/allowed_repo/testcase/reject_1.yaml

คุณควรพบว่า K8s จะปฏิเสธคำขอนี้และระบุว่า webhook เป็นเหตุผลที่คำขอนี้ถูกปฏิเสธ อย่างไรก็ตาม เมื่อคุณลอง apply example/allowed_repo/testcase/approve_2.yaml, มันจะถูกยอมรับ

4. วิธีการเขียนโมเดลและนโยบายด้วย K8s-gatekeeper

ขั้นแรกเลย ตรวจสอบให้แน่ใจว่าคุณคุ้นเคยกับไวยากรณ์พื้นฐานของ Casbin Models และ Policies หากคุณยังไม่คุ้นเคย โปรดอ่านส่วน Get Started ก่อน ในบทนี้ เราสมมติว่าคุณเข้าใจแล้วว่า Casbin Models และ Policies คืออะไร

4.1 คำนิยามของคำขอในโมเดล

เมื่อ K8s-gatekeeper กำลังอนุญาตคำขอ ข้อมูลที่ป้อนเข้ามาจะเป็นออบเจกต์เสมอ: ออบเจกต์ Go ของคำขอ Admission นั่นหมายความว่า enforcer จะถูกใช้เสมอเช่นนี้:

ok, err := enforcer.Enforce(admission)

ที่ admission เป็นออบเจกต์ AdmissionReview ที่กำหนดโดย go api อย่างเป็นทางการของ K8s คือ "k8s.io/api/admission/v1" คุณสามารถหาคำนิยามของโครงสร้างนี้ได้ใน repository นี้: https://github.com/kubernetes/api/blob/master/admission/v1/types.go สำหรับข้อมูลเพิ่มเติม คุณสามารถอ้างอิงได้ที่ https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#webhook-request-and-response

ดังนั้น สำหรับโมเดลใดๆ ที่ใช้โดย K8s-gatekeeper คำนิยามของ request_definition ควรเป็นเช่นนี้เสมอ:

    [request_definition]
r = obj

ชื่อ 'obj' ไม่จำเป็นต้องใช้ ตราบใดที่ชื่อนั้นสอดคล้องกับชื่อที่ใช้ในส่วน [matchers]

4.2 Matchers ของโมเดล

คุณควรใช้คุณสมบัติ ABAC ของ Casbin เพื่อเขียนกฎของคุณ อย่างไรก็ตาม ตัวประเมินนิพจน์ที่รวมอยู่ใน Casbin ไม่รองรับการดัชนีในแผนที่หรืออาร์เรย์ (slices) หรือการขยายอาร์เรย์ ดังนั้น K8s-gatekeeper จึงมี 'Casbin functions' ต่างๆ เป็นส่วนขยายเพื่อใช้งานคุณสมบัติเหล่านี้ หากคุณยังพบว่าความต้องการของคุณไม่สามารถเติมเต็มได้ด้วยส่วนขยายเหล่านี้ อย่าลังเลที่จะเริ่ม issue หรือสร้าง pull request

หากคุณไม่คุ้นเคยกับ Casbin functions คุณสามารถอ้างอิงได้ที่ Function เพื่อข้อมูลเพิ่มเติม

นี่คือฟังก์ชันส่วนขยาย:

4.2.1 ฟังก์ชันส่วนขยาย

4.2.1.1 access

Access ใช้เพื่อแก้ปัญหาที่ Casbin ไม่รองรับการดัชนีในแผนที่หรืออาร์เรย์ ตัวอย่าง example/allowed_repo/model.yaml แสดงการใช้งานของฟังก์ชันนี้:

[matchers]
m = r.obj.Request.Namespace == "default" && r.obj.Request.Resource.Resource =="deployments" && \
access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Image") == p.obj

ใน matcher นี้ access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Image") เทียบเท่ากับ r.obj.Request.Object.Object.Spec.Template.Spec.Containers[0].Image ที่ r.obj.Request.Object.Object.Spec.Template.Spec.Containers เป็น slice

Access ยังสามารถเรียกใช้ฟังก์ชันง่ายๆ ที่ไม่มีพารามิเตอร์และคืนค่าเพียงค่าเดียว ตัวอย่าง example/container_resource_limit/model.yaml แสดงการใช้งานนี้:

[matchers]
m = r.obj.Request.Namespace == "default" && r.obj.Request.Resource.Resource =="deployments" && \
parseFloat(access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Resources","Limits","cpu","Value")) >= parseFloat(p.cpu) && \
parseFloat(access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Resources","Limits","memory","Value")) >= parseFloat(p.memory)

ใน matcher นี้ access(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , 0, "Resources","Limits","cpu","Value") เทียบเท่ากับ r.obj.Request.Object.Object.Spec.Template.Spec.Containers[0].Resources.Limits["cpu"].Value() ที่ r.obj.Request.Object.Object.Spec.Template.Spec.Containers[0].Resources.Limits เป็นแผนที่ และ Value() เป็นฟังก์ชันง่ายๆ ที่ไม่มีพารามิเตอร์และคืนค่าเพียงค่าเดียว

4.2.1.2 accessWithWildcard

บางครั้ง คุณอาจมีความต้องการเช่นนี้: ทุกองค์ประกอบในอาร์เรย์ต้องมีคำนำหน้า "aaa" อย่างไรก็ตาม Casbin ไม่รองรับลูป for ด้วย accessWithWildcard และคุณสมบัติ "การขยายแผนที่/slice" คุณสามารถใช้งานความต้องการเช่นนี้ได้อย่างง่ายดาย

ตัวอย่างเช่น สมมติว่า a.b.c เป็นอาร์เรย์ [aaa,bbb,ccc,ddd,eee], ผลลัพธ์ของ accessWithWildcard(a,"b","c","*") จะเป็น slice [aaa,bbb,ccc,ddd,eee] โดยการใช้ wildcard *, slice จะถูกขยาย

ในทำนองเดียวกัน wildcard สามารถใช้ได้มากกว่าหนึ่งครั้ง ตัวอย่างเช่น ผลลัพธ์ของ accessWithWildcard(a,"b","c","*","*") จะเป็น [a.b.c[0][0], a.b.c[0][1], ..., a.b.c[1][0], a.b.c[1][1], ...]

4.2.1.3 ฟังก์ชันที่รองรับอาร์กิวเมนต์ความยาวแปรผัน

ในตัวประเมินนิพจน์ของ Casbin เมื่อพารามิเตอร์เป็นอาร์เรย์ มันจะถูกขยายอัตโนมัติเป็นอาร์กิวเมนต์ความยาวแปรผัน โดยใช้คุณสมบัตินี้เพื่อรองรับการขยายอาร์เรย์/slice/แผนที่ เรายังได้รวมฟังก์ชันหลายอย่างที่ยอมรับอาร์เรย์/slice เป็นพารามิเตอร์:

  • contain(): ยอมรับพารามิเตอร์หลายตัวและคืนค่าว่าพารามิเตอร์ใดๆ (ยกเว้นพารามิเตอร์สุดท้าย) เท่ากับพารามิเตอร์สุดท้ายหรือไม่
  • split(a,b,c...,sep,index): คืนค่าส่วนที่มี ['splits(a,sep)[index]', 'splits(b,sep)[index]', 'splits(a,sep)[index]', ...]
  • len(): คืนค่าความยาวของอาร์กิวเมนต์ที่มีความยาวไม่แน่นอน
  • matchRegex(a,b,c...,regex): คืนค่าว่าพารามิเตอร์ทั้งหมดที่กำหนด ('a', 'b', 'c', ...) ตรงกับ regex ที่กำหนด

นี่คือตัวอย่างใน 'example/disallowed_tag/model.yaml':

    [matchers]
m = r.obj.Request.Namespace == "default" && r.obj.Request.Resource.Resource =="deployments" && \
contain(split(accessWithWildcard(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , "*", "Image"),":",1) , p.obj)

สมมติว่า 'accessWithWildcard(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , "", "Image")' คืนค่า ['a:b', 'c:d', 'e:f', 'g:h'], เพราะ splits รองรับอาร์กิวเมนต์ที่มีความยาวไม่แน่นอนและทำการแบ่งข้อมูลในแต่ละองค์ประกอบ, องค์ประกอบที่อยู่ที่ดัชนี 1 จะถูกเลือกและคืนค่ากลับมา ดังนั้น, 'split(accessWithWildcard(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , "", "Image"),":",1)' คืนค่า ['b','d','f','h'] และ 'contain(split(accessWithWildcard(r.obj.Request.Object.Object.Spec.Template.Spec.Containers , "*", "Image"),":",1) , p.obj)' คืนค่าว่า 'p.obj' มีอยู่ใน ['b','d','f','h'] หรือไม่

4.2.1.2 ฟังก์ชันการแปลงประเภทข้อมูล

  • ParseFloat(): แปลงจำนวนเต็มเป็นจำนวนทศนิยม (นี่เป็นสิ่งจำเป็นเพราะต้องแปลงทุกตัวเลขที่ใช้ในการเปรียบเทียบเป็นจำนวนทศนิยม)
  • ToString(): แปลงออบเจ็กต์เป็นสตริง ออบเจ็กต์นี้ต้องมีประเภทพื้นฐานเป็นสตริง (ตัวอย่างเช่น, ออบเจ็กต์ประเภท 'XXX' เมื่อมีคำสั่ง 'type XXX string')
  • IsNil(): คืนค่าว่าพารามิเตอร์เป็น nil หรือไม่

5. การตั้งค่าขั้นสูง

5.1 เกี่ยวกับใบรับรอง

ใน Kubernetes (k8s), จำเป็นที่ webhook ควรใช้ HTTPS มีสองวิธีในการทำเช่นนี้:

  • ใช้ใบรับรองที่ลงนามเอง (ตัวอย่างในที่เก็บนี้ใช้วิธีนี้)
  • ใช้ใบรับรองปกติ

5.1.1 ใบรับรองที่ลงนามเอง

การใช้ใบรับรองที่ลงนามเองหมายความว่า Certificate Authority (CA) ที่ออกใบรับรองไม่ใช่หนึ่งใน CA ที่รู้จักกันดี ดังนั้น, คุณต้องแจ้งให้ k8s ทราบเกี่ยวกับ CA นี้

ปัจจุบัน, ตัวอย่างในที่เก็บนี้ใช้ CA ที่สร้างเอง, ซึ่งมีกุญแจส่วนตัวและใบรับรองจัดเก็บอยู่ใน 'config/certificate/ca.crt' และ 'config/certificate/ca.key' ตามลำดับ ใบรับรองสำหรับ webhook คือ 'config/certificate/server.crt', ซึ่งออกโดย CA ที่สร้างเอง โดเมนของใบรับรองนี้คือ 'webhook.domain.local' (สำหรับ webhook ภายนอก) และ 'casbin-webhook-svc.default.svc' (สำหรับ webhook ภายใน)

ข้อมูลเกี่ยวกับ CA ถูกส่งไปยัง k8s ผ่านไฟล์การกำหนดค่า webhook ทั้ง 'config/webhook_external.yaml' และ 'config/webhook_internal.yaml' มีฟิลด์ที่เรียกว่า 'CABundle', ซึ่งมีสตริงที่เข้ารหัส base64 ของใบรับรองของ CA

ในกรณีที่คุณต้องการเปลี่ยนใบรับรอง/โดเมน (ตัวอย่างเช่น, ถ้าคุณต้องการวาง webhook นี้ลงในเนมสเปซอื่นของ k8s ในขณะที่ใช้ webhook ภายใน, หรือถ้าคุณต้องการเปลี่ยนโดเมนในขณะที่ใช้ webhook ภายนอก), ควรปฏิบัติตามขั้นตอนต่อไปนี้:

  1. สร้าง CA ใหม่:

    • สร้างกุญแจส่วนตัวสำหรับ CA ปลอม:

      openssl genrsa -des3 -out ca.key 2048
    • ลบการป้องกันรหัสผ่านของกุญแจส่วนตัว:

      openssl rsa -in ca.key -out ca.key
  2. สร้างกุญแจส่วนตัวสำหรับเซิร์ฟเวอร์ webhook:

    openssl genrsa -des3 -out server.key 2048
    openssl rsa -in server.key -out server.key
  3. ใช้ CA ที่สร้างเองเพื่อลงนามใบรับรองสำหรับ webhook:

    • คัดลอกไฟล์การกำหนดค่า openssl ของระบบของคุณสำหรับการใช้งานชั่วคราว คุณสามารถหาตำแหน่งของไฟล์การกำหนดค่าได้โดยการรัน 'openssl version -a', โดยปกติเรียกว่า 'openssl.cnf'

    • ในไฟล์การกำหนดค่า:

      • ค้นหาย่อหน้า '[req]' และเพิ่มบรรทัดต่อไปนี้: 'req_extensions = v3_req'

      • ค้นหาย่อหน้า '[v3_req]' และเพิ่มบรรทัดต่อไปนี้: 'subjectAltName = @alt_names'

      • เพิ่มบรรทัดต่อไปนี้ลงในไฟล์:

        [alt_names]
        DNS.2=<The domain you want>

        หมายเหตุ: แทนที่ 'casbin-webhook-svc.default.svc' ด้วยชื่อบริการจริงของบริการของคุณเองหากคุณตัดสินใจที่จะแก้ไขชื่อบริการ

    • ใช้ไฟล์การกำหนดค่าที่แก้ไขแล้วเพื่อสร้างไฟล์คำขอใบรับรอง:

      openssl req -new -nodes -keyout server.key -out server.csr -config openssl.cnf
    • ใช้ CA ที่สร้างเองเพื่อตอบสนองต่อคำขอและลงนามใบรับรอง:

      openssl x509 -req -days 3650 -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -extensions v3_req -extensions SAN -extfile openssl.cnf
  4. แทนที่ฟิลด์ 'CABundle': ทั้ง 'config/webhook_external.yaml' และ 'config/webhook_internal.yaml' มีฟิลด์ที่เรียกว่า 'CABundle', ซึ่งมีสตริงที่เข้ารหัส base64 ของใบรับรองของ CA

  5. อัปเดตฟิลด์นี้ด้วยใบรับรองใหม่

ถ้าคุณใช้ helm, การเปลี่ยนแปลงที่คล้ายกันจำเป็นต้องถูกนำไปใช้กับแผนภูมิ helm

5.1.2 ใบรับรองที่ถูกต้องตามกฎหมาย ถ้าคุณใช้ใบรับรองที่ถูกต้องตามกฎหมาย, คุณไม่จำเป็นต้องทำตามขั้นตอนทั้งหมดเหล่านี้