Demo
Esta guía le orienta a través de un ejercicio completo de Defensa del lado del cliente en F5 Distributed Cloud utilizando la API — estructurado en cuatro fases que un asistente de IA u operador humano puede ejecutar de principio a fin. Cada paso incluye un comando curl listo para ejecutar con valores de marcador de posición que puede personalizar mediante el formulario en la parte superior de la página, un archivo .env, o cualquier herramienta de Automatización.
Fases del ejercicio
Sección titulada «Fases del ejercicio»| Fase | Objetivo | Pasos |
|---|---|---|
| Fase 1 — Construcción | Desplegar y validar la infraestructura CSD completa | Pasos 1–7 |
| Fase 2 — Ataque | Generar tráfico de ataque simulado y confirmar que CSD lo detectó | Pasos 8–9 |
| Fase 3 — Mitigación | Prueba antes/después de mitigación — ejecutar ataque, aplicar mitigaciones, volver a ejecutar ataque, comparar | Pasos 1–6 |
| Fase 4 — Desmontaje | Eliminar todos los objetos de despliegue tras confirmación explícita | Desmontaje |
Verificación previa al vuelo
Sección titulada «Verificación previa al vuelo»Antes de iniciar la Fase 1, verifique que el entorno esté limpio. Ejecute estas verificaciones de API para determinar si existen objetos residuales de una ejecución anterior:
# Check all Phase 1 objects and compute environment statusHTTP_LB=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-http")HTTPS_LB=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-https")ORIGIN=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/xF5XC_ORIGIN_POOLx")HC=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/xF5XC_HC_NAMEx")PD_COUNT=$(curl -s -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains" \ | jq '[.items // [] | .[] | select(.metadata.name != null)] | length')MD_COUNT=$(curl -s -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains" \ | jq '[.items // [] | .[] | select(.metadata.name != null)] | length')
# If HTTPS LB exists, fetch body to detect skeleton stateHTTPS_IS_SKELETON="false"if [ "$HTTPS_LB" = "200" ]; then HTTPS_LB_BODY=$(curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/xF5XC_LB_NAMEx-https") HTTPS_IS_SKELETON=$(echo "$HTTPS_LB_BODY" | jq ' ((.spec.default_route_pools // []) | length == 0) and (.spec.client_side_defense == null) ')fi
# Compute deterministic environment statusjq -n \ --argjson http_lb "$HTTP_LB" \ --argjson https_lb "$HTTPS_LB" \ --argjson origin "$ORIGIN" \ --argjson hc "$HC" \ --argjson pd "$PD_COUNT" \ --argjson md "$MD_COUNT" \ --argjson https_skeleton "$HTTPS_IS_SKELETON" \'{ objects: [ { name: "http_lb", http_code: $http_lb, exists: ($http_lb == 200) }, { name: "https_lb", http_code: $https_lb, exists: ($https_lb == 200), is_skeleton: $https_skeleton }, { name: "origin_pool", http_code: $origin, exists: ($origin == 200) }, { name: "healthcheck", http_code: $hc, exists: ($hc == 200) }, { name: "protected_domains", count: $pd, exists: ($pd > 0) }, { name: "mitigated_domains", count: $md, exists: ($md > 0) } ], any_infra_exists: ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200), any_csd_exists: ($pd > 0 or $md > 0), status: ( if ($http_lb == 404 and $https_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "CLEAN" elif ($https_lb == 200 and $https_skeleton and $http_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "HTTPS_SKELETON" elif ($http_lb == 200 and $origin == 200) then "ALL_EXIST" elif ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200) then "TEARDOWN_NEEDED" elif ($md > 0 and $http_lb == 404 and ($https_lb == 404 or ($https_lb == 200 and $https_skeleton)) and $origin == 404 and $hc == 404) then "MITIGATIONS_ONLY" else "TEARDOWN_NEEDED" end ), action: ( if ($http_lb == 404 and $https_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "Proceed to Phase 1" elif ($https_lb == 200 and $https_skeleton and $http_lb == 404 and $origin == 404 and $hc == 404 and $pd == 0 and $md == 0) then "Proceed to Phase 1 (HTTPS LB skeleton will be restored via PUT)" elif ($http_lb == 200 and $origin == 200) then "All Phase 1 objects exist — verify health, optionally skip to Phase 2" elif ($http_lb == 200 or ($https_lb == 200 and ($https_skeleton | not)) or $origin == 200 or $hc == 200) then "Run Phase 4 Teardown first, then re-check" elif ($md > 0 and $http_lb == 404 and ($https_lb == 404 or ($https_lb == 200 and $https_skeleton)) and $origin == 404 and $hc == 404) then "Delete mitigated domains inline, then proceed" else "Run Phase 4 Teardown first, then re-check" end )}'Verificación de avance rápido
Sección titulada «Verificación de avance rápido»Cuando todos los objetos de la Fase 1 existen (200) y planea omitir hasta la Fase 2,
ejecute los comandos de verificación del Paso 7 de la Fase 1 para confirmar el estado de la
infraestructura antes de omitir. Use los comandos exactos de
Fase 1 — Paso 7: Verificar:
- Resolución DNS:
dig +short xF5XC_DOMAINNAMEx A - Estado del LB HTTP:
GET .../http_loadbalancers/xF5XC_LB_NAMEx-httpcanalizando ajq '{state: .spec.state}'— debe mostrarVIRTUAL_HOST_READY - Configuración JS de CSD:
GET .../js_configuration— debe contenerscriptTag - Estado de CSD:
GET .../statuscanalizando ajq '{configured: .isConfigured, enabled: .isEnabled}'— ambos deben sertrue
Todas las verificaciones requeridas (DNS-1, LB-1, CSD-1, CSD-2) deben pasar (PASS) antes de omitir hacia la Fase 2. Si alguna verificación falla, ejecute la Fase 1 comenzando desde el paso fallido.
Matriz de verificación de preparación
Sección titulada «Matriz de verificación de preparación»La verificación previa al vuelo anterior verifica que el entorno esté limpio. La matriz de preparación a continuación verifica que el entorno sea capaz — que todos los requisitos previos, cuotas, conectividad y servicios de plataforma estén en su lugar para una demostración exitosa. Ejecute esta matriz antes de cada reunión como parte de la etapa de Preparación.
Cada verificación tiene un ID de prueba, un nivel (T0–T5), un criterio PASS/FAIL/WARN y una ruta de corrección. Los niveles son secuenciales — un FAIL en un nivel anterior bloquea los niveles posteriores para que no se ejecuten.
Resumen de niveles
Sección titulada «Resumen de niveles»| Nivel | Categoría | ¿Bloquea la demostración? | Propósito |
|---|---|---|---|
| T0 | Conectividad y distribución y Autenticación | Sí | ¿Podemos llegar a la plataforma y autenticarnos? |
| T1 | Cuotas y Capacidad | Sí (si está en el límite) | ¿Hay espacio para crear objetos de demostración? |
| T2 | Requisitos previos de la Plataforma | Sí | ¿Están configurados los servicios a nivel de tenant? |
| T3 | Estado del Servidor de origen | Advertencia | ¿Está respondiendo la aplicación backend? |
| T4 | Entorno limpio | Auto-corrección | ¿Existen objetos residuales de una ejecución anterior? |
| T5 | Preparación de certificados | Informativo | ¿Funcionará HTTPS o debemos planificar solo HTTP? |
T0: Conectividad y Autenticación
Sección titulada «T0: Conectividad y Autenticación»Estas verificaciones confirman que el host de ejecución puede llegar a la API de F5 XC y que las credenciales son válidas.
PF-T0-1: Conectividad de API
Sección titulada «PF-T0-1: Conectividad de API»HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' --connect-timeout 10 --max-time 15 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-1", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 401 then "FAIL" else "FAIL" end ), detail: ( if .http_code == 200 then "API reachable, token valid" elif .http_code == 401 then "Token expired or invalid — regenerate under Administration > Credentials > API Credentials" elif .http_code == 0 then "Network unreachable — check connectivity, VPN, or TLS compatibility (try --tlsv1.2 --tls-max 1.2)" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-2: Acceso al espacio de nombres
Sección titulada «PF-T0-2: Acceso al espacio de nombres»HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-2", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 404 then "WARN" else "FAIL" end ), detail: ( if .http_code == 200 then "Token has namespace access" elif .http_code == 403 then "Token lacks permissions for namespace — check role bindings" elif .http_code == 404 then "Namespace does not exist — will be created in Phase 1 Step 0" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-3: Acceso a la API de CSD
Sección titulada «PF-T0-3: Acceso a la API de CSD»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: Matriz de permisos RBAC
Sección titulada «PF-T0-4: Matriz de permisos RBAC»Las sondas no destructivas prueban los permisos de lectura y escritura para cada tipo de objeto que necesita la demostración. La lectura se prueba mediante GET en los endpoints de lista. La escritura se prueba mediante DELETE en objetos conocidos inexistentes — la API devuelve 403 si RBAC deniega la operación, o 404 si la operación está permitida pero el objeto no existe. Esta técnica de efecto cero evita crear objetos de sonda temporales.
PROBE_NAME="rbac-probe-nonexistent"
# Read probesNS_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces/xF5XC_NAMESPACEx")HC_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks")OP_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools")LB_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")CSD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/status")PD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains")MD_R=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains")
# Write probes (non-destructive: DELETE/cascade_delete on non-existent objects)NS_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X POST -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d "{\"name\":\"$PROBE_NAME\"}" \ "xF5XC_API_URLx/api/web/namespaces/$PROBE_NAME/cascade_delete")HC_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/$PROBE_NAME")OP_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/origin_pools/$PROBE_NAME")LB_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/$PROBE_NAME")PD_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains/$PROBE_NAME.example.com")MD_W=$(curl -s -o /dev/null -w '%\{http_code\}' --max-time 10 \ -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/mitigated_domains/$PROBE_NAME.example.com")
# Compute deterministic permission matrixjq -n \ --argjson ns_r "$NS_R" --argjson ns_w "$NS_W" \ --argjson hc_r "$HC_R" --argjson hc_w "$HC_W" \ --argjson op_r "$OP_R" --argjson op_w "$OP_W" \ --argjson lb_r "$LB_R" --argjson lb_w "$LB_W" \ --argjson csd_r "$CSD_R" \ --argjson pd_r "$PD_R" --argjson pd_w "$PD_W" \ --argjson md_r "$MD_R" --argjson md_w "$MD_W" \'{ check: "PF-T0-4", permissions: [ { object: "namespace", read: ($ns_r != 403), write: ($ns_w != 403), required: false, note: "conditional — only if ns must be created" }, { object: "healthcheck", read: ($hc_r != 403), write: ($hc_w != 403), required: false, note: "optional for CSD" }, { object: "origin_pool", read: ($op_r != 403), write: ($op_w != 403), required: true, note: "" }, { object: "http_loadbalancer", read: ($lb_r != 403), write: ($lb_w != 403), required: true, note: "" }, { object: "csd_status", read: ($csd_r != 403), write: true, required: true, note: "read-only check" }, { object: "protected_domain", read: ($pd_r != 403), write: ($pd_w != 403), required: true, note: "" }, { object: "mitigated_domain", read: ($md_r != 403), write: ($md_w != 403), required: false, note: "Phase 3 only" } ], status: ( if [ ($op_r == 403), ($op_w == 403), ($lb_r == 403), ($lb_w == 403), ($csd_r == 403), ($pd_r == 403), ($pd_w == 403) ] | any then "FAIL" elif ($ns_w == 403 or $hc_w == 403 or $md_w == 403) then "WARN" else "PASS" end ), detail: ( [ (if ($op_r == 403 or $op_w == 403) then "Origin pool: permission denied" else null end), (if ($lb_r == 403 or $lb_w == 403) then "Load balancer: permission denied" else null end), (if $csd_r == 403 then "CSD API: permission denied — CSD may not be enabled for this namespace" else null end), (if ($pd_r == 403 or $pd_w == 403) then "Protected domain: permission denied" else null end), (if $ns_w == 403 then "Namespace: write denied — namespace must already exist (cannot create)" else null end), (if $hc_w == 403 then "Healthcheck: write denied — will skip healthcheck creation" else null end), (if $md_w == 403 then "Mitigated domain: write denied — Phase 3 mitigation will be skipped" else null end) ] | map(select(. != null)) | join("; ") )}'T1: Cuotas y Capacidad
Sección titulada «T1: Cuotas y Capacidad»Estas verificaciones consultan la API de Uso de Cuota del tenant para determinar límites, uso actual y capacidad restante para cada tipo de objeto que necesita la demostración. Esto reemplaza las pruebas de sonda y eliminación con una única llamada a la API de solo lectura que reporta números exactos.
PF-T1-0: Verificación de uso de cuota
Sección titulada «PF-T1-0: Verificación de uso de cuota»Consulte el endpoint de uso de cuota a nivel de tenant y calcule un estado determinista PASS/WARN/FAIL para cada tipo de objeto que necesita la demostración. Este endpoint requiere el namespace system. Una sola llamada a la API verifica todas las cuotas a nivel de plataforma a la vez.
La verificación define un array demo_needs que especifica cuántos objetos de cada tipo consumirá la demostración, si el tipo es requerido y el mínimo necesario para que la demostración continúe. El filtro jq compara remaining contra needed y calcula el campo status de forma determinista — no se requiere interpretación del operador.
# Step 1: Fetch quota datacurl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/web/namespaces/system/quota/usage?namespace=system" \ > /tmp/quota.json
# Step 2: Compute gate statusjq ' . as $data | [ { kind: "healthcheck", needed: 1, required: false, min_proceed: 0 }, { kind: "origin_pool", needed: 1, required: true, min_proceed: 1 }, { kind: "endpoint", needed: 1, required: true, min_proceed: 1 }, { kind: "http_loadbalancer", needed: 2, required: true, min_proceed: 1 } ] | map( . as $req | $data.objects[$req.kind] as $obj | $obj.limit.maximum as $limit | $obj.usage.current as $usage | (if $limit == -1 then null else ($limit - $usage) end) as $remaining | { kind: $req.kind, limit: (if $limit == -1 then "unlimited" else $limit end), usage: $usage, remaining: (if $remaining == null then "unlimited" else $remaining end), needed: $req.needed, status: ( if $remaining == null then "PASS" elif $remaining >= $req.needed then "PASS" elif $remaining >= $req.min_proceed then "WARN" else (if $req.required then "FAIL" else "WARN" end) end ) } ) | { checks: ., gate: (if any(.[]; .status == "FAIL") then "FAIL" elif any(.[]; .status == "WARN") then "WARN" else "PASS" end) }' /tmp/quota.jsonSalida de la verificación — el campo gate es el veredicto determinista único:
PASS— todos los tipos de objetos tienenremaining >= needed. La demostración puede continuar.WARN— al menos un tipo tiene capacidad reducida pero se cumple el mínimo para continuar (p. ej., solo hay 1 ranura de LB disponible en lugar de 2, o la cuota de healthcheck está agotada). La demostración puede continuar con limitaciones.FAIL— al menos un tipo requerido tieneremaining < min_proceed. La demostración no puede continuar hasta que se libere cuota.
Ejemplo de salida (WARN — endpoint al límite de capacidad, healthcheck casi lleno):
{ "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"}Valor de gate | Acción |
|---|---|
| PASS | Continuar a PF-T1-4 (verificación de dominio protegido), luego T2 |
| WARN | Anotar limitaciones en el informe de preparación, continuar con capacidad reducida |
| FAIL | Detener — reportar qué tipos están agotados y los pasos de corrección a continuación |
Corrección por tipo:
| Tipo | Corrección |
|---|---|
healthcheck | Eliminar healthchecks no utilizados para liberar capacidad. La demostración continúa sin healthcheck (CSD no requiere uno). |
origin_pool | Eliminar origin pools no utilizados o contactar a su administrador para aumentar el límite del tenant. |
endpoint | Eliminar origin pools no utilizados en otros namespaces para liberar capacidad de endpoints (los endpoints son sub-objetos de los origin pools), o contactar a su administrador. |
http_loadbalancer | Eliminar load balancers no utilizados o contactar a su administrador. Si solo hay 1 ranura disponible, se creará el LB HTTP (primario) pero se omitirá el LB HTTPS (secundario). |
PF-T1-4: Cuota de dominio protegido
Sección titulada «PF-T1-4: Cuota de dominio protegido»Los dominios protegidos de CSD no aparecen en la API de Uso de Cuota de la plataforma. Use una verificación basada en sondas: cree y elimine inmediatamente un dominio protegido de sonda.
# Create probe and capture both HTTP code and response bodyPROBE_BODY=$(curl -s -w '\n%\{http_code\}' -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-probe.example.com", "namespace": "xF5XC_NAMESPACEx" }, "spec": { "protected_domain": "example.com" } }' \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains")PROBE_HTTP=$(echo "$PROBE_BODY" | tail -1)PROBE_JSON=$(echo "$PROBE_BODY" | sed '$d')
# Compute statusecho "$PROBE_JSON" | jq --argjson http "$PROBE_HTTP" '{ check: "PF-T1-4", http_code: $http, status: ( if $http == 409 then "PASS" elif (.code // 0) == 8 then "FAIL" elif .metadata.name then "PASS" else "FAIL" end ), detail: ( if $http == 409 then "example.com already registered — quota not exhausted" elif (.code // 0) == 8 then "Protected domain quota exhausted — delete unused protected domains" elif .metadata.name then "Probe created — quota available" else "Unexpected response" end )}'
# Cleanup probe (404 is expected if 409 occurred)curl -s -X DELETE \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/protected_domains/preflight-probe.example.com" \ > /dev/nullAlternativa: Verificaciones de cuota basadas en sondas
Sección titulada «Alternativa: Verificaciones de cuota basadas en sondas»Si PF-T1-0 falla (la API de Uso de Cuota devuelve 403, 404 o un formato inesperado), recurra a las verificaciones de sonda y eliminación para las cuotas de healthcheck, origin pool, endpoint y load balancer. Estas verificaciones crean un objeto temporal y lo eliminan inmediatamente — si la creación devuelve el código de error 8 con “exhausted limits”, la cuota está llena.
Cada sonda alternativa usa el mismo patrón: crear un objeto temporal, calcular un estado determinista a partir de la respuesta y luego eliminar la sonda. El campo status es PASS si el objeto fue creado (.metadata.name presente), WARN o FAIL si el código de error es 8 (límites agotados), según si el tipo es requerido.
Sonda de healthcheck (WARN si está agotado — los healthchecks son opcionales para CSD):
RESULT=$(curl -s -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-quota-probe", "namespace": "xF5XC_NAMESPACEx" }, "spec": { "http_health_check": { "use_origin_server_name": {}, "path": "/", "use_http2": false }, "timeout": 3, "interval": 15, "unhealthy_threshold": 1, "healthy_threshold": 3 } }' \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks")echo "$RESULT" | jq '{ check: "fallback-healthcheck", status: (if .metadata.name then "PASS" elif (.code // 0) == 8 then "WARN" else "FAIL" end), detail: (if .metadata.name then "Quota available" elif (.code // 0) == 8 then "Quota full — healthcheck optional, demo proceeds" else "Unexpected: \(.message // "unknown error")" end)}'curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/healthchecks/preflight-quota-probe" \ > /dev/nullSonda de origin pool y endpoint (FAIL si está agotado — ambos son requeridos):
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/nullSonda de HTTP load balancer (FAIL si está agotado — los LBs son requeridos):
RESULT=$(curl -s -X POST \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d '{ "metadata": { "name": "preflight-lb-probe", "namespace": "xF5XC_NAMESPACEx", "disable": false }, "spec": { "domains": ["preflight-probe.example.com"], "http": { "dns_volterra_managed": false, "port": 80 }, "advertise_on_public_default_vip": {}, "default_route_pools": [], "disable_rate_limit": {}, "no_service_policies": {}, "round_robin": {}, "disable_waf": {}, "no_challenge": {}, "disable_bot_defense": {}, "disable_api_definition": {}, "disable_api_discovery": {}, "disable_ip_reputation": {}, "disable_malicious_user_detection": {}, "single_lb_app": { "disable_discovery": {}, "disable_ddos_detection": {}, "disable_malicious_user_detection": {} }, "disable_trust_client_ip_headers": {}, "user_id_client_ip": {}, "disable_threat_mesh": {}, "l7_ddos_action_default": {}, "system_default_timeouts": {}, "default_sensitive_data_policy": {}, "disable_malware_protection": {}, "disable_api_testing": {} } }' \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")echo "$RESULT" | jq '{ check: "fallback-http-lb", status: (if .metadata.name then "PASS" elif (.code // 0) == 8 then "FAIL" else "FAIL" end), detail: (if .metadata.name then "Quota available" elif (.code // 0) == 8 then "Quota exhausted — \(.message // "limit reached")" else "Unexpected: \(.message // "unknown error")" end)}'curl -s -X DELETE -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers/preflight-lb-probe" \ > /dev/nullT2: Requisitos previos de la Plataforma
Sección titulada «T2: Requisitos previos de la Plataforma»Estas verificaciones validan los servicios a nivel de tenant de los que depende la demostración.
PF-T2-1: Estado de CSD en el tenant
Sección titulada «PF-T2-1: Estado de CSD en el tenant»curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/shape/csd/namespaces/xF5XC_NAMESPACEx/status" \ | jq '{ check: "PF-T2-1", configured: .isConfigured, enabled: .isEnabled, status: (if .isConfigured and .isEnabled then "PASS" else "FAIL" end), detail: ( if .isConfigured and .isEnabled then "CSD is active" elif (.isConfigured | not) then "CSD not enabled at tenant level — contact F5 XC administrator" else "CSD configured but not active — contact administrator" end ) }'PF-T2-2: Zona DNS existente
Sección titulada «PF-T2-2: Zona DNS existente»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: Registros DNS gestionados habilitados
Sección titulada «PF-T2-3: Registros DNS gestionados habilitados»Solo ejecute si PF-T2-2 devolvió 200 (existe la zona DNS de F5 XC).
Verificar estado actual:
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-corrección si es necesario: Si el status es WARN Y PF-T2-4 muestra servidores de nombres de F5 XC (ns1.f5clouddns.com, ns2.f5clouddns.com), habilite automáticamente los registros gestionados mediante GET+PUT:
# Get current zone configZONE_CONFIG=$(curl -s \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx")
# Update with managed records enabledecho "$ZONE_CONFIG" \ | jq '.spec.primary.allow_http_lb_managed_records = true' \ | curl -s -X PUT \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ -H "Content-Type: application/json" \ -d @- \ "xF5XC_API_URLx/api/config/dns/namespaces/system/dns_zones/xF5XC_ROOT_DOMAINx" \ | jq .Luego vuelva a verificar para confirmar que la actualización tuvo efecto:
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'| Resultado | Autoridad DNS | Estado | Corrección |
|---|---|---|---|
true | Cualquiera | PASS | Los registros DNS gestionados por LB se crearán automáticamente |
false/null | F5 XC | Auto-corrección | Habilitar mediante GET+PUT, verificar, reportar resultado |
false/null | Externo | INFO | Los registros gestionados no aplican para DNS externo — La Fase 1 Paso 4 usará la Opción B (creación manual de registros) |
| Auto-corrección fallida | F5 XC | FAIL | El token puede carecer de acceso de escritura al namespace del sistema — contacte al administrador del tenant |
PF-T2-4: Autoridad del servidor de nombres DNS
Sección titulada «PF-T2-4: Autoridad del servidor de nombres DNS»NS_RECORDS=$(dig +short NS xF5XC_ROOT_DOMAINx)echo "$NS_RECORDS" | jq -Rs '{ check: "PF-T2-4", nameservers: (split("\n") | map(select(length > 0))), status: ( if (split("\n") | map(select(length > 0)) | length) == 0 then "FAIL" elif test("f5clouddns\\.com") then "PASS" else "INFO" end ), detail: ( if (split("\n") | map(select(length > 0)) | length) == 0 then "No NS records — DNS is broken for this domain" elif test("f5clouddns\\.com") then "F5 XC is authoritative — automatic DNS management available" else "External DNS provider — Phase 1 Step 4 will use Option B (manual record creation)" end )}'T3: Estado del Servidor de origen
Sección titulada «T3: Estado del Servidor de origen»Estas verificaciones validan que la aplicación backend es accesible.
Verificación de condición de omisión: Calcule si la IP de origen es una dirección TEST-NET del RFC 5737 antes de ejecutar las pruebas de conectividad:
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)}'Si status es SKIP, registre PF-T3-1 y PF-T3-2 como SKIP y continúe con T4. De lo contrario, ejecute las verificaciones a continuación.
PF-T3-1: Conectividad del Servidor de origen
Sección titulada «PF-T3-1: Conectividad del Servidor de origen»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: El origen sirve contenido HTML
Sección titulada «PF-T3-2: El origen sirve contenido HTML»Solo ejecute si PF-T3-1 devolvió un estado HTTP válido:
curl -s --max-time 10 "http://xF5XC_ORIGIN_IPx:xF5XC_ORIGIN_PORTx/" \ | grep -qi '</html>' && echo "PASS: HTML content" || echo "WARN: No HTML detected"| Resultado | Estado | Corrección |
|---|---|---|
PASS: HTML content | PASS | El origen sirve páginas HTML (requerido para la inyección JS de CSD) |
WARN: No HTML detected | WARN | El origen puede ser un servicio solo de API o devolver contenido no HTML — la inyección JS de CSD requiere respuestas de páginas HTML |
T4: Entorno limpio
Sección titulada «T4: Entorno limpio»Estas verificaciones validan que no quedan objetos de configuración de F5 XC nombrados de una ejecución de demostración anterior — HTTP load balancers, HTTPS load balancers, origin pools, healthchecks, dominios protegidos y dominios mitigados. T4 trata sobre la limpieza a nivel de objetos: si existen objetos de API que entrarían en conflicto con la creación en la Fase 1. No prueba direcciones IP, conectividad de red ni el estado del origen (esas preocupaciones pertenecen a T3).
Ejecute los seis comandos de verificación previa al vuelo de la sección Verificación previa al vuelo anterior. Aplique la Lógica de decisión para determinar los próximos pasos. Si existen objetos, el desmontaje automático se realiza durante la etapa de Preparación (no se necesita confirmación).
También verifique y elimine los objetos de sonda obsoletos de ejecuciones de verificación previa al vuelo interrumpidas anteriormente. Estas sondas solo se crean cuando la API de Uso de Cuota no está disponible y se usaron las verificaciones alternativas basadas en sondas, o para la sonda de dominio protegido (PF-T1-4) que siempre usa verificación basada en sondas:
# 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/nullCada DELETE devuelve 200 (vacío {}) si el objeto existía, o 404 si no existía — ambos son esperados.
T5: Preparación de certificados
Sección titulada «T5: Preparación de certificados»Estas verificaciones evalúan si HTTPS funcionará o si la demostración debe planificarse solo para HTTP.
PF-T5-1: Historial reciente de emisión de certificados
Sección titulada «PF-T5-1: Historial reciente de emisión de certificados»Verifique si recientemente se emitió un certificado de Let’s Encrypt para el dominio de demostración. Los ciclos frecuentes de creación y destrucción pueden agotar el límite de frecuencia semanal (5 certificados duplicados por semana por dominio).
PF-T5-2: Estado del certificado del LB HTTPS existente
Sección titulada «PF-T5-2: Estado del certificado del LB HTTPS existente»Solo ejecute si existe un LB HTTPS de una ejecución anterior (PF-T4 encontró objetos):
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 ) }'fiFormato del informe de preparación
Sección titulada «Formato del informe de preparación»Después de ejecutar todos los niveles, presente un informe de preparación consolidado:
## Preparación para la demostración: LISTO / NO LISTO / LISTO CON ADVERTENCIAS
### T0: Conectividad y Autenticación| Verificación | Resultado | Estado ||---|---|---|| PF-T0-1: Conectividad de API | 200 | PASS || PF-T0-2: Acceso al namespace | 200 | PASS || PF-T0-3: Acceso a la API de CSD | 200 | PASS |
### T1: Cuotas y Capacidad| Verificación | Tipo | Límite | Uso | Restante | Necesario | Estado ||---|---|---|---|---|---|---|| PF-T1-0: Verificación de uso de cuota | `healthcheck` | 150 | 148 | 2 | 1 | PASS || PF-T1-0: Verificación de uso de cuota | `origin_pool` | unlimited | 420 | unlimited | 1 | PASS || PF-T1-0: Verificación de uso de cuota | `endpoint` | 500 | 498 | 2 | 1 | PASS || PF-T1-0: Verificación de uso de cuota | `http_loadbalancer` | unlimited | 116 | unlimited | 2 | PASS || PF-T1-0: Verificación de uso de cuota | **gate** | — | — | — | — | **PASS** || PF-T1-4: Dominio protegido | — | — | — | — | 1 | PASS (sonda) |
### T2: Requisitos previos de la Plataforma| Verificación | Resultado | Estado ||---|---|---|| PF-T2-1: Estado de CSD en el tenant | configurado + habilitado | PASS || PF-T2-2: Zona DNS existente | 200 | PASS || PF-T2-3: Registros DNS gestionados | true | PASS || PF-T2-4: Autoridad del servidor de nombres DNS | f5clouddns.com | PASS |
### T3: Estado del Servidor de origen| Verificación | Resultado | Estado ||---|---|---|| PF-T3-1: Conectividad del origen | Dirección TEST-NET (192.0.2.1) | SKIP || PF-T3-2: Contenido HTML | Dirección TEST-NET | SKIP |
### T4: Entorno limpio| Verificación | Resultado | Estado ||---|---|---|| HTTP LB | 404 | PASS || HTTPS LB | 404 | PASS || Origin Pool | 404 | PASS || Healthcheck | 404 | PASS || Dominios protegidos | 0 | PASS || Dominios mitigados | 0 | PASS |
### T5: Preparación de certificados| Verificación | Resultado | Estado ||---|---|---|| PF-T5-2: Estado del certificado | SKIP (sin LB HTTPS) | INFO |
### Advertencias- (enumerar cualquier elemento WARN o INFO con contexto)Reglas de estado general:
| Condición | Estado |
|---|---|
| Todas las verificaciones T0–T4 pasan (PASS) | LISTO |
| Todas las verificaciones T0–T4 pasan (PASS) pero T3 o T5 tienen WARN/INFO | LISTO CON ADVERTENCIAS |
| Cualquier verificación de T0, T1 o T2 es FAIL | NO LISTO — resolver antes de continuar |
| T4 tiene objetos residuales | Auto-corrección (desmontaje), luego volver a verificar |
Protocolo de ejecución del asistente de IA
Sección titulada «Protocolo de ejecución del asistente de IA»Esta sección define un flujo de trabajo determinista para los asistentes de IA (Claude Code, Copilot, etc.) que ejecutan los pasos de Automatización de la API. Seguir este protocolo elimina las suposiciones — cada punto de decisión tiene una ruta de resolución definida.
Protocolo de resolución de variables
Sección titulada «Protocolo de resolución de variables»Resuelva cada variable en este orden exacto. Deténgase en la primera fuente que proporcione un valor que no sea un marcador de posición:
- Verificar el archivo
.env— busque.enven la raíz del repositorio. Si existe, analice todos los paresKEY=VALUE. - Verificar el entorno de shell — ejecute
env | grep F5XC_para encontrar cualquier valor ya exportado en la sesión actual. - Identificar valores faltantes — compare los valores resueltos con la tabla de requeridos/opcionales a continuación. Un valor está “faltante” si está ausente, vacío o todavía configurado como un valor predeterminado de marcador de posición (p. ej.,
example-api-token,example-tenant,example-namespace,app.example.com,user@example.com). - Solicitar al operador humano — para cada variable requerida faltante, solicite al operador que proporcione el valor. No continúe hasta que todas las variables requeridas estén resueltas.
- Aplicar valores predeterminados — para cada variable opcional faltante, use el valor predeterminado de la tabla a continuación sin solicitar confirmación.
Cadena vacía = faltante: Una variable exportada con un valor vacío (p. ej.,
F5XC_HC_NAME="") se trata igual que una variable no establecida — aplique el valor predeterminado. Use la expansión de parámetros de shell (${F5XC_HC_NAME:-csd-hc}) para aplicar los valores predeterminados en un solo paso.
- Mostrar confirmación — muestre la tabla final de variables resueltas al operador y espere aprobación antes de ejecutar cualquier llamada a la API.
Anulación de la etapa de Preparación: Durante la Etapa 1 de Preparación, omita la espera en el paso 6. Muestre la tabla de variables resueltas para el registro y continúe de inmediato. Los pasos 1–5 aún se aplican — si alguna variable requerida falta después de verificar
.envy el shell, deténgase y reporte las variables faltantes.
Variables requeridas vs. opcionales
Sección titulada «Variables requeridas vs. opcionales»| Variable | Requerida | Predeterminado | Marcador de posición (tratar como faltante) |
|---|---|---|---|
F5XC_API_TOKEN | Sí | — | example-api-token |
F5XC_API_URL | Sí | — | https://example-tenant.console.ves.volterra.io |
F5XC_NAMESPACE | Sí | — | example-namespace |
F5XC_DOMAINNAME | Sí | — | app.example.com |
F5XC_ROOT_DOMAIN | Sí | — | example.com |
F5XC_LB_NAME | Sí | — | example-lb-name, example-lb |
F5XC_EMAIL | Sí | — | user@example.com |
F5XC_HC_NAME | Opcional | csd-hc | — |
F5XC_ORIGIN_IP | Opcional | 44.232.69.192 | — |
F5XC_ORIGIN_POOL | Opcional | csd-origin | — |
F5XC_ORIGIN_PORT | Opcional | 3000 | — |
Modos de ejecución
Sección titulada «Modos de ejecución»El asistente de IA opera en uno de tres modos durante la demostración:
| Modo | Cuándo está activo | Comportamiento |
|---|---|---|
| Normal | Predeterminado durante Preparación, Ejecución, Desmontaje | Únicamente comandos documentados literales |
| Depuración | Se activa automáticamente al fallar | Resolución de problemas creativa, actualizar documentación |
| Preguntas y respuestas | Durante la etapa de Preguntas y respuestas | Improvisado — se permiten comandos ad-hoc para responder preguntas de la audiencia |
Modo normal (predeterminado):
- Cada llamada a la API, consulta de verificación y comando de shell debe provenir literalmente de los archivos de fase (Fases 1–4) o de la sección de Verificación previa al vuelo anterior
- Sustituya únicamente los marcadores de posición
xTOKENxcon los valores de variables resueltos - No construya endpoints de API, filtros jq ni comandos cURL desde conocimiento general o inferencia
- Si un comando necesario no está documentado, deténgase y reporte al operador: “Este paso de verificación no está cubierto por la documentación de fases”
Modo de depuración (se activa automáticamente al fallar):
- Se activa automáticamente cuando un comando documentado produce un resultado inesperado: respuesta HTTP no 2xx, error de análisis de jq, tiempo de espera agotado del comando o cuerpo de respuesta que contradice la tabla de evidencias
- En modo de depuración, el asistente de IA puede construir comandos de diagnóstico, inspeccionar respuestas de API sin procesar, probar variaciones de endpoints y usar resolución de problemas creativa para encontrar la causa raíz
- Prefije toda la salida de depuración con
[DEBUG]para que el operador pueda distinguir la actividad de diagnóstico de la ejecución normal - Documente lo que aprende: después de resolver un problema, actualice el
archivo de fase relevante o la sección de resolución de problemas con:
- El escenario de fallo (qué salió mal)
- Qué se intentó y NO funcionó (para que ejecuciones futuras no lo repitan)
- La resolución que funcionó (el comando o corrección que lo solucionó)
- El objetivo del modo de depuración es eliminarse a sí mismo — cada sesión de depuración debe producir una actualización de documentación que haga que la siguiente ejecución sea completamente determinista
- Una vez que la documentación esté actualizada y el problema resuelto, regrese al modo normal y reanude desde el último paso documentado exitoso
- Si el modo de depuración no puede resolver el problema, reporte los hallazgos al operador y deténgase — no continúe a la siguiente fase
Modo de Preguntas y respuestas (durante la etapa de Preguntas y respuestas):
- Activo únicamente durante la etapa de reunión de Preguntas y respuestas, después de la conclusión de la demostración
- El asistente de IA puede construir llamadas a la API ad-hoc, ejecutar comandos de diagnóstico, navegar a páginas no programadas y modificar el entorno de demostración en vivo para ilustrar respuestas a las preguntas de la audiencia
- Sin prefijo
[DEBUG]— este es comportamiento improvisado intencional, no recuperación de errores - Utiliza la sección de Experiencia en el producto CSD en
DEMO_EXECUTOR.mdcomo base de conocimiento para las preguntas sobre el producto
Gestión del contexto del navegador
Sección titulada «Gestión del contexto del navegador»La acumulación de initScript es una fuente común de fallos en la demostración. Cada
llamada a navigate_page con un parámetro initScript agrega el script a
una lista persistente que se ejecuta en cada carga de documento posterior. Siga
estas reglas:
- Siempre navegue a
about:blankantes de cualquier navegación coninitScriptpara borrar los scripts acumulados de ejecuciones anteriores - Use
new_pageconisolatedContextal cambiar entre fases de demostración (p. ej., Fase 2 → Fase 3) para garantizar un estado de navegador completamente limpio - Recuperación de páginas que no responden — si
take_screenshototake_snapshotgeneran tiempos de espera agotados, el contexto del navegador está agotado de recursos. Usenew_pageconisolatedContextpara crear un contexto nuevo y luego reintente desde el paso de navegación aabout:blank - Consulte los avisos de la simulación de ataque de la Fase 2 para orientación detallada sobre fallos transitorios de origen y recuperación por agotamiento de recursos
Protocolo de visualización de evidencias
Sección titulada «Protocolo de visualización de evidencias»Después de cada llamada a la API, el asistente de IA debe presentar evidencias estructuradas al operador humano usando este formato:
Pasos de creación (POST):
| Campo | Valor | Estado |
|---|---|---|
| Estado HTTP | 200 | PASS |
| Nombre del objeto | csd-origin | — |
| Propiedad clave | (extraída mediante jq) | — |
Después de cada paso de creación, ejecute un GET para confirmar que el objeto existe y mostrar sus propiedades clave. Si el GET devuelve 404, reporte FAIL y deténgase.
Pasos de verificación (GET/dig):
| Prueba | Resultado | Estado |
|---|---|---|
| DNS-1: Registro A | 198.51.100.10 | PASS |
| LB-1: Estado del LB HTTP | VIRTUAL_HOST_READY | PASS |
| LB-2: Estado del LB HTTPS | VIRTUAL_HOST_READY | INFO (opcional) |
| TLS-1: Estado del certificado | CertificateValid | INFO (opcional) |
| CSD-1: Etiqueta JS | scriptTag presente | PASS |
Consulte los IDs de casos de prueba de Diagnósticos y Verificación (DNS-1, TLS-1, LB-1, CSD-1, etc.) como estándar de verificación para cada capa.
Resumen del flujo de ejecución
Sección titulada «Resumen del flujo de ejecución»La ejecución de fases es secuencial y con control de acceso: cada fase debe alcanzar PASS en todas las verificaciones requeridas antes de que comience la siguiente fase. La demostración sigue un ciclo de vida de reunión de cuatro etapas — consulte la sección de Etapas de reunión en DEMO_EXECUTOR.md para las frases desencadenantes y las reglas de comportamiento.
El asistente de IA sigue esta secuencia:
- Preparar — resolver variables, ejecutar verificaciones previas al vuelo, confirmar entorno limpio (puede ejecutarse por separado antes de la reunión)
- Introducción — el SE se presenta y establece los objetivos del resultado (visibilidad de amenazas del lado del cliente, cumplimiento PCI, detección en tiempo real)
- Ejecutar Fase 1 (Pasos 1–7) — creación y verificación de infraestructura; todas las verificaciones de la Fase 1 deben pasar (PASS) antes de continuar
- Ejecutar Fase 2 (Pasos 8–9) — simulación de ataque y verificación de detección mediante API; los asistentes de IA con Automatización de navegador ejecutan los pasos del navegador directamente, los operadores sin herramientas de navegador los realizan manualmente
- Ejecutar Fase 3 — aplicar mitigación para todos los dominios detectados, volver a ejecutar el ataque, verificar que el bloqueo es efectivo
- Conclusión — reafirmar los objetivos del resultado, resumir la evidencia de cada fase, destacar las detecciones y mitigaciones clave
- Preguntas y respuestas — etapa improvisada, la demostración permanece en vivo, el SE responde las preguntas de la audiencia y hace preguntas de retorno
- Desmontaje (posterior a la reunión) — Fase 4, se requiere confirmación explícita del operador, eliminar todos los objetos en orden de dependencia inversa, confirmar entorno limpio
Si algún paso devuelve FAIL, deténgase y reporte el fallo con el enlace a la sección de resolución de problemas relevante antes de continuar.
Requisitos previos
Sección titulada «Requisitos previos»- Un token de API de F5 XC — genere uno en Administración → Credenciales → Credenciales de API
curlyjqinstalados localmente- Un namespace con permisos para crear healthchecks, origin pools y HTTP load balancers
Configuración del entorno
Sección titulada «Configuración del entorno»Cree un archivo .env con los valores de su entorno. Se proporciona una plantilla en el repositorio:
cp .env.example .envEdite .env con sus valores reales:
# Required — your environmentF5XC_API_TOKEN=example-api-tokenF5XC_API_URL=https://example-tenant.console.ves.volterra.ioF5XC_DOMAINNAME=app.example.comF5XC_EMAIL=user@example.comF5XC_LB_NAME=example-lb-nameF5XC_NAMESPACE=example-namespaceF5XC_ROOT_DOMAIN=example.com
# Optional — Juice Shop demo defaults are used when not set# F5XC_HC_NAME=csd-hc# F5XC_ORIGIN_IP=44.232.69.192# F5XC_ORIGIN_POOL=csd-origin# F5XC_ORIGIN_PORT=3000Cargue el archivo para importar las variables en su sesión de shell:
set -a && source .env && set +aCada marcador de posición xTOKENx en los comandos curl se corresponde directamente con una variable de entorno — por ejemplo, xF5XC_API_TOKENx corresponde a $F5XC_API_TOKEN. Puede sustituir estos valores usando el formulario interactivo en la parte superior de la página, o dejar que un asistente de IA como Claude Code lea su .env y construya los comandos por usted.
Tokens de marcador de posición
Sección titulada «Tokens de marcador de posición»| Token | Predeterminado | Descripción |
|---|---|---|
xF5XC_API_URLx | https://example-tenant.console.ves.volterra.io | URL de la API de la F5 XC Consola |
xF5XC_API_TOKENx | example-api-token | Token de credencial de API |
xF5XC_EMAILx | user@example.com | Dirección de correo electrónico para notificaciones de CSD |
xF5XC_NAMESPACEx | example-namespace | Namespace |
xF5XC_LB_NAMEx | example-lb | Nombre base del HTTP Load Balancer (crea ${name}-http y ${name}-https) |
xF5XC_DOMAINNAMEx | app.example.com | FQDN a proteger |
xF5XC_ROOT_DOMAINx | example.com | Dominio raíz (eTLD+1) para el dominio protegido de CSD |
xF5XC_ORIGIN_POOLx | csd-origin | Nombre del origin pool |
xF5XC_ORIGIN_IPx | 44.232.69.192 | IP del Servidor de origen |
xF5XC_ORIGIN_PORTx | 3000 | Puerto del Servidor de origen |
xF5XC_HC_NAMEx | csd-hc | Nombre del healthcheck |
Referencia de Automatización
Sección titulada «Referencia de Automatización»Esta sección resume el flujo de trabajo completo del ejercicio para scripting o Automatización.
Inicio rápido
Sección titulada «Inicio rápido»- Clone el repositorio y copie la plantilla de entorno:
cp .env.example .env - Edite
.envcon su URL de tenant, token de API, namespace y valores de dominio - Cargue el entorno:
set -a && source .env && set +a - Ejecute cada fase en orden, verificando PASS en cada bloque de Evidencia antes de continuar a la siguiente fase
Resolución de variables
Sección titulada «Resolución de variables»Los valores se resuelven utilizando el protocolo determinista definido en Protocolo de ejecución del asistente de IA:
- Archivo
.env— analizar los paresKEY=VALUEdesde la raíz del repositorio - Entorno de shell — verificar
env | grep F5XC_para valores exportados - Detección de marcadores de posición — marcar cualquier valor que coincida con un marcador de posición predeterminado (p. ej.,
example-api-token,example-namespace) como faltante - Solicitar al operador — pedir cada variable requerida faltante
- Aplicar valores predeterminados — usar valores predeterminados integrados para variables opcionales faltantes
- Confirmar — mostrar la tabla de variables resueltas y esperar aprobación del operador
Orden de ejecución
Sección titulada «Orden de ejecución»- Fase 1 — Construcción: Desplegar infraestructura (healthcheck, origin pool, LB HTTP + LB HTTPS), configurar DNS, habilitar CSD, registrar dominio protegido, verificar todos los componentes. El LB HTTP es el objetivo principal de la demostración; el LB HTTPS es opcional.
- Fase 2 — Ataque: Ejecutar la simulación de ataque en un navegador usando URLs
http://, esperar 5–10 minutos, verificar detecciones mediante API (/scripts,/detected_domains,/formFields) - Fase 3 — Mitigación: Confirmar línea base limpia, ejecutar ataque (prueba anterior), POST de cada dominio a
/mitigated_domains, verificar mitigaciones aplicadas, volver a ejecutar ataque usando URLshttp://(prueba posterior), presentar comparación antes/después - Fase 4 — Desmontaje (requiere confirmación humana explícita): Eliminar LB HTTPS → LB HTTP → origin pool → limpieza de zona DNS (solo registros manuales) → healthcheck → dominio protegido. No elimine la zona DNS.
Variables
Sección titulada «Variables»| Token | Descripción | Predeterminado |
|---|---|---|
xF5XC_API_URLx | URL de la API de la F5 XC Consola | https://example-tenant.console.ves.volterra.io |
xF5XC_API_TOKENx | Token de credencial de API | (proporcionado por el usuario) |
xF5XC_EMAILx | Correo electrónico de notificación de CSD | user@example.com |
xF5XC_NAMESPACEx | Namespace | example-namespace |
xF5XC_LB_NAMEx | Nombre base del HTTP Load Balancer (crea ${name}-http y ${name}-https) | example-lb |
xF5XC_DOMAINNAMEx | FQDN a proteger | app.example.com |
xF5XC_ROOT_DOMAINx | Dominio raíz (eTLD+1) | example.com |
xF5XC_ORIGIN_POOLx | Nombre del origin pool | csd-origin |
xF5XC_ORIGIN_IPx | IP del Servidor de origen | 44.232.69.192 |
xF5XC_ORIGIN_PORTx | Puerto del Servidor de origen | 3000 |
xF5XC_HC_NAMEx | Nombre del healthcheck | csd-hc |
Grupos de elección oneOf
Sección titulada «Grupos de elección oneOf»La especificación del HTTP Load Balancer usa grupos de elección oneOf donde exactamente una opción debe establecerse por grupo. Establecer cero o más de una opción en un grupo provoca un error 422.
Elecciones clave relacionadas con CSD:
| Grupo de elección | Opciones | Predeterminado de CSD |
|---|---|---|
client_side_defense_choice | client_side_defense, disable_client_side_defense | client_side_defense |
java_script_choice (anidado en CSD) | disable_js_insert, js_insert_all_pages, js_insert_all_pages_except, js_insertion_rules | js_insert_all_pages |
Elección de tipo de escucha (HTTP vs HTTPS):
La demostración crea dos LBs con diferentes configuraciones de escucha:
| LB | Elección de escucha | Configuración |
|---|---|---|
${F5XC_LB_NAME}-http (primario) | http | "http": { "dns_volterra_managed": true, "port": 80 } |
${F5XC_LB_NAME}-https (secundario) | https_auto_cert | "https_auto_cert": { "http_redirect": true, "port": 443, ... } |
Las claves http y https_auto_cert son mutuamente excluyentes — cada LB usa exactamente una.
Elecciones anidadas de auto-certificado HTTPS (solo LB secundario):
| Grupo de elección | Opciones | Predeterminado |
|---|---|---|
| port | port (número) | 443 |
server_header_choice | default_header, server_name, append_server_name | default_header |
path_normalize_choice | enable_path_normalize, disable_path_normalize | enable_path_normalize |
mtls_choice | no_mtls, use_mtls | no_mtls |
default_loadbalancer_choice | default_loadbalancer, non_default_loadbalancer | default_loadbalancer |
Elecciones anidadas de single_lb_app (configuración ML):
El objeto single_lb_app tiene sus propios grupos oneOf requeridos. Establecer single_lb_app: \{\} sin estas elecciones anidadas provoca un error 400.
| Grupo de elección | Opciones | Predeterminado |
|---|---|---|
api_discovery_choice | disable_discovery, enable_discovery | disable_discovery |
ddos_detection_choice | disable_ddos_detection, enable_ddos_detection | disable_ddos_detection |
malicious_user_detection_choice | disable_malicious_user_detection, enable_malicious_user_detection | disable_malicious_user_detection |
Otras elecciones a nivel de LB (todas configuradas como deshabilitar/predeterminado):
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
Manejo de errores
Sección titulada «Manejo de errores»- 401 Unauthorized — El token de API es inválido o ha expirado. Regenere en Administración → Credenciales.
- 403 Forbidden — El token carece de permisos para el namespace. Verifique los enlaces de roles.
- 404 Not Found — El nombre del namespace o del objeto es incorrecto. Enumere los objetos con
GET /api/config/namespaces/\{namespace\}/\{object_type\}. - 409 Conflict — El objeto ya existe. Para los dominios protegidos, un
409con “domain already exists (in uriList)” significa que el dominio raíz ya está registrado en el tenant — esta es una condición de éxito, no un error. Para otros objetos, elimine primero o usePUTpara actualizar. - 422 Unprocessable Entity — La validación del esquema JSON falló. Causas comunes: elección
oneOffaltante, múltiples elecciones establecidas en el mismo grupo, tipo de campo incorrecto. Verifique el mensaje de error para el campo específico. - Límite de objetos agotado (código de error
8, mensaje"Object kind {kind} has exhausted limits({N})") — El tenant ha alcanzado un límite de cuota de objetos. La API devuelve HTTP 200 con un cuerpo JSON de error que contiene"code": 8, no HTTP 429. Puede verificar proactivamente la capacidad de cuota antes de encontrar este error usando la API de Uso de Cuota (GET /api/web/namespaces/system/quota/usage?namespace=system). El comportamiento depende del tipo de objeto:- Healthcheck (límite ~150): No bloqueante — omita el Paso 1 de la Fase 1 y cree el origin pool sin referencia a healthcheck. CSD no depende del monitoreo de salud.
- Endpoint (límite ~500): Bloqueante — los endpoints son sub-objetos creados dentro de los origin pools. Si se alcanza este límite, la creación del origin pool falla. Elimine origin pools no utilizados (lo que libera sus sub-objetos de endpoint) o contacte a su administrador para aumentar el límite del tenant.
- Origin pool: Bloqueante — elimine origin pools no utilizados o contacte a su administrador.
- HTTP load balancer: Bloqueante — elimine load balancers no utilizados o contacte a su administrador.
- Protected domain: Bloqueante — elimine dominios protegidos no utilizados o contacte a su administrador.
Resolución de problemas
Sección titulada «Resolución de problemas»Healthcheck no vinculado al origin pool
Sección titulada «Healthcheck no vinculado al origin pool»Si el Paso 2 de la Fase 1 (Verificar que el Healthcheck está vinculado) muestra un array vacío []:
- Elimine el origin pool:
DELETE /api/config/namespaces/{namespace}/origin_pools/{pool_name} - Verifique que el healthcheck existe:
GET /api/config/namespaces/{namespace}/healthchecks/{hc_name} - Vuelva a crear el origin pool con la referencia correcta al healthcheck
LB bloqueado en VIRTUAL_HOST_PENDING_A_RECORD
Sección titulada «LB bloqueado en VIRTUAL_HOST_PENDING_A_RECORD»Si el state del load balancer permanece VIRTUAL_HOST_PENDING_A_RECORD después del Paso 4 de la Fase 1:
-
Verifique que la zona DNS existe (solo DNS gestionado de F5 XC):
Ventana de terminal 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
404significa que la zona DNS no ha sido creada en F5 XC. -
Verifique
allow_http_lb_managed_records— si la zona existe pero el LB está pendiente, los registros gestionados pueden estar deshabilitados:Ventana de terminal 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'Si es
falseonull, habilítelo usando el comandoPUTen Fase 1 Paso 4, Opción A. -
DNS externo — si F5 XC no es autoritativo, cree los registros A y ACME CNAME manualmente en su proveedor DNS (consulte Fase 1 Paso 4, Opción B).
-
Verificar resolución — después de corregir el DNS, confirme:
Ventana de terminal dig +short xF5XC_DOMAINNAMEx ASi el registro A se resuelve, el LB pasa a
VIRTUAL_HOST_READY. Realice consultas cada 30 segundos, hasta 4 iteraciones (2 minutos en total). Si sigue siendoVIRTUAL_HOST_PENDING_A_RECORDdespués de 2 minutos, vuelva a verificar la propagación del DNS y reporte al operador.
Estado de CSD muestra isConfigured: false
Sección titulada «Estado de CSD muestra isConfigured: false»CSD debe estar habilitado a nivel de tenant. Contacte a su administrador de F5 XC para habilitar la Defensa del lado del cliente para su tenant. Esta es una configuración a nivel de tenant que no se puede configurar mediante API.
La inyección de JS no funciona
Sección titulada «La inyección de JS no funciona»- Verifique que CSD está habilitado a nivel de tenant (Fase 1 Paso 5)
- Confirme que el load balancer tiene
client_side_defenseestablecido en la especificación - Verifique que el endpoint de configuración JS devuelve un
scriptTag - Visite el dominio protegido en un navegador y vea el código fuente de la página para confirmar que el script está inyectado
El registro de dominio protegido devuelve 409
Sección titulada «El registro de dominio protegido devuelve 409»Un 409 con “domain already exists (in uriList)” significa que el dominio raíz ya está registrado en el tenant. Los dominios protegidos son de ámbito de tenant — no pertenecen a ningún namespace individual. Esta es una condición de éxito: el dominio ya está protegido y no se necesita ninguna acción adicional. Continúe con el Paso 7 de la Fase 1.
AutoCertDomainRateLimited
Sección titulada «AutoCertDomainRateLimited»Si el cert_state del LB HTTPS muestra AutoCertDomainRateLimited, significa que Let’s Encrypt ha aplicado límites de frecuencia a la emisión de certificados para este dominio. Esto es esperado en entornos de demostración donde la infraestructura se crea y destruye con frecuencia.
Impacto: El LB HTTPS no servirá tráfico hasta que se restablezca el límite de frecuencia (normalmente 1 hora). El LB HTTP no se ve afectado en absoluto — todo el tráfico de demostración continúa normalmente a través de http://.
Resolución: No se requiere ninguna acción para la progresión de la demostración. El LB HTTP (${F5XC_LB_NAME}-http) es el objetivo principal de la demostración y no depende del aprovisionamiento de certificados. Si se desea HTTPS, espere a que se restablezca el límite de frecuencia y el certificado se aprovisionará automáticamente.
Certificado bloqueado — Recreación limpia (opcional)
Sección titulada «Certificado bloqueado — Recreación limpia (opcional)»Cuando el certificado del LB HTTPS está bloqueado en DomainChallengePending o PreDomainChallengePending durante más de 15 minutos, la ruta de recuperación más rápida es eliminar el LB HTTPS y volver a crearlo. Con la zona DNS ya configurada (registros gestionados habilitados), la recreación limpia normalmente produce CertificateValid en 5–7 minutos — a menos que haya un límite de frecuencia.
- Elimine el HTTPS Load Balancer:
DELETE .../http_loadbalancers/${F5XC_LB_NAME}-https - Espere 30 segundos para la limpieza de la plataforma
- Vuelva a crear el HTTPS Load Balancer (Fase 1 Paso 3)
- Monitoree el estado del certificado (Fase 1 Paso 7) — espere
CertificateValiden 5–10 minutos
Referencia de OpenAPI
Sección titulada «Referencia de OpenAPI»La especificación canónica de la API de F5 Distributed Cloud está disponible en:
https://docs.cloud.f5.com/docs-v2/downloads/f5-distributed-cloud-open-api.zip
Este ZIP contiene las especificaciones de OpenAPI 3.0 para todos los grupos de API, incluyendo ves.io.schema.views.http_loadbalancer, ves.io.schema.healthcheck, ves.io.schema.origin_pool y ves.io.schema.shape.csd. Use estas especificaciones para validar los payloads JSON y descubrir campos adicionales.