สาธิต
คู่มือนี้จะพาคุณผ่าน แบบฝึกหัด Client-Side Defense แบบครบวงจร บน F5 Distributed Cloud โดยใช้ API — จัดโครงสร้างเป็นสี่เฟสที่ผู้ช่วย AI หรือผู้ดำเนินการมนุษย์สามารถดำเนินการได้ตั้งแต่ต้นจนจบ แต่ละขั้นตอนมีคำสั่ง curl พร้อมใช้งานพร้อมค่า placeholder ที่คุณสามารถปรับแต่งได้โดยใช้แบบฟอร์มที่ด้านบนของหน้า, ไฟล์ .env หรือเครื่องมืออัตโนมัติใดๆ
เฟสของแบบฝึกหัด
หัวข้อที่มีชื่อว่า “เฟสของแบบฝึกหัด”| เฟส | เป้าหมาย | ขั้นตอน |
|---|---|---|
| เฟส 1 — สร้าง | ปรับใช้และตรวจสอบโครงสร้างพื้นฐาน CSD ทั้งหมด | ขั้นตอน 1–7 |
| เฟส 2 — โจมตี | สร้างทราฟฟิกการโจมตีจำลองและยืนยันว่า CSD ตรวจพบ | ขั้นตอน 8–9 |
| เฟส 3 — บรรเทา | หลักฐานก่อน/หลังการบรรเทา — รันการโจมตี, ใช้การบรรเทา, รันการโจมตีอีกครั้ง, เปรียบเทียบ | ขั้นตอน 1–6 |
| เฟส 4 — รื้อถอน | ลบออบเจ็กต์การปรับใช้ทั้งหมดหลังจากได้รับการยืนยันอย่างชัดแจ้ง | รื้อถอน |
การตรวจสอบก่อนเริ่มต้น
หัวข้อที่มีชื่อว่า “การตรวจสอบก่อนเริ่มต้น”ก่อนเริ่มเฟส 1 ให้ตรวจสอบว่าสภาพแวดล้อมสะอาด รันการตรวจสอบ API เหล่านี้เพื่อพิจารณาว่ามีออบเจ็กต์ที่เหลือจากการรันก่อนหน้าหรือไม่:
# Check all Phase 1 objects and compute environment statusHTTP_LB=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-http")HTTPS_LB=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-https")ORIGIN=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/xF5XC_ORIGIN_POOLx")HC=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/xF5XC_HC_NAMEx")PD_COUNT=$(curl -s -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains" \ | jq '[.items // [] | .[] | select(.metadata.name != null)] | length')MD_COUNT=$(curl -s -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains" \ | jq '[.items // [] | .[] | select(.metadata.name != null)] | length')
# If HTTPS LB exists, fetch body to detect skeleton stateHTTPS_IS_SKELETON="false"if [ "$HTTPS_LB" = "200" ]; then HTTPS_LB_BODY=$(curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-https") HTTPS_IS_SKELETON=$(echo "$HTTPS_LB_BODY" | jq ' ((.spec.default_route_pools // []) | length == 0) and (.spec.client_side_defense == null) ')fi
# Compute deterministic environment statusjq -n \ --argjson http_lb "$HTTP_LB" \ --argjson https_lb "$HTTPS_LB" \ --argjson origin "$ORIGIN" \ --argjson hc "$HC" \ --argjson pd "$PD_COUNT" \ --argjson md "$MD_COUNT" \ --argjson https_skeleton "$HTTPS_IS_SKELETON" \'{ objects: [ { name: "http_lb", http_code: $http_lb, exists: ($http_lb == 200) }, { name: "https_lb", http_code: $https_lb, exists: ($https_lb == 200), is_skeleton: $https_skeleton }, { name: "origin_pool", http_code: $origin, exists: ($origin == 200) }, { name: "healthcheck", http_code: $hc, exists: ($hc == 200) }, { name: "protected_domains", count: $pd, exists: ($pd > 0) }, { name: "mitigated_domains", count: $md, exists: ($md > 0) } ], any_infra_exists: ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200), any_csd_exists: ($pd > 0 or $md > 0), status: ( if ($http_lb == 404 and $https_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "CLEAN" elif ($https_lb == 200 and $https_skeleton and $http_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "HTTPS_SKELETON" elif ($http_lb == 200 and $origin == 200) then "ALL_EXIST" elif ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200) then "TEARDOWN_NEEDED" elif ($md > 0 and $http_lb == 404 and ($https_lb == 404 or ($https_lb == 200 and $https_skeleton)) and $origin == 404 and $hc == 404) then "MITIGATIONS_ONLY" else "TEARDOWN_NEEDED" end ), action: ( if ($http_lb == 404 and $https_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "Proceed to Phase 1" elif ($https_lb == 200 and $https_skeleton and $http_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "Proceed to Phase 1 (HTTPS LB skeleton will be restored via PUT)" elif ($http_lb == 200 and $origin == 200) then "All Phase 1 objects exist — verify health, optionally skip to Phase 2" elif ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200) then "Run Phase 4 Teardown first, then re-check" elif ($md > 0 and $http_lb == 404 and ($https_lb == 404 or ($https_lb == 200 and $https_skeleton)) and $origin == 404 and $hc == 404) then "Delete mitigated domains inline, then proceed" else "Run Phase 4 Teardown first, then re-check" end )}'การตรวจสอบเพื่อข้ามขั้นตอน
หัวข้อที่มีชื่อว่า “การตรวจสอบเพื่อข้ามขั้นตอน”เมื่อออบเจ็กต์เฟส 1 ทั้งหมดมีอยู่ (200) และคุณวางแผนจะข้ามไปเฟส 2
ให้รัน คำสั่งตรวจสอบขั้นตอนที่ 7 ของเฟส 1 เพื่อยืนยันสุขภาพโครงสร้างพื้นฐาน
ก่อนข้าม ใช้คำสั่งที่แน่นอนจาก
เฟส 1 — ขั้นตอนที่ 7: ตรวจสอบ:
- การแก้ไข DNS:
dig +short xF5XC_DOMAINNAMEx A - สถานะ HTTP LB:
GET .../http_loadbalancers/xF5XC_LB_NAMEx-httpส่งต่อไปยังjq '{state: .spec.state}'— ต้องแสดงVIRTUAL_HOST_READY - การกำหนดค่า CSD JS:
GET .../js_configuration— ต้องมีscriptTag - สถานะ CSD:
GET .../statusส่งต่อไปยังjq '{configured: .isConfigured, enabled: .isEnabled}'— ทั้งสองต้องเป็นtrue
การตรวจสอบที่จำเป็นทั้งหมด (DNS-1, LB-1, CSD-1, CSD-2) ต้อง PASS ก่อน ข้ามไปเฟส 2 หากการตรวจสอบใดล้มเหลว ให้ดำเนินการเฟส 1 เริ่มจาก ขั้นตอนที่ล้มเหลว
ตารางการตรวจสอบความพร้อม
หัวข้อที่มีชื่อว่า “ตารางการตรวจสอบความพร้อม”การตรวจสอบก่อนเริ่มต้นด้านบนจะยืนยันว่าสภาพแวดล้อม สะอาด ตารางความพร้อมด้านล่างจะยืนยันว่าสภาพแวดล้อม มีความสามารถ — ว่าข้อกำหนดเบื้องต้น โควตา การเชื่อมต่อ และบริการแพลตฟอร์มทั้งหมดพร้อมสำหรับการสาธิตที่ประสบความสำเร็จ รันตารางนี้ก่อนการประชุมทุกครั้งเป็นส่วนหนึ่งของขั้นตอนเตรียมการ
การตรวจสอบแต่ละรายการมี test ID, ระดับ (T0–T5), เกณฑ์ PASS/FAIL/WARN และเส้นทางการแก้ไข ระดับเป็นลำดับ — การ FAIL ในระดับก่อนหน้าจะบล็อกระดับถัดไปจากการทำงาน
สรุประดับ
หัวข้อที่มีชื่อว่า “สรุประดับ”| ระดับ | หมวดหมู่ | บล็อกการสาธิต? | วัตถุประสงค์ |
|---|---|---|---|
| T0 | การเชื่อมต่อ & การยืนยันตัวตน | ใช่ | เราสามารถเข้าถึงแพลตฟอร์มและยืนยันตัวตนได้หรือไม่? |
| T1 | โควตา & ความจุ | ใช่ (หากถึงขีดจำกัด) | มีพื้นที่เพียงพอสำหรับสร้างออบเจ็กต์สาธิตหรือไม่? |
| T2 | ข้อกำหนดเบื้องต้นแพลตฟอร์ม | ใช่ | บริการระดับ tenant ได้รับการกำหนดค่าแล้วหรือไม่? |
| T3 | สุขภาพ Origin | เตือน | แอปพลิเคชันแบ็คเอนด์ตอบสนองหรือไม่? |
| T4 | สภาพแวดล้อมสะอาด | แก้ไขอัตโนมัติ | มีออบเจ็กต์ที่เหลือจากการรันก่อนหน้าหรือไม่? |
| T5 | ความพร้อมของใบรับรอง | ข้อมูล | HTTPS จะทำงานหรือเราควรวางแผนสำหรับ HTTP เท่านั้น? |
T0: การเชื่อมต่อ & การยืนยันตัวตน
หัวข้อที่มีชื่อว่า “T0: การเชื่อมต่อ & การยืนยันตัวตน”การตรวจสอบเหล่านี้ยืนยันว่าเครื่องปฏิบัติการสามารถเข้าถึง F5 XC API และข้อมูลประจำตัวถูกต้อง
PF-T0-1: การเชื่อมต่อ API
หัวข้อที่มีชื่อว่า “PF-T0-1: การเชื่อมต่อ API”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' --connect-timeout 10 --max-time 15 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-1", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 401 then "FAIL" else "FAIL" end ), detail: ( if .http_code == 200 then "API reachable, token valid" elif .http_code == 401 then "Token expired or invalid — regenerate under Administration > Credentials > API Credentials" elif .http_code == 0 then "Network unreachable — check connectivity, VPN, or TLS compatibility (try --tlsv1.2 --tls-max 1.2)" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-2: การเข้าถึง Namespace
หัวข้อที่มีชื่อว่า “PF-T0-2: การเข้าถึง Namespace”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-2", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 404 then "WARN" else "FAIL" end ), detail: ( if .http_code == 200 then "Token has namespace access" elif .http_code == 403 then "Token lacks permissions for namespace — check role bindings" elif .http_code == 404 then "Namespace does not exist — will be created in Phase 1 Step 0" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-3: การเข้าถึง CSD API
หัวข้อที่มีชื่อว่า “PF-T0-3: การเข้าถึง CSD API”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/status")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-3", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 404 then "WARN" else "FAIL" end ), detail: ( if .http_code == 200 then "Token has CSD/Shape API permissions" elif .http_code == 403 then "Token lacks CSD role binding — contact tenant administrator" elif .http_code == 404 then "Namespace does not exist — CSD access will be verified after namespace creation in Phase 1" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-4: ตารางสิทธิ์ RBAC
หัวข้อที่มีชื่อว่า “PF-T0-4: ตารางสิทธิ์ RBAC”การตรวจสอบที่ไม่ทำลายจะทดสอบสิทธิ์การอ่านและเขียนสำหรับออบเจ็กต์ทุกประเภทที่การสาธิตต้องการ การอ่านทดสอบผ่าน GET บน list endpoints การเขียนทดสอบผ่าน DELETE บนออบเจ็กต์ที่ไม่มีอยู่จริง — API คืนค่า 403 หาก RBAC ปฏิเสธการดำเนินการ หรือ 404 หากการดำเนินการได้รับอนุญาตแต่ออบเจ็กต์ไม่มีอยู่ เทคนิคที่ไม่มีผลข้างเคียงนี้หลีกเลี่ยงการสร้างออบเจ็กต์ probe ชั่วคราว
PROBE_NAME="rbac-probe-nonexistent"
# Read probesNS_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces/xF5XC_NAMESPACEx")HC_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks")OP_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools")LB_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")CSD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/status")PD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains")MD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains")
# Write probes (non-destructive: DELETE/cascade_delete on non-existent objects)NS_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X POST -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d "{\"name\":\"$PROBE_NAME\"}" \ "xF5XC_API_URLx/api/web/namespaces/$PROBE_NAME/cascade_delete")HC_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/$PROBE_NAME")OP_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/$PROBE_NAME")LB_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/$PROBE_NAME")PD_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains/$PROBE_NAME.example.com")MD_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains/$PROBE_NAME.example.com")
# Compute deterministic permission matrixjq -n \ --argjson ns_r "$NS_R" --argjson ns_w "$NS_W" \ --argjson hc_r "$HC_R" --argjson hc_w "$HC_W" \ --argjson op_r "$OP_R" --argjson op_w "$OP_W" \ --argjson lb_r "$LB_R" --argjson lb_w "$LB_W" \ --argjson csd_r "$CSD_R" \ --argjson pd_r "$PD_R" --argjson pd_w "$PD_W" \ --argjson md_r "$MD_R" --argjson md_w "$MD_W" \'{ check: "PF-T0-4", permissions: [ { object: "namespace", read: ($ns_r != 403), write: ($ns_w != 403), required: false, note: "conditional — only if ns must be created" }, { object: "healthcheck", read: ($hc_r != 403), write: ($hc_w != 403), required: false, note: "optional for CSD" }, { object: "origin_pool", read: ($op_r != 403), write: ($op_w != 403), required: true, note: "" }, { object: "http_loadbalancer", read: ($lb_r != 403), write: ($lb_w != 403), required: true, note: "" }, { object: "csd_status", read: ($csd_r != 403), write: true, required: true, note: "read-only check" }, { object: "protected_domain", read: ($pd_r != 403), write: ($pd_w != 403), required: true, note: "" }, { object: "mitigated_domain", read: ($md_r != 403), write: ($md_w != 403), required: false, note: "Phase 3 only" } ], status: ( if [ ($op_r == 403), ($op_w == 403), ($lb_r == 403), ($lb_w == 403), ($csd_r == 403), ($pd_r == 403), ($pd_w == 403) ] | any then "FAIL" elif ($ns_w == 403 or $hc_w == 403 or $md_w == 403) then "WARN" else "PASS" end ), detail: ( [ (if ($op_r == 403 or $op_w == 403) then "Origin pool: permission denied" else null end), (if ($lb_r == 403 or $lb_w == 403) then "Load balancer: permission denied" else null end), (if $csd_r == 403 then "CSD API: permission denied — CSD may not be enabled for this namespace" else null end), (if ($pd_r == 403 or $pd_w == 403) then "Protected domain: permission denied" else null end), (if $ns_w == 403 then "Namespace: write denied — namespace must already exist (cannot create)" else null end), (if $hc_w == 403 then "Healthcheck: write denied — will skip healthcheck creation" else null end), (if $md_w == 403 then "Mitigated domain: write denied — Phase 3 mitigation will be skipped" else null end) ] | map(select(. != null)) | join("; ") )}'T1: โควตา & ความจุ
หัวข้อที่มีชื่อว่า “T1: โควตา & ความจุ”การตรวจสอบเหล่านี้สอบถาม Quota Usage API ของ tenant เพื่อพิจารณาขีดจำกัด การใช้งานปัจจุบัน และความจุที่เหลือสำหรับออบเจ็กต์แต่ละชนิดที่การสาธิตต้องการ ซึ่งแทนที่การทดสอบแบบ probe-and-delete ด้วย API call แบบอ่านอย่างเดียวครั้งเดียวที่รายงานตัวเลขที่แน่นอน
PF-T1-0: เกตการใช้โควตา
หัวข้อที่มีชื่อว่า “PF-T1-0: เกตการใช้โควตา”สอบถาม endpoint การใช้โควตาระดับ tenant และคำนวณสถานะ PASS/WARN/FAIL แบบกำหนดได้สำหรับออบเจ็กต์แต่ละชนิดที่การสาธิตต้องการ endpoint นี้ต้องใช้ namespace system API call เดียวตรวจสอบโควตาระดับแพลตฟอร์มทั้งหมดพร้อมกัน
เกตกำหนดอาร์เรย์ demo_needs ที่ระบุจำนวนออบเจ็กต์แต่ละชนิดที่การสาธิตจะใช้ ว่าชนิดนั้นจำเป็นหรือไม่ และจำนวนขั้นต่ำที่จำเป็นเพื่อให้การสาธิตดำเนินการต่อได้ ตัวกรอง jq เปรียบเทียบ remaining กับ needed และคำนวณฟิลด์ status แบบกำหนดได้ — ไม่จำเป็นต้องมีผู้ดำเนินการตีความ
# Step 1: Fetch quota datacurl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces/system/quota/usage?namespace=system" \ > /tmp/quota.json
# Step 2: Compute gate statusjq ' . as $data | [ { kind: "healthcheck", needed: 1, required: false, min_proceed: 0 }, { kind: "origin_pool", needed: 1, required: true, min_proceed: 1 }, { kind: "endpoint", needed: 1, required: true, min_proceed: 1 }, { kind: "http_loadbalancer", needed: 2, required: true, min_proceed: 1 } ] | map( . as $req | $data.objects[$req.kind] as $obj | $obj.limit.maximum as $limit | $obj.usage.current as $usage | (if $limit == -1 then null else ($limit - $usage) end) as $remaining | { kind: $req.kind, limit: (if $limit == -1 then "unlimited" else $limit end), usage: $usage, remaining: (if $remaining == null then "unlimited" else $remaining end), needed: $req.needed, status: ( if $remaining == null then "PASS" elif $remaining >= $req.needed then "PASS" elif $remaining >= $req.min_proceed then "WARN" else (if $req.required then "FAIL" else "WARN" end) end ) } ) | { checks: ., gate: (if any(.[]; .status == "FAIL") then "FAIL" elif any(.[]; .status == "WARN") then "WARN" else "PASS" end) }' /tmp/quota.jsonผลลัพธ์เกต — ฟิลด์ gate คือผลตัดสินแบบกำหนดได้เดียว:
PASS— ออบเจ็กต์ทุกชนิดมีremaining >= neededการสาธิตสามารถดำเนินการต่อได้WARN— อย่างน้อยหนึ่งชนิดมีความจุลดลงแต่ขั้นต่ำที่จะดำเนินการต่อได้ถูกบรรลุ (เช่น มีช่อง LB ว่างเพียง 1 แทนที่จะเป็น 2 หรือโควตา healthcheck หมด) การสาธิตสามารถดำเนินการต่อได้แต่มีข้อจำกัดFAIL— อย่างน้อยหนึ่งชนิดที่จำเป็นมีremaining < min_proceedการสาธิตไม่สามารถดำเนินการต่อได้จนกว่าจะเพิ่มโควตา
ผลลัพธ์ตัวอย่าง (WARN — endpoint เต็มความจุ, healthcheck เกือบเต็ม):
{ "checks": [ { "kind": "healthcheck", "limit": 150, "usage": 149, "remaining": 1, "needed": 1, "status": "PASS" }, { "kind": "origin_pool", "limit": "unlimited", "usage": 420, "remaining": "unlimited", "needed": 1, "status": "PASS" }, { "kind": "endpoint", "limit": 500, "usage": 500, "remaining": 0, "needed": 1, "status": "FAIL" }, { "kind": "http_loadbalancer", "limit": "unlimited", "usage": 116, "remaining": "unlimited", "needed": 2, "status": "PASS" } ], "gate": "FAIL"}ค่า gate | การดำเนินการ |
|---|---|
| PASS | ดำเนินการต่อไปยัง PF-T1-4 (การตรวจสอบ protected domain) แล้วไป T2 |
| WARN | บันทึกข้อจำกัดในรายงานความพร้อม ดำเนินการต่อด้วยความสามารถที่ลดลง |
| FAIL | หยุด — รายงานชนิดที่หมดและขั้นตอนการแก้ไขด้านล่าง |
การแก้ไขตามชนิด:
| ชนิด | การแก้ไข |
|---|---|
healthcheck | ลบ healthcheck ที่ไม่ได้ใช้เพื่อเพิ่มความจุ การสาธิตดำเนินต่อได้โดยไม่มี healthcheck (CSD ไม่ต้องการ) |
origin_pool | ลบ origin pool ที่ไม่ได้ใช้หรือติดต่อผู้ดูแลระบบเพื่อเพิ่มขีดจำกัดของ tenant |
endpoint | ลบ origin pool ที่ไม่ได้ใช้ใน namespace อื่นเพื่อเพิ่มความจุ endpoint (endpoint เป็นออบเจ็กต์ย่อยของ origin pool) หรือติดต่อผู้ดูแลระบบ |
http_loadbalancer | ลบ load balancer ที่ไม่ได้ใช้หรือติดต่อผู้ดูแลระบบ หากมีเพียง 1 ช่องว่าง HTTP LB (หลัก) จะถูกสร้างแต่ HTTPS LB (รอง) จะถูกข้าม |
PF-T1-4: โควตา Protected Domain
หัวข้อที่มีชื่อว่า “PF-T1-4: โควตา Protected Domain”CSD protected domain ไม่ปรากฏใน Quota Usage API ของแพลตฟอร์ม ใช้การตรวจสอบแบบ probe: สร้างและลบ probe protected domain ทันที
# Create probe and capture both HTTP code and response bodyPROBE_BODY=$(curl -s -w '\n%\{http_code\}' -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-probe.example.com", "namespace": "xF5XC_NAMESPACEx" }, "spec": { "protected_domain": "example.com" } }' \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains")PROBE_HTTP=$(echo "$PROBE_BODY" | tail -1)PROBE_JSON=$(echo "$PROBE_BODY" | sed '$d')
# Compute statusecho "$PROBE_JSON" | jq --argjson http "$PROBE_HTTP" '{ check: "PF-T1-4", http_code: $http, status: ( if $http == 409 then "PASS" elif (.code // 0) == 8 then "FAIL" elif .metadata.name then "PASS" else "FAIL" end ), detail: ( if $http == 409 then "example.com already registered — quota not exhausted" elif (.code // 0) == 8 then "Protected domain quota exhausted — delete unused protected domains" elif .metadata.name then "Probe created — quota available" else "Unexpected response" end )}'
# Cleanup probe (404 is expected if 409 occurred)curl -s -X DELETE \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains/preflight-probe.example.com" \ > /dev/nullสำรอง: การตรวจสอบโควตาแบบ Probe
หัวข้อที่มีชื่อว่า “สำรอง: การตรวจสอบโควตาแบบ Probe”หาก PF-T1-0 ล้มเหลว (Quota Usage API คืนค่า 403, 404 หรือรูปแบบที่ไม่คาดคิด) ให้ใช้การตรวจสอบแบบ probe-and-delete สำรองสำหรับโควตา healthcheck, origin pool, endpoint และ load balancer การตรวจสอบเหล่านี้สร้างออบเจ็กต์ชั่วคราวและลบทันที — หากการสร้างคืนค่า error code 8 พร้อม “exhausted limits” แสดงว่าโควตาเต็ม
แต่ละ fallback probe ใช้รูปแบบเดียวกัน: สร้างออบเจ็กต์ชั่วคราว คำนวณสถานะแบบกำหนดได้จากการตอบกลับ จากนั้นลบ probe ฟิลด์ status เป็น PASS หากออบเจ็กต์ถูกสร้าง (มี .metadata.name), WARN หรือ FAIL หาก error code 8 (exhausted limits) ขึ้นอยู่กับว่าชนิดนั้นจำเป็นหรือไม่
Probe ของ Healthcheck (WARN หากหมด — healthcheck เป็นตัวเลือกสำหรับ CSD):
RESULT=$(curl -s -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-quota-probe", "namespace": "xF5XC_NAMESPACEx" }, "spec": { "http_health_check": { "use_origin_server_name": {}, "path": "/", "use_http2": false }, "timeout": 3, "interval": 15, "unhealthy_threshold": 1, "healthy_threshold": 3 } }' \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks")echo "$RESULT" | jq '{ check: "fallback-healthcheck", status: (if .metadata.name then "PASS" elif (.code // 0) == 8 then "WARN" else "FAIL" end), detail: (if .metadata.name then "Quota available" elif (.code // 0) == 8 then "Quota full — healthcheck optional, demo proceeds" else "Unexpected: \(.message // "unknown error")" end)}'curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/preflight-quota-probe" \ > /dev/nullProbe ของ Origin pool & endpoint (FAIL หากหมด — ทั้งสองจำเป็น):
RESULT=$(curl -s -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-origin-probe", "namespace": "xF5XC_NAMESPACEx" }, "spec": { "origin_servers": [{ "public_ip": { "ip": "192.0.2.1" }, "labels": {} }], "no_tls": {}, "port": 80, "same_as_endpoint_port": {}, "healthcheck": [], "loadbalancer_algorithm": "LB_OVERRIDE", "endpoint_selection": "LOCAL_PREFERRED" } }' \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools")echo "$RESULT" | jq '{ check: "fallback-origin-pool", status: (if .metadata.name then "PASS" elif (.code // 0) == 8 then "FAIL" else "FAIL" end), detail: (if .metadata.name then "Quota available" elif (.code // 0) == 8 then "Quota exhausted — \(.message // "limit reached")" else "Unexpected: \(.message // "unknown error")" end)}'curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/preflight-origin-probe" \ > /dev/nullProbe ของ HTTP load balancer (FAIL หากหมด — LB จำเป็น):
RESULT=$(curl -s -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-lb-probe", "namespace": "xF5XC_NAMESPACEx", "disable": false }, "spec": { "domains": ["preflight-probe.example.com"], "http": { "dns_volterra_managed": false, "port": 80 }, "advertise_on_public_default_vip": {}, "default_route_pools": [], "disable_rate_limit": {}, "no_service_policies": {}, "round_robin": {}, "disable_waf": {}, "no_challenge": {}, "disable_bot_defense": {}, "disable_api_definition": {}, "disable_api_discovery": {}, "disable_ip_reputation": {}, "disable_malicious_user_detection": {}, "single_lb_app": { "disable_discovery": {}, "disable_ddos_detection": {}, "disable_malicious_user_detection": {} }, "disable_trust_client_ip_headers": {}, "user_id_client_ip": {}, "disable_threat_mesh": {}, "l7_ddos_action_default": {}, "system_default_timeouts": {}, "default_sensitive_data_policy": {}, "disable_malware_protection": {}, "disable_api_testing": {} } }' \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")echo "$RESULT" | jq '{ check: "fallback-http-lb", status: (if .metadata.name then "PASS" elif (.code // 0) == 8 then "FAIL" else "FAIL" end), detail: (if .metadata.name then "Quota available" elif (.code // 0) == 8 then "Quota exhausted — \(.message // "limit reached")" else "Unexpected: \(.message // "unknown error")" end)}'curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/preflight-lb-probe" \ > /dev/nullT2: ข้อกำหนดเบื้องต้นแพลตฟอร์ม
หัวข้อที่มีชื่อว่า “T2: ข้อกำหนดเบื้องต้นแพลตฟอร์ม”การตรวจสอบเหล่านี้ยืนยันบริการระดับ tenant ที่การสาธิตต้องพึ่งพา
PF-T2-1: สถานะ CSD ของ Tenant
หัวข้อที่มีชื่อว่า “PF-T2-1: สถานะ CSD ของ Tenant”curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/status" \ | jq '{ check: "PF-T2-1", configured: .isConfigured, enabled: .isEnabled, status: (if .isConfigured and .isEnabled then "PASS" else "FAIL" end), detail: ( if .isConfigured and .isEnabled then "CSD is active" elif (.isConfigured | not) then "CSD not enabled at tenant level — contact F5 XC administrator" else "CSD configured but not active — contact administrator" end ) }'PF-T2-2: DNS Zone มีอยู่
หัวข้อที่มีชื่อว่า “PF-T2-2: DNS Zone มีอยู่”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T2-2", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 404 then "WARN" elif .http_code == 403 then "WARN" else "FAIL" end ), detail: ( if .http_code == 200 then "DNS zone exists in F5 XC" elif .http_code == 404 then "No F5 XC DNS zone — external DNS may be in use" elif .http_code == 403 then "Token lacks DNS zone read access (system namespace)" else "Unexpected HTTP \(.http_code)" end )}'PF-T2-3: เปิดใช้งาน DNS Managed Records
หัวข้อที่มีชื่อว่า “PF-T2-3: เปิดใช้งาน DNS Managed Records”รันเฉพาะเมื่อ PF-T2-2 คืนค่า 200 (มี F5 XC DNS zone)
ตรวจสอบสถานะปัจจุบัน:
curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \ | jq '{ check: "PF-T2-3", managed_records: (.spec.primary.allow_http_lb_managed_records // false), status: (if .spec.primary.allow_http_lb_managed_records == true then "PASS" else "WARN" end), detail: (if .spec.primary.allow_http_lb_managed_records == true then "LB-managed DNS records enabled" else "Managed records not enabled — auto-remediation may be needed" end) }'แก้ไขอัตโนมัติหากจำเป็น: หาก status เป็น WARN และ PF-T2-4 แสดง nameserver ของ F5 XC (ns1.f5clouddns.com, ns2.f5clouddns.com) ให้เปิดใช้งาน managed records อัตโนมัติโดยใช้ GET+PUT:
# Get current zone configZONE_CONFIG=$(curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx")
# Update with managed records enabledecho "$ZONE_CONFIG" \ | jq '.spec.primary.allow_http_lb_managed_records = true' \ | curl -s -X PUT \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d @- \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \ | jq .จากนั้นตรวจสอบอีกครั้งเพื่อยืนยันว่าการอัปเดตมีผล:
curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \ | jq '.spec.primary.allow_http_lb_managed_records'| ผลลัพธ์ | DNS Authority | สถานะ | การแก้ไข |
|---|---|---|---|
true | ใดก็ได้ | PASS | LB-managed DNS records จะถูกสร้างอัตโนมัติ |
false/null | F5 XC | แก้ไขอัตโนมัติ | เปิดใช้งานผ่าน GET+PUT, ตรวจสอบ, รายงานผลลัพธ์ |
false/null | ภายนอก | INFO | Managed records ไม่ใช้ได้กับ DNS ภายนอก — ขั้นตอนที่ 4 ของเฟส 1 จะใช้ ตัวเลือก B (สร้าง record ด้วยตนเอง) |
| การแก้ไขอัตโนมัติล้มเหลว | F5 XC | FAIL | Token อาจไม่มีสิทธิ์เขียน system namespace — ติดต่อผู้ดูแลระบบ tenant |
PF-T2-4: DNS Nameserver Authority
หัวข้อที่มีชื่อว่า “PF-T2-4: DNS Nameserver Authority”NS_RECORDS=$(dig +short NS xF5XC_ROOT_DOMAINx)echo "$NS_RECORDS" | jq -Rs '{ check: "PF-T2-4", nameservers: (split("\n") | map(select(length > 0))), status: ( if (split("\n") | map(select(length > 0)) | length) == 0 then "FAIL" elif test("f5clouddns\\.com") then "PASS" else "INFO" end ), detail: ( if (split("\n") | map(select(length > 0)) | length) == 0 then "No NS records — DNS is broken for this domain" elif test("f5clouddns\\.com") then "F5 XC is authoritative — automatic DNS management available" else "External DNS provider — Phase 1 Step 4 will use Option B (manual record creation)" end )}'T3: สุขภาพ Origin
หัวข้อที่มีชื่อว่า “T3: สุขภาพ Origin”การตรวจสอบเหล่านี้ยืนยันว่าแอปพลิเคชันแบ็คเอนด์สามารถเข้าถึงได้
การตรวจสอบเงื่อนไขข้าม: คำนวณว่า origin IP เป็นที่อยู่ RFC 5737 TEST-NET หรือไม่ก่อนรันการทดสอบการเชื่อมต่อ:
echo "xF5XC_ORIGIN_IPx" | jq -Rs '{ check: "PF-T3-skip", origin_ip: (rtrimstr("\n")), is_test_net: (rtrimstr("\n") | test("^192\\.0\\.2\\.|^198\\.51\\.100\\.|^203\\.0\\.113\\.")), status: (if (rtrimstr("\n") | test("^192\\.0\\.2\\.|^198\\.51\\.100\\.|^203\\.0\\.113\\.")) then "SKIP" else "CONTINUE" end), detail: (if (rtrimstr("\n") | test("^192\\.0\\.2\\.|^198\\.51\\.100\\.|^203\\.0\\.113\\.")) then "RFC 5737 TEST-NET address — not routable, connectivity testing skipped" else "Routable IP — proceed with connectivity tests" end)}'หาก status เป็น SKIP ให้บันทึก PF-T3-1 และ PF-T3-2 เป็น SKIP และไปยัง T4 มิฉะนั้นให้รันการตรวจสอบด้านล่าง
PF-T3-1: การเชื่อมต่อเซิร์ฟเวอร์ Origin
หัวข้อที่มีชื่อว่า “PF-T3-1: การเชื่อมต่อเซิร์ฟเวอร์ Origin”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' --connect-timeout 10 --max-time 15 \ "http://xF5XC_ORIGIN_IPx:xF5XC_ORIGIN_PORTx/")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T3-1", http_code: .http_code, status: (if .http_code >= 200 and .http_code < 600 then "PASS" elif .http_code == 0 then "WARN" else "WARN" end), detail: ( if .http_code >= 200 and .http_code < 600 then "Origin responding with HTTP \(.http_code)" elif .http_code == 0 then "Origin unreachable from this network — LB may use a different path" else "Unexpected response code \(.http_code)" end )}'PF-T3-2: Origin ให้บริการเนื้อหา HTML
หัวข้อที่มีชื่อว่า “PF-T3-2: Origin ให้บริการเนื้อหา HTML”รันเฉพาะเมื่อ PF-T3-1 คืนค่า HTTP status ที่ถูกต้อง:
curl -s --max-time 10 "http://xF5XC_ORIGIN_IPx:xF5XC_ORIGIN_PORTx/" \ | grep -qi '</html>' && echo "PASS: HTML content" || echo "WARN: No HTML detected"| ผลลัพธ์ | สถานะ | การแก้ไข |
|---|---|---|
PASS: HTML content | PASS | Origin ให้บริการหน้า HTML (จำเป็นสำหรับการฉีด CSD JS) |
WARN: No HTML detected | WARN | Origin อาจเป็นบริการ API เท่านั้นหรือคืนค่าที่ไม่ใช่ HTML — การฉีด CSD JS ต้องการการตอบกลับหน้า HTML |
T4: สภาพแวดล้อมสะอาด
หัวข้อที่มีชื่อว่า “T4: สภาพแวดล้อมสะอาด”การตรวจสอบเหล่านี้ยืนยันว่าไม่มี ออบเจ็กต์การกำหนดค่า F5 XC ที่มีชื่อ เหลือจากการรันสาธิตก่อนหน้า — HTTP load balancer, HTTPS load balancer, origin pool, healthcheck, protected domain และ mitigated domain T4 เกี่ยวกับการทำความสะอาดระดับออบเจ็กต์: ว่าออบเจ็กต์ API ที่จะขัดแย้งกับการสร้างเฟส 1 ยังคงมีอยู่หรือไม่ มันไม่ทดสอบที่อยู่ IP การเชื่อมต่อเครือข่าย หรือสุขภาพ origin (ข้อกังวลเหล่านั้นอยู่ใน T3)
รันคำสั่ง pre-flight ทั้งหกจากส่วน การตรวจสอบก่อนเริ่มต้น ด้านบน ใช้ ตรรกะการตัดสินใจ เพื่อกำหนดขั้นตอนถัดไป หากมีออบเจ็กต์อยู่ การรื้อถอนอัตโนมัติจะดำเนินการในขั้นตอนเตรียมการ (ไม่ต้องมีการยืนยัน)
ตรวจสอบและลบออบเจ็กต์ probe ค้างจากการรัน pre-flight ที่ถูกขัดจังหวะก่อนหน้าด้วย probe เหล่านี้สร้างขึ้นเฉพาะเมื่อ Quota Usage API ไม่สามารถใช้งานได้และมีการใช้ การตรวจสอบแบบ probe สำรอง หรือสำหรับ protected domain probe (PF-T1-4) ซึ่งใช้การตรวจสอบแบบ probe เสมอ:
# Stale probe cleanup (delete in any order — probes have no dependencies)curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/preflight-quota-probe" \ > /dev/null
curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/preflight-lb-probe" \ > /dev/null
curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/preflight-origin-probe" \ > /dev/null
curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains/preflight-probe.example.com" \ > /dev/nullDELETE แต่ละรายการคืนค่า 200 ({} ว่าง) หากออบเจ็กต์มีอยู่ หรือ 404 หากไม่มี — ทั้งสองเป็นสิ่งที่คาดหวัง
T5: ความพร้อมของใบรับรอง
หัวข้อที่มีชื่อว่า “T5: ความพร้อมของใบรับรอง”การตรวจสอบเหล่านี้ประเมินว่า HTTPS จะทำงานหรือการสาธิตควรวางแผนสำหรับ HTTP เท่านั้น
PF-T5-1: ประวัติการออกใบรับรองล่าสุด
หัวข้อที่มีชื่อว่า “PF-T5-1: ประวัติการออกใบรับรองล่าสุด”ตรวจสอบว่ามีการออกใบรับรอง Let’s Encrypt สำหรับโดเมนสาธิตเมื่อเร็วๆ นี้หรือไม่ วงจรสร้าง/ทำลายบ่อยๆ อาจทำให้ถึงขีดจำกัดอัตรารายสัปดาห์ (5 ใบรับรองซ้ำต่อสัปดาห์ต่อโดเมน)
PF-T5-2: สถานะใบรับรอง HTTPS LB ที่มีอยู่
หัวข้อที่มีชื่อว่า “PF-T5-2: สถานะใบรับรอง HTTPS LB ที่มีอยู่”รันเฉพาะเมื่อมี HTTPS LB จากการรันก่อนหน้า (PF-T4 พบออบเจ็กต์):
CERT_BODY=$(curl -s -w '\n%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-https")CERT_HTTP=$(echo "$CERT_BODY" | tail -1)CERT_JSON=$(echo "$CERT_BODY" | sed '$d')
if [ "$CERT_HTTP" = "404" ]; then echo '{"check":"PF-T5-2","cert_state":null,"status":"SKIP","detail":"No HTTPS LB — certificate state assessed after Phase 1 Step 3"}'else echo "$CERT_JSON" | jq '{ check: "PF-T5-2", cert_state: .spec.cert_state, status: ( if .spec.cert_state == "CertificateValid" then "PASS" elif .spec.cert_state == "AutoCertDomainRateLimited" then "INFO" elif (.spec.cert_state | test("Pending|Started")) then "INFO" else "INFO" end ), detail: ( if .spec.cert_state == "CertificateValid" then "Certificate healthy — HTTPS will work" elif .spec.cert_state == "AutoCertDomainRateLimited" then "Let'\''s Encrypt rate limit hit — plan for HTTP-only demo" elif (.spec.cert_state | test("Pending|Started")) then "Certificate provisioning in progress" else "Certificate state: \(.spec.cert_state // "unknown")" end ) }'fiรูปแบบรายงานความพร้อม
หัวข้อที่มีชื่อว่า “รูปแบบรายงานความพร้อม”หลังจากรันทุกระดับแล้ว ให้นำเสนอรายงานความพร้อมรวม:
## ความพร้อมสาธิต: พร้อม / ไม่พร้อม / พร้อมพร้อมคำเตือน
### T0: การเชื่อมต่อ & การยืนยันตัวตน| การตรวจสอบ | ผลลัพธ์ | สถานะ ||---|---|---|| PF-T0-1: API Connectivity | 200 | PASS || PF-T0-2: Namespace Access | 200 | PASS || PF-T0-3: CSD API Access | 200 | PASS |
### T1: โควตา & ความจุ| การตรวจสอบ | ชนิด | ขีดจำกัด | การใช้งาน | เหลือ | ต้องการ | สถานะ ||---|---|---|---|---|---|---|| PF-T1-0: Quota Usage Gate | `healthcheck` | 150 | 148 | 2 | 1 | PASS || PF-T1-0: Quota Usage Gate | `origin_pool` | unlimited | 420 | unlimited | 1 | PASS || PF-T1-0: Quota Usage Gate | `endpoint` | 500 | 498 | 2 | 1 | PASS || PF-T1-0: Quota Usage Gate | `http_loadbalancer` | unlimited | 116 | unlimited | 2 | PASS || PF-T1-0: Quota Usage Gate | **gate** | — | — | — | — | **PASS** || PF-T1-4: Protected Domain | — | — | — | — | 1 | PASS (probe) |
### T2: ข้อกำหนดเบื้องต้นแพลตฟอร์ม| การตรวจสอบ | ผลลัพธ์ | สถานะ ||---|---|---|| PF-T2-1: CSD Tenant Status | configured + enabled | PASS || PF-T2-2: DNS Zone Exists | 200 | PASS || PF-T2-3: DNS Managed Records | true | PASS || PF-T2-4: DNS Nameserver Authority | f5clouddns.com | PASS |
### T3: สุขภาพ Origin| การตรวจสอบ | ผลลัพธ์ | สถานะ ||---|---|---|| PF-T3-1: Origin Connectivity | TEST-NET address (192.0.2.1) | SKIP || PF-T3-2: HTML Content | TEST-NET address | SKIP |
### T4: สภาพแวดล้อมสะอาด| การตรวจสอบ | ผลลัพธ์ | สถานะ ||---|---|---|| HTTP LB | 404 | PASS || HTTPS LB | 404 | PASS || Origin Pool | 404 | PASS || Healthcheck | 404 | PASS || Protected Domains | 0 | PASS || Mitigated Domains | 0 | PASS |
### T5: ความพร้อมของใบรับรอง| การตรวจสอบ | ผลลัพธ์ | สถานะ ||---|---|---|| PF-T5-2: Cert State | SKIP (no HTTPS LB) | INFO |
### คำเตือน- (ระบุรายการ WARN หรือ INFO พร้อมบริบท)กฎสถานะโดยรวม:
| เงื่อนไข | สถานะ |
|---|---|
| การตรวจสอบ T0–T4 ทั้งหมด PASS | พร้อม |
| การตรวจสอบ T0–T4 ทั้งหมด PASS แต่ T3 หรือ T5 มี WARN/INFO | พร้อมพร้อมคำเตือน |
| การตรวจสอบ T0, T1 หรือ T2 ใดเป็น FAIL | ไม่พร้อม — แก้ไขก่อนดำเนินการต่อ |
| T4 มีออบเจ็กต์ที่เหลือ | แก้ไขอัตโนมัติ (รื้อถอน) จากนั้นตรวจสอบอีกครั้ง |
โปรโตคอลการดำเนินการของผู้ช่วย AI
หัวข้อที่มีชื่อว่า “โปรโตคอลการดำเนินการของผู้ช่วย AI”ส่วนนี้กำหนด ขั้นตอนการทำงานแบบกำหนดได้ สำหรับผู้ช่วย AI (Claude Code, Copilot ฯลฯ) ที่ดำเนินการขั้นตอนอัตโนมัติ API การปฏิบัติตามโปรโตคอลนี้ขจัดการคาดเดา — จุดตัดสินใจทุกจุดมีเส้นทางการแก้ไขที่กำหนดไว้
โปรโตคอลการแก้ไขตัวแปร
หัวข้อที่มีชื่อว่า “โปรโตคอลการแก้ไขตัวแปร”แก้ไขตัวแปรแต่ละตัวตามลำดับที่แน่นอนนี้ หยุดที่แหล่งแรกที่ให้ค่าที่ไม่ใช่ placeholder:
- ตรวจสอบไฟล์
.env— มองหา.envในรูทของ repository หากมีอยู่ ให้แยกวิเคราะห์คู่KEY=VALUEทั้งหมด - ตรวจสอบ shell environment — รัน
env | grep F5XC_เพื่อหาค่าที่ export แล้วในเซสชันปัจจุบัน - ระบุค่าที่ขาด — เปรียบเทียบค่าที่แก้ไขแล้วกับตารางจำเป็น/ตัวเลือกด้านล่าง ค่าจะ “ขาด” หากไม่มี ว่างเปล่า หรือยังคงตั้งค่าเป็น placeholder เริ่มต้น (เช่น
example-api-token,example-tenant,example-namespace,app.example.com,user@example.com) - ถามผู้ดำเนินการ — สำหรับตัวแปร จำเป็น ที่ขาดแต่ละตัว ให้ถามผู้ดำเนินการเพื่อให้ค่า อย่าดำเนินการต่อจนกว่าตัวแปรจำเป็นทั้งหมดจะได้รับการแก้ไข
- ใช้ค่าเริ่มต้น — สำหรับตัวแปร ตัวเลือก ที่ขาดแต่ละตัว ใช้ค่าเริ่มต้นจากตารางด้านล่างโดยไม่ต้องถาม
สตริงว่าง = ขาด: ตัวแปรที่ export ด้วยค่าว่าง (เช่น
F5XC_HC_NAME="") ถูกถือเสมือนตัวแปรที่ไม่ได้ตั้งค่า — ใช้ค่าเริ่มต้น ใช้ shell parameter expansion (${F5XC_HC_NAME:-csd-hc}) เพื่อใช้ค่าเริ่มต้นในขั้นตอนเดียว
- แสดงการยืนยัน — แสดงตารางตัวแปรที่แก้ไขแล้วให้ผู้ดำเนินการดูและรอการอนุมัติก่อนดำเนินการ API call ใดๆ
การ override ขั้นตอนเตรียมการ: ระหว่างขั้นตอนที่ 1 เตรียมการ ให้ข้ามการรอใน ขั้นตอนที่ 6 แสดงตารางตัวแปรที่แก้ไขแล้วเพื่อบันทึก จากนั้น ดำเนินการต่อทันที ขั้นตอนที่ 1–5 ยังคงใช้ได้ — หากตัวแปรจำเป็นใดขาด หลังจากตรวจสอบ
.envและ shell ให้หยุดและรายงาน ตัวแปรที่ขาด
ตัวแปรจำเป็น vs ตัวเลือก
หัวข้อที่มีชื่อว่า “ตัวแปรจำเป็น vs ตัวเลือก”| ตัวแปร | จำเป็น | ค่าเริ่มต้น | Placeholder (ถือว่าขาด) |
|---|---|---|---|
F5XC_API_TOKEN | ใช่ | — | example-api-token |
F5XC_API_URL | ใช่ | — | https://example-tenant.console.ves.volterra.io |
F5XC_NAMESPACE | ใช่ | — | example-namespace |
F5XC_DOMAINNAME | ใช่ | — | app.example.com |
F5XC_ROOT_DOMAIN | ใช่ | — | example.com |
F5XC_LB_NAME | ใช่ | — | example-lb-name, example-lb |
F5XC_EMAIL | ใช่ | — | user@example.com |
F5XC_HC_NAME | ตัวเลือก | csd-hc | — |
F5XC_ORIGIN_IP | ตัวเลือก | 44.232.69.192 | — |
F5XC_ORIGIN_POOL | ตัวเลือก | csd-origin | — |
F5XC_ORIGIN_PORT | ตัวเลือก | 3000 | — |
โหมดการดำเนินการ
หัวข้อที่มีชื่อว่า “โหมดการดำเนินการ”ผู้ช่วย AI ทำงานในหนึ่งในสามโหมดระหว่างการสาธิต:
| โหมด | เมื่อใช้งาน | พฤติกรรม |
|---|---|---|
| ปกติ | ค่าเริ่มต้นระหว่างเตรียมการ, ดำเนินการ, รื้อถอน | คำสั่งที่บันทึกไว้เท่านั้น |
| ดีบัก | เปิดอัตโนมัติเมื่อเกิดข้อผิดพลาด | การแก้ไขปัญหาอย่างสร้างสรรค์, อัปเดตเอกสาร |
| ถาม-ตอบ | ระหว่างขั้นตอนถาม-ตอบ | ด้นสด — อนุญาตคำสั่ง ad-hoc เพื่อตอบคำถามผู้ชม |
โหมดปกติ (ค่าเริ่มต้น):
- API call, คำค้นตรวจสอบ และคำสั่ง shell ทุกรายการ ต้องมาจาก ไฟล์เฟสโดยตรง (เฟส 1–4) หรือจากส่วนการตรวจสอบก่อนเริ่มต้นด้านบน
- แทนที่เฉพาะ placeholder
xTOKENxด้วยค่าตัวแปรที่แก้ไขแล้ว - อย่าสร้าง API endpoint, jq filter หรือคำสั่ง cURL จาก ความรู้ทั่วไปหรือการอนุมาน
- หากคำสั่งที่จำเป็นไม่ได้บันทึกไว้ ให้หยุดและรายงานให้ผู้ดำเนินการ: “ขั้นตอนการตรวจสอบนี้ไม่ครอบคลุมในเอกสารเฟส”
โหมดดีบัก (เปิดอัตโนมัติเมื่อเกิดข้อผิดพลาด):
- เปิดอัตโนมัติเมื่อคำสั่งที่บันทึกไว้ให้ผลลัพธ์ที่ไม่คาดคิด: HTTP response ที่ไม่ใช่ 2xx, jq parse error, command timeout หรือ response body ที่ขัดแย้งกับตารางหลักฐาน
- ในโหมดดีบัก ผู้ช่วย AI อาจสร้างคำสั่งวินิจฉัย ตรวจสอบ API response ดิบ ทดสอบ endpoint ที่แตกต่าง และใช้ การแก้ไขปัญหาอย่างสร้างสรรค์เพื่อหาสาเหตุ
- นำหน้าผลลัพธ์ดีบักทั้งหมดด้วย
[DEBUG]เพื่อให้ผู้ดำเนินการสามารถ แยกแยะกิจกรรมวินิจฉัยจากการดำเนินการปกติ - บันทึกสิ่งที่เรียนรู้: หลังจากแก้ไขปัญหาแล้ว ให้อัปเดต
ไฟล์เฟสที่เกี่ยวข้องหรือส่วนการแก้ไขปัญหาด้วย:
- สถานการณ์ความล้มเหลว (อะไรผิดพลาด)
- สิ่งที่ลองแล้วไม่ได้ผล (เพื่อให้การรันในอนาคตไม่ต้องทำซ้ำ)
- การแก้ไขที่ทำงาน (คำสั่งหรือการแก้ไขที่แก้ปัญหาได้)
- เป้าหมายของโหมดดีบักคือ ขจัดตัวเอง — ทุกเซสชันดีบัก ควรสร้างการอัปเดตเอกสารที่ทำให้การดำเนินการครั้งถัดไป เป็นแบบกำหนดได้อย่างสมบูรณ์
- เมื่อเอกสารได้รับการอัปเดตและปัญหาได้รับการแก้ไขแล้ว ให้กลับ ไปโหมดปกติและดำเนินการต่อจากขั้นตอนที่บันทึกไว้สำเร็จล่าสุด
- หากโหมดดีบักไม่สามารถแก้ไขปัญหาได้ ให้รายงานผลการค้นพบให้ ผู้ดำเนินการและหยุด — อย่าดำเนินการต่อไปยังเฟสถัดไป
โหมดถาม-ตอบ (ระหว่างขั้นตอนถาม-ตอบ):
- ใช้งานเฉพาะระหว่างขั้นตอนถาม-ตอบของการประชุม หลังจากสรุปการสาธิต
- ผู้ช่วย AI อาจสร้าง API call แบบ ad-hoc, รันคำสั่ง วินิจฉัย, นำทางไปยังหน้าที่ไม่ได้เตรียมสคริปต์ไว้ และแก้ไข สภาพแวดล้อมสาธิตสดเพื่อแสดงคำตอบสำหรับคำถามของผู้ชม
- ไม่มีนำหน้า
[DEBUG]— นี่เป็นพฤติกรรมด้นสดที่ตั้งใจ ไม่ใช่การกู้คืนข้อผิดพลาด - ใช้ส่วน CSD Product Expertise ใน
DEMO_EXECUTOR.mdเป็น ฐานความรู้สำหรับคำถามเกี่ยวกับผลิตภัณฑ์
การจัดการ Browser Context
หัวข้อที่มีชื่อว่า “การจัดการ Browser Context”การสะสม initScript เป็นสาเหตุทั่วไปของความล้มเหลวในการสาธิต การเรียก
navigate_page แต่ละครั้งพร้อมพารามิเตอร์ initScript จะเพิ่มสคริปต์ไปยัง
รายการถาวรที่ทำงานทุกครั้งที่โหลดเอกสารในภายหลัง ปฏิบัติตาม
กฎเหล่านี้:
- นำทางไปยัง
about:blankเสมอ ก่อนการนำทางใดๆ ที่มีinitScriptเพื่อล้างสคริปต์ที่สะสมจากการรันก่อนหน้า - ใช้
new_pageพร้อมisolatedContextเมื่อสลับระหว่าง เฟสสาธิต (เช่น เฟส 2 → เฟส 3) เพื่อให้แน่ใจว่ามีสถานะเบราว์เซอร์ ที่สะอาดสมบูรณ์ - การกู้คืนจากหน้าที่ไม่ตอบสนอง — หากเกิด timeout ของ
take_screenshotหรือtake_snapshotแสดงว่า browser context ใช้ ทรัพยากรหมด ใช้new_pageพร้อมisolatedContextเพื่อสร้าง context ใหม่ จากนั้นลองอีกครั้งจากขั้นตอนนำทางabout:blank - ดู aside ของ การจำลองการโจมตีเฟส 2 สำหรับ คำแนะนำโดยละเอียดเกี่ยวกับข้อผิดพลาด origin ชั่วคราวและการกู้คืนจาก ทรัพยากรหมด
โปรโตคอลการแสดงหลักฐาน
หัวข้อที่มีชื่อว่า “โปรโตคอลการแสดงหลักฐาน”หลังจาก API call ทุกครั้ง ผู้ช่วย AI ต้องนำเสนอหลักฐานที่มีโครงสร้างให้ผู้ดำเนินการโดยใช้รูปแบบนี้:
ขั้นตอนการสร้าง (POST):
| ฟิลด์ | ค่า | สถานะ |
|---|---|---|
| HTTP Status | 200 | PASS |
| Object Name | csd-origin | — |
| Key Property | (แยกผ่าน jq) | — |
หลังจากแต่ละขั้นตอนการสร้าง ให้รัน GET เพื่อยืนยันว่าออบเจ็กต์มีอยู่และแสดงคุณสมบัติหลัก หาก GET คืนค่า 404 ให้รายงาน FAIL และหยุด
ขั้นตอนการตรวจสอบ (GET/dig):
| การทดสอบ | ผลลัพธ์ | สถานะ |
|---|---|---|
| DNS-1: A Record | 198.51.100.10 | PASS |
| LB-1: HTTP LB State | VIRTUAL_HOST_READY | PASS |
| LB-2: HTTPS LB State | VIRTUAL_HOST_READY | INFO (ตัวเลือก) |
| TLS-1: Cert State | CertificateValid | INFO (ตัวเลือก) |
| CSD-1: JS Tag | มี scriptTag | PASS |
อ้างอิง test case ID ของ การวินิจฉัย & การตรวจสอบ (DNS-1, TLS-1, LB-1, CSD-1 ฯลฯ) เป็นมาตรฐานการตรวจสอบสำหรับแต่ละชั้น
สรุปขั้นตอนการดำเนินการ
หัวข้อที่มีชื่อว่า “สรุปขั้นตอนการดำเนินการ”การดำเนินการเฟสเป็นลำดับและมีเกต: แต่ละเฟสต้อง PASS ในการตรวจสอบที่จำเป็นทั้งหมดก่อนเฟสถัดไปจะเริ่ม การสาธิตปฏิบัติตามวงจรชีวิตการประชุมสี่ขั้นตอน — ดูส่วน Meeting Stages ใน DEMO_EXECUTOR.md สำหรับวลีกระตุ้นและกฎพฤติกรรม
ผู้ช่วย AI ปฏิบัติตามลำดับนี้:
- เตรียมการ — แก้ไขตัวแปร, รันการตรวจสอบ pre-flight, ยืนยันสภาพแวดล้อมสะอาด (สามารถรันแยกก่อนการประชุม)
- แนะนำ — SE แนะนำตัวเองและระบุเป้าหมายผลลัพธ์ (การมองเห็นภัยคุกคามฝั่งไคลเอนต์, การปฏิบัติตาม PCI, การตรวจจับแบบเรียลไทม์)
- ดำเนินการเฟส 1 (ขั้นตอน 1–7) — การสร้างและตรวจสอบโครงสร้างพื้นฐาน; การตรวจสอบเฟส 1 ทั้งหมดต้อง PASS ก่อนดำเนินการต่อ
- ดำเนินการเฟส 2 (ขั้นตอน 8–9) — การจำลองการโจมตีและการตรวจสอบการตรวจจับผ่าน API; ผู้ช่วย AI ที่มีระบบอัตโนมัติเบราว์เซอร์จะดำเนินการขั้นตอนเบราว์เซอร์โดยตรง ผู้ดำเนินการที่ไม่มีเครื่องมือเบราว์เซอร์จะดำเนินการด้วยตนเอง
- ดำเนินการเฟส 3 — ยืนยัน baseline ที่สะอาด, รันการโจมตี (หลักฐานก่อน), POST แต่ละโดเมนไปยัง
/mitigated_domains, ตรวจสอบว่ามีการใช้ mitigation, รันการโจมตีอีกครั้งโดยใช้ URLhttp://(หลักฐานหลัง), นำเสนอการเปรียบเทียบก่อน/หลัง - สรุป — ย้ำเป้าหมายผลลัพธ์, สรุปหลักฐานจากแต่ละเฟส, เน้นการตรวจจับและ mitigation สำคัญ
- ถาม-ตอบ — ขั้นตอนด้นสด, การสาธิตยังคงเปิดอยู่, SE ตอบคำถามผู้ชมและถามคำถามกลับ
- รื้อถอน (หลังการประชุม) — เฟส 4, ต้องมีการยืนยันจากผู้ดำเนินการอย่างชัดแจ้ง, ลบออบเจ็กต์ทั้งหมดตามลำดับย้อนกลับของ dependency, ยืนยันสภาพแวดล้อมสะอาด
หากขั้นตอนใดคืนค่า FAIL ให้หยุดและรายงานความล้มเหลวพร้อมลิงก์ส่วนการแก้ไขปัญหาที่เกี่ยวข้องก่อนดำเนินการต่อ
ข้อกำหนดเบื้องต้น
หัวข้อที่มีชื่อว่า “ข้อกำหนดเบื้องต้น”- F5 XC API token — สร้างได้ที่ Administration → Credentials → API Credentials
- ติดตั้ง
curlและjqในเครื่อง - namespace ที่มีสิทธิ์สร้าง healthcheck, origin pool และ HTTP load balancer
การตั้งค่าสภาพแวดล้อม
หัวข้อที่มีชื่อว่า “การตั้งค่าสภาพแวดล้อม”สร้างไฟล์ .env พร้อมค่าสภาพแวดล้อมของคุณ มีเทมเพลตในที่เก็บข้อมูล:
cp .env.example .envแก้ไข .env ด้วยค่าจริงของคุณ:
# Required — your environmentF5XC_API_TOKEN=example-api-tokenF5XC_API_URL=https://example-tenant.console.ves.volterra.ioF5XC_DOMAINNAME=app.example.comF5XC_EMAIL=user@example.comF5XC_LB_NAME=example-lb-nameF5XC_NAMESPACE=example-namespaceF5XC_ROOT_DOMAIN=example.com
# Optional — Juice Shop demo defaults are used when not set# F5XC_HC_NAME=csd-hc# F5XC_ORIGIN_IP=44.232.69.192# F5XC_ORIGIN_POOL=csd-origin# F5XC_ORIGIN_PORT=3000Source ไฟล์เพื่อโหลดตัวแปรเข้า shell session ของคุณ:
set -a && source .env && set +aplaceholder xTOKENx แต่ละตัวในคำสั่ง curl แมปโดยตรงกับตัวแปรสภาพแวดล้อม — ตัวอย่างเช่น xF5XC_API_TOKENx ตรงกับ $F5XC_API_TOKEN คุณสามารถแทนที่ค่าเหล่านี้ได้โดยใช้แบบฟอร์มแบบโต้ตอบที่ด้านบนของหน้า หรือให้ผู้ช่วย AI เช่น Claude Code อ่าน .env ของคุณและสร้างคำสั่งให้
โทเค็น Placeholder
หัวข้อที่มีชื่อว่า “โทเค็น Placeholder”| โทเค็น | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|
xF5XC_API_URLx | https://example-tenant.console.ves.volterra.io | URL ของ XC Console API |
xF5XC_API_TOKENx | example-api-token | โทเค็นข้อมูลประจำตัว API |
xF5XC_EMAILx | user@example.com | ที่อยู่อีเมลการแจ้งเตือน CSD |
xF5XC_NAMESPACEx | example-namespace | Namespace |
xF5XC_LB_NAMEx | example-lb | ชื่อฐานของ HTTP Load Balancer (สร้าง ${name}-http และ ${name}-https) |
xF5XC_DOMAINNAMEx | app.example.com | FQDN ที่จะปกป้อง |
xF5XC_ROOT_DOMAINx | example.com | โดเมนราก (eTLD+1) สำหรับ CSD protected domain |
xF5XC_ORIGIN_POOLx | csd-origin | ชื่อ origin pool |
xF5XC_ORIGIN_IPx | 44.232.69.192 | IP ของเซิร์ฟเวอร์ origin |
xF5XC_ORIGIN_PORTx | 3000 | พอร์ตของเซิร์ฟเวอร์ origin |
xF5XC_HC_NAMEx | csd-hc | ชื่อ healthcheck |
การอ้างอิงระบบอัตโนมัติ
หัวข้อที่มีชื่อว่า “การอ้างอิงระบบอัตโนมัติ”ส่วนนี้สรุปขั้นตอนการทำงานทั้งหมดของแบบฝึกหัดสำหรับการเขียนสคริปต์หรือระบบอัตโนมัติ
เริ่มต้นอย่างรวดเร็ว
หัวข้อที่มีชื่อว่า “เริ่มต้นอย่างรวดเร็ว”- Clone repository และคัดลอกเทมเพลตสภาพแวดล้อม:
cp .env.example .env - แก้ไข
.envด้วย tenant URL, API token, namespace และค่าโดเมนของคุณ - Source สภาพแวดล้อม:
set -a && source .env && set +a - ดำเนินการแต่ละเฟสตามลำดับ ตรวจสอบ PASS ในแต่ละบล็อกหลักฐานก่อนดำเนินการเฟสถัดไป
การแก้ไขตัวแปร
หัวข้อที่มีชื่อว่า “การแก้ไขตัวแปร”ค่าจะถูกแก้ไขโดยใช้โปรโตคอลแบบกำหนดได้ที่กำหนดใน โปรโตคอลการดำเนินการของผู้ช่วย AI:
- ไฟล์
.env— แยกวิเคราะห์คู่KEY=VALUEจากรูทของ repository - Shell environment — ตรวจสอบ
env | grep F5XC_สำหรับค่าที่ export - การตรวจจับ placeholder — ทำเครื่องหมายค่าที่ตรงกับ placeholder เริ่มต้น (เช่น
example-api-token,example-namespace) ว่าขาด - ถามผู้ดำเนินการ — ถามสำหรับตัวแปร จำเป็น ที่ขาดแต่ละตัว
- ใช้ค่าเริ่มต้น — ใช้ค่าเริ่มต้นในตัวสำหรับตัวแปร ตัวเลือก ที่ขาด
- ยืนยัน — แสดงตารางตัวแปรที่แก้ไขแล้วและรอการอนุมัติจากผู้ดำเนินการ
ลำดับการดำเนินการ
หัวข้อที่มีชื่อว่า “ลำดับการดำเนินการ”- เฟส 1 — สร้าง: ปรับใช้โครงสร้างพื้นฐาน (healthcheck, origin pool, HTTP LB + HTTPS LB), กำหนดค่า DNS, เปิดใช้งาน CSD, ลงทะเบียน protected domain, ตรวจสอบส่วนประกอบทั้งหมด HTTP LB เป็นเป้าหมายสาธิตหลัก; HTTPS LB เป็นตัวเลือก
- เฟส 2 — โจมตี: รันการจำลองการโจมตีในเบราว์เซอร์โดยใช้ URL
http://, รอ 5–10 นาที, ตรวจสอบการตรวจจับผ่าน API (/scripts,/detected_domains,/formFields) - เฟส 3 — บรรเทา: ยืนยัน baseline ที่สะอาด, รันการโจมตี (หลักฐานก่อน), POST แต่ละโดเมนไปยัง
/mitigated_domains, ตรวจสอบว่ามีการใช้ mitigation, รันการโจมตีอีกครั้งโดยใช้ URLhttp://(หลักฐานหลัง), นำเสนอการเปรียบเทียบก่อน/หลัง - เฟส 4 — รื้อถอน (ต้องมีการยืนยันจากมนุษย์อย่างชัดแจ้ง): ลบ HTTPS LB → HTTP LB → origin pool → ทำความสะอาด DNS zone (record ที่สร้างด้วยตนเองเท่านั้น) → healthcheck → protected domain อย่าลบ DNS zone
| โทเค็น | คำอธิบาย | ค่าเริ่มต้น |
|---|---|---|
xF5XC_API_URLx | URL ของ XC Console API | https://example-tenant.console.ves.volterra.io |
xF5XC_API_TOKENx | โทเค็นข้อมูลประจำตัว API | (ผู้ใช้ระบุ) |
xF5XC_EMAILx | อีเมลการแจ้งเตือน CSD | user@example.com |
xF5XC_NAMESPACEx | Namespace | example-namespace |
xF5XC_LB_NAMEx | ชื่อฐานของ HTTP Load Balancer (สร้าง ${name}-http และ ${name}-https) | example-lb |
xF5XC_DOMAINNAMEx | FQDN ที่จะปกป้อง | app.example.com |
xF5XC_ROOT_DOMAINx | โดเมนราก (eTLD+1) | example.com |
xF5XC_ORIGIN_POOLx | ชื่อ origin pool | csd-origin |
xF5XC_ORIGIN_IPx | IP ของเซิร์ฟเวอร์ origin | 44.232.69.192 |
xF5XC_ORIGIN_PORTx | พอร์ตของเซิร์ฟเวอร์ origin | 3000 |
xF5XC_HC_NAMEx | ชื่อ healthcheck | csd-hc |
กลุ่มตัวเลือก oneOf
หัวข้อที่มีชื่อว่า “กลุ่มตัวเลือก oneOf”spec ของ HTTP Load Balancer ใช้กลุ่มตัวเลือก oneOf ที่ต้องตั้งค่าตัวเลือกเดียวต่อกลุ่ม การตั้งค่าศูนย์หรือมากกว่าหนึ่งตัวเลือกในกลุ่มจะทำให้เกิดข้อผิดพลาด 422
ตัวเลือกที่เกี่ยวข้องกับ CSD ที่สำคัญ:
| กลุ่มตัวเลือก | ตัวเลือก | ค่าเริ่มต้น CSD |
|---|---|---|
client_side_defense_choice | client_side_defense, disable_client_side_defense | client_side_defense |
java_script_choice (ซ้อนใน CSD) | disable_js_insert, js_insert_all_pages, js_insert_all_pages_except, js_insertion_rules | js_insert_all_pages |
ตัวเลือกประเภท listener (HTTP vs HTTPS):
การสาธิตสร้าง LB สองตัวที่มีการกำหนดค่า listener แตกต่างกัน:
| LB | ตัวเลือก Listener | การกำหนดค่า |
|---|---|---|
${F5XC_LB_NAME}-http (หลัก) | http | "http": { "dns_volterra_managed": true, "port": 80 } |
${F5XC_LB_NAME}-https (รอง) | https_auto_cert | "https_auto_cert": { "http_redirect": true, "port": 443, ... } |
คีย์ http และ https_auto_cert เป็นแบบ mutually exclusive — LB แต่ละตัวใช้เพียงตัวเดียว
ตัวเลือกซ้อนของ HTTPS auto-cert (LB รองเท่านั้น):
| กลุ่มตัวเลือก | ตัวเลือก | ค่าเริ่มต้น |
|---|---|---|
| port | port (number) | 443 |
server_header_choice | default_header, server_name, append_server_name | default_header |
path_normalize_choice | enable_path_normalize, disable_path_normalize | enable_path_normalize |
mtls_choice | no_mtls, use_mtls | no_mtls |
default_loadbalancer_choice | default_loadbalancer, non_default_loadbalancer | default_loadbalancer |
ตัวเลือกซ้อนของ single_lb_app (การกำหนดค่า ML):
ออบเจ็กต์ single_lb_app มีกลุ่ม oneOf ที่จำเป็นของตัวเอง การตั้งค่า single_lb_app: \{\} โดยไม่มีตัวเลือกซ้อนเหล่านี้จะทำให้เกิดข้อผิดพลาด 400
| กลุ่มตัวเลือก | ตัวเลือก | ค่าเริ่มต้น |
|---|---|---|
api_discovery_choice | disable_discovery, enable_discovery | disable_discovery |
ddos_detection_choice | disable_ddos_detection, enable_ddos_detection | disable_ddos_detection |
malicious_user_detection_choice | disable_malicious_user_detection, enable_malicious_user_detection | disable_malicious_user_detection |
ตัวเลือกระดับ LB อื่นๆ (ทั้งหมดตั้งเป็น disable/default):
disable_rate_limit · no_service_policies · round_robin · disable_waf · no_challenge · disable_bot_defense · disable_api_definition · disable_api_discovery · disable_ip_reputation · disable_malicious_user_detection · single_lb_app · disable_trust_client_ip_headers · user_id_client_ip · disable_threat_mesh · l7_ddos_action_default · system_default_timeouts · default_sensitive_data_policy · disable_malware_protection · disable_api_testing
การจัดการข้อผิดพลาด
หัวข้อที่มีชื่อว่า “การจัดการข้อผิดพลาด”- 401 Unauthorized — API token ไม่ถูกต้องหรือหมดอายุ สร้างใหม่ที่ Administration → Credentials
- 403 Forbidden — token ขาดสิทธิ์สำหรับ namespace ตรวจสอบ role bindings
- 404 Not Found — namespace หรือชื่อออบเจ็กต์ไม่ถูกต้อง แสดงรายการออบเจ็กต์ด้วย
GET /api/config/namespaces/\{namespace\}/\{object_type\} - 409 Conflict — ออบเจ็กต์มีอยู่แล้ว สำหรับ protected domain,
409พร้อม “domain already exists (in uriList)” หมายความว่าโดเมนรากถูกลงทะเบียนแล้วบน tenant — นี่คือเงื่อนไขสำเร็จ ไม่ใช่ข้อผิดพลาด สำหรับออบเจ็กต์อื่น ให้ลบก่อนหรือใช้PUTเพื่ออัปเดต - 422 Unprocessable Entity — การตรวจสอบ JSON schema ล้มเหลว สาเหตุทั่วไป: ขาดตัวเลือก
oneOf, ตั้งหลายตัวเลือกในกลุ่มเดียวกัน, ประเภทฟิลด์ผิด ตรวจสอบข้อความข้อผิดพลาดสำหรับฟิลด์ที่เฉพาะเจาะจง - โควตาออบเจ็กต์หมด (error code
8, ข้อความ"Object kind {kind} has exhausted limits({N})") — tenant ถึงขีดจำกัดโควตาออบเจ็กต์ API คืนค่า HTTP 200 พร้อม JSON error body ที่มี"code": 8ไม่ใช่ HTTP 429 คุณสามารถตรวจสอบความจุโควตาเชิงรุกก่อนพบข้อผิดพลาดนี้โดยใช้ Quota Usage API (GET /api/web/namespaces/system/quota/usage?namespace=system) พฤติกรรมขึ้นอยู่กับประเภทออบเจ็กต์:- Healthcheck (ขีดจำกัด ~150): ไม่บล็อก — ข้ามขั้นตอนที่ 1 ของเฟส 1 และสร้าง origin pool โดยไม่มีการอ้างอิง healthcheck CSD ไม่ต้องพึ่งพาการตรวจสอบสุขภาพ
- Endpoint (ขีดจำกัด ~500): บล็อก — endpoint เป็นออบเจ็กต์ย่อยที่สร้างภายใน origin pool หากถึงขีดจำกัดนี้ การสร้าง origin pool จะล้มเหลว ลบ origin pool ที่ไม่ได้ใช้ (ซึ่งจะปลดปล่อยออบเจ็กต์ย่อย endpoint) หรือติดต่อผู้ดูแลระบบเพื่อเพิ่มขีดจำกัดของ tenant
- Origin pool: บล็อก — ลบ origin pool ที่ไม่ได้ใช้หรือติดต่อผู้ดูแลระบบ
- HTTP load balancer: บล็อก — ลบ load balancer ที่ไม่ได้ใช้หรือติดต่อผู้ดูแลระบบ
- Protected domain: บล็อก — ลบ protected domain ที่ไม่ได้ใช้หรือติดต่อผู้ดูแลระบบ
การแก้ไขปัญหา
หัวข้อที่มีชื่อว่า “การแก้ไขปัญหา”Healthcheck ไม่ได้เชื่อมต่อกับ Origin Pool
หัวข้อที่มีชื่อว่า “Healthcheck ไม่ได้เชื่อมต่อกับ Origin Pool”หากขั้นตอนที่ 2 ของเฟส 1 (ตรวจสอบว่า Healthcheck เชื่อมต่อ) แสดงอาร์เรย์ว่าง []:
- ลบ origin pool:
DELETE /api/config/namespaces/{namespace}/origin_pools/{pool_name} - ตรวจสอบว่า healthcheck มีอยู่:
GET /api/config/namespaces/{namespace}/healthchecks/{hc_name} - สร้าง origin pool ใหม่ด้วยการอ้างอิง healthcheck ที่ถูกต้อง
LB ค้างใน VIRTUAL_HOST_PENDING_A_RECORD
หัวข้อที่มีชื่อว่า “LB ค้างใน VIRTUAL_HOST_PENDING_A_RECORD”หากสถานะ state ของ load balancer ยังคงเป็น VIRTUAL_HOST_PENDING_A_RECORD หลังจากขั้นตอนที่ 4 ของเฟส 1:
-
ตรวจสอบว่ามี DNS zone (F5 XC managed DNS เท่านั้น):
Terminal window curl -s \-H "Authorization: APIToken xF5XC_API_TOKENx" \"xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \| jq '.metadata.name'404หมายความว่า DNS zone ยังไม่ได้ถูกสร้างใน F5 XC -
ตรวจสอบ
allow_http_lb_managed_records— หาก zone มีอยู่แต่ LB กำลังรออยู่ managed records อาจถูกปิดใช้งาน:Terminal window curl -s \-H "Authorization: APIToken xF5XC_API_TOKENx" \"xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \| jq '.spec.primary.allow_http_lb_managed_records'หากเป็น
falseหรือnullให้เปิดใช้งานโดยใช้คำสั่งPUTใน ขั้นตอนที่ 4 ของเฟส 1, ตัวเลือก A -
DNS ภายนอก — หาก F5 XC ไม่ใช่ authoritative ให้สร้าง A record และ ACME CNAME record ด้วยตนเองที่ผู้ให้บริการ DNS ของคุณ (ดู ขั้นตอนที่ 4 ของเฟส 1, ตัวเลือก B)
-
ตรวจสอบการ resolve — หลังจากแก้ไข DNS ให้ยืนยัน:
Terminal window dig +short xF5XC_DOMAINNAMEx Aหาก A record resolve ได้ LB จะเปลี่ยนเป็น
VIRTUAL_HOST_READYตรวจสอบทุก 30 วินาที สูงสุด 4 รอบ (รวม 2 นาที) หากยังคงเป็นVIRTUAL_HOST_PENDING_A_RECORDหลัง 2 นาที ให้ตรวจสอบการเผยแพร่ DNS อีกครั้งและรายงานให้ผู้ดำเนินการ
สถานะ CSD แสดง isConfigured: false
หัวข้อที่มีชื่อว่า “สถานะ CSD แสดง isConfigured: false”CSD ต้องเปิดใช้งานที่ระดับ tenant ติดต่อผู้ดูแลระบบ F5 XC ของคุณเพื่อเปิดใช้งาน Client-Side Defense สำหรับ tenant ของคุณ นี่เป็นการตั้งค่าระดับ tenant ที่ไม่สามารถกำหนดค่าผ่าน API
การฉีด JS ไม่ทำงาน
หัวข้อที่มีชื่อว่า “การฉีด JS ไม่ทำงาน”- ตรวจสอบว่า CSD เปิดใช้งานที่ระดับ tenant (ขั้นตอนที่ 5 ของเฟส 1)
- ยืนยันว่า load balancer มี
client_side_defenseตั้งค่าใน spec - ตรวจสอบว่า JS configuration endpoint คืนค่า
scriptTag - เข้าชม protected domain ในเบราว์เซอร์และดู page source เพื่อยืนยันว่าสคริปต์ถูกฉีด
การลงทะเบียน Protected Domain คืนค่า 409
หัวข้อที่มีชื่อว่า “การลงทะเบียน Protected Domain คืนค่า 409”409 พร้อม “domain already exists (in uriList)” หมายความว่าโดเมนรากถูกลงทะเบียนแล้วบน tenant Protected domain เป็น ขอบเขตระดับ tenant — ไม่ได้เป็นของ namespace ใดโดยเฉพาะ นี่คือเงื่อนไขสำเร็จ: โดเมนได้รับการปกป้องแล้วและไม่จำเป็นต้องดำเนินการเพิ่มเติม ดำเนินการต่อไปขั้นตอนที่ 7 ของเฟส 1
AutoCertDomainRateLimited
หัวข้อที่มีชื่อว่า “AutoCertDomainRateLimited”หาก cert_state ของ HTTPS LB แสดง AutoCertDomainRateLimited หมายความว่า Let’s Encrypt ได้จำกัดอัตราการออกใบรับรองสำหรับโดเมนนี้ นี่ คาดหวังในสภาพแวดล้อมสาธิต ที่มีการสร้างและทำลายโครงสร้างพื้นฐานบ่อยครั้ง
ผลกระทบ: HTTPS LB จะไม่ให้บริการทราฟฟิกจนกว่าขีดจำกัดอัตราจะรีเซ็ต (โดยทั่วไป 1 ชั่วโมง) HTTP LB ไม่ได้รับผลกระทบเลย — ทราฟฟิกสาธิตทั้งหมดดำเนินการตามปกติผ่าน http://
การแก้ไข: ไม่ต้องดำเนินการใดๆ สำหรับความคืบหน้าของการสาธิต HTTP LB (${F5XC_LB_NAME}-http) เป็นเป้าหมายสาธิตหลักและไม่ต้องพึ่งพาการจัดเตรียมใบรับรอง หากต้องการ HTTPS ให้รอจนกว่าขีดจำกัดอัตราจะรีเซ็ตและใบรับรองจะจัดเตรียมอัตโนมัติ
ใบรับรองค้าง — การสร้างใหม่ที่สะอาด (ตัวเลือก)
หัวข้อที่มีชื่อว่า “ใบรับรองค้าง — การสร้างใหม่ที่สะอาด (ตัวเลือก)”เมื่อใบรับรอง HTTPS LB ค้างใน DomainChallengePending หรือ PreDomainChallengePending นานกว่า 15 นาที เส้นทางการกู้คืนที่เร็วที่สุดคือลบ HTTPS LB และสร้างใหม่ ด้วย DNS zone ที่กำหนดค่าแล้ว (เปิดใช้งาน managed records) การสร้างใหม่ที่สะอาดมักจะได้ CertificateValid ใน 5–7 นาที — เว้นแต่จะถูกจำกัดอัตรา
- ลบ HTTPS Load Balancer:
DELETE .../http_loadbalancers/${F5XC_LB_NAME}-https - รอ 30 วินาทีสำหรับการทำความสะอาดแพลตฟอร์ม
- สร้าง HTTPS Load Balancer ใหม่ (ขั้นตอนที่ 3 ของเฟส 1)
- ตรวจสอบสถานะใบรับรอง (ขั้นตอนที่ 7 ของเฟส 1) — คาดหวัง
CertificateValidภายใน 5–10 นาที
การอ้างอิง OpenAPI
หัวข้อที่มีชื่อว่า “การอ้างอิง OpenAPI”ข้อกำหนด API F5 Distributed Cloud อย่างเป็นทางการมีให้ที่:
https://docs.cloud.f5.com/docs-v2/downloads/f5-distributed-cloud-open-api.zip
ZIP นี้มี OpenAPI 3.0 spec สำหรับกลุ่ม API ทั้งหมดรวมถึง ves.io.schema.views.http_loadbalancer, ves.io.schema.healthcheck, ves.io.schema.origin_pool และ ves.io.schema.shape.csd ใช้ spec เหล่านี้เพื่อตรวจสอบ JSON payload และค้นพบฟิลด์เพิ่มเติม