Salta ai contenuti

Demo

Questa guida illustra un esercizio completo di Difesa lato client su F5 Distributed Cloud tramite API — strutturato in quattro fasi che un assistente IA o un operatore umano può eseguire dall’inizio alla fine. Ogni passaggio include un comando curl pronto all’uso con valori segnaposto personalizzabili tramite il modulo in cima alla pagina, un file .env o qualsiasi strumento di Automazione.

FaseObiettivoPassaggi
Fase 1 — CostruzioneDistribuire e validare l’intera infrastruttura CSDPassaggi 1–7
Fase 2 — AttaccoGenerare traffico di attacco simulato e confermare che il CSD lo abbia rilevatoPassaggi 8–9
Fase 3 — MitigazioneProva prima/dopo la mitigazione — eseguire l’attacco, applicare le mitigazioni, rieseguire l’attacco, confrontarePassaggi 1–6
Fase 4 — SmantellamentoRimuovere tutti gli oggetti di distribuzione dopo conferma esplicitaSmantellamento

Prima di avviare la Fase 1, verificare che l’ambiente sia pulito. Eseguire questi controlli API per determinare se esistono oggetti residui da un’esecuzione precedente:

Terminal window
# Check all Phase 1 objects and compute environment status
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')
# If HTTPS LB exists, fetch body to detect skeleton state
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
# Compute deterministic environment status
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
)
}'

Quando tutti gli oggetti della Fase 1 esistono (200) e si desidera passare direttamente alla Fase 2, eseguire i comandi di verifica del Passaggio 7 della Fase 1 per confermare lo stato dell’infrastruttura prima di saltare. Utilizzare i comandi esatti indicati in Fase 1 — Passaggio 7: Verifica:

  1. Risoluzione DNS: dig +short xF5XC_DOMAINNAMEx A
  2. Stato HTTP LB: GET .../http_loadbalancers/xF5XC_LB_NAMEx-http reindirizzato a jq '{state: .spec.state}' — deve mostrare VIRTUAL_HOST_READY
  3. Configurazione JS CSD: GET .../js_configuration — deve contenere scriptTag
  4. Stato CSD: GET .../status reindirizzato a jq '{configured: .isConfigured, enabled: .isEnabled}' — entrambi devono essere true

Tutti i controlli richiesti (DNS-1, LB-1, CSD-1, CSD-2) devono essere SUPERATI prima di passare alla Fase 2. Se un controllo fallisce, eseguire la Fase 1 a partire dal passaggio non superato.

Il controllo pre-volo sopra indicato verifica che l’ambiente sia pulito. La matrice di prontezza qui sotto verifica che l’ambiente sia operativo — che tutti i prerequisiti, le quote, la connettività e i servizi di piattaforma siano in essere per una demo di successo. Eseguire questa matrice prima di ogni riunione come parte della fase di Preparazione.

Ogni controllo ha un ID test, un livello (T0–T5), criteri SUPERATO/FALLITO/AVVISO e un percorso di rimedio. I livelli sono sequenziali — un FALLITO in un livello precedente blocca l’esecuzione dei livelli successivi.

LivelloCategoriaBlocca la demo?Scopo
T0Connettività e autenticazionePossiamo raggiungere la piattaforma e autenticarci?
T1Quote e capacità (se al limite)C’è spazio per creare oggetti demo?
T2Prerequisiti di PiattaformaI servizi a livello di tenant sono configurati?
T3Stato dell’origineAvvisoL’applicazione backend risponde?
T4Ambiente pulitoAuto-rimedioEsistono oggetti residui da un’esecuzione precedente?
T5Prontezza del certificatoInformativoHTTPS funzionerà, o dovremmo pianificare solo HTTP?

Questi controlli confermano che l’host di esecuzione può raggiungere l’API F5 XC e che le credenziali sono valide.

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

I probe non distruttivi testano le autorizzazioni di lettura e scrittura per ogni tipo di oggetto necessario alla demo. La lettura viene testata tramite GET sugli endpoint di elenco. La scrittura viene testata tramite DELETE su oggetti noti come inesistenti — l’API restituisce 403 se RBAC nega l’operazione, o 404 se l’operazione è consentita ma l’oggetto non esiste. Questa tecnica a zero effetti collaterali evita la creazione di oggetti probe temporanei.

Terminal window
PROBE_NAME="rbac-probe-nonexistent"
# Read probes
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")
# 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 matrix
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("; ")
)
}'

Questi controlli interrogano l’API di utilizzo delle quote del tenant per determinare i limiti, l’utilizzo corrente e la capacità residua per ogni tipo di oggetto necessario alla demo. Questo sostituisce i test probe-e-delete con una singola chiamata API in sola lettura che riporta numeri esatti.

Interrogare l’endpoint di utilizzo delle quote a livello di tenant e calcolare uno stato deterministico SUPERATO/AVVISO/FALLITO per ogni tipo di oggetto necessario alla demo. Questo endpoint richiede il namespace system. Una singola chiamata API verifica tutte le quote a livello di piattaforma contemporaneamente.

Il gate definisce un array demo_needs che specifica quanti oggetti di ciascun tipo verranno consumati dalla demo, se il tipo è obbligatorio e il minimo necessario per procedere. Il filtro jq confronta remaining con needed e calcola il campo status in modo deterministico — nessuna interpretazione da parte dell’operatore richiesta.

Terminal window
# Step 1: Fetch quota data
curl -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 status
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

Output del gate — il campo gate è il verdetto deterministico unico:

  • PASS — tutti i tipi di oggetto hanno remaining >= needed. La demo può procedere.
  • WARN — almeno un tipo ha capacità ridotta ma il minimo per procedere è soddisfatto (ad esempio, disponibile solo 1 slot LB invece di 2, o quota healthcheck esaurita). La demo può procedere con limitazioni.
  • FAIL — almeno un tipo obbligatorio ha remaining < min_proceed. La demo non può procedere finché la quota non viene liberata.

Output di esempio (WARN — endpoint a capacità, healthcheck quasi esaurito):

{
"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"
}
Valore gateAzione
PASSProcedere a PF-T1-4 (controllo dominio protetto), poi T2
WARNAnnotare le limitazioni nel report di prontezza, procedere con capacità ridotta
FAILInterrompere — segnalare quali tipi sono esauriti e i passaggi di rimedio di seguito

Rimedio per tipo:

TipoRimedio
healthcheckEliminare gli healthcheck inutilizzati per liberare capacità. La demo procede senza healthcheck (CSD non richiede il monitoraggio dello stato).
origin_poolEliminare i pool di origine inutilizzati o contattare l’amministratore per aumentare il limite del tenant.
endpointEliminare i pool di origine inutilizzati in altri namespace per liberare la capacità degli endpoint (gli endpoint sono sotto-oggetti dei pool di origine), oppure contattare l’amministratore.
http_loadbalancerEliminare i load balancer inutilizzati o contattare l’amministratore. Se è disponibile solo 1 slot, verrà creato l’HTTP LB (primario) ma l’HTTPS LB (secondario) verrà saltato.

I domini protetti CSD non compaiono nell’API di utilizzo delle quote della piattaforma. Utilizzare un controllo basato su probe: creare e cancellare immediatamente un dominio protetto probe.

Terminal window
# Create probe and capture both HTTP code and response body
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')
# Compute status
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
)
}'
# 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

Se PF-T1-0 fallisce (l’API di utilizzo delle quote restituisce 403, 404 o un formato imprevisto), ricorrere ai controlli probe-e-delete per le quote di healthcheck, pool di origine, endpoint e load balancer. Questi controlli creano un oggetto temporaneo e lo eliminano immediatamente — se la creazione restituisce il codice di errore 8 con “exhausted limits”, la quota è esaurita.

Ogni probe di fallback utilizza lo stesso schema: creare un oggetto temporaneo, calcolare uno stato deterministico dalla risposta, quindi eliminare il probe. Il campo status è PASS se l’oggetto è stato creato (.metadata.name presente), WARN o FAIL se il codice di errore è 8 (limiti esauriti), a seconda che il tipo sia obbligatorio.

Probe healthcheck (AVVISO se esaurito — gli healthcheck sono facoltativi per 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

Probe pool di origine & endpoint (FALLIMENTO se esaurito — entrambi sono obbligatori):

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

Probe HTTP load balancer (FALLIMENTO se esaurito — gli LB sono obbligatori):

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

Questi controlli verificano i servizi a livello di tenant da cui dipende la demo.

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

Eseguire solo se PF-T2-2 ha restituito 200 (zona DNS F5 XC esistente).

Verificare lo stato corrente:

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

Auto-rimedio se necessario: Se lo status è WARN E PF-T2-4 mostra i nameserver F5 XC (ns1.f5clouddns.com, ns2.f5clouddns.com), abilitare automaticamente i record gestiti tramite GET+PUT:

Terminal window
# Get current zone config
ZONE_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 enabled
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 .

Quindi ri-verificare per confermare che l’aggiornamento sia stato applicato:

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'
RisultatoAutorità DNSStatoRimedio
trueQualsiasiSUPERATOI record DNS gestiti dall’LB verranno creati automaticamente
false/nullF5 XCAuto-rimedioAbilitare tramite GET+PUT, verificare, segnalare il risultato
false/nullEsternoINFOI record gestiti non sono applicabili per DNS esterno — la Fase 1 Passaggio 4 utilizzerà l’Opzione B (creazione manuale dei record)
Auto-rimedio fallitoF5 XCFALLIMENTOIl token potrebbe non avere accesso in scrittura al namespace di sistema — contattare l’amministratore del tenant
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
)
}'

Questi controlli verificano che l’applicazione backend sia raggiungibile.

Controllo della condizione di salto: Calcolare se l’IP di origine è un indirizzo TEST-NET RFC 5737 prima di eseguire i test di connettività:

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

Se status è SKIP, registrare PF-T3-1 e PF-T3-2 come SKIP e passare a T4. In caso contrario, eseguire i controlli seguenti.

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

Eseguire solo se PF-T3-1 ha restituito un codice di stato HTTP valido:

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"
RisultatoStatoRimedio
PASS: HTML contentSUPERATOL’origine serve pagine HTML (necessario per l’iniezione JS CSD)
WARN: No HTML detectedAVVISOL’origine potrebbe essere un servizio solo API o restituire contenuto non HTML — l’iniezione JS CSD richiede risposte di pagine HTML

Questi controlli verificano che non rimangano oggetti di configurazione F5 XC denominati da un’esecuzione demo precedente — HTTP load balancer, HTTPS load balancer, pool di origine, healthcheck, domini protetti e domini mitigati. T4 riguarda la pulizia a livello di oggetti: se gli oggetti API che potrebbero entrare in conflitto con la creazione della Fase 1 esistono ancora. Non testa indirizzi IP, connettività di rete o stato dell’origine (questi aspetti appartengono a T3).

Eseguire i sei comandi di pre-volo dalla sezione Controllo pre-volo sopra. Applicare la Logica decisionale per determinare i passaggi successivi. Se esistono oggetti, lo smantellamento automatico viene eseguito durante la fase di Preparazione (nessuna conferma necessaria).

Verificare e rimuovere anche eventuali oggetti probe non aggiornati da esecuzioni di pre-volo interrotte in precedenza. Questi probe vengono creati solo quando l’API di utilizzo delle quote non è disponibile e sono stati utilizzati i controlli basati su probe di fallback, oppure per il probe del dominio protetto (PF-T1-4) che utilizza sempre il controllo basato su probe:

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

Ogni DELETE restituisce 200 (vuoto {}) se l’oggetto esisteva, o 404 se non esisteva — entrambi sono previsti.

Questi controlli valutano se HTTPS funzionerà o se la demo deve essere pianificata solo per HTTP.

PF-T5-1: Cronologia recente delle emissioni di certificati

Sezione intitolata “PF-T5-1: Cronologia recente delle emissioni di certificati”

Verificare se un certificato Let’s Encrypt è stato emesso di recente per il dominio demo. I frequenti cicli di creazione/distruzione possono esaurire il limite settimanale (5 certificati duplicati per settimana per dominio).

Eseguire solo se un HTTPS LB esiste da un’esecuzione precedente (PF-T4 ha trovato oggetti):

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

Dopo aver eseguito tutti i livelli, presentare un report di prontezza consolidato:

## Demo Readiness: READY / NOT READY / READY WITH WARNINGS
### T0: Connectivity & Auth
| Check | Result | Status |
|---|---|---|
| PF-T0-1: API Connectivity | 200 | PASS |
| PF-T0-2: Namespace Access | 200 | PASS |
| PF-T0-3: CSD API Access | 200 | PASS |
### T1: Quotas & Capacity
| Check | Kind | Limit | Usage | Remaining | Needed | Status |
|---|---|---|---|---|---|---|
| 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: Platform Prerequisites
| Check | Result | Status |
|---|---|---|
| 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 Health
| Check | Result | Status |
|---|---|---|
| PF-T3-1: Origin Connectivity | TEST-NET address (192.0.2.1) | SKIP |
| PF-T3-2: HTML Content | TEST-NET address | SKIP |
### T4: Environment Clean
| Check | Result | Status |
|---|---|---|
| HTTP LB | 404 | PASS |
| HTTPS LB | 404 | PASS |
| Origin Pool | 404 | PASS |
| Healthcheck | 404 | PASS |
| Protected Domains | 0 | PASS |
| Mitigated Domains | 0 | PASS |
### T5: Certificate Readiness
| Check | Result | Status |
|---|---|---|
| PF-T5-2: Cert State | SKIP (no HTTPS LB) | INFO |
### Warnings
- (elencare eventuali elementi WARN o INFO con contesto)

Regole di stato complessivo:

CondizioneStato
Tutti i controlli T0–T4 SUPERATIPRONTO
Tutti i controlli T0–T4 SUPERATI ma T3 o T5 hanno AVVISO/INFOPRONTO CON AVVISI
Qualsiasi controllo T0, T1 o T2 è FALLITONON PRONTO — risolvere prima di procedere
T4 ha oggetti residuiAuto-rimedio (smantellamento), poi ri-verificare

Questa sezione definisce un flusso di lavoro deterministico per gli assistenti IA (Claude Code, Copilot, ecc.) che eseguono i passaggi di Automazione API. Seguire questo protocollo elimina le incertezze — ogni punto decisionale ha un percorso di risoluzione definito.

Risolvere ogni variabile in quest’ordine esatto. Fermarsi alla prima fonte che fornisce un valore non segnaposto:

  1. Verificare il file .env — cercare .env nella radice del repository. Se esiste, analizzare tutte le coppie KEY=VALUE.
  2. Verificare l’ambiente shell — eseguire env | grep F5XC_ per trovare i valori già esportati nella sessione corrente.
  3. Identificare i valori mancanti — confrontare i valori risolti con la tabella obbligatori/facoltativi di seguito. Un valore è “mancante” se è assente, vuoto o ancora impostato su un valore segnaposto predefinito (ad esempio, example-api-token, example-tenant, example-namespace, app.example.com, user@example.com).
  4. Chiedere all’operatore umano — per ogni variabile obbligatoria mancante, chiedere all’operatore di fornire il valore. Non procedere finché tutte le variabili obbligatorie non sono risolte.
  5. Applicare i valori predefiniti — per ogni variabile facoltativa mancante, utilizzare il valore predefinito dalla tabella di seguito senza chiedere conferma.

Stringa vuota = mancante: Una variabile esportata con un valore vuoto (ad esempio, F5XC_HC_NAME="") viene trattata come una variabile non impostata — applicare il valore predefinito. Utilizzare l’espansione dei parametri shell (${F5XC_HC_NAME:-csd-hc}) per applicare i valori predefiniti in un solo passaggio.

  1. Visualizzare la conferma — mostrare la tabella delle variabili risolte finale all’operatore e attendere l’approvazione prima di eseguire qualsiasi chiamata API.

Override della fase di preparazione: Durante la Fase di Preparazione 1, saltare l’attesa al punto 6. Visualizzare la tabella delle variabili risolte per il registro, poi procedere immediatamente. I punti 1–5 si applicano ancora — se qualsiasi variabile obbligatoria è mancante dopo aver verificato .env e shell, interrompere e segnalare le variabili mancanti.

VariabileObbligatoriaPredefinitoSegnaposto (trattare come mancante)
F5XC_API_TOKENexample-api-token
F5XC_API_URLhttps://example-tenant.console.ves.volterra.io
F5XC_NAMESPACEexample-namespace
F5XC_DOMAINNAMEapp.example.com
F5XC_ROOT_DOMAINexample.com
F5XC_LB_NAMEexample-lb-name, example-lb
F5XC_EMAILuser@example.com
F5XC_HC_NAMEFacoltativacsd-hc
F5XC_ORIGIN_IPFacoltativa44.232.69.192
F5XC_ORIGIN_POOLFacoltativacsd-origin
F5XC_ORIGIN_PORTFacoltativa3000

L’assistente IA opera in una delle tre modalità durante la demo:

ModalitàQuando attivaComportamento
NormalePredefinita durante Preparazione, Esecuzione, SmantellamentoSolo comandi documentati verbatim
DebugSi attiva automaticamente in caso di erroreRisoluzione dei problemi creativa, aggiornamento documentazione
Domande e risposteDurante la fase di domande e risposteImprovvisazione — comandi ad hoc consentiti per rispondere alle domande del pubblico

Modalità normale (predefinita):

  • Ogni chiamata API, query di verifica e comando shell deve provenire verbatim dai file di fase (Fasi 1–4) o dalla sezione Controllo pre-volo sopra
  • Sostituire solo i segnaposto xTOKENx con i valori delle variabili risolte
  • Non costruire endpoint API, filtri jq o comandi cURL dalla conoscenza generale o per inferenza
  • Se un comando necessario non è documentato, interrompere e segnalare all’operatore: “Questo passaggio di verifica non è coperto dalla documentazione delle fasi”

Modalità debug (si attiva automaticamente in caso di errore):

  • Si attiva automaticamente quando un comando documentato produce un risultato inatteso: risposta HTTP non-2xx, errore di analisi jq, timeout del comando o corpo della risposta che contraddice la tabella delle evidenze
  • In modalità debug, l’assistente IA può costruire comandi diagnostici, ispezionare le risposte API grezze, testare varianti degli endpoint e utilizzare la risoluzione dei problemi creativa per trovare la causa principale
  • Prefissare tutti gli output di debug con [DEBUG] in modo che l’operatore possa distinguere l’attività diagnostica dall’esecuzione normale
  • Documentare quanto appreso: dopo aver risolto un problema, aggiornare il file di fase pertinente o la sezione di risoluzione dei problemi con:
    1. Lo scenario di errore (cosa è andato storto)
    2. Cosa è stato provato e NON ha funzionato (per non ripetere i tentativi nelle esecuzioni future)
    3. La risoluzione funzionante (il comando o la correzione che ha risolto il problema)
  • L’obiettivo della modalità debug è eliminarsi da sola — ogni sessione di debug dovrebbe produrre un aggiornamento della documentazione che renda la prossima esecuzione completamente deterministica
  • Una volta che la documentazione è aggiornata e il problema è risolto, tornare alla modalità normale e riprendere dall’ultimo passaggio documentato completato con successo
  • Se la modalità debug non riesce a risolvere il problema, segnalare i risultati all’operatore e interrompere — non continuare con la fase successiva

Modalità domande e risposte (durante la fase di domande e risposte):

  • Attiva solo durante la fase di domande e risposte della riunione, dopo la conclusione della demo
  • L’assistente IA può costruire chiamate API ad hoc, eseguire comandi diagnostici, navigare verso pagine non pianificate e modificare l’ambiente demo live per illustrare le risposte alle domande del pubblico
  • Nessun prefisso [DEBUG] — si tratta di comportamento improvvisativo intenzionale, non di recupero da errori
  • Utilizza la sezione Competenza sul prodotto CSD in DEMO_EXECUTOR.md come base di conoscenza per le domande sui prodotti

L’accumulo di initScript è una fonte comune di errori nella demo. Ogni chiamata navigate_page con un parametro initScript aggiunge lo script a un elenco persistente che viene eseguito ad ogni successivo caricamento del documento. Seguire queste regole:

  • Navigare sempre su about:blank prima di qualsiasi navigazione con initScript per cancellare gli script accumulati dalle esecuzioni precedenti
  • Utilizzare new_page con isolatedContext quando si passa tra fasi demo (ad esempio, Fase 2 → Fase 3) per garantire uno stato del browser completamente pulito
  • Recupero da pagine non responsive — se si verificano timeout di take_screenshot o take_snapshot, il contesto del browser è a corto di risorse. Utilizzare new_page con isolatedContext per creare un contesto nuovo, quindi riprovare dal passaggio di navigazione about:blank
  • Consultare le note della simulazione di attacco della Fase 2 per una guida dettagliata sugli errori transitori dell’origine e il recupero dall’esaurimento delle risorse

Dopo ogni chiamata API, l’assistente IA deve presentare evidenze strutturate all’operatore umano utilizzando questo formato:

Passaggi di creazione (POST):

CampoValoreStato
Stato HTTP200SUPERATO
Nome oggettocsd-origin
Proprietà chiave(estratta tramite jq)

Dopo ogni passaggio di creazione, eseguire un GET per confermare che l’oggetto esiste e visualizzarne le proprietà chiave. Se il GET restituisce 404, segnalare FALLIMENTO e interrompere.

Passaggi di verifica (GET/dig):

TestRisultatoStato
DNS-1: Record A198.51.100.10SUPERATO
LB-1: Stato HTTP LBVIRTUAL_HOST_READYSUPERATO
LB-2: Stato HTTPS LBVIRTUAL_HOST_READYINFO (facoltativo)
TLS-1: Stato certificatoCertificateValidINFO (facoltativo)
CSD-1: Tag JSscriptTag presenteSUPERATO

Fare riferimento agli ID dei casi di test Diagnostica e verifica (DNS-1, TLS-1, LB-1, CSD-1, ecc.) come standard di verifica per ogni livello.

L’esecuzione delle fasi è sequenziale e condizionata: ogni fase deve raggiungere SUPERATO su tutti i controlli obbligatori prima che inizi la fase successiva. La demo segue un ciclo di vita della riunione in quattro fasi — vedere la sezione Fasi della riunione in DEMO_EXECUTOR.md per le frasi trigger e le regole di comportamento.

L’assistente IA segue questa sequenza:

  1. Preparazione — risolvere le variabili, eseguire i controlli pre-volo, confermare l’ambiente pulito (può essere eseguita separatamente prima della riunione)
  2. Introduzione — il SE si presenta e dichiara gli obiettivi del risultato (visibilità sulle minacce lato client, conformità PCI, rilevamento in tempo reale)
  3. Esecuzione della Fase 1 (Passaggi 1–7) — creazione dell’infrastruttura e verifica; tutti i controlli della Fase 1 devono essere SUPERATI prima di procedere
  4. Esecuzione della Fase 2 (Passaggi 8–9) — simulazione dell’attacco e verifica del rilevamento tramite API; gli assistenti IA con Automazione del browser eseguono i passaggi del browser direttamente, gli operatori senza strumenti browser li eseguono manualmente
  5. Esecuzione della Fase 3 — applicare la mitigazione per tutti i domini rilevati, rieseguire l’attacco, verificare che il blocco sia efficace
  6. Conclusione — ribadire gli obiettivi del risultato, riassumere le evidenze di ogni fase, evidenziare i rilevamenti e le mitigazioni chiave
  7. Domande e risposte — fase improvvisativa, la demo rimane attiva, il SE risponde alle domande del pubblico e pone domande di ritorno
  8. Smantellamento (post-riunione) — Fase 4, conferma esplicita dell’operatore richiesta, eliminare tutti gli oggetti in ordine inverso di dipendenza, confermare l’ambiente pulito

Se un passaggio restituisce FALLIMENTO, interrompere e segnalare l’errore con il link alla sezione di risoluzione dei problemi pertinente prima di continuare.

  • Un token API F5 XC — generarne uno sotto AmministrazioneCredenzialiCredenziali API
  • curl e jq installati localmente
  • Un namespace con le autorizzazioni per creare healthcheck, pool di origine e HTTP load balancer

Creare un file .env con i valori dell’ambiente. Nel repository è disponibile un template:

Terminal window
cp .env.example .env

Modificare .env con i valori effettivi:

.env
# Required — your environment
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
# 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=3000

Importare il file per caricare le variabili nella sessione shell:

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

Ogni segnaposto xTOKENx nei comandi curl corrisponde direttamente a una variabile d’ambiente — ad esempio, xF5XC_API_TOKENx corrisponde a $F5XC_API_TOKEN. È possibile sostituire questi valori utilizzando il modulo interattivo in cima alla pagina, oppure lasciare che un assistente IA come Claude Code legga il .env e costruisca i comandi.

TokenPredefinitoDescrizione
xF5XC_API_URLxhttps://example-tenant.console.ves.volterra.ioURL API della console XC
xF5XC_API_TOKENxexample-api-tokenToken delle credenziali API
xF5XC_EMAILxuser@example.comIndirizzo email per le notifiche CSD
xF5XC_NAMESPACExexample-namespaceNamespace
xF5XC_LB_NAMExexample-lbNome base dell’HTTP Load Balancer (crea ${name}-http e ${name}-https)
xF5XC_DOMAINNAMExapp.example.comFQDN da proteggere
xF5XC_ROOT_DOMAINxexample.comDominio radice (eTLD+1) per il dominio protetto CSD
xF5XC_ORIGIN_POOLxcsd-originNome del pool di origine
xF5XC_ORIGIN_IPx44.232.69.192IP del server di origine
xF5XC_ORIGIN_PORTx3000Porta del server di origine
xF5XC_HC_NAMExcsd-hcNome dell’healthcheck

Questa sezione riassume il flusso di lavoro completo dell’esercizio per lo scripting o l’Automazione.

  1. Clonare il repository e copiare il template dell’ambiente: cp .env.example .env
  2. Modificare .env con l’URL del tenant, il token API, il namespace e i valori del dominio
  3. Importare l’ambiente: set -a && source .env && set +a
  4. Eseguire ogni fase in ordine, verificando SUPERATO ad ogni blocco di evidenze prima di procedere alla fase successiva

I valori vengono risolti utilizzando il protocollo deterministico definito nel Protocollo di esecuzione per assistente IA:

  1. File .env — analizzare le coppie KEY=VALUE dalla radice del repository
  2. Ambiente shell — verificare env | grep F5XC_ per i valori esportati
  3. Rilevamento segnaposto — contrassegnare come mancante qualsiasi valore corrispondente a un segnaposto predefinito (ad esempio, example-api-token, example-namespace)
  4. Chiedere all’operatore — richiedere ogni variabile obbligatoria mancante
  5. Applicare i valori predefiniti — utilizzare i valori predefiniti integrati per le variabili facoltative mancanti
  6. Confermare — visualizzare la tabella delle variabili risolte e attendere l’approvazione dell’operatore
  1. Fase 1 — Costruzione: Distribuire l’infrastruttura (healthcheck, pool di origine, HTTP LB + HTTPS LB), configurare il DNS, abilitare CSD, registrare il dominio protetto, verificare tutti i componenti. L’HTTP LB è il target demo principale; l’HTTPS LB è facoltativo.
  2. Fase 2 — Attacco: Eseguire la simulazione dell’attacco in un browser utilizzando URL http://, attendere 5–10 minuti, verificare i rilevamenti tramite API (/scripts, /detected_domains, /formFields)
  3. Fase 3 — Mitigazione: Confermare la baseline pulita, eseguire l’attacco (prova preliminare), fare POST di ogni dominio su /mitigated_domains, verificare le mitigazioni applicate, rieseguire l’attacco utilizzando URL http:// (prova successiva), presentare il confronto prima/dopo
  4. Fase 4 — Smantellamento (richiede conferma esplicita da parte dell’operatore): Eliminare HTTPS LB → HTTP LB → pool di origine → pulizia zona DNS (solo record manuali) → healthcheck → dominio protetto. Non eliminare la zona DNS.
TokenDescrizionePredefinito
xF5XC_API_URLxURL API della console XChttps://example-tenant.console.ves.volterra.io
xF5XC_API_TOKENxToken delle credenziali API(fornito dall’utente)
xF5XC_EMAILxEmail per le notifiche CSDuser@example.com
xF5XC_NAMESPACExNamespaceexample-namespace
xF5XC_LB_NAMExNome base dell’HTTP Load Balancer (crea ${name}-http e ${name}-https)example-lb
xF5XC_DOMAINNAMExFQDN da proteggereapp.example.com
xF5XC_ROOT_DOMAINxDominio radice (eTLD+1)example.com
xF5XC_ORIGIN_POOLxNome del pool di originecsd-origin
xF5XC_ORIGIN_IPxIP del server di origine44.232.69.192
xF5XC_ORIGIN_PORTxPorta del server di origine3000
xF5XC_HC_NAMExNome dell’healthcheckcsd-hc

La specifica dell’HTTP Load Balancer utilizza gruppi di scelte oneOf dove esattamente un’opzione deve essere impostata per gruppo. L’impostazione di zero o più di un’opzione in un gruppo causa un errore 422.

Scelte chiave relative a CSD:

Gruppo di scelteOpzioniPredefinito CSD
client_side_defense_choiceclient_side_defense, disable_client_side_defenseclient_side_defense
java_script_choice (annidato in CSD)disable_js_insert, js_insert_all_pages, js_insert_all_pages_except, js_insertion_rulesjs_insert_all_pages

Scelta del tipo di listener (HTTP vs HTTPS):

La demo crea due LB con configurazioni di listener diverse:

LBScelta listenerConfigurazione
${F5XC_LB_NAME}-http (primario)http"http": { "dns_volterra_managed": true, "port": 80 }
${F5XC_LB_NAME}-https (secondario)https_auto_cert"https_auto_cert": { "http_redirect": true, "port": 443, ... }

Le chiavi http e https_auto_cert si escludono a vicenda — ogni LB ne utilizza esattamente una.

Scelte annidate auto-cert HTTPS (solo LB secondario):

Gruppo di scelteOpzioniPredefinito
portaport (numero)443
server_header_choicedefault_header, server_name, append_server_namedefault_header
path_normalize_choiceenable_path_normalize, disable_path_normalizeenable_path_normalize
mtls_choiceno_mtls, use_mtlsno_mtls
default_loadbalancer_choicedefault_loadbalancer, non_default_loadbalancerdefault_loadbalancer

Scelte annidate single_lb_app (configurazione ML):

L’oggetto single_lb_app ha i propri gruppi oneOf obbligatori. Impostare single_lb_app: \{\} senza queste scelte annidate causa un errore 400.

Gruppo di scelteOpzioniPredefinito
api_discovery_choicedisable_discovery, enable_discoverydisable_discovery
ddos_detection_choicedisable_ddos_detection, enable_ddos_detectiondisable_ddos_detection
malicious_user_detection_choicedisable_malicious_user_detection, enable_malicious_user_detectiondisable_malicious_user_detection

Altre scelte a livello LB (tutte impostate su disabilita/predefinito):

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 — Il token API non è valido o è scaduto. Rigenerarlo sotto AmministrazioneCredenziali.
  • 403 Forbidden — Il token non dispone delle autorizzazioni per il namespace. Verificare i binding dei ruoli.
  • 404 Not Found — Il namespace o il nome dell’oggetto non è corretto. Elencare gli oggetti con GET /api/config/namespaces/\{namespace\}/\{object_type\}.
  • 409 Conflict — L’oggetto esiste già. Per i domini protetti, un 409 con “domain already exists (in uriList)” significa che il dominio radice è già registrato nel tenant — questa è una condizione di successo, non un errore. Per altri oggetti, eliminare prima o utilizzare PUT per aggiornare.
  • 422 Unprocessable Entity — Validazione dello schema JSON fallita. Cause comuni: scelta oneOf mancante, più scelte impostate nello stesso gruppo, tipo di campo errato. Verificare il messaggio di errore per il campo specifico.
  • Limite oggetti esaurito (codice errore 8, messaggio "Object kind {kind} has exhausted limits({N})") — Il tenant ha raggiunto un limite di quota degli oggetti. L’API restituisce HTTP 200 con un corpo JSON di errore contenente "code": 8, non HTTP 429. È possibile verificare proattivamente la capacità della quota prima di incontrare questo errore utilizzando l’API di utilizzo delle quote (GET /api/web/namespaces/system/quota/usage?namespace=system). Il comportamento dipende dal tipo di oggetto:
    • Healthcheck (limite ~150): Non bloccante — saltare il Passaggio 1 della Fase 1 e creare il pool di origine senza riferimento all’healthcheck. CSD non dipende dal monitoraggio dello stato.
    • Endpoint (limite ~500): Bloccante — gli endpoint sono sotto-oggetti creati all’interno dei pool di origine. Se questo limite viene raggiunto, la creazione del pool di origine fallisce. Eliminare i pool di origine inutilizzati (che libera i loro sotto-oggetti endpoint) o contattare l’amministratore per aumentare il limite del tenant.
    • Pool di origine: Bloccante — eliminare i pool di origine inutilizzati o contattare l’amministratore.
    • HTTP load balancer: Bloccante — eliminare i load balancer inutilizzati o contattare l’amministratore.
    • Dominio protetto: Bloccante — eliminare i domini protetti inutilizzati o contattare l’amministratore.

Se il Passaggio 2 della Fase 1 (Verifica healthcheck collegato) mostra un array vuoto []:

  1. Eliminare il pool di origine: DELETE /api/config/namespaces/{namespace}/origin_pools/{pool_name}
  2. Verificare che l’healthcheck esista: GET /api/config/namespaces/{namespace}/healthchecks/{hc_name}
  3. Ricreare il pool di origine con il riferimento corretto all’healthcheck

Se lo state del load balancer rimane VIRTUAL_HOST_PENDING_A_RECORD dopo il Passaggio 4 della Fase 1:

  1. Verificare che la zona DNS esista (solo DNS gestito da F5 XC):

    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'

    Un 404 significa che la zona DNS non è stata creata in F5 XC.

  2. Verificare allow_http_lb_managed_records — se la zona esiste ma l’LB è in attesa, i record gestiti potrebbero essere disabilitati:

    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'

    Se false o null, abilitarlo utilizzando il comando PUT nella Fase 1 Passaggio 4, Opzione A.

  3. DNS esterno — se F5 XC non è autorevole, creare manualmente i record A e ACME CNAME presso il provider DNS (vedere Fase 1 Passaggio 4, Opzione B).

  4. Verificare la risoluzione — dopo aver corretto il DNS, confermare:

    Terminal window
    dig +short xF5XC_DOMAINNAMEx A

    Se il record A si risolve, l’LB passa a VIRTUAL_HOST_READY. Interrogare ogni 30 secondi, fino a 4 iterazioni (2 minuti totali). Se ancora VIRTUAL_HOST_PENDING_A_RECORD dopo 2 minuti, ri-verificare la propagazione DNS e segnalare all’operatore.

CSD deve essere abilitato a livello di tenant. Contattare l’amministratore F5 XC per abilitare la Difesa lato client per il tenant. Si tratta di un’impostazione a livello di tenant che non può essere configurata tramite API.

  1. Verificare che CSD sia abilitato a livello di tenant (Fase 1 Passaggio 5)
  2. Confermare che il load balancer abbia client_side_defense impostato nella specifica
  3. Verificare che l’endpoint di configurazione JS restituisca un scriptTag
  4. Visitare il dominio protetto in un browser e visualizzare il sorgente della pagina per confermare che lo script sia iniettato

La registrazione del dominio protetto restituisce 409

Sezione intitolata “La registrazione del dominio protetto restituisce 409”

Un 409 con “domain already exists (in uriList)” significa che il dominio radice è già registrato nel tenant. I domini protetti hanno scope a livello di tenant — non appartengono a nessun singolo namespace. Si tratta di una condizione di successo: il dominio è già protetto e non è necessaria alcuna ulteriore azione. Continuare con il Passaggio 7 della Fase 1.

Se l’cert_state dell’HTTPS LB mostra AutoCertDomainRateLimited, significa che Let’s Encrypt ha limitato la frequenza di emissione dei certificati per questo dominio. Questo è previsto negli ambienti demo dove l’infrastruttura viene frequentemente creata e distrutta.

Impatto: L’HTTPS LB non servirà traffico finché il limite di frequenza non viene ripristinato (tipicamente 1 ora). L’HTTP LB è completamente non influenzato — tutto il traffico demo procede normalmente tramite http://.

Risoluzione: Nessuna azione necessaria per la progressione della demo. L’HTTP LB (${F5XC_LB_NAME}-http) è il target demo principale e non dipende dal provisioning del certificato. Se HTTPS è desiderato, attendere il ripristino del limite di frequenza e il certificato verrà provisioned automaticamente.

Certificato bloccato — Ricreazione pulita (facoltativa)

Sezione intitolata “Certificato bloccato — Ricreazione pulita (facoltativa)”

Quando il certificato dell’HTTPS LB è bloccato in DomainChallengePending o PreDomainChallengePending per più di 15 minuti, il percorso di recupero più rapido è eliminare l’HTTPS LB e ricrearlo. Con la zona DNS già configurata (record gestiti abilitati), la ricreazione pulita produce tipicamente CertificateValid in 5–7 minuti — a meno che non sia limitata dalla frequenza.

  1. Eliminare l’HTTPS Load Balancer: DELETE .../http_loadbalancers/${F5XC_LB_NAME}-https
  2. Attendere 30 secondi per la pulizia della piattaforma
  3. Ricreare l’HTTPS Load Balancer (Fase 1 Passaggio 3)
  4. Monitorare lo stato del certificato (Fase 1 Passaggio 7) — aspettarsi CertificateValid entro 5–10 minuti

La specifica API canonica di F5 Distributed Cloud è disponibile all’indirizzo:

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

Questo ZIP contiene le specifiche OpenAPI 3.0 per tutti i gruppi API inclusi ves.io.schema.views.http_loadbalancer, ves.io.schema.healthcheck, ves.io.schema.origin_pool e ves.io.schema.shape.csd. Utilizzare queste specifiche per validare i payload JSON e scoprire campi aggiuntivi.