コンテンツにスキップ

デモ

このガイドでは、APIを使用してF5 Distributed Cloud上で完全なクライアントサイド防御の演習を実施する手順を説明します。AIアシスタントまたは人間のオペレーターがエンドツーエンドで実行できる4つのフェーズで構成されています。各ステップには、すぐに実行できるcurlコマンドとプレースホルダー値が含まれており、ページ上部のフォーム、.envファイル、または任意の自動化ツールを使用してカスタマイズできます。

フェーズ目標ステップ
フェーズ1 — ビルド完全なCSDインフラストラクチャのデプロイと検証ステップ1〜7
フェーズ2 — 攻撃シミュレートされた攻撃トラフィックの生成とCSDによる検出の確認ステップ8〜9
フェーズ3 — 緩和緩和前後の証明 — 攻撃実行、緩和適用、攻撃再実行、比較ステップ1〜6
フェーズ4 — ティアダウン明示的な確認後にすべてのデプロイオブジェクトを削除ティアダウン

フェーズ1を開始する前に、環境がクリーンであることを確認してください。これらのAPIチェックを実行して、前回の実行から残存するオブジェクトが存在するかどうかを確認します。

Terminal window
# フェーズ1のすべてのオブジェクトを確認し、環境ステータスを計算する
HTTP_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')
# HTTPS LBが存在する場合、スケルトン状態を検出するためにボディを取得する
HTTPS_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
# 決定論的な環境ステータスを計算する
jq -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にスキップする予定の場合は、フェーズ1 ステップ7の確認コマンドを実行してインフラストラクチャの健全性を確認してからスキップしてください。正確なコマンドはフェーズ1 — ステップ7: 確認を参照してください:

  1. DNS解決: dig +short xF5XC_DOMAINNAMEx A
  2. HTTP LBの状態: GET .../http_loadbalancers/xF5XC_LB_NAMEx-httpjq '{state: .spec.state}'にパイプ — VIRTUAL_HOST_READYと表示される必要があります
  3. CSD JS設定: GET .../js_configurationscriptTagが含まれている必要があります
  4. CSDのステータス: GET .../statusjq '{configured: .isConfigured, enabled: .isEnabled}'にパイプ — 両方がtrueである必要があります

フェーズ2にスキップする前に、必要なすべてのチェック(DNS-1、LB-1、CSD-1、CSD-2)がPASSである必要があります。いずれかのチェックが失敗した場合は、失敗したステップからフェーズ1を実行してください。

上記の事前確認は環境がクリーンであることを確認します。以下の準備状況マトリックスは、環境が準備完了であることを確認します — デモを成功させるために必要なすべての前提条件、クォータ、接続性、およびプラットフォームサービスが整っているかどうかを確認します。準備ステージの一環として、すべてのミーティングの前にこのマトリックスを実行してください。

各チェックには、テストID、ティア(T0〜T5)、PASS/FAIL/WARNの基準、および修復パスがあります。ティアは順次実行されます — 早いティアでのFAILは、後のティアの実行をブロックします。

ティアカテゴリーデモをブロックするか?目的
T0接続とデリバリーおよび認証はいプラットフォームに到達して認証できるか?
T1クォータとキャパシティはい(制限に達している場合)デモオブジェクトを作成する余地があるか?
T2プラットフォームの前提条件はいテナントレベルのサービスが設定されているか?
T3オリジンの健全性警告バックエンドアプリケーションは応答しているか?
T4環境のクリーン状態自動修復前回の実行からの残留オブジェクトがあるか?
T5証明書の準備状況情報提供のみHTTPSは機能するか、それともHTTPのみで計画すべきか?

T0: 接続とデリバリーおよび認証

Section titled “T0: 接続とデリバリーおよび認証”

これらのチェックは、実行ホストがF5 XC APIに到達でき、認証情報が有効であることを確認します。

Terminal window
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
)
}'
Terminal window
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
)
}'
Terminal window
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パーミッションマトリックス

Section titled “PF-T0-4: RBACパーミッションマトリックス”

非破壊的なプローブは、デモが必要とするすべてのオブジェクトタイプの読み取りおよび書き込み権限をテストします。読み取りはリストエンドポイントへのGETによってテストされます。書き込みは既知の存在しないオブジェクトへのDELETEによってテストされます — RBACが操作を拒否した場合はAPIが403を返し、操作は許可されているがオブジェクトが存在しない場合は404を返します。このゼロ副作用のテクニックにより、一時的なプローブオブジェクトの作成を回避できます。

Terminal window
PROBE_NAME="rbac-probe-nonexistent"
# 読み取りプローブ
NS_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")
# 書き込みプローブ(非破壊的: 存在しないオブジェクトへのDELETE/cascade_delete)
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")
# 決定論的なパーミッションマトリックスを計算する
jq -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("; ")
)
}'

これらのチェックは、テナントのクォータ使用量APIに問い合わせて、デモが必要とする各オブジェクト種別の制限、現在の使用量、および残余キャパシティを確認します。これにより、プローブアンドデリートテストが、正確な数値を報告する単一の読み取り専用API呼び出しに置き換えられます。

テナント全体のクォータ使用量エンドポイントにクエリし、デモが必要とするすべてのオブジェクト種別に対して決定論的なPASS/WARN/FAILステータスを計算します。このエンドポイントはsystem名前空間を必要とします。単一のAPI呼び出しで、すべてのプラットフォームレベルのクォータを一度に確認します。

ゲートは、デモが各オブジェクト種別をいくつ消費するか、その種別が必要かどうか、およびデモを続行するために必要な最小数を指定するdemo_needs配列を定義します。jqフィルターはremainingneededと比較し、statusフィールドを決定論的に計算します — オペレーターの解釈は不要です。

Terminal window
# ステップ1: クォータデータを取得する
curl -s \
-H "Authorization: APIToken xF5XC_API_TOKENx" \
"xF5XC_API_URLx/api/web/namespaces/system/quota/usage?namespace=system" \
> /tmp/quota.json
# ステップ2: ゲートステータスを計算する
jq '
. 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 — 少なくとも1つの種別のキャパシティが削減されているが、続行するための最小限は満たされている(例: LBスロットが2つではなく1つしか利用できない、またはヘルスチェッククォータが枯渇している)。デモは制限付きで続行可能。
  • FAIL — 少なくとも1つの必要な種別がremaining < min_proceedである。クォータが解放されるまでデモは続行できない。

出力例(WARN — エンドポイントが上限に達しており、ヘルスチェックがほぼ満杯):

{
"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の値アクション
PASSPF-T1-4(保護ドメインのチェック)に進み、次にT2へ
WARN準備状況レポートに制限を記載し、機能を縮小して続行
FAIL停止 — 枯渇した種別と以下の修復ステップを報告する

種別ごとの修復方法:

種別修復方法
healthcheck未使用のヘルスチェックを削除してキャパシティを解放する。ヘルスチェックなしでデモは続行できる(CSDは正常性監視を必要としない)。
origin_pool未使用のオリジンプールを削除するか、管理者にテナント制限の引き上げを依頼する。
endpoint他の名前空間の未使用オリジンプールを削除してエンドポイントキャパシティを解放する(エンドポイントはオリジンプールのサブオブジェクト)か、管理者に依頼する。
http_loadbalancer未使用のロードバランサーを削除するか、管理者に依頼する。1スロットのみ利用可能な場合、HTTP LB(プライマリ)は作成されるが、HTTPS LB(セカンダリ)はスキップされる。

PF-T1-4: 保護ドメインのクォータ

Section titled “PF-T1-4: 保護ドメインのクォータ”

CSDの保護ドメインはプラットフォームのクォータ使用量APIには表示されません。プローブベースのチェックを使用してください: プローブ保護ドメインを作成してすぐに削除します。

Terminal window
# プローブを作成し、HTTPコードとレスポンスボディの両方を取得する
PROBE_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')
# ステータスを計算する
echo "$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
)
}'
# プローブをクリーンアップする(409が発生した場合は404が予想される)
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

フォールバック: プローブベースのクォータチェック

Section titled “フォールバック: プローブベースのクォータチェック”

PF-T1-0が失敗した場合(クォータ使用量APIが403404、または予期しない形式を返す場合)、ヘルスチェック、オリジンプール、エンドポイント、およびロードバランサーのクォータについてプローブアンドデリートチェックにフォールバックします。これらのチェックは一時的なオブジェクトを作成してすぐに削除します — 作成時にエラーコード8と”exhausted limits”が返された場合、クォータが満杯です。

各フォールバックプローブは同じパターンを使用します: 一時オブジェクトを作成し、レスポンスから決定論的なステータスを計算し、プローブを削除します。オブジェクトが作成された場合(.metadata.nameが存在する)statusPASS、エラーコード8(制限枯渇)の場合は種別が必要かどうかに応じてWARNまたはFAILです。

ヘルスチェックプローブ(枯渇した場合はWARN — ヘルスチェックはCSDではオプション):

Terminal window
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/null

オリジンプールおよびエンドポイントプローブ(枯渇した場合はFAIL — 両方とも必須):

Terminal window
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/null

HTTPロードバランサープローブ(枯渇した場合はFAIL — LBは必須):

Terminal window
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/null

T2: プラットフォームの前提条件

Section titled “T2: プラットフォームの前提条件”

これらのチェックは、デモが依存するテナントレベルのサービスを確認します。

PF-T2-1: CSDテナントのステータス

Section titled “PF-T2-1: CSDテナントのステータス”
Terminal window
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
)
}'
Terminal window
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管理レコードが有効化されているか

Section titled “PF-T2-3: DNS管理レコードが有効化されているか”

PF-T2-2が200を返した場合(F5 XC 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 '{
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)
}'

必要に応じて自動修復する: statusWARNで、かつPF-T2-4がF5 XCネームサーバー(ns1.f5clouddns.comns2.f5clouddns.com)を示している場合は、GET+PUTを使用して管理レコードを自動的に有効化します:

Terminal window
# 現在のゾーン設定を取得する
ZONE_CONFIG=$(curl -s \
-H "Authorization: APIToken xF5XC_API_TOKENx" \
"xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx")
# 管理レコードを有効化して更新する
echo "$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 .

次に再確認して更新が反映されたことを確認します:

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'
結果DNSの権威ステータス修復方法
trueいずれかPASSLB管理のDNSレコードが自動作成される
false/nullF5 XC自動修復GET+PUTで有効化し、確認して結果を報告する
false/null外部情報外部DNSでは管理レコードは適用されない — フェーズ1 ステップ4ではオプションB(手動レコード作成)を使用する
自動修復が失敗F5 XCFAILトークンにシステム名前空間の書き込みアクセスがない可能性がある — テナント管理者に連絡する

PF-T2-4: DNSネームサーバーの権威

Section titled “PF-T2-4: DNSネームサーバーの権威”
Terminal window
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
)
}'

これらのチェックは、バックエンドアプリケーションが到達可能であることを確認します。

スキップ条件のチェック: 接続テストを実行する前に、オリジンIPがRFC 5737 TEST-NETアドレスかどうかを計算します:

Terminal window
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)
}'

statusSKIPの場合、PF-T3-1とPF-T3-2をSKIPとして記録し、T4に移動します。それ以外の場合は、以下のチェックを実行します。

PF-T3-1: オリジンサーバーの接続性

Section titled “PF-T3-1: オリジンサーバーの接続性”
Terminal window
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: オリジンがHTMLコンテンツを提供しているか

Section titled “PF-T3-2: オリジンがHTMLコンテンツを提供しているか”

PF-T3-1が有効なHTTPステータスを返した場合のみ実行してください:

Terminal window
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 contentPASSオリジンはHTMLページを提供している(CSD JSインジェクションに必要)
WARN: No HTML detectedWARNオリジンがAPIのみのサービスまたは非HTMLを返している可能性がある — CSD JSインジェクションにはHTMLページレスポンスが必要

これらのチェックは、前回のデモ実行からの名前付きF5 XC設定オブジェクトが残っていないことを確認します — HTTPロードバランサー、HTTPSロードバランサー、オリジンプール、ヘルスチェック、保護ドメイン、および緩和済みドメイン。T4はオブジェクトレベルのクリーンアップに関するものです: フェーズ1の作成と競合するAPIオブジェクトがまだ存在するかどうか。IPアドレス、ネットワーク接続性、またはオリジンの健全性はテストしません(これらの懸念はT3に属します)。

上記の事前確認セクションから6つの事前確認コマンドを実行します。次のステップを決定するために判断ロジックを適用します。オブジェクトが存在する場合、準備ステージ中に自動ティアダウンが実行されます(確認不要)。

また、以前に中断された事前確認の実行からの古いプローブオブジェクトも確認して削除します。これらのプローブは、クォータ使用量APIが利用できずフォールバックプローブベースのチェックが使用された場合、または常にプローブベースのチェックを使用する保護ドメインプローブ(PF-T1-4)に対してのみ作成されます:

Terminal window
# 古いプローブのクリーンアップ(依存関係がないため任意の順序で削除)
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/null

各DELETEは、オブジェクトが存在した場合は200(空の{})を返し、存在しなかった場合は404を返します — 両方とも予想される動作です。

これらのチェックは、HTTPSが機能するか、またはデモをHTTPのみで計画すべきかを評価します。

デモドメインに対してLet’s Encrypt証明書が最近発行されたかどうかを確認します。頻繁な作成/破棄サイクルは、週次のレート制限(ドメインごとに週5つの重複証明書)を超える可能性があります。

PF-T5-2: 既存のHTTPS LB証明書の状態

Section titled “PF-T5-2: 既存のHTTPS LB証明書の状態”

前回の実行からHTTPS LBが存在する場合のみ実行してください(PF-T4でオブジェクトが見つかった場合):

Terminal window
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接続性 | 200 | PASS |
| PF-T0-2: 名前空間アクセス | 200 | PASS |
| PF-T0-3: CSD APIアクセス | 200 | PASS |
### T1: クォータとキャパシティ
| チェック | 種別 | 制限 | 使用量 | 残余 | 必要数 | ステータス |
|---|---|---|---|---|---|---|
| PF-T1-0: クォータ使用量ゲート | `healthcheck` | 150 | 148 | 2 | 1 | PASS |
| PF-T1-0: クォータ使用量ゲート | `origin_pool` | unlimited | 420 | unlimited | 1 | PASS |
| PF-T1-0: クォータ使用量ゲート | `endpoint` | 500 | 498 | 2 | 1 | PASS |
| PF-T1-0: クォータ使用量ゲート | `http_loadbalancer` | unlimited | 116 | unlimited | 2 | PASS |
| PF-T1-0: クォータ使用量ゲート | **gate** | — | — | — | — | **PASS** |
| PF-T1-4: 保護ドメイン | — | — | — | — | 1 | PASS (probe) |
### T2: プラットフォームの前提条件
| チェック | 結果 | ステータス |
|---|---|---|
| PF-T2-1: CSDテナントステータス | configured + enabled | PASS |
| PF-T2-2: DNSゾーンの存在 | 200 | PASS |
| PF-T2-3: DNS管理レコード | true | PASS |
| PF-T2-4: DNSネームサーバーの権威 | f5clouddns.com | PASS |
### T3: オリジンの健全性
| チェック | 結果 | ステータス |
|---|---|---|
| PF-T3-1: オリジン接続性 | TEST-NETアドレス (192.0.2.1) | SKIP |
| PF-T3-2: HTMLコンテンツ | TEST-NETアドレス | SKIP |
### T4: 環境のクリーン状態
| チェック | 結果 | ステータス |
|---|---|---|
| HTTP LB | 404 | PASS |
| HTTPS LB | 404 | PASS |
| オリジンプール | 404 | PASS |
| ヘルスチェック | 404 | PASS |
| 保護ドメイン | 0 | PASS |
| 緩和済みドメイン | 0 | PASS |
### T5: 証明書の準備状況
| チェック | 結果 | ステータス |
|---|---|---|
| PF-T5-2: 証明書状態 | SKIP (HTTPS LBなし) | INFO |
### 警告
- (WARNまたはINFOのアイテムをコンテキストとともにリストアップ)

総合ステータスのルール:

条件ステータス
T0〜T4のすべてのチェックがPASS準備完了
T0〜T4のすべてのチェックがPASSだが、T3またはT5にWARN/INFOがある警告あり準備完了
T0、T1、またはT2のいずれかのチェックがFAIL準備未完了 — 続行前に解決する
T4に残留オブジェクトがある自動修復(ティアダウン)し、再確認する

AIアシスタントの実行プロトコル

Section titled “AIアシスタントの実行プロトコル”

このセクションでは、API自動化ステップを実行するAIアシスタント(Claude Code、Copilotなど)向けの決定論的なワークフローを定義します。このプロトコルに従うことで、推測が不要になります — すべての判断ポイントには定義された解決パスがあります。

以下の正確な順序で各変数を解決します。プレースホルダー以外の値を提供する最初のソースで停止します:

  1. .envファイルを確認する — リポジトリルートの.envを探します。存在する場合は、すべてのKEY=VALUEペアを解析します。
  2. シェル環境を確認するenv | grep F5XC_を実行して、現在のセッションでエクスポートされた値を見つけます。
  3. 欠落している値を特定する — 解決された値を以下の必須/オプションの表と比較します。値がない、空、またはまだプレースホルダーのデフォルト(例: example-api-tokenexample-tenantexample-namespaceapp.example.comuser@example.com)に設定されている場合は「欠落」とみなします。
  4. 人間のオペレーターに確認を求める — 欠落している必須変数ごとに、オペレーターに値の提供を求めます。すべての必須変数が解決されるまで続行しないでください。
  5. デフォルトを適用する — 欠落しているオプション変数ごとに、プロンプトなしで以下の表からデフォルトを使用します。

空の文字列 = 欠落: 空の値でエクスポートされた変数 (例: F5XC_HC_NAME="")は、未設定の変数と同じように扱われます — デフォルトを適用します。シェルのパラメーター展開 (${F5XC_HC_NAME:-csd-hc})を使用して、一ステップでデフォルトを適用します。

  1. 確認を表示する — 最終的に解決された変数の表をオペレーターに表示し、API呼び出しを実行する前に承認を待ちます。

準備ステージのオーバーライド: ステージ1の準備中は、ステップ6の 待機をスキップします。記録用に解決された変数の表を表示してから、 すぐに進んでください。ステップ1〜5は引き続き適用されます — .envとシェルを確認した後も必須変数が欠落している場合は、 停止して欠落している変数を報告します。

変数必須デフォルトプレースホルダー(欠落として扱う)
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-nameexample-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アシスタントはデモ中に3つのモードのいずれかで動作します:

モードアクティブになる時動作
通常準備、実行、ティアダウン中のデフォルトドキュメント記載のコマンドをそのまま使用
デバッグ失敗時に自動でアクティブになるクリエイティブなトラブルシューティング、ドキュメントの更新
Q&AQ&Aステージ中即興 — アドホックなコマンドを使用して聴衆の質問に回答

通常モード(デフォルト):

  • すべてのAPI呼び出し、確認クエリ、シェルコマンドはフェーズファイル(フェーズ1〜4)または上記の事前確認セクションからそのまま実行する必要があります
  • 解決された変数値でxTOKENxプレースホルダーのみを置換する
  • 一般的な知識や推論からAPIエンドポイント、jqフィルター、cURLコマンドを構築しない
  • 必要なコマンドがドキュメント化されていない場合は、停止してオペレーターに報告する: 「この確認ステップはフェーズのドキュメントでカバーされていません」

デバッグモード(失敗時に自動でアクティブになる):

  • ドキュメント化されたコマンドが予期しない結果を生成した場合に自動的にアクティブになります: 2xx以外のHTTPレスポンス、jqの解析エラー、コマンドのタイムアウト、または証拠テーブルと矛盾するレスポンスボディ
  • デバッグモードでは、AIアシスタントは診断コマンドを構築し、生のAPIレスポンスを検査し、エンドポイントのバリエーションをテストし、根本原因を見つけるためのクリエイティブなトラブルシューティングを使用できます
  • すべてのデバッグ出力の先頭に[DEBUG]を付けて、オペレーターが通常の実行から診断アクティビティを区別できるようにします
  • 学んだことをドキュメント化する: 問題を解決した後、関連するフェーズファイルまたはトラブルシューティングセクションを以下の内容で更新します:
    1. 失敗シナリオ(何が問題だったか)
    2. 試みたが機能しなかったこと(将来の実行で繰り返さないように)
    3. 機能した解決策(問題を解決したコマンドまたは修正)
  • デバッグモードの目標は自身を不要にすることです — すべてのデバッグセッションは、次の実行を完全に決定論的にするドキュメントの更新を生成すべきです
  • ドキュメントが更新されて問題が解決されたら、通常モードに戻り、最後に成功したドキュメント化されたステップから再開します
  • デバッグモードで問題を解決できない場合は、オペレーターに調査結果を報告して停止します — 次のフェーズには続行しません

Q&Aモード(Q&Aステージ中):

  • デモ終了後のQ&Aミーティングステージ中のみアクティブです
  • AIアシスタントはアドホックなAPI呼び出しを構築し、診断コマンドを実行し、スクリプト化されていないページに移動し、聴衆の質問への回答を説明するためにライブデモ環境を変更できます
  • [DEBUG]プレフィックスは付けません — これは意図的な即興の動作であり、エラー回復ではありません
  • 製品に関する質問のナレッジベースとして、DEMO_EXECUTOR.mdのCSD製品専門知識セクションを使用します

initScriptの蓄積はデモ失敗の一般的な原因です。initScriptパラメーターを含む各navigate_page呼び出しは、以降のすべてのドキュメント読み込みで実行される永続的なリストにスクリプトを追加します。以下のルールに従ってください:

  • initScriptを使用した任意のナビゲーションの前に、必ずabout:blankにナビゲートすることで、前回の実行から蓄積されたスクリプトをクリアします
  • デモフェーズを切り替える際(例: フェーズ2 → フェーズ3)はisolatedContext付きのnew_pageを使用して、完全にクリーンなブラウザ状態を確保します
  • 応答しないページからの回復take_screenshotまたはtake_snapshotのタイムアウトが発生した場合、ブラウザコンテキストはリソースが枯渇しています。isolatedContext付きのnew_pageを使用して新鮮なコンテキストを作成し、about:blankナビゲーションステップから再試行します
  • 一時的なオリジン障害とリソース枯渇の回復についての詳細なガイダンスは、フェーズ2の攻撃シミュレーションのアサイドを参照してください

すべてのAPI呼び出し後、AIアシスタントはこの形式を使用して構造化された証拠を人間のオペレーターに提示する必要があります:

作成ステップ(POST):

フィールドステータス
HTTPステータス200PASS
オブジェクト名csd-origin
キープロパティ(jqで抽出)

各作成ステップの後、GETを実行してオブジェクトが存在することを確認し、その主要なプロパティを表示します。GETが404を返した場合は、FAILと報告して停止します。

確認ステップ(GET/dig):

テスト結果ステータス
DNS-1: Aレコード198.51.100.10PASS
LB-1: HTTP LBの状態VIRTUAL_HOST_READYPASS
LB-2: HTTPS LBの状態VIRTUAL_HOST_READYINFO(オプション)
TLS-1: 証明書の状態CertificateValidINFO(オプション)
CSD-1: JSタグscriptTagが存在するPASS

各レイヤーの確認標準として、診断と確認のテストケースID(DNS-1、TLS-1、LB-1、CSD-1など)を参照してください。

フェーズの実行は順次かつゲート制御されています: 各フェーズは次のフェーズが始まる前に、必要なすべてのチェックでPASSに達する必要があります。デモは4段階のミーティングライフサイクルに従います — トリガーフレーズと動作ルールについては、DEMO_EXECUTOR.mdのミーティングステージセクションを参照してください。

AIアシスタントは以下の順序に従います:

  1. 準備 — 変数を解決し、事前確認チェックを実行し、クリーンな環境を確認する(ミーティング前に別途実行可能)
  2. イントロダクション — SEが自己紹介し、成果目標を述べる(クライアントサイドの脅威への可視性、PCIコンプライアンス、リアルタイム検出)
  3. フェーズ1の実行(ステップ1〜7) — インフラストラクチャの作成と確認; すべてのフェーズ1チェックがPASSになるまで次に進まない
  4. フェーズ2の実行(ステップ8〜9) — 攻撃シミュレーションとAPI経由の検出確認; ブラウザ自動化ツールを持つAIアシスタントはブラウザステップを直接実行し、ブラウザツールを持たないオペレーターは手動で実行する
  5. フェーズ3の実行 — 検出されたすべてのドメインに対して緩和を適用し、攻撃を再実行し、ブロッキングが有効であることを確認する
  6. まとめ — 成果目標を再述し、各フェーズからの証拠を要約し、主要な検出と緩和をハイライトする
  7. Q&A — 即興ステージ、デモはライブのまま、SEが聴衆の質問に回答し、返答の質問をする
  8. ティアダウン(ミーティング後) — フェーズ4、明示的なオペレーターの確認が必要、依存関係の逆順でオブジェクトをすべて削除し、クリーンな環境を確認する

いずれかのステップがFAILを返した場合は、続行前に失敗と関連するトラブルシューティングセクションのリンクを報告して停止します。

  • F5 XC APIトークン管理認証情報API認証情報の下で生成する
  • curljqがローカルにインストールされていること
  • ヘルスチェック、オリジンプール、およびHTTPロードバランサーを作成する権限を持つ名前空間

環境値を含む.envファイルを作成します。リポジトリにテンプレートが提供されています:

Terminal window
cp .env.example .env

実際の値で.envを編集します:

.env
# 必須 — お使いの環境
F5XC_API_TOKEN=example-api-token
F5XC_API_URL=https://example-tenant.console.ves.volterra.io
F5XC_DOMAINNAME=app.example.com
F5XC_EMAIL=user@example.com
F5XC_LB_NAME=example-lb-name
F5XC_NAMESPACE=example-namespace
F5XC_ROOT_DOMAIN=example.com
# オプション — 設定されていない場合はJuice Shopデモのデフォルトが使用される
# F5XC_HC_NAME=csd-hc
# F5XC_ORIGIN_IP=44.232.69.192
# F5XC_ORIGIN_POOL=csd-origin
# F5XC_ORIGIN_PORT=3000

ファイルをソースしてシェルセッションに変数を読み込みます:

Terminal window
set -a && source .env && set +a

curlコマンド内の各xTOKENxプレースホルダーは環境変数に直接マッピングされます — 例えば、xF5XC_API_TOKENx$F5XC_API_TOKENに対応します。ページ上部のインタラクティブフォームを使用してこれらの値を置換するか、Claude CodeなどのAIアシスタントに.envを読み込んでコマンドを構築させることができます。

トークンデフォルト説明
xF5XC_API_URLxhttps://example-tenant.console.ves.volterra.ioXC コンソールAPI URL
xF5XC_API_TOKENxexample-api-tokenAPI認証情報トークン
xF5XC_EMAILxuser@example.comCSD通知メールアドレス
xF5XC_NAMESPACExexample-namespace名前空間
xF5XC_LB_NAMExexample-lbHTTPロードバランサーのベース名(${name}-http${name}-httpsを作成)
xF5XC_DOMAINNAMExapp.example.com保護するFQDN
xF5XC_ROOT_DOMAINxexample.comCSD保護ドメインのルートドメイン(eTLD+1)
xF5XC_ORIGIN_POOLxcsd-originオリジンプール名
xF5XC_ORIGIN_IPx44.232.69.192オリジンサーバーIP
xF5XC_ORIGIN_PORTx3000オリジンサーバーポート
xF5XC_HC_NAMExcsd-hcヘルスチェック名

このセクションでは、スクリプトや自動化のための完全な演習ワークフローをまとめます。

  1. リポジトリをクローンして環境テンプレートをコピーする: cp .env.example .env
  2. テナントURL、APIトークン、名前空間、およびドメイン値で.envを編集する
  3. 環境をソースする: set -a && source .env && set +a
  4. 各フェーズを順番に実行し、次のフェーズに進む前に各証拠ブロックでPASSを確認する

値はAIアシスタントの実行プロトコルで定義された決定論的なプロトコルを使用して解決されます:

  1. .envファイル — リポジトリルートからKEY=VALUEペアを解析する
  2. シェル環境 — エクスポートされた値のためにenv | grep F5XC_を確認する
  3. プレースホルダーの検出 — プレースホルダーのデフォルト(例: example-api-tokenexample-namespace)に一致する値を欠落としてフラグを立てる
  4. オペレーターへの確認 — 欠落している各必須変数の値を求める
  5. デフォルトの適用 — 欠落しているオプション変数に組み込みのデフォルトを使用する
  6. 確認 — 解決された変数の表を表示し、オペレーターの承認を待つ
  1. フェーズ1 — ビルド: インフラストラクチャのデプロイ(ヘルスチェック、オリジンプール、HTTP LB + HTTPS LB)、DNSの設定、CSDの有効化、保護ドメインの登録、すべてのコンポーネントの確認。HTTP LBがプライマリデモターゲット; HTTPS LBはオプション。
  2. フェーズ2 — 攻撃: http:// URLを使用してブラウザで攻撃シミュレーションを実行し、5〜10分待ち、API(/scripts/detected_domains/formFields)で検出を確認する
  3. フェーズ3 — 緩和: クリーンなベースラインを確認し、攻撃を実行(前の証明)、各ドメインを/mitigated_domainsにPOSTし、緩和が適用されたことを確認し、http:// URLを使用して攻撃を再実行(後の証明)、前後の比較を提示する
  4. フェーズ4 — ティアダウン (明示的な人間の確認が必要): HTTPS LBを削除 → HTTP LBを削除 → オリジンプールを削除 → DNSゾーンのクリーンアップ(手動レコードのみ)→ ヘルスチェックを削除 → 保護ドメインを削除。DNSゾーンは削除しない
トークン説明デフォルト
xF5XC_API_URLxXC コンソールAPI URLhttps://example-tenant.console.ves.volterra.io
xF5XC_API_TOKENxAPI認証情報トークン(ユーザー提供)
xF5XC_EMAILxCSD通知メールuser@example.com
xF5XC_NAMESPACEx名前空間example-namespace
xF5XC_LB_NAMExHTTPロードバランサーのベース名(${name}-http${name}-httpsを作成)example-lb
xF5XC_DOMAINNAMEx保護するFQDNapp.example.com
xF5XC_ROOT_DOMAINxルートドメイン(eTLD+1)example.com
xF5XC_ORIGIN_POOLxオリジンプール名csd-origin
xF5XC_ORIGIN_IPxオリジンサーバーIP44.232.69.192
xF5XC_ORIGIN_PORTxオリジンサーバーポート3000
xF5XC_HC_NAMExヘルスチェック名csd-hc

HTTPロードバランサーのspecは、グループごとに正確に1つのオプションを設定する必要があるoneOfチョイスグループを使用します。グループ内でゼロまたは複数のオプションを設定すると422エラーが発生します。

CSD関連の主要なチョイス:

チョイスグループオプションCSDのデフォルト
client_side_defense_choiceclient_side_defensedisable_client_side_defenseclient_side_defense
java_script_choice(CSD内にネスト)disable_js_insertjs_insert_all_pagesjs_insert_all_pages_exceptjs_insertion_rulesjs_insert_all_pages

リスナータイプのチョイス(HTTP対HTTPS):

デモは異なるリスナー設定を持つ2つのLBを作成します:

LBリスナーチョイス設定
${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, ... }

httphttps_auto_certキーは相互に排他的です — 各LBは正確に1つを使用します。

HTTPSオートサートのネストされたチョイス(セカンダリLBのみ):

チョイスグループオプションデフォルト
ポートport(数値)443
server_header_choicedefault_headerserver_nameappend_server_namedefault_header
path_normalize_choiceenable_path_normalizedisable_path_normalizeenable_path_normalize
mtls_choiceno_mtlsuse_mtlsno_mtls
default_loadbalancer_choicedefault_loadbalancernon_default_loadbalancerdefault_loadbalancer

single_lb_appのネストされたチョイス(ML設定):

single_lb_appオブジェクトには独自の必須oneOfグループがあります。これらのネストされたチョイスなしにsingle_lb_app: \{\}を設定すると400エラーが発生します。

チョイスグループオプションデフォルト
api_discovery_choicedisable_discoveryenable_discoverydisable_discovery
ddos_detection_choicedisable_ddos_detectionenable_ddos_detectiondisable_ddos_detection
malicious_user_detection_choicedisable_malicious_user_detectionenable_malicious_user_detectiondisable_malicious_user_detection

その他のLBレベルのチョイス(すべて無効/デフォルトに設定):

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トークンが無効または期限切れです。管理認証情報で再生成してください。
  • 403 Forbidden — トークンに名前空間の権限がありません。ロールバインディングを確認してください。
  • 404 Not Found — 名前空間またはオブジェクト名が正しくありません。GET /api/config/namespaces/\{namespace\}/\{object_type\}でオブジェクトをリストしてください。
  • 409 Conflict — オブジェクトがすでに存在します。保護ドメインの場合、「domain already exists (in uriList)」の409はルートドメインがすでにテナントに登録されていることを意味します — これは成功条件であり、エラーではありません。その他のオブジェクトの場合は、最初に削除するかPUTを使用して更新してください。
  • 422 Unprocessable Entity — JSONスキーマの検証に失敗しました。一般的な原因: oneOfチョイスの欠落、同じグループで複数のチョイスが設定されている、フィールドの型が間違っている。特定のフィールドについてはエラーメッセージを確認してください。
  • オブジェクト制限枯渇(エラーコード8、メッセージ"Object kind {kind} has exhausted limits({N})") — テナントがオブジェクトクォータ制限に達しました。APIはHTTP 429ではなく、"code": 8を含むJSONエラーボディを持つHTTP 200を返します。このエラーに遭遇する前に、クォータ使用量APIGET /api/web/namespaces/system/quota/usage?namespace=system)を使用してクォータキャパシティを事前に確認できます。動作はオブジェクトタイプによって異なります:
    • ヘルスチェック(制限約150): 非ブロッキング — フェーズ1 ステップ1をスキップして、ヘルスチェック参照なしでオリジンプールを作成します。CSDは正常性監視に依存しません。
    • エンドポイント(制限約500): ブロッキング — エンドポイントはオリジンプール内に作成されるサブオブジェクトです。この制限に達した場合、オリジンプールの作成が失敗します。他の名前空間の未使用オリジンプールを削除して(エンドポイントサブオブジェクトも解放される)、またはテナント制限の引き上げを管理者に依頼してください。
    • オリジンプール: ブロッキング — 未使用のオリジンプールを削除するか、管理者に依頼してください。
    • HTTPロードバランサー: ブロッキング — 未使用のロードバランサーを削除するか、管理者に依頼してください。
    • 保護ドメイン: ブロッキング — 未使用の保護ドメインを削除するか、管理者に依頼してください。

ヘルスチェックがオリジンプールにリンクされていない

Section titled “ヘルスチェックがオリジンプールにリンクされていない”

フェーズ1 ステップ2(ヘルスチェックのリンクを確認)で空の配列[]が表示される場合:

  1. オリジンプールを削除する: DELETE /api/config/namespaces/{namespace}/origin_pools/{pool_name}
  2. ヘルスチェックが存在することを確認する: GET /api/config/namespaces/{namespace}/healthchecks/{hc_name}
  3. 正しいヘルスチェック参照でオリジンプールを再作成する

LBがVIRTUAL_HOST_PENDING_A_RECORDのままになっている

Section titled “LBがVIRTUAL_HOST_PENDING_A_RECORDのままになっている”

フェーズ1 ステップ4後もロードバランサーのstateVIRTUAL_HOST_PENDING_A_RECORDのままの場合:

  1. DNSゾーンの存在を確認する(F5 XC管理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はF5 XCでDNSゾーンが作成されていないことを意味します。

  2. allow_http_lb_managed_recordsを確認する — ゾーンが存在するがLBが保留中の場合、管理レコードが無効になっている可能性があります:

    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の場合は、フェーズ1 ステップ4、オプションAPUTコマンドを使用して有効化してください。

  3. 外部DNS — F5 XCが権威を持たない場合は、DNSプロバイダーで手動でAレコードとACME CNAMEレコードを作成してください(フェーズ1 ステップ4、オプションBを参照)。

  4. 解決の確認 — DNS修正後、以下を確認します:

    Terminal window
    dig +short xF5XC_DOMAINNAMEx A

    Aレコードが解決されれば、LBはVIRTUAL_HOST_READYに移行します。30秒ごとにポーリングし、最大4回(合計2分)実行します。2分後もまだVIRTUAL_HOST_PENDING_A_RECORDの場合は、DNSの伝播を再確認してオペレーターに報告してください。

CSDのステータスがisConfigured: falseを示している

Section titled “CSDのステータスがisConfigured: falseを示している”

CSDはテナントレベルで有効化する必要があります。テナントのクライアントサイド防御を有効化するには、F5 XC管理者に連絡してください。これはAPIで設定できないテナント全体の設定です。

JSインジェクションが機能していない

Section titled “JSインジェクションが機能していない”
  1. テナントレベルでCSDが有効になっていることを確認する(フェーズ1 ステップ5)
  2. ロードバランサーのspecにclient_side_defenseが設定されていることを確認する
  3. JS設定エンドポイントがscriptTagを返すことを確認する
  4. ブラウザで保護されたドメインにアクセスし、ページソースを表示してスクリプトがインジェクトされていることを確認する

保護ドメインの登録が409を返す

Section titled “保護ドメインの登録が409を返す”

「domain already exists (in uriList)」の409は、ルートドメインがすでにテナントに登録されていることを意味します。保護ドメインはテナントスコープ — 単一の名前空間に属しません。これは成功条件です: ドメインはすでに保護されており、追加のアクションは不要です。フェーズ1 ステップ7に進んでください。

HTTPS LBのcert_stateAutoCertDomainRateLimitedを示している場合、Let’s Encryptがこのドメインの証明書発行のレート制限を設けたことを意味します。これはインフラストラクチャが頻繁に作成および破棄されるデモ環境では予想される動作です。

影響: レート制限がリセットされる(通常1時間)まで、HTTPS LBはトラフィックを提供しません。HTTP LBは完全に影響を受けません — すべてのデモトラフィックはhttp://で正常に続行されます。

解決策: デモの進行には何もアクションは不要です。HTTP LB(${F5XC_LB_NAME}-http)がプライマリデモターゲットであり、証明書のプロビジョニングに依存しません。HTTPSが必要な場合は、レート制限がリセットされるのを待てば証明書が自動的にプロビジョニングされます。

証明書がスタック — クリーンな再作成(オプション)

Section titled “証明書がスタック — クリーンな再作成(オプション)”

HTTPS LBの証明書が15分以上DomainChallengePendingまたはPreDomainChallengePendingでスタックしている場合、最も早い回復パスはHTTPS LBを削除して再作成することです。DNSゾーンがすでに設定されている(管理レコードが有効)状態で、クリーンな再作成は通常5〜7分でCertificateValidを生成します — レート制限がない場合。

  1. HTTPSロードバランサーを削除する: DELETE .../http_loadbalancers/${F5XC_LB_NAME}-https
  2. プラットフォームのクリーンアップのために30秒待つ
  3. HTTPSロードバランサーを再作成する(フェーズ1 ステップ3
  4. 証明書の状態を監視する(フェーズ1 ステップ7)— 5〜10分以内にCertificateValidになることを期待する

F5 Distributed CloudのAPIの標準仕様は以下から入手できます:

https://docs.cloud.f5.com/docs-v2/downloads/f5-distributed-cloud-open-api.zip

このZIPには、ves.io.schema.views.http_loadbalancerves.io.schema.healthcheckves.io.schema.origin_pool、およびves.io.schema.shape.csdを含むすべてのAPIグループのOpenAPI 3.0 specが含まれています。これらのspecを使用してJSONペイロードを検証し、追加フィールドを確認してください。