Install
openclaw skills install @sdk-team/alibabacloud-waf-rule-effectiveness-checkDiagnose why a configured Alibaba Cloud WAF 3.0 custom protection rule (custom ACL, CC / rate limiting, scan protection, IP blacklist) is not working: name the first broken link in the chain and hand back the console fix path. Read-only checks of configuration state only; never sends test traffic. Use it when a customer says a rule has no effect at all, a rule matches in the logs but nothing is blocked, an attack that should have been blocked got through, a rule worked yesterday but not today, or a CC or rate-limiting rule does not trigger or bans far too widely. Not for: explaining why one specific request was blocked or looking it up by trace_id, whitelist rule effectiveness itself, live attack sample validation, built-in rule toggles, config export, or reports. Triggers: "规则不生效", "规则配了但不生效", "自定义规则不生效", "预期拦未拦", "该拦的没拦住", "漏拦截", "规则命中但没拦", "规则昨天还好今天失效", "CC不触发", "误封面过大", "规则为什么没生效", "WAF rule not effective", "rule not taking effect", "rule hit but not blocked"
openclaw skills install @sdk-team/alibabacloud-waf-rule-effectiveness-checkAnswers one precise question: is this custom rule currently in effect for this protection object, and if
not, which link is broken. Statically checks the configuration chain; sends no test traffic.
WAF 3.0 only (waf-openapi 2021-10-01). Use when the customer reports "I configured the rule but it does not
work / it should have been blocked but was not / CC does not trigger or the ban scope is too wide".
Scope: user-defined rules with DefenseOrigin = custom (custom_acl / cc / rate limiting / scan / blacklist).
Interaction stance — confirm first, query second. Asking the customer for a required input that is missing or ambiguous, and then waiting for the answer, is correct behaviour in this skill — never a failure to act. Guessing an input, or querying around the gap, is the failure.
region or no matched_host → call nothing at all. Both are prerequisites for every query in this
skill. When either is missing, ask the customer and WAIT for the answer: not one API call, not even
describe-instance, and never guess a region from the domain name. This gate covers all APIs, not only
the template-level ones, and no other instruction in this document overrides it.region and
matched_host already in hand, do not stall on "please provide the rule ID" and do not stop at "the rule
does not exist". Enumerate the candidate templates (list rules by scene or name keyword to collect their
TemplateIds), then still check the object binding, the template status and the binding quota on those
candidates, so the customer learns whether the object is bound to any enabled template. Zero-result
lookups only; never overrides constraint 4; several candidates is constraint 11 — confirm first.DescribeTemplateResources, DescribeDefenseTemplate and
DescribeTemplateResourceCount. Calling them is forbidden until both hold: (a) the rule's
DefenseOrigin is custom — for a built-in (system) rule report "built-in rule, out of scope" and stop,
do not touch the template APIs at all; (b) the customer has confirmed which rule, whenever the rule was
reached through a name keyword instead of an exact ID — list the matches with RuleId / RuleName /
TemplateId and wait for the pick, even if only one rule matched. This outranks any
evidence-collection instruction below.Customer report: custom rule not effective / expected block missed / CC not triggering or over-banning
│
├── Phase 1: DescribeInstance (InstanceId / Edition / quota) + DescribeDefenseResource (existence / status)
│
├── Phase 2: DescribeDefenseRules → confirm DefenseOrigin=custom; detect statistical rules (CC / rate / scan)
│
├── Phase 3 (core): Check the effectiveness quad element by element
│ ├── ① rule Status=1
│ ├── ② object (or its object group) bound to the rule's template ← top root cause
│ ├── ③ template TemplateStatus=1
│ └── ④ disposal action is block, not observe/monitor ← top root cause for missed blocks
│ └── Auxiliary gates: ResourceStatus=active / default object group / binding quota
│
├── Phase 4: missed-block checklist (observe mode, origin pass-through, priority, timing)
│ or statistical-rule checklist (window and threshold, counting subject, blacklist scope)
│
├── Phase 5: Reverse corroboration with SLS logs (optional)
│
└── Phase 6: Emit the checklist verdict (first broken link + temporary / permanent fix)
| How the customer asks | Which skill |
|---|---|
| "Why was this request blocked?" | A block-reason lookup skill (trace_id → matched rule → rule detail) |
| "Why is the custom rule I configured not taking effect?" | This skill |
| "I allow-listed it and it is still blocked" | The dedicated whitelist skill (whitelist effectiveness itself is out of scope here; but "whitelist early allow made my blocking rule miss" is a cause this skill rules out) |
| "Can my protection rules really block attacks?" (wants real samples sent) | An active validation skill |
| "Export all my protection configuration" / "Give me an attack and protection report" | A configuration export skill / a reporting skill |
One ticket may need both this skill and a block-reason lookup skill: use this skill first, then let the other analyse the request by trace_id (different leads: rule_id vs trace_id) — do not mix them.
Pre-check: Aliyun CLI >= 3.3.3 required
[MUST] Verify:
aliyun version— must be >= 3.3.3.
- Preferred (no remote script execution): download
https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz(macOS:aliyun-cli-macosx-latest-{amd64|arm64}.tgz),tar tzfto inspect,tar xzf,sudo mv aliyun /usr/local/bin/.- Alternative:
/bin/bash -c "$(curl -fsSL --connect-timeout 10 --max-time 120 https://aliyuncli.alicdn.com/setup.sh)"- Update (CLI >= 3.3.5):
aliyun upgrade. Full instructions:references/cli-installation-guide.md.
Pre-check: Aliyun CLI plugin update required
[MUST] run
aliyun configure set --auto-plugin-install trueto enable automatic plugin installation. [MUST] runaliyun plugin updateto ensure that any existing plugins are always up-to-date. The WAF 3.0 commands live in thewaf-openapiplugin:aliyun plugin install --names aliyun-cli-waf-openapi.
Pre-check: Python 3.8+ required
The bundled
scripts/check_rule_effectiveness.pyrequires Python 3.8+. No additional pip packages needed.
Pre-check: Alibaba Cloud Credentials Required
Security Rules:
- NEVER read, echo, or print AK/SK values (e.g.,
echo $ALIBABA_CLOUD_ACCESS_KEY_IDis FORBIDDEN)- NEVER ask the user to input AK/SK directly in the conversation or command line
- NEVER use
aliyun configure setwith literal credential values- ONLY use
aliyun configure listto check credential statusRun
aliyun configure listand check the output for a valid profile (AK, STS, or OAuth identity).If no valid profile exists, STOP here.
- Obtain credentials from Alibaba Cloud Console
- Configure credentials outside of this session (via
aliyun configurein terminal or environment variables in shell profile)- Return and re-run after
aliyun configure listshows a valid profile
This skill is strictly read-only and needs WAF read permissions only. Full policy JSON: references/ram-policies.md.
| Action | Purpose |
|---|---|
yundun-waf:DescribeInstance | Instance ID / edition / per-template binding quota |
yundun-waf:DescribeDefenseRules | Rule detail: Status, DefenseOrigin, DefenseScene, TemplateId, Config |
yundun-waf:DescribeDefenseTemplate | Template TemplateStatus, DefenseScene |
yundun-waf:DescribeTemplateResources | Protection objects / object groups bound to the template (element ②) |
yundun-waf:DescribeDefenseResource | Object existence, ResourceStatus, owning object group |
[MUST] Permission Failure Handling: When any command or API call fails due to permission errors at any point during execution, follow this process:
- Read
references/ram-policies.mdto get the full list of permissions required by this SKILL- Use
ram-permission-diagnoseskill to guide the user through requesting the necessary permissions- Pause and wait until the user confirms that the required permissions have been granted
Upon loading this skill, generate a random session ID (32-char lowercase hex string) once for the entire session. Use it as {session-id} below.
Rule: Every aliyun CLI command that calls a cloud API MUST include the --user-agent flag.
Local utility commands (e.g. configure, plugin, version) do not support this flag and should be excluded.
--user-agent AlibabaCloud-Agent-Skills/alibabacloud-waf-rule-effectiveness-check/{session-id}
Example (assuming session-id is a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6):
aliyun waf-openapi describe-instance --biz-region-id cn-hangzhou --user-agent AlibabaCloud-Agent-Skills/alibabacloud-waf-rule-effectiveness-check/a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
Do not skip, alter the format, or omit --user-agent on any aliyun API command invocation.
Script / Terraform execution: When running Python SDK scripts or Terraform commands or bash scripts, inject the session-id via inline environment variable so the code can read it at runtime:
# Python SDK script
SKILL_SESSION_ID={session-id} python3 scripts/check_rule_effectiveness.py --rule-id <rule_id> --resource <matched_host>
Scripts read SKILL_SESSION_ID from the environment (default to empty string if absent).
IMPORTANT: Parameter Confirmation — Never assume or silently default a parameter the customer did not provide. When the required inputs below (rule identifier, protection object, region) are already present in the request, treat them as confirmed and start the read-only checks straight away — do not ask again. Ask only for a required input that is genuinely missing or ambiguous.
| Parameter Name | Required/Optional | Description | Default Value |
|---|---|---|---|
rule_id / rule_name | Required (either one) | ID of the custom protection rule under check, or a name keyword (fuzzy match) | None |
matched_host | Required | Protection object name (usually the object for a domain, e.g. www.example.com-waf) | None |
region | Required | Region of the WAF instance: cn-hangzhou (Chinese mainland) or ap-southeast-1 (outside the Chinese mainland) | Read it from the customer's wording (e.g. Chinese mainland / Singapore); ask only when absent |
| Symptom | Optional | Expected block missed / CC not triggering / ban scope too wide — decides which Phase 4 checklist to run | None |
| Expected vs actual behaviour | Optional | What the customer wanted the rule to achieve and what they actually observed (including the status code) | None |
| Configuration time | Optional | When the rule was configured and whether it ever worked — the key input for the timing check (Phase 4.1) | None |
| Time the failure started | Optional | For "it suddenly stopped working", record the approximate time to assess change / rollout impact | None |
With region and matched_host in hand but no rule_id / rule name, do not simply demand it and stop —
reverse-look-up from the object's template first:
# Infer candidate rules from the template that the protection object is bound to
# (get template_id first, then list the rules of that template)
aliyun waf-openapi describe-defense-rules --biz-region-id <region> --instance-id <instance_id> \
--query '{"templateId": <template_id>}'
If that still turns up nothing, output known facts + preliminary judgement (which class of root cause the symptom suggests) + missing inputs + advice — do not stop at a bare "please provide the rule ID".
This section assumes
regionandmatched_hostare already known. If either is missing, constraint 4 applies instead — ask and wait, issue no API call, and never fall back to "let me at least check the rule's own state". When the object name is merely uncertain but present, page throughaliyun waf-openapi describe-defense-resourcesto compare, or filter by name keyword.
[MUST] Three gates, in order, before any API call — they outrank the evidence set below; when a gate closes, answer the customer instead of querying: (a)
regionormatched_hostmissing → ask and wait, zero API calls, not evendescribe-instance(constraint 4); (b)DefenseOrigin ≠ custom→ report "built-in rule, out of scope" and stop, no template-level call (constraint 11); (c) the rule was reached through a name keyword rather than an exact ID → list the matches and let the customer confirm which one, even if only one matched (constraint 11). [MUST] Baseline evidence set — once all three gates pass, work throughdescribe-instance,describe-defense-resource,describe-defense-rules,describe-template-resources(--resource-type singlethengroup),describe-defense-template,describe-template-resource-countbefore the verdict, even when the first broken link looks obvious.
aliyun waf-openapi describe-instance --biz-region-id cn-hangzhou
# Key fields: InstanceId, Details.Edition, Details.DefenseObjectInTemplateMaxCount
aliyun waf-openapi describe-defense-resource --biz-region-id cn-hangzhou --resource <matched_host>
# Key fields: Resource.ResourceStatus (initializing / active / init_failed), Resource.ResourceGroup
ResourceStatus = initializing: a newly created object is still initializing (seconds to tens of seconds);
binding a template may fail during this window. Wait and retry — do not call it a misconfiguration.ResourceStatus = init_failed: initialization failed; guide the customer to recreate it in onboarding
management or open a ticket.# Exact lookup by rule ID (custom protection rule)
aliyun waf-openapi describe-defense-rules --biz-region-id cn-hangzhou --instance-id <instance_id> \
--query '{"ruleId": <rule_id>}'
# Fuzzy lookup by name
aliyun waf-openapi describe-defense-rules --biz-region-id cn-hangzhou --instance-id <instance_id> \
--query '{"nameLike": "<rule name keyword>"}'
If you reached the rule through nameLike (a name keyword) instead of an exact ruleId, stop here and
report the matches — list RuleId / RuleName / TemplateId for every hit, even when only one matched,
and wait for the customer to confirm which rule they mean. Phase 3 must not start before that (constraint 11).
Read DefenseOrigin from the returned Rules[] to pick the path:
DefenseOrigin = custom → user-defined rule (custom ACL / CC / rate limiting / scan protection /
IP blacklist, etc.) → continue with Phase 3 → 4 once the rule under check is confirmed.DefenseOrigin = system → built-in rule, out of scope: say plainly that this skill only checks custom
rules, that built-in rules also depend on per-rule toggles inside the template, and point them at built-in
rule docs or a dedicated skill. No template-level calls (constraint 11); do not force a verdict.defenseScene / nameLike to collect TemplateIds for the Phase 3 template
checks (constraint 9). Several candidates rather than zero → constraint 11: list them and wait.Statistical rule detection — any of these DefenseScene values qualifies:
antiscan_highfreq (high-frequency triggering) / antiscan_dirscan (directory scanning) /
antiscan_scantools (scanning tools) / cc (CC protection) / custom_acl with rate limiting enabled in
Config. Statistical rules additionally go through Phase 4.2.
Record: RuleId, RuleName, Status, TemplateId, DefenseScene, Config (a JSON string holding the
disposal action, match conditions, rate-limit settings, and blacklist scope — element ④ and the
statistical checklist both parse it).
Elements ①②③ decide whether the rule is in effect (all three must hold; if any fails the rule has no effect at all). Element ④ decides whether an effective rule actually blocks the request — in observe/monitor mode the rule matches and is logged, but the request is allowed through.
| # | Element | How to check | How to word the failure |
|---|---|---|---|
| ① | Rule status is enabled | Status from the rule lookup (1=enabled, 0=disabled) | "Rule X is currently disabled" |
| ② | The object is bound to the template containing the rule | Run describe-template-resources --template-id <tid> twice — --resource-type single and --resource-type group, both are required evidence: does Resources contain matched_host, or the object's ResourceGroup? | "Template Y is not bound to protection object Z, so the rule has no effect" |
| ③ | The template status is enabled | TemplateStatus from describe-defense-template --template-id <tid> (1=enabled, 0=disabled) | "Template Y is disabled" |
| ④ | The disposal action is block, not observe/monitor | Parse the action field (e.g. action) out of the rule Config; log-side corroboration below | "Rule X is in observe mode: it matches but does not block the request" |
# Element ②: run twice — --resource-type single, then group (both are required, never only one)
aliyun waf-openapi describe-template-resources --biz-region-id cn-hangzhou --instance-id <instance_id> \
--template-id <template_id> --resource-type single
# Element ③: template status
aliyun waf-openapi describe-defense-template --biz-region-id cn-hangzhou --instance-id <instance_id> \
--template-id <template_id>
Element ② is the top root cause for "the rule has no effect at all", especially "template and rule are both set up but no protection object was ever bound"; element ④ is the top root cause for "the rule matched but nothing was blocked". Suggested order: if the customer reports "nothing happens at all / no hit records", go ② → ① → ③ → ④; if they report "the logs show hits but the request was not blocked", check ④ first. The output must name the exact template that is missing the exact object, or the exact action of the exact rule — never stop at "please check your configuration".
A rule in observe/monitor mode matches and is logged, but does not block the request. Two classes of evidence:
| Evidence source | Criterion |
|---|---|
| Configuration side (authoritative) | The action field in the rule Config is an observe/monitor-style value (e.g. monitor) rather than block |
| Log side (corroboration) | When a plugin-level xx_test field in the SLS WAF log (e.g. acl_test / cc_test / antiscan_test) is true, the paired xx_action is recorded as block by default, but that does not mean the request was blocked — it was allowed through. Only when xx_test = false is xx_action the real disposal action |
| Supporting signals | final_action / final_plugin empty → no actual disposal took place; status == upstream_status → the status code is passed through from the origin |
Hard constraint: once observe mode is confirmed (action is monitor, or the log shows xx_test=true, or
final_action is empty while status == upstream_status), that IS the root cause — state the verdict as
"observe-mode misreading" directly. Do not demote it to a "side note", and do not go looking for binding /
timing / config-rollout explanations (none of those are the root cause in observe mode).
If the customer also reported a specific status code, state that the code comes from the origin and point
them at the origin.
Branches:
Auxiliary gates:
ResourceStatus becomes active (already checked in Phase 1).Resource.ResourceGroup against the template's
group binding list).describe-template-resource-count against the
Details.DefenseObjectInTemplateMaxCount returned by DescribeInstance (the source of truth, not
memorized edition numbers). At the cap, binding fails; trim bindings or open a ticket for an assessment.Pick the checklist that matches the symptom. Full tables: references/symptom-checklists.md.
status == upstream_status), preceding-rule short-circuit and
priority, whitelist early allow, config rollout timing, 3xx forced redirects bypassing the engine, the ALB
service-mode 8KB body inspection limit, onboarding-mode capability differences, out-of-scope attack types,
unmatchable match conditions, IP geolocation bias, and a 405 block being misread as "not blocked".acw_tc, unavailable when AcwCookieStatus=0) and the blacklist scope
(effect: service vs effect: rule).When the customer has WAF log service enabled, corroborate against their own SLS WAF logs (filter by
matched_host + final_rule_id / rule_id). Interpretation table:
references/symptom-checklists.md.
Key readings: hits with xx_test=true → observe mode; no block record while the customer sees 4xx/5xx, or
status == upstream_status → origin pass-through; hits for other rules only → preceding-rule short-circuit or
whitelist early allow; the quad passes yet no hit exists → contradictory evidence, escalate.
If the logs cannot be retrieved or log service is not enabled, mark it "not retrieved" and state which rulings therefore cannot be closed. Never use that as "no hit".
Always emit one checklist verdict plus a single root-cause sentence the customer can act on:
**Verdict**: {rule X is currently not effective for protection object Z; broken at "element ② object not bound to template"}
**Checklist**:
① Rule status: pass / fail (actual value)
② Object binding: pass / fail (template Y is not bound to Z)
③ Template status: pass / fail (actual value)
④ Disposal action: block / observe mode (actual value) / not retrieved
⑤ Statistical window and threshold / blacklist scope: pass / fail / not applicable
**Actions**: {<=3 items, temporary + permanent per the table below, with the console path}
Output language: respond in the customer's language (Chinese for domestic tickets). Keep console navigation paths in their original Chinese console wording, e.g. "WAF 3.0 控制台 → 防护配置 → 模板 Y → 防护对象 → 添加 Z", so the customer can find them in the UI.
Hard constraints: at most 15 lines total; every ruling must cite the field value actually retrieved, and anything unavailable is written as "not retrieved" with its impact stated; never paste raw API JSON in bulk; the first failing link is the root cause — do not enumerate every possibility; if everything passes yet the problem persists, say so honestly and open a ticket instead of inventing a root cause.
Map the located root cause to a temporary fix (what the customer can do now) plus a permanent fix, and deliver the console path. Full table with all 19 root causes: references/remediation-table.md.
Ticket / escalation criteria: the quad and checklists all pass yet the logs show no hit (contradictory evidence), or multiple domains / rules fail at once with no configuration cause — open a ticket with the ruled-out items attached. Do not rationalize it into a customer configuration problem.
region + matched_host are in hand: reverse-look-up first; if still nothing,
output known facts + judgement + missing inputs rather than a bare "please provide the rule ID". This never
licenses a query while region / matched_host are still missing (constraint 4).# Inject the session-level session-id (see Observability), then check the effectiveness quad for one custom
# rule against one protection object (read-only)
SKILL_SESSION_ID={session-id} python3 scripts/check_rule_effectiveness.py --rule-id <rule_id> --resource <matched_host>
# Fuzzy match by rule name
SKILL_SESSION_ID={session-id} python3 scripts/check_rule_effectiveness.py --rule-name "<name keyword>" --resource <matched_host>
# JSON output for programmatic use
SKILL_SESSION_ID={session-id} python3 scripts/check_rule_effectiveness.py --rule-id <rule_id> --resource <matched_host> --json
Exit codes:
0: the quad and the auxiliary gates all pass (the rule is effective for the object and will block)1: a broken link exists, or the rule is in observe mode (the first break is reported)2: query failure, or the rule / protection object does not exist (human intervention needed)Script output is evidence, not judgement: when the action field cannot be determined the script emits the raw value as a note for manual review. Never read "action could not be parsed" as "the action is block".
WAF openapi throttling limit: 5 calls/second per uid.
sleep 0.3 (300ms) between every aliyun API commandThrottling.User / HTTP 429): exponential backoff (2s → 4s → 8s), stop after 3 failuresModify* / Create* / Delete* WAF APIs.No persistent cloud resources are created. Delete any temporary report file the investigation produced
(e.g. effectiveness_report.json).
matched_host — and never query without it either: ask and wait (constraint 4).DefenseOrigin = custom first; built-in and whitelist rule effectiveness are out of scope.DescribeTemplateResources is the source of truth for bindings; never miss the object-group and
default-group indirect paths.DescribeInstance response, not memorized edition numbers.| Reference | Description |
|---|---|
| references/scenario-description.md | Scenario workflow and information sources |
| references/related-commands.md | WAF 3.0 CLI commands and key response fields |
| references/ram-policies.md | Read-only RAM policy JSON |
| references/effectiveness-chain-basics.md | Effectiveness chain and common root causes |
| references/symptom-checklists.md | Phase 4 / 5 detail: missed-block and statistical checklists, log readings |
| references/remediation-table.md | Root cause → temporary / permanent fix, with console paths |
| references/verification-method.md | Step-by-step verification method and criteria |
| references/acceptance-criteria.md | Acceptance criteria: correct / incorrect patterns |
| references/cli-installation-guide.md | Aliyun CLI installation and upgrade guide |