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 ภายนอก), ควรปฏิบัติตามขั้นตอนต่อไปนี้:
สร้าง CA ใหม่:
สร้างกุญแจส่วนตัวสำหรับ CA ปลอม:
openssl genrsa -des3 -out ca.key 2048
ลบการป้องกันรหัสผ่านของกุญแจส่วนตัว:
openssl rsa -in ca.key -out ca.key
สร้างกุญแจส่วนตัวสำหรับเซิร์ฟเวอร์ webhook:
openssl genrsa -des3 -out server.key 2048
openssl rsa -in server.key -out server.keyใช้ 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
แทนที่ฟิลด์ 'CABundle': ทั้ง 'config/webhook_external.yaml' และ 'config/webhook_internal.yaml' มีฟิลด์ที่เรียกว่า 'CABundle', ซึ่งมีสตริงที่เข้ารหัส base64 ของใบรับรองของ CA
อัปเดตฟิลด์นี้ด้วยใบรับรองใหม่
ถ้าคุณใช้ helm, การเปลี่ยนแปลงที่คล้ายกันจำเป็นต้องถูกนำไปใช้กับแผนภูมิ helm
5.1.2 ใบรับรองที่ถูกต้องตามกฎหมาย ถ้าคุณใช้ใบรับรองที่ถูกต้องตามกฎหมาย, คุณไม่จำเป็นต้องทำตามขั้นตอนทั้งหมดเหล่านี้