Demonstração
Este guia orienta você por um exercício completo de Client-Side Defense no F5 Distributed Cloud usando a API — estruturado em quatro fases que um assistente de IA ou operador humano pode executar de ponta a ponta. Cada etapa inclui um comando curl pronto para execução com valores de placeholder que você pode personalizar usando o formulário no topo da página, um arquivo .env ou qualquer ferramenta de automação.
Fases do Exercício
Seção intitulada “Fases do Exercício”| Fase | Objetivo | Etapas |
|---|---|---|
| Fase 1 — Construir | Implantar e validar toda a infraestrutura CSD | Etapas 1–7 |
| Fase 2 — Atacar | Gerar tráfego de ataque simulado e confirmar que o CSD o detectou | Etapas 8–9 |
| Fase 3 — Mitigar | Prova antes/depois da mitigação — executar ataque, aplicar mitigações, re-executar ataque, comparar | Etapas 1–6 |
| Fase 4 — Desmontar | Remover todos os objetos de implantação após confirmação explícita | Desmontagem |
Verificação Pré-voo
Seção intitulada “Verificação Pré-voo”Antes de iniciar a Fase 1, verifique se o ambiente está limpo. Execute estas verificações de API para determinar se existem objetos remanescentes de uma execução 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 )}'Verificação para Pular Etapas
Seção intitulada “Verificação para Pular Etapas”Quando todos os objetos da Fase 1 existem (200) e você planeja pular para a Fase 2,
execute os comandos de verificação da Etapa 7 da Fase 1 para confirmar a saúde da infraestrutura
antes de pular. Use os comandos exatos de
Fase 1 — Etapa 7: Verificar:
- Resolução DNS:
dig +short xF5XC_DOMAINNAMEx A - Estado do HTTP LB:
GET .../http_loadbalancers/xF5XC_LB_NAMEx-httpdirecionado parajq '{state: .spec.state}'— deve mostrarVIRTUAL_HOST_READY - Configuração JS do CSD:
GET .../js_configuration— deve conterscriptTag - Status do CSD:
GET .../statusdirecionado parajq '{configured: .isConfigured, enabled: .isEnabled}'— ambos devem sertrue
Todas as verificações obrigatórias (DNS-1, LB-1, CSD-1, CSD-2) devem PASSAR antes de pular para a Fase 2. Se alguma verificação falhar, execute a Fase 1 a partir da etapa que falhou.
Matriz de Verificação de Prontidão
Seção intitulada “Matriz de Verificação de Prontidão”A verificação pré-voo acima verifica se o ambiente está limpo. A matriz de prontidão abaixo verifica se o ambiente é capaz — que todos os pré-requisitos, cotas, conectividade e serviços de plataforma estão configurados para uma demonstração bem-sucedida. Execute esta matriz antes de cada reunião como parte do estágio de Preparação.
Cada verificação tem um ID de teste, um nível (T0–T5), critérios PASS/FAIL/WARN e um caminho de remediação. Os níveis são sequenciais — um FAIL em um nível anterior bloqueia os níveis posteriores de serem executados.
Resumo dos Níveis
Seção intitulada “Resumo dos Níveis”| Nível | Categoria | Bloqueia a Demo? | Propósito |
|---|---|---|---|
| T0 | Conectividade e Autenticação | Sim | Conseguimos alcançar a plataforma e autenticar? |
| T1 | Cotas e Capacidade | Sim (se no limite) | Há espaço para criar objetos da demo? |
| T2 | Pré-requisitos da Plataforma | Sim | Os serviços em nível de tenant estão configurados? |
| T3 | Saúde da Origem | Aviso | A aplicação backend está respondendo? |
| T4 | Ambiente Limpo | Auto-remediar | Há objetos remanescentes de uma execução anterior? |
| T5 | Prontidão de Certificado | Informativo | O HTTPS funcionará ou devemos planejar apenas HTTP? |
T0: Conectividade e Autenticação
Seção intitulada “T0: Conectividade e Autenticação”Estas verificações confirmam que o host de execução pode alcançar a API do F5 XC e que as credenciais são válidas.
PF-T0-1: Conectividade da API
Seção intitulada “PF-T0-1: Conectividade da 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: Acesso ao Namespace
Seção intitulada “PF-T0-2: Acesso ao Namespace”HTTP_CODE=$(curl -s -o /dev/null -w '%\{http_code\}' \ -H "Authorization: APIToken xF5XC_API_TOKENx" \ "xF5XC_API_URLx/api/config/namespaces/xF5XC_NAMESPACEx/http_loadbalancers")echo "{\"http_code\": $HTTP_CODE}" | jq '{ check: "PF-T0-2", http_code: .http_code, status: ( if .http_code == 200 then "PASS" elif .http_code == 404 then "WARN" else "FAIL" end ), detail: ( if .http_code == 200 then "Token has namespace access" elif .http_code == 403 then "Token lacks permissions for namespace — check role bindings" elif .http_code == 404 then "Namespace does not exist — will be created in Phase 1 Step 0" else "Unexpected HTTP \(.http_code)" end )}'PF-T0-3: Acesso à API do CSD
Seção intitulada “PF-T0-3: Acesso à API do 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 Permissões RBAC
Seção intitulada “PF-T0-4: Matriz de Permissões RBAC”Sondas não destrutivas testam permissões de leitura e escrita para cada tipo de objeto que a demo necessita. A leitura é testada via GET em endpoints de listagem. A escrita é testada via DELETE em objetos reconhecidamente inexistentes — a API retorna 403 se o RBAC nega a operação, ou 404 se a operação é permitida mas o objeto não existe. Esta técnica com zero efeitos colaterais evita a criação de objetos de sondagem temporários.
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: Cotas e Capacidade
Seção intitulada “T1: Cotas e Capacidade”Estas verificações consultam a API de Uso de Cotas do tenant para determinar limites, uso atual e capacidade restante para cada tipo de objeto que a demo necessita. Isso substitui testes de sondagem e exclusão por uma única chamada de API somente leitura que reporta números exatos.
PF-T1-0: Portão de Uso de Cotas
Seção intitulada “PF-T1-0: Portão de Uso de Cotas”Consulte o endpoint de uso de cotas em nível de tenant e compute um status determinístico PASS/WARN/FAIL para cada tipo de objeto que a demo necessita. Este endpoint requer o namespace system. Uma única chamada de API verifica todas as cotas em nível de plataforma de uma vez.
O portão define um array demo_needs que especifica quantos de cada tipo de objeto a demo consumirá, se o tipo é obrigatório e o mínimo necessário para a demo prosseguir. O filtro jq compara remaining contra needed e computa o campo status deterministicamente — nenhuma interpretação do operador é necessária.
# 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.jsonSaída do portão — o campo gate é o veredito único determinístico:
PASS— todos os tipos de objeto têmremaining >= needed. A demo pode prosseguir.WARN— pelo menos um tipo tem capacidade reduzida mas o mínimo para prosseguir é atendido (ex.: apenas 1 slot de LB disponível em vez de 2, ou cota de healthcheck esgotada). A demo pode prosseguir com limitações.FAIL— pelo menos um tipo obrigatório temremaining < min_proceed. A demo não pode prosseguir até que cotas sejam liberadas.
Exemplo de saída (WARN — endpoint no limite, healthcheck quase cheio):
{ "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 | Ação |
|---|---|
| PASS | Prossiga para PF-T1-4 (verificação de domínio protegido), depois T2 |
| WARN | Anote as limitações no relatório de prontidão, prossiga com capacidade reduzida |
| FAIL | Pare — reporte quais tipos estão esgotados e as etapas de remediação abaixo |
Remediação por tipo:
| Tipo | Remediação |
|---|---|
healthcheck | Exclua healthchecks não utilizados para liberar capacidade. A demo prossegue sem healthcheck (CSD não requer um). |
origin_pool | Exclua origin pools não utilizados ou entre em contato com seu administrador para aumentar o limite do tenant. |
endpoint | Exclua origin pools não utilizados em outros namespaces para liberar capacidade de endpoints (endpoints são sub-objetos de origin pools), ou entre em contato com seu administrador. |
http_loadbalancer | Exclua load balancers não utilizados ou entre em contato com seu administrador. Se apenas 1 slot estiver disponível, o HTTP LB (primário) será criado mas o HTTPS LB (secundário) será pulado. |
PF-T1-4: Cota de Domínio Protegido
Seção intitulada “PF-T1-4: Cota de Domínio Protegido”Domínios protegidos do CSD não aparecem na API de Uso de Cotas da plataforma. Use uma verificação baseada em sondagem: crie e imediatamente exclua um domínio protegido de sondagem.
# 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: Verificações de Cotas Baseadas em Sondagem
Seção intitulada “Alternativa: Verificações de Cotas Baseadas em Sondagem”Se PF-T1-0 falhar (a API de Uso de Cotas retorna 403, 404 ou um formato inesperado), utilize verificações alternativas de sondagem e exclusão para cotas de healthcheck, origin pool, endpoint e load balancer. Estas verificações criam um objeto temporário e o excluem imediatamente — se a criação retornar código de erro 8 com “exhausted limits”, a cota está cheia.
Cada sondagem alternativa usa o mesmo padrão: criar um objeto temporário, computar um status determinístico a partir da resposta, depois excluir a sondagem. O campo status é PASS se o objeto foi criado (.metadata.name presente), WARN ou FAIL se código de erro 8 (limites esgotados), dependendo se o tipo é obrigatório.
Sondagem de healthcheck (WARN se esgotado — healthchecks são opcionais 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/nullSondagem de origin pool e endpoint (FAIL se esgotado — ambos são obrigatórios):
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/nullSondagem de HTTP load balancer (FAIL se esgotado — LBs são obrigatórios):
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: Pré-requisitos da Plataforma
Seção intitulada “T2: Pré-requisitos da Plataforma”Estas verificações validam serviços em nível de tenant dos quais a demo depende.
PF-T2-1: Status do Tenant CSD
Seção intitulada “PF-T2-1: Status do Tenant CSD”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 Existe
Seção intitulada “PF-T2-2: Zona DNS Existe”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 Gerenciados Habilitados
Seção intitulada “PF-T2-3: Registros DNS Gerenciados Habilitados”Execute apenas se PF-T2-2 retornou 200 (zona DNS do F5 XC existe).
Verificar estado atual:
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-remediar se necessário: Se o status for WARN E PF-T2-4 mostrar nameservers do F5 XC (ns1.f5clouddns.com, ns2.f5clouddns.com), habilite automaticamente os registros gerenciados usando 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 .Depois verifique novamente para confirmar que a atualização teve efeito:
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 | Autoridade DNS | Status | Remediação |
|---|---|---|---|
true | Qualquer | PASS | Registros DNS gerenciados pelo LB serão auto-criados |
false/null | F5 XC | Auto-remediar | Habilitar via GET+PUT, verificar, reportar resultado |
false/null | Externo | INFO | Registros gerenciados não aplicáveis para DNS externo — Fase 1 Etapa 4 usará Opção B (criação manual de registro) |
| Auto-remediação falhou | F5 XC | FAIL | Token pode não ter acesso de escrita ao namespace system — entre em contato com o administrador do tenant |
PF-T2-4: Autoridade de Nameserver DNS
Seção intitulada “PF-T2-4: Autoridade de Nameserver 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: Saúde da Origem
Seção intitulada “T3: Saúde da Origem”Estas verificações validam se a aplicação backend está acessível.
Verificação de condição de pular: Compute se o IP de origem é um endereço TEST-NET RFC 5737 antes de executar testes de conectividade:
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 for SKIP, registre PF-T3-1 e PF-T3-2 como SKIP e prossiga para T4. Caso contrário, execute as verificações abaixo.
PF-T3-1: Conectividade do Servidor de Origem
Seção intitulada “PF-T3-1: Conectividade do Servidor de Origem”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: Origem Serve Conteúdo HTML
Seção intitulada “PF-T3-2: Origem Serve Conteúdo HTML”Execute apenas se PF-T3-1 retornou um status 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 | Status | Remediação |
|---|---|---|
PASS: HTML content | PASS | Origem serve páginas HTML (necessário para injeção de JS do CSD) |
WARN: No HTML detected | WARN | Origem pode ser um serviço apenas API ou retornando não-HTML — a injeção de JS do CSD requer respostas de página HTML |
T4: Ambiente Limpo
Seção intitulada “T4: Ambiente Limpo”Estas verificações validam que nenhum objeto de configuração nomeado do F5 XC permanece de uma execução anterior da demo — HTTP load balancers, HTTPS load balancers, origin pools, healthchecks, domínios protegidos e domínios mitigados. T4 trata de limpeza em nível de objetos: se objetos de API que conflitariam com a criação da Fase 1 ainda existem. Não testa endereços IP, conectividade de rede ou saúde da origem (essas preocupações pertencem ao T3).
Execute os seis comandos de pré-voo da seção Verificação Pré-voo acima. Aplique a Lógica de Decisão para determinar os próximos passos. Se objetos existirem, a auto-desmontagem é realizada durante o estágio de Preparação (sem necessidade de confirmação).
Também verifique e exclua objetos de sondagem obsoletos de execuções de pré-voo anteriores interrompidas. Estas sondagens são criadas apenas quando a API de Uso de Cotas está indisponível e as verificações alternativas baseadas em sondagem foram usadas, ou para a sondagem de domínio protegido (PF-T1-4) que sempre usa verificação baseada em sondagem:
# 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 retorna 200 ({} vazio) se o objeto existia, ou 404 se não — ambos são esperados.
T5: Prontidão de Certificado
Seção intitulada “T5: Prontidão de Certificado”Estas verificações avaliam se o HTTPS funcionará ou se a demo deve planejar apenas HTTP.
PF-T5-1: Histórico Recente de Emissão de Certificado
Seção intitulada “PF-T5-1: Histórico Recente de Emissão de Certificado”Verifique se um certificado Let’s Encrypt foi emitido recentemente para o domínio da demo. Ciclos frequentes de criação/destruição podem esgotar o limite semanal de taxa (5 certificados duplicados por semana por domínio).
PF-T5-2: Estado do Certificado do HTTPS LB Existente
Seção intitulada “PF-T5-2: Estado do Certificado do HTTPS LB Existente”Execute apenas se um HTTPS LB existe de uma execução anterior (PF-T4 encontrou 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 do Relatório de Prontidão
Seção intitulada “Formato do Relatório de Prontidão”Após executar todos os níveis, apresente um relatório de prontidão consolidado:
## Prontidão da Demo: PRONTO / NÃO PRONTO / PRONTO COM AVISOS
### T0: Conectividade e Autenticação| Verificação | Resultado | Status ||---|---|---|| PF-T0-1: Conectividade da API | 200 | PASS || PF-T0-2: Acesso ao Namespace | 200 | PASS || PF-T0-3: Acesso à API do CSD | 200 | PASS |
### T1: Cotas e Capacidade| Verificação | Tipo | Limite | Uso | Restante | Necessário | Status ||---|---|---|---|---|---|---|| PF-T1-0: Portão de Uso de Cotas | `healthcheck` | 150 | 148 | 2 | 1 | PASS || PF-T1-0: Portão de Uso de Cotas | `origin_pool` | unlimited | 420 | unlimited | 1 | PASS || PF-T1-0: Portão de Uso de Cotas | `endpoint` | 500 | 498 | 2 | 1 | PASS || PF-T1-0: Portão de Uso de Cotas | `http_loadbalancer` | unlimited | 116 | unlimited | 2 | PASS || PF-T1-0: Portão de Uso de Cotas | **portão** | — | — | — | — | **PASS** || PF-T1-4: Domínio Protegido | — | — | — | — | 1 | PASS (sondagem) |
### T2: Pré-requisitos da Plataforma| Verificação | Resultado | Status ||---|---|---|| PF-T2-1: Status do Tenant CSD | configurado + habilitado | PASS || PF-T2-2: Zona DNS Existe | 200 | PASS || PF-T2-3: Registros DNS Gerenciados | true | PASS || PF-T2-4: Autoridade de Nameserver DNS | f5clouddns.com | PASS |
### T3: Saúde da Origem| Verificação | Resultado | Status ||---|---|---|| PF-T3-1: Conectividade da Origem | Endereço TEST-NET (192.0.2.1) | SKIP || PF-T3-2: Conteúdo HTML | Endereço TEST-NET | SKIP |
### T4: Ambiente Limpo| Verificação | Resultado | Status ||---|---|---|| HTTP LB | 404 | PASS || HTTPS LB | 404 | PASS || Origin Pool | 404 | PASS || Healthcheck | 404 | PASS || Domínios Protegidos | 0 | PASS || Domínios Mitigados | 0 | PASS |
### T5: Prontidão de Certificado| Verificação | Resultado | Status ||---|---|---|| PF-T5-2: Estado do Cert | SKIP (sem HTTPS LB) | INFO |
### Avisos- (liste quaisquer itens WARN ou INFO com contexto)Regras de status geral:
| Condição | Status |
|---|---|
| Todas as verificações T0–T4 PASS | PRONTO |
| Todas as verificações T0–T4 PASS mas T3 ou T5 têm WARN/INFO | PRONTO COM AVISOS |
| Qualquer verificação T0, T1 ou T2 é FAIL | NÃO PRONTO — resolver antes de prosseguir |
| T4 tem objetos remanescentes | Auto-remediar (desmontagem), depois re-verificar |
Protocolo de Execução para Assistente de IA
Seção intitulada “Protocolo de Execução para Assistente de IA”Esta seção define um fluxo de trabalho determinístico para assistentes de IA (Claude Code, Copilot, etc.) executando as etapas de automação da API. Seguir este protocolo elimina adivinhações — cada ponto de decisão tem um caminho de resolução definido.
Protocolo de Resolução de Variáveis
Seção intitulada “Protocolo de Resolução de Variáveis”Resolva cada variável nesta ordem exata. Pare na primeira fonte que fornecer um valor não-placeholder:
- Verificar arquivo
.env— procure por.envna raiz do repositório. Se existir, analise todos os paresKEY=VALUE. - Verificar ambiente shell — execute
env | grep F5XC_para encontrar quaisquer valores já exportados na sessão atual. - Identificar valores ausentes — compare os valores resolvidos contra a tabela de obrigatórios/opcionais abaixo. Um valor está “ausente” se estiver inexistente, vazio ou ainda definido como um valor padrão placeholder (ex.:
example-api-token,example-tenant,example-namespace,app.example.com,user@example.com). - Solicitar ao operador humano — para cada variável obrigatória ausente, pergunte ao operador o valor. Não prossiga até que todas as variáveis obrigatórias estejam resolvidas.
- Aplicar padrões — para cada variável opcional ausente, use o padrão da tabela abaixo sem solicitar.
String vazia = ausente: Uma variável exportada com valor vazio (ex.:
F5XC_HC_NAME="") é tratada da mesma forma que uma variável não definida — aplique o padrão. Use expansão de parâmetro shell (${F5XC_HC_NAME:-csd-hc}) para aplicar padrões em um único passo.
- Exibir confirmação — mostre a tabela final de variáveis resolvidas ao operador e aguarde aprovação antes de executar qualquer chamada de API.
Substituição no estágio de Preparação: Durante o Estágio 1 Preparação, pule a espera no passo 6. Exiba a tabela de variáveis resolvidas para registro, depois prossiga imediatamente. Os passos 1–5 ainda se aplicam — se alguma variável obrigatória estiver ausente após verificar
.enve shell, pare e reporte as variáveis ausentes.
Variáveis Obrigatórias vs Opcionais
Seção intitulada “Variáveis Obrigatórias vs Opcionais”| Variável | Obrigatória | Padrão | Placeholder (tratar como ausente) |
|---|---|---|---|
F5XC_API_TOKEN | Sim | — | example-api-token |
F5XC_API_URL | Sim | — | https://example-tenant.console.ves.volterra.io |
F5XC_NAMESPACE | Sim | — | example-namespace |
F5XC_DOMAINNAME | Sim | — | app.example.com |
F5XC_ROOT_DOMAIN | Sim | — | example.com |
F5XC_LB_NAME | Sim | — | example-lb-name, example-lb |
F5XC_EMAIL | Sim | — | 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 Execução
Seção intitulada “Modos de Execução”O assistente de IA opera em um de três modos durante a demo:
| Modo | Quando ativo | Comportamento |
|---|---|---|
| Normal | Padrão durante Preparação, Execução, Desmontagem | Apenas comandos documentados literalmente |
| Debug | Auto-ativa em caso de falha | Resolução criativa de problemas, atualizar documentação |
| Q&A | Durante estágio de Q&A | Improvisacional — comandos ad-hoc permitidos para responder perguntas da audiência |
Modo normal (padrão):
- Cada chamada de API, consulta de verificação e comando shell deve vir literalmente dos arquivos de fase (Fase 1–4) ou da seção de Verificação Pré-voo acima
- Substitua apenas placeholders
xTOKENxcom valores de variáveis resolvidos - Não construa endpoints de API, filtros jq ou comandos cURL a partir de conhecimento geral ou inferência
- Se um comando necessário não estiver documentado, pare e reporte ao operador: “Esta etapa de verificação não está coberta pela documentação da fase”
Modo debug (auto-ativa em caso de falha):
- Ativa automaticamente quando um comando documentado produz um resultado inesperado: resposta HTTP não-2xx, erro de parse jq, timeout de comando ou corpo de resposta que contradiz a tabela de evidências
- No modo debug, o assistente de IA pode construir comandos diagnósticos, inspecionar respostas brutas da API, testar variações de endpoint e usar resolução criativa de problemas para encontrar a causa raiz
- Prefixe toda saída de debug com
[DEBUG]para que o operador possa distinguir atividade diagnóstica da execução normal - Documente o que você aprender: após resolver um problema, atualize o
arquivo de fase relevante ou seção de resolução de problemas com:
- O cenário de falha (o que deu errado)
- O que foi tentado e NÃO funcionou (para que execuções futuras não repitam)
- A resolução funcional (o comando ou correção que resolveu)
- O objetivo do modo debug é eliminar a si mesmo — cada sessão de debug deve produzir uma atualização de documentação que torne a próxima execução totalmente determinística
- Uma vez que a documentação esteja atualizada e o problema resolvido, retorne ao modo normal e retome a partir da última etapa documentada bem-sucedida
- Se o modo debug não conseguir resolver o problema, reporte as descobertas ao operador e pare — não continue para a próxima fase
Modo Q&A (durante estágio de Q&A):
- Ativo apenas durante o estágio de Q&A da reunião, após a conclusão da demo
- O assistente de IA pode construir chamadas de API ad-hoc, executar comandos diagnósticos, navegar para páginas não roteirizadas e modificar o ambiente de demo ao vivo para ilustrar respostas às perguntas da audiência
- Sem prefixo
[DEBUG]— este é comportamento improvisacional intencional, não recuperação de erros - Usa a seção de Expertise em Produto CSD em
DEMO_EXECUTOR.mdcomo a base de conhecimento para perguntas sobre o produto
Gerenciamento de Contexto do Navegador
Seção intitulada “Gerenciamento de Contexto do Navegador”O acúmulo de initScript é uma fonte comum de falhas na demo. Cada
chamada navigate_page com um parâmetro initScript adiciona o script a
uma lista persistente que executa em cada carregamento de documento subsequente. Siga
estas regras:
- Sempre navegue para
about:blankantes de qualquer navegação cominitScriptpara limpar scripts acumulados de execuções anteriores - Use
new_pagecomisolatedContextao alternar entre fases da demo (ex.: Fase 2 → Fase 3) para garantir um estado de navegador completamente limpo - Recuperação de páginas não responsivas — se timeouts de
take_screenshotoutake_snapshotocorrerem, o contexto do navegador está com recursos esgotados. Usenew_pagecomisolatedContextpara criar um contexto novo, depois tente novamente a partir da etapa de navegaçãoabout:blank - Consulte os avisos da simulação de ataque da Fase 2 para orientação detalhada sobre falhas transitórias de origem e recuperação de esgotamento de recursos
Protocolo de Exibição de Evidências
Seção intitulada “Protocolo de Exibição de Evidências”Após cada chamada de API, o assistente de IA deve apresentar evidências estruturadas ao operador humano usando este formato:
Etapas de criação (POST):
| Campo | Valor | Status |
|---|---|---|
| Status HTTP | 200 | PASS |
| Nome do Objeto | csd-origin | — |
| Propriedade Chave | (extraída via jq) | — |
Após cada etapa de criação, execute um GET para confirmar que o objeto existe e exiba suas propriedades chave. Se o GET retornar 404, reporte FAIL e pare.
Etapas de verificação (GET/dig):
| Teste | Resultado | Status |
|---|---|---|
| DNS-1: Registro A | 198.51.100.10 | PASS |
| LB-1: Estado do HTTP LB | VIRTUAL_HOST_READY | PASS |
| LB-2: Estado do HTTPS LB | VIRTUAL_HOST_READY | INFO (opcional) |
| TLS-1: Estado do Cert | CertificateValid | INFO (opcional) |
| CSD-1: Tag JS | scriptTag presente | PASS |
Referencie os IDs de caso de teste de Diagnósticos e Verificação (DNS-1, TLS-1, LB-1, CSD-1, etc.) como o padrão de verificação para cada camada.
Resumo do Fluxo de Execução
Seção intitulada “Resumo do Fluxo de Execução”A execução de fases é sequencial e bloqueada: cada fase deve atingir PASS em todas as verificações obrigatórias antes que a próxima fase comece. A demo segue um ciclo de vida de reunião em quatro estágios — consulte a seção Estágios da Reunião em DEMO_EXECUTOR.md para frases-gatilho e regras comportamentais.
O assistente de IA segue esta sequência:
- Preparar — resolver variáveis, executar verificações pré-voo, confirmar ambiente limpo (pode ser executado separadamente antes da reunião)
- Introdução — o SE se apresenta e declara os objetivos de resultado (visibilidade de ameaças client-side, conformidade PCI, detecção em tempo real)
- Executar Fase 1 (Etapas 1–7) — criação e verificação de infraestrutura; todas as verificações da Fase 1 devem PASSAR antes de prosseguir
- Executar Fase 2 (Etapas 8–9) — simulação de ataque e verificação de detecção via API; assistentes de IA com automação de navegador executam as etapas do navegador diretamente, operadores sem ferramentas de navegador as realizam manualmente
- Executar Fase 3 — aplicar mitigação para todos os domínios detectados, re-executar ataque, verificar se o bloqueio é eficaz
- Conclusão — reafirmar objetivos de resultado, resumir evidências de cada fase, destacar detecções e mitigações principais
- Q&A — estágio improvisacional, demo permanece ao vivo, SE responde perguntas da audiência e faz perguntas de retorno
- Desmontagem (pós-reunião) — Fase 4, confirmação explícita do operador necessária, excluir todos os objetos na ordem inversa de dependência, confirmar ambiente limpo
Se alguma etapa retornar FAIL, pare e reporte a falha com o link da seção de resolução de problemas relevante antes de continuar.
Pré-requisitos
Seção intitulada “Pré-requisitos”- Um token de API do F5 XC — gere um em Administração → Credenciais → Credenciais de API
curlejqinstalados localmente- Um namespace com permissões para criar healthchecks, origin pools e HTTP load balancers
Configuração do Ambiente
Seção intitulada “Configuração do Ambiente”Crie um arquivo .env com os valores do seu ambiente. Um modelo é fornecido no repositório:
cp .env.example .envEdite .env com seus valores reais:
# 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=3000Carregue o arquivo para inserir as variáveis na sua sessão shell:
set -a && source .env && set +aCada placeholder xTOKENx nos comandos curl mapeia diretamente para uma variável de ambiente — por exemplo, xF5XC_API_TOKENx corresponde a $F5XC_API_TOKEN. Você pode substituir estes valores usando o formulário interativo no topo da página, ou deixar um assistente de IA como o Claude Code ler seu .env e construir os comandos para você.
Tokens de Placeholder
Seção intitulada “Tokens de Placeholder”| Token | Padrão | Descrição |
|---|---|---|
xF5XC_API_URLx | https://example-tenant.console.ves.volterra.io | URL da API do Console XC |
xF5XC_API_TOKENx | example-api-token | Token de credencial da API |
xF5XC_EMAILx | user@example.com | Endereço de email para notificações CSD |
xF5XC_NAMESPACEx | example-namespace | Namespace |
xF5XC_LB_NAMEx | example-lb | Nome base do HTTP Load Balancer (cria ${name}-http e ${name}-https) |
xF5XC_DOMAINNAMEx | app.example.com | FQDN a proteger |
xF5XC_ROOT_DOMAINx | example.com | Domínio raiz (eTLD+1) para domínio protegido CSD |
xF5XC_ORIGIN_POOLx | csd-origin | Nome do origin pool |
xF5XC_ORIGIN_IPx | 44.232.69.192 | IP do servidor de origem |
xF5XC_ORIGIN_PORTx | 3000 | Porta do servidor de origem |
xF5XC_HC_NAMEx | csd-hc | Nome do healthcheck |
Referência de Automação
Seção intitulada “Referência de Automação”Esta seção resume o fluxo de trabalho completo do exercício para scripting ou automação.
Início Rápido
Seção intitulada “Início Rápido”- Clone o repositório e copie o modelo de ambiente:
cp .env.example .env - Edite
.envcom a URL do seu tenant, token de API, namespace e valores de domínio - Carregue o ambiente:
set -a && source .env && set +a - Execute cada fase na ordem, verificando PASS em cada bloco de Evidências antes de prosseguir para a próxima fase
Resolução de Variáveis
Seção intitulada “Resolução de Variáveis”Os valores são resolvidos usando o protocolo determinístico definido no Protocolo de Execução para Assistente de IA:
- Arquivo
.env— analise paresKEY=VALUEda raiz do repositório - Ambiente shell — verifique
env | grep F5XC_para valores exportados - Detecção de placeholder — sinalize qualquer valor que corresponda a um padrão placeholder (ex.:
example-api-token,example-namespace) como ausente - Solicitar operador — pergunte cada variável obrigatória ausente
- Aplicar padrões — use padrões incorporados para variáveis opcionais ausentes
- Confirmar — exiba a tabela de variáveis resolvidas e aguarde aprovação do operador
Ordem de Execução
Seção intitulada “Ordem de Execução”- Fase 1 — Construir: Implantar infraestrutura (healthcheck, origin pool, HTTP LB + HTTPS LB), configurar DNS, habilitar CSD, registrar domínio protegido, verificar todos os componentes. O HTTP LB é o alvo principal da demo; o HTTPS LB é opcional.
- Fase 2 — Atacar: Executar a simulação de ataque em um navegador usando URLs
http://, aguardar 5–10 minutos, verificar detecções via API (/scripts,/detected_domains,/formFields) - Fase 3 — Mitigar: Confirmar baseline limpo, executar ataque (prova antes), POST de cada domínio para
/mitigated_domains, verificar mitigações aplicadas, re-executar ataque usando URLshttp://(prova depois), apresentar comparação antes/depois - Fase 4 — Desmontar (requer confirmação humana explícita): Excluir HTTPS LB → HTTP LB → origin pool → limpeza da zona DNS (apenas registros manuais) → healthcheck → domínio protegido. Não exclua a zona DNS.
Variáveis
Seção intitulada “Variáveis”| Token | Descrição | Padrão |
|---|---|---|
xF5XC_API_URLx | URL da API do Console XC | https://example-tenant.console.ves.volterra.io |
xF5XC_API_TOKENx | Token de credencial da API | (fornecido pelo usuário) |
xF5XC_EMAILx | Email para notificação CSD | user@example.com |
xF5XC_NAMESPACEx | Namespace | example-namespace |
xF5XC_LB_NAMEx | Nome base do HTTP Load Balancer (cria ${name}-http e ${name}-https) | example-lb |
xF5XC_DOMAINNAMEx | FQDN a proteger | app.example.com |
xF5XC_ROOT_DOMAINx | Domínio raiz (eTLD+1) | example.com |
xF5XC_ORIGIN_POOLx | Nome do origin pool | csd-origin |
xF5XC_ORIGIN_IPx | IP do servidor de origem | 44.232.69.192 |
xF5XC_ORIGIN_PORTx | Porta do servidor de origem | 3000 |
xF5XC_HC_NAMEx | Nome do healthcheck | csd-hc |
Grupos de Escolha oneOf
Seção intitulada “Grupos de Escolha oneOf”A especificação do HTTP Load Balancer usa grupos de escolha oneOf onde exatamente uma opção deve ser definida por grupo. Definir zero ou mais de uma opção em um grupo causa um erro 422.
Escolhas principais relacionadas ao CSD:
| Grupo de Escolha | Opções | Padrão CSD |
|---|---|---|
client_side_defense_choice | client_side_defense, disable_client_side_defense | client_side_defense |
java_script_choice (aninhado no CSD) | disable_js_insert, js_insert_all_pages, js_insert_all_pages_except, js_insertion_rules | js_insert_all_pages |
Escolha de tipo de listener (HTTP vs HTTPS):
A demo cria dois LBs com configurações de listener diferentes:
| LB | Escolha de Listener | Configuração |
|---|---|---|
${F5XC_LB_NAME}-http (primário) | http | "http": { "dns_volterra_managed": true, "port": 80 } |
${F5XC_LB_NAME}-https (secundário) | https_auto_cert | "https_auto_cert": { "http_redirect": true, "port": 443, ... } |
As chaves http e https_auto_cert são mutuamente exclusivas — cada LB usa exatamente uma.
Escolhas aninhadas de auto-cert HTTPS (apenas LB secundário):
| Grupo de Escolha | Opções | Padrão |
|---|---|---|
| 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 |
Escolhas aninhadas de single_lb_app (configuração ML):
O objeto single_lb_app tem seus próprios grupos oneOf obrigatórios. Definir single_lb_app: \{\} sem essas escolhas aninhadas causa um erro 400.
| Grupo de Escolha | Opções | Padrão |
|---|---|---|
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 |
Outras escolhas em nível de LB (todas definidas como desabilitar/padrão):
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
Tratamento de Erros
Seção intitulada “Tratamento de Erros”- 401 Unauthorized — token de API é inválido ou expirou. Regenere em Administração → Credenciais.
- 403 Forbidden — token não tem permissões para o namespace. Verifique os role bindings.
- 404 Not Found — namespace ou nome do objeto está incorreto. Liste objetos com
GET /api/config/namespaces/\{namespace\}/\{object_type\}. - 409 Conflict — objeto já existe. Para domínios protegidos, um
409com “domain already exists (in uriList)” significa que o domínio raiz já está registrado no tenant — esta é uma condição de sucesso, não um erro. Para outros objetos, exclua primeiro ou usePUTpara atualizar. - 422 Unprocessable Entity — validação de schema JSON falhou. Causas comuns: escolha
oneOfausente, múltiplas escolhas definidas no mesmo grupo, tipo de campo errado. Verifique a mensagem de erro para o campo específico. - Limite de objetos esgotado (código de erro
8, mensagem"Object kind {kind} has exhausted limits({N})") — tenant atingiu um limite de cota de objetos. A API retorna HTTP 200 com um corpo JSON de erro contendo"code": 8, não HTTP 429. Você pode verificar proativamente a capacidade de cota antes de encontrar este erro usando a API de Uso de Cotas (GET /api/web/namespaces/system/quota/usage?namespace=system). O comportamento depende do tipo de objeto:- Healthcheck (limite ~150): Não bloqueante — pule a Fase 1 Etapa 1 e crie o origin pool sem referência de healthcheck. CSD não depende de monitoramento de saúde.
- Endpoint (limite ~500): Bloqueante — endpoints são sub-objetos criados dentro de origin pools. Se este limite for atingido, a criação do origin pool falha. Exclua origin pools não utilizados (o que libera seus sub-objetos endpoint) ou entre em contato com seu administrador para aumentar o limite do tenant.
- Origin pool: Bloqueante — exclua origin pools não utilizados ou entre em contato com seu administrador.
- HTTP load balancer: Bloqueante — exclua load balancers não utilizados ou entre em contato com seu administrador.
- Domínio protegido: Bloqueante — exclua domínios protegidos não utilizados ou entre em contato com seu administrador.
Resolução de Problemas
Seção intitulada “Resolução de Problemas”Healthcheck Não Vinculado ao Origin Pool
Seção intitulada “Healthcheck Não Vinculado ao Origin Pool”Se a Fase 1 Etapa 2 (Verificar Healthcheck está Vinculado) mostrar um array vazio []:
- Exclua o origin pool:
DELETE /api/config/namespaces/{namespace}/origin_pools/{pool_name} - Verifique se o healthcheck existe:
GET /api/config/namespaces/{namespace}/healthchecks/{hc_name} - Recrie o origin pool com a referência correta de healthcheck
LB Preso em VIRTUAL_HOST_PENDING_A_RECORD
Seção intitulada “LB Preso em VIRTUAL_HOST_PENDING_A_RECORD”Se o state do load balancer permanecer VIRTUAL_HOST_PENDING_A_RECORD após a Fase 1 Etapa 4:
-
Verifique se a zona DNS existe (apenas DNS gerenciado pelo 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'Um
404significa que a zona DNS não foi criada no F5 XC. -
Verifique
allow_http_lb_managed_records— se a zona existe mas o LB está pendente, registros gerenciados podem estar desabilitados: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
falseounull, habilite usando o comandoPUTna Fase 1 Etapa 4, Opção A. -
DNS Externo — se o F5 XC não é autoritativo, crie os registros A e CNAME ACME manualmente no seu provedor DNS (consulte Fase 1 Etapa 4, Opção B).
-
Verifique a resolução — após corrigir o DNS, confirme:
Terminal window dig +short xF5XC_DOMAINNAMEx ASe o registro A resolver, o LB transiciona para
VIRTUAL_HOST_READY. Consulte a cada 30 segundos, até 4 iterações (2 minutos no total). Se ainda estiverVIRTUAL_HOST_PENDING_A_RECORDapós 2 minutos, re-verifique a propagação DNS e reporte ao operador.
Status do CSD Mostra isConfigured: false
Seção intitulada “Status do CSD Mostra isConfigured: false”O CSD deve ser habilitado no nível do tenant. Entre em contato com seu administrador F5 XC para habilitar o Client-Side Defense para seu tenant. Esta é uma configuração em nível de tenant que não pode ser configurada via API.
Injeção JS Não Funcionando
Seção intitulada “Injeção JS Não Funcionando”- Verifique se o CSD está habilitado no nível do tenant (Fase 1 Etapa 5)
- Confirme que o load balancer tem
client_side_defensedefinido na especificação - Verifique se o endpoint de configuração JS retorna um
scriptTag - Visite o domínio protegido em um navegador e visualize o código fonte da página para confirmar que o script está injetado
Registro de Domínio Protegido Retorna 409
Seção intitulada “Registro de Domínio Protegido Retorna 409”Um 409 com “domain already exists (in uriList)” significa que o domínio raiz já está registrado no tenant. Domínios protegidos são com escopo de tenant — não pertencem a nenhum namespace individual. Esta é uma condição de sucesso: o domínio já está protegido e nenhuma ação adicional é necessária. Continue para a Fase 1 Etapa 7.
AutoCertDomainRateLimited
Seção intitulada “AutoCertDomainRateLimited”Se o cert_state do HTTPS LB mostrar AutoCertDomainRateLimited, isso significa que o Let’s Encrypt limitou a emissão de certificados para este domínio. Isso é esperado em ambientes de demo onde a infraestrutura é frequentemente criada e destruída.
Impacto: O HTTPS LB não servirá tráfego até que o limite de taxa seja resetado (tipicamente 1 hora). O HTTP LB não é afetado de forma alguma — todo o tráfego da demo prossegue normalmente via http://.
Resolução: Nenhuma ação necessária para progressão da demo. O HTTP LB (${F5XC_LB_NAME}-http) é o alvo principal da demo e não depende de provisionamento de certificado. Se HTTPS for desejado, aguarde o reset do limite de taxa e o certificado será auto-provisionado.
Certificado Preso — Recriação Limpa (Opcional)
Seção intitulada “Certificado Preso — Recriação Limpa (Opcional)”Quando o certificado do HTTPS LB está preso em DomainChallengePending ou PreDomainChallengePending por mais de 15 minutos, o caminho de recuperação mais rápido é excluir o HTTPS LB e recriá-lo. Com a zona DNS já configurada (registros gerenciados habilitados), a recriação limpa tipicamente produz CertificateValid em 5–7 minutos — a menos que esteja com limite de taxa.
- Exclua o HTTPS Load Balancer:
DELETE .../http_loadbalancers/${F5XC_LB_NAME}-https - Aguarde 30 segundos para limpeza da plataforma
- Recrie o HTTPS Load Balancer (Fase 1 Etapa 3)
- Monitore o estado do certificado (Fase 1 Etapa 7) — espere
CertificateValiddentro de 5–10 minutos
Referência OpenAPI
Seção intitulada “Referência OpenAPI”A especificação canônica da API do F5 Distributed Cloud está disponível em:
https://docs.cloud.f5.com/docs-v2/downloads/f5-distributed-cloud-open-api.zip
Este ZIP contém especificações OpenAPI 3.0 para todos os grupos de API incluindo ves.io.schema.views.http_loadbalancer, ves.io.schema.healthcheck, ves.io.schema.origin_pool e ves.io.schema.shape.csd. Use estas especificações para validar payloads JSON e descobrir campos adicionais.