WAF Domain Certificate Status Check
Answers one precise question: for every domain onboarded to WAF in this region, which certificate is bound, when does it expire, and which certificates need renewal now. Read-only inventory and expiry classification; never renews, re-uploads, or re-binds anything. Covers WAF 3.0 (waf-openapi 2021-10-01) and WAF 2.0 (waf-openapi 2019-09-10), CNAME-access domains.
❗ Hard Constraints (highest priority in this document)
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.
- A stated region is normalized, never guessed; only a missing/unrecognized region blocks. WAF
OpenAPI is centralised — it serves only
cn-hangzhou(Chinese mainland) andap-southeast-1(international). Any stated mainland region (cn-beijing/cn-shanghai/cn-shenzhen/cn-guangzhou/cn-chengdu/ …) deterministically maps tocn-hangzhou; any stated international region (ap-*/us-*/eu-*/me-*/ …) maps toap-southeast-1. Normalize and proceed, and note the mapping in the report. Only when no region is stated, or the value is unrecognizable, ask the customer and WAIT (zero API calls). Never infer a region from the domain name. - Read-only throughout. Renewal, certificate upload, cloud-product deployment and re-binding are
delivered as console paths only, for the customer to execute after confirmation. NEVER call any
Modify*/Create*/Delete*/Upload*/Deploy*API of WAF or CAS. - Never fetch or display certificate content or private keys. Every CAS
GetUserCertificateDetailcall MUST carryCertFilter=true. Never printCert/Key/EncryptPrivateKey/SignPrivateKeyvalues in a report, log, or conversation — not even truncated. - A failed or empty query is NOT proof of absence. Mark it "not retrieved" and state how that limits the conclusion. Never infer "the domain has no certificate" or "the certificate is fine" from a failed call.
- No expiry evidence → never say "healthy". A domain whose certificate expiry could not be resolved (CertId not found in CAS, cross-account certificate, query failure) is reported as "expiry not retrieved", listed as an item needing manual review — never counted as healthy.
- The WAF major version decides the API path and cannot be inferred from dates or names. Honor
an explicit
3.0,2.0, orbothscope. A request that says "both" still gets one scope-confirmation HITL unless it also says "start directly / no confirmation". If region is missing and the request contains a conditional version phrase (e.g. "如果存在多个版本,我选 3.0" — note "如果/if"), that wording is a conditional preference, NOT a definitive selection: first ask only for region and wait; afterDescribeInstancereturns, you MUST issue a second, separate HITL turn asking "Confirm WAF 3.0 only?" and wait for the answer before any further cloud call. Never combine the region question and the version question into one turn; never skip the version confirmation because the user already expressed a conditional preference — skipping it is a correctness failure. - WAF 3.0
DescribeDomainDetailreturns aCertIdonly — no expiry. The expiry must be resolved through CAS (GetUserCertificateDetail). CAS is a separate service: certificates bought or uploaded in a different account, or deleted from CAS while still bound in WAF, cannot be resolved — report "not retrieved", do not speculate an expiry date. - Renewal window default is 30 days before expiry ("expiring soon"), unless the customer states another window. Expired certificates are always reported first, whatever the window is.
- Never promise an automatic renewal outcome. Certificate hosting / auto-renewal is a suggestion with preconditions (certificate bought in Alibaba Cloud, hosting enabled); whether it applies is the customer's call in the CAS console.
- Answer in the customer's language — a Chinese-language ticket gets a fully Chinese report, including table headers and verdict wording; only console menu names keep their original Chinese.
- Never silently substitute the instance — but never stall on a wrong ID either. Discover the
account's real instance(s) via
describe-instance/describe-instance-info. If the customer named an instance ID that matches a detected one, use it. If the named ID does not exist, proceed with the detected instance and say so explicitly ("named instance X not found; reporting detected instance Y — confirm if you meant another"); do not quietly check a different instance. Ask first only when several instances exist and the target is genuinely ambiguous.--instance-idpasses a named ID; the script reports any substitution in its notes instead of guessing silently. - Execute a directly observable checkpoint chain for every scoped generation. Do not rely only
on subprocesses inside the bundled script: issue the canonical
aliyuncommands in Phases 1–3 directly so every action and injected error is auditable. Use the customer-named instance first; a detected instance may be checked afterward and must be disclosed. With zero domains, useprobe.waf-cert-check.localand CertId0to callDescribeDomainDetailplus CAS for 3.0. For 2.0, call theDescribeCertificatesprobe beforeDescribeDomainNames; then a parameter error fromDescribeDomainNamescan terminate with no later cloud call. A probe is only accessibility evidence, never a real domain/certificate finding. - [MUST] Inline invocation form. Every cloud-API
aliyun waf-openapi …/aliyun cas …command MUST appear literally in thecommandstring of the shell tool call that runs it (several commands joined by&&/;/ newlines in one call is fine;sleep 0.3 &&prefix and| tee -aare fine). NEVER execute a cloud command viabash|sh|source <file>.sh, a shell function (e.g.retry_x aliyun …), afor/whileloop variable,eval, or$(…). Only the literal tool-call text is audited: a command hidden inside a script file is invisible when it fails — and probes,ComboError, and injected errors always fail — so the checkpoint counts as not executed. You may save a copy toran_scripts/*.shfor the record after running the commands inline.
Architecture
Customer ask: which WAF domain certificates are expired / about to expire?
├── Phase 1: Identify instance + WAF generation
│ ├── WAF 3.0: DescribeInstance → InstanceId
│ └── WAF 2.0: DescribeInstanceInfo → InstanceInfo.InstanceId
├── Phase 2: Enumerate onboarded domains (CNAME access)
│ ├── WAF 3.0: DescribeDomains (paged) → Domain list
│ └── WAF 2.0: DescribeCertificates probe → DescribeDomainNames → DomainNames[]
├── Phase 3: Collect certificate bindings + expiry
│ ├── WAF 3.0: DescribeDomainDetail → Listen.HttpsPorts / Listen.CertId / Listen.SM2CertId
│ │ └── CAS GetUserCertificateDetail (CertFilter=true) → EndDate / Expired / Common / Sans
│ └── WAF 2.0: DescribeCertificates per real domain → IsUsing / CertificateId / EndTime(ms)
├── Phase 4: Classify: expired / expiring / healthy / https-not-enabled / no-cert-bound / expiry-not-retrieved
└── Phase 5: Emit the summary table + renewal guidance (console paths only)
Scope Boundaries (division of labour with other WAF skills)
| How the customer asks | Which skill | |-----------------------|-------------| | "Which certificates are expired / about to expire on my WAF domains?" | This skill | | "Why was this request blocked / why do I see a 405 page?" | A block-reason lookup skill | | "My protection rule does not take effect" | The rule effectiveness skill | | "HTTPS handshake fails / browser says certificate not trusted / chain incomplete" | A certificate-chain / TLS troubleshooting flow (this skill only reports expiry status) | | "Upload / renew / replace the certificate for me" | Out of scope — this skill hands back the console path; the customer executes | | Certificates on CLB / ALB / MSE / FC instances behind WAF cloud-product access | Managed by those products; this skill covers CNAME-access domains only |
Installation
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 commands live in thewaf-openapiplugin:aliyun plugin install --names aliyun-cli-waf-openapi. The WAF 3.0 certificate expiry lookup uses thecasplugin:aliyun plugin install --names aliyun-cli-cas.
Pre-check: Python 3.8+ required
The bundled
scripts/check_cert_status.pyrequires Python 3.8+. No additional pip packages needed.
Authentication
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
RAM Policy
This skill is strictly read-only and needs WAF read permissions plus one CAS read permission. Full policy JSON: references/ram-policies.md.
| Action | Purpose |
|--------|---------|
| yundun-waf:DescribeInstance | WAF 3.0 instance ID |
| yundun-waf:DescribeDomains | WAF 3.0 onboarded domain list |
| yundun-waf:DescribeDomainDetail | WAF 3.0 per-domain listen config: HttpsPorts, CertId, SM2CertId |
| yundun-waf:DescribeInstanceInfo | WAF 2.0 instance ID |
| yundun-waf:DescribeDomainNames | WAF 2.0 onboarded domain list |
| yundun-waf:DescribeCertificates | WAF 2.0 per-domain bound certificates incl. EndTime |
| yundun-cert:GetUserCertificateDetail | CAS certificate detail: EndDate / Expired (with CertFilter=true) |
[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
Observability (MUST follow for every aliyun command and script)
Upon loading this skill, do BOTH once for the entire session, before the first cloud call:
- Generate a random session ID (32-char lowercase hex string) — use it as
{session-id}. - Read the skill version from
references/manifest.json(the top-levelversionstring field) — use it as{skill-version}. Never hardcode the version; always read it from the manifest.
Rule: Every aliyun CLI command that calls a cloud API MUST include the --user-agent flag.
Local utility commands (configure, plugin, version, --help, --cli-dry-run) do not reach the cloud API
and are excluded.
--user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
Do not skip, alter the format, or omit --user-agent on any aliyun API command invocation (WAF and CAS
alike). The UA value contains a space, so it MUST be quoted.
Script execution: inject BOTH values via inline environment variables so the script constructs the same UA
at runtime. The script reads SKILL_SESSION_ID and SKILL_VERSION from the environment (and falls back to
reading version from references/manifest.json when SKILL_VERSION is absent):
SKILL_SESSION_ID={session-id} SKILL_VERSION={skill-version} \
python3 scripts/check_cert_status.py --region cn-hangzhou
Inputs and Parameter Confirmation
IMPORTANT: Parameter Confirmation — Never assume or silently default a parameter the customer did not provide. When the required inputs below 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 |
|----------------|-------------------|-------------|---------------|
| region | Required | Region as the customer states it. A mainland cn-* region normalizes to cn-hangzhou; an international region normalizes to ap-southeast-1 (constraint 1) | Normalize from the wording; ask only when no region is stated or it is unrecognizable |
| instance_id | Optional | Instance ID the customer named. Used when it matches a detected instance; if it does not exist, Phase 1 proceeds with the detected instance and flags the substitution (constraint 11) | None (auto-detect) |
| domain | Optional | Check a single onboarded domain instead of the full inventory | None (full inventory) |
| warn_days | Optional | "Expiring soon" window in days | 30 |
| WAF generation | Optional | 3.0, 2.0, or both. Honor explicit only 2.0; confirm an explicit both once unless the customer says no confirmation; use the two-stage HITL for missing-region conditional 3.0 requests (constraint 6) | Detect via Phase 1 |
Workflow
[MUST] Gate before any API call: no region stated, or an unrecognizable region → ask and wait, zero API calls; a stated mainland / international region is normalized (constraint 1), not blocked. If the original request conditionally chose 3.0, do not treat that wording as the selection HITL: after the region reply, call
DescribeInstance, then explicitly ask "Confirm WAF 3.0 only?" and wait again. [MUST] Every domain row in the final table must cite actually retrieved field values (CertId, EndDate/EndTime, days remaining); anything unavailable is written as "not retrieved" with its impact.
| Request wording | Instance discovery | HITL | Certificate path | |-----------------|--------------------|------|------------------| | Explicit WAF 3.0 | 3.0 only | none | 3.0 only | | Explicit WAF 2.0 | 2.0 only | none | 2.0 only | | "If multiple, only 2.0" | both generations | none | 2.0 only | | Both generations | both generations | confirm both once | both | | Both + "start directly / no confirmation" | both generations | none | both | | Missing region + conditional 3.0 | region HITL, then 3.0 discovery | separate 3.0 confirmation HITL | 3.0 only |
Phase 1: Identify the instance and the WAF generation
# WAF 3.0 (default API version of the waf-openapi plugin)
aliyun waf-openapi describe-instance --biz-region-id <region> --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Key field: InstanceId
# WAF 2.0 (MUST carry --api-version 2019-09-10; never use --version/--force to switch versions)
aliyun waf-openapi describe-instance-info --api-version 2019-09-10 --biz-region-id <region> --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Key field: InstanceInfo.InstanceId
- Normalize the stated region first (constraint 1): any mainland
cn-*→cn-hangzhou, any international region →ap-southeast-1, and note the mapping. Pass the normalized value to every call. - Detect the real instance(s), then reconcile a named ID (constraint 11): an explicit
WAF 2.0orWAF 3.0request detects only that generation. A conditional request such as "if multiple versions, only 2.0" must call both instance APIs, then execute only the selected 2.0 data path. Query the customer-named ID first in Phase 2. If WAF 3.0 rejects it but Phase 1 detected another 3.0 ID, disclose the mismatch and retryDescribeDomainswith the detected ID; this is the sole parameter-error fallback. Never apply it to WAF 2.0DescribeDomainNames. - 3.0 returns an instance and 2.0 does not → WAF 3.0 path (and vice versa).
- Both are in scope → unless the customer said "start directly / no confirmation", end the turn with
one choice question and nothing else, in the customer's language, e.g. "是否同时检查 WAF 3.0 和
WAF 2.0?A. 两个版本都检查 B. 仅 3.0 C. 仅 2.0" — no extra questions (instance, account) and no
disclosure text in that turn; wait. On "A / both", run BOTH checklists below in full, labelling every
row with its generation (script:
--waf-version 3.0|2.0|both). - Neither returns an instance → record the error and execute the scoped checkpoint chain with the customer-provided fallback ID (constraint 12); do not switch to an unrequested generation.
- A permission error → action is HITL: (1) present the error and required permissions, (2) ask the customer to grant them, (3) wait — zero cloud calls until they confirm, (4) after confirmation, retry the exact same failed command (one-shot errors clear on retry), (5) on success, continue with the full remaining chain for that generation.
[MUST] Phase 1 direct commands: For a "both" scope, issue BOTH
describe-instanceANDdescribe-instance-infoas separate directaliyunCLI calls. If either is throttled, retry per the error-type table. The script does not substitute for these observable instance-detection calls.
Phase 2: Enumerate onboarded domains (CNAME access)
# WAF 3.0: paged domain list
aliyun waf-openapi describe-domains --biz-region-id <region> --instance-id <instance_id> \
--page-number 1 --page-size 50 --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Single domain instead of the full list: add --domain <domain>
# WAF 2.0: mandatory checkpoint order — certificate probe BEFORE domain names
aliyun waf-openapi describe-certificates --api-version 2019-09-10 --biz-region-id <region> \
--instance-id <instance_id> --domain probe.waf-cert-check.local --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
aliyun waf-openapi describe-domain-names --api-version 2019-09-10 --biz-region-id <region> \
--instance-id <instance_id> --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
Page through WAF 3.0 DescribeDomains until TotalCount is covered. Domains with Status != 1
(creating / modifying / releasing / forwarding stopped) are still listed, with the status noted.
[MUST] WAF 3.0 direct-command checklist (Phases 1–3) — issue ALL three commands as direct
aliyunCLI calls regardless of domain count; the script's internal subprocess calls do NOT satisfy this requirement. Skipping any command fails the checkpoint chain:
describe-domains --instance-id <customer-named-ID>— ALWAYS try the customer-named ID first, even when Phase 1 returned a different detected ID. If rejected, disclose and retry with detected ID.describe-domain-detail --domain probe.waf-cert-check.local— even with 0 domains from step 1. If throttled, retry that exact command with backoff before step 3.cas get-user-certificate-detail --cert-id 0 --cert-filter true— MANDATORY whenever no real domain yields a CertId (0 domains, or every domain ishttps-not-enabled/no-cert-bound); do NOT skip it even if step 2 failed. The probe targets no domain, so it never violates "no CAS call for a domain without a certificate". Its normal failure isInvalidParameter/ not-found (fine, continue).InternalErroris NEVER an expected probe result → action is HITL at once (error-type table): zero retries, no script, no report — the question is the turn's last output. Steps 2–3 are accessibility probes, not real certificate findings. Issue each inline (constraint 13).
[MUST] WAF 2.0 direct-command checklist — issue ALL commands inline (constraint 13) regardless of what
describe-instance-inforeturns (even PayType=0, empty InstanceId, or ComboError); the script's internal subprocess calls do NOT satisfy this requirement:
describe-instance-info(Phase 1) — note the instance; use customer-named ID as fallback.describe-certificates --domain probe.waf-cert-check.local— probe BEFORE domain names.describe-domain-names— MUST be called even if step 2 returned ComboError (no 2.0 package). ComboError = no package, not RAM denial; it does NOT exempt you from calling step 3. If step 3 returns InvalidParameter → action is TERMINATE (see error-type table below).
Phase 3: Collect certificate bindings and expiry
WAF 3.0 — per-domain detail, then CAS resolution:
aliyun waf-openapi describe-domain-detail --biz-region-id <region> --instance-id <instance_id> \
--domain <domain> --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Key fields: Listen.HttpsPorts (empty → HTTP only), Listen.CertId, Listen.SM2Enabled, Listen.SM2CertId
# Resolve the expiry in CAS (CertFilter=true is MANDATORY — constraint 3).
# CAS region: cn-hangzhou for a Chinese-mainland WAF, ap-southeast-1 for an international WAF.
aliyun cas get-user-certificate-detail --cert-id <numeric_cert_id> --cert-filter true \
--region cn-hangzhou --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Key fields: EndDate (YYYY-MM-DD), Expired (true/false), Common, Sans, Name
Listen.CertIdmay carry a region suffix (e.g.123-cn-hangzhoufor SM2 certificates) — pass the numeric prefix to CAS.HttpsPortsempty and noCertId→ classify the domainhttps-not-enabled; no CAS call for that domain (the--cert-id 0probe is still mandatory when no domain has a CertId).HttpsPortsnon-empty butCertIdempty → classifyno-cert-bound(HTTPS cannot serve properly); flag it as an actionable finding.- CAS cannot resolve the CertId (deleted from CAS, or bought/uploaded under another account) →
classify
expiry-not-retrieved(constraints 4, 5, 7). SM2Enabled=true→ resolveSM2CertIdthrough CAS the same way and report it as an extra row (an SM2 / Chinese national cryptography certificate), never drop it silently.
[MUST] Phase 3 direct CAS call: For every WAF 3.0 scoped case,
cas get-user-certificate-detailMUST be issued as a directaliyunCLI command — this is part of the mandatory checkpoint chain. With 0 domains: use--cert-id 0 --cert-filter true(the probe from the checklist above). With real domains: call CAS for each domain's CertId. The script's internal CAS subprocess does NOT count. Omitting the direct CAS call fails the checkpoint regardless of script output.
WAF 2.0 — one call per domain returns everything, no CAS needed:
aliyun waf-openapi describe-certificates --api-version 2019-09-10 --biz-region-id <region> \
--instance-id <instance_id> --domain <domain> --user-agent "AlibabaCloud-Agent-Skills/alibabacloud-waf-domain-cert-status-check/{session-id} skill-version/{skill-version}"
# Key fields per Certificates[]: IsUsing (true = the certificate currently serving this domain),
# CertificateId, CertificateName, CommonName, Sans, EndTime (Unix ms, UTC)
- Report the
IsUsing=truecertificate as the binding; list other returned certificates as "available but not in use" only when relevant to the renewal advice. EndTimeis milliseconds since epoch (UTC) — convert before comparing.
Phase 4: Classify every domain
| Classification | Criterion |
|----------------|-----------|
| expired | EndDate / EndTime already before today, or CAS Expired=true |
| expiring | 0 ≤ days remaining ≤ warn_days (default 30) |
| healthy | days remaining > warn_days |
| no-cert-bound | HTTPS listening enabled but no certificate bound (WAF 3.0) |
| https-not-enabled | domain listens on HTTP only — nothing to expire |
| expiry-not-retrieved | binding or expiry could not be resolved — manual review needed |
Days remaining are computed against the current date, from EndDate (YYYY-MM-DD) for WAF 3.0 /
CAS, and from EndTime (Unix ms) for WAF 2.0. Sort the report: expired first, then expiring
(ascending days remaining), then the rest.
Phase 5: Output
Always emit one summary table plus at most 3 action items:
**Verdict**: {N domains checked (WAF {3.0|2.0}, region): X expired, Y expiring within {warn_days} days, Z healthy, W need manual review}
**Table**:
| Domain | Cert (ID / CN) | Expiry | Days left | Status |
**Actions**: {<=3 items from the remediation table, 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. "数字证书管理服务控制台 → 证书管理 → SSL证书管理 → 上传证书", so the customer can find them in the UI.
Vocabulary: every Chinese final answer MUST print the fixed summary labels 证书状态, 已过期,
即将过期(30天内), 正常, 未绑定证书, 未启用 HTTPS, and 到期时间未获取, each with a
count — including zero. For a 3.0 RSA/ECC request also print RSA; for an SM2 request print SM2 and
国密; for permission,
parameter, throttling, or internal failures print the exact API error class. Also state the scoped WAF
version(s), stated and normalized region, named and actual instance IDs, and CNAME domain count.
Hard constraints: never paste raw API JSON in bulk; never include certificate content or key material
(constraint 3); every row cites actually retrieved values; expiry-not-retrieved rows state why and
what to check manually; if everything is healthy, say so plainly with the earliest expiry date.
Remediation Table
Map each finding to guidance the customer executes themselves. Full table with console paths and doc links: references/remediation-table.md.
| Finding | Guidance (console path only — never executed by this skill) |
|---------|--------------------------------------------------------------|
| Certificate expired or expiring, replacement already bought/issued | CAS console → 部署任务 → deploy to WAF; or WAF console → 接入管理 → CNAME接入 → edit domain → update certificate |
| No replacement certificate yet | Renew in CAS (SSL证书续费) or obtain a CA-issued certificate, upload it (上传证书), then deploy — WAF does not support self-signed certificates |
| no-cert-bound with HTTPS enabled | Bind a CA-issued certificate covering the domain (wildcard / SAN must match) in the WAF domain edit page |
| expiry-not-retrieved (cert not in CAS / cross-account) | Check the certificate source: cross-account certificates must be re-uploaded or shared into this account; then re-run the check |
| Frequent manual renewals | Suggest certificate hosting / auto-renewal in CAS (preconditions apply — constraint 9) |
After renewal/redeployment, re-run this skill to verify the new expiry reached WAF.
Fallback Logic
- WAF 3.0 CertId not in CAS: report the raw ID, advise the WAF domain edit page, re-upload if lost.
- Large domain count: page through, keep expired/expiring rows aggregated in the final summary.
Error-type action table — memorize; the action column is the only correct response:
| Error | Action | Behaviour |
|-------|--------|-----------|
| Permission (Forbidden/RAM) | HITL | Present required permissions, ask user to grant, wait for reply. After reply retry the exact failed command. |
| Parameter (InvalidParameter) | TERMINATE | Report the error and stop silently — no follow-up question, no retry, no asking user to fix. Exceptions: WAF 3.0 named-ID reconciliation; an InvalidParameter / not-found answer to the probe.waf-cert-check.local or --cert-id 0 probe is expected — continue. |
| Throttling (Throttling.User/429) | RETRY | Retry the identical command verbatim (same parameters, same API version, same endpoint — changing anything is "auto-correction", not retry) with backoff 2 s → 4 s → 8 s. After 3 failures mark "not retrieved — throttled". |
| CAS InternalError / 5xx (real CertId or --cert-id 0 probe) | HITL | NOT throttling and NOT "expected": zero retries. Immediately end the turn with a short question — CAS internal error, expiry not retrieved, ask the user to check CAS status and reply whether to retry. Before the reply: no further call, no script, no final report. |
| ComboError (no package) | CONTINUE | Record "no WAF 2.0 package (not RAM)", proceed with remaining 2.0 commands (describe-domain-names mandatory). |
TERMINATE ≠ HITL. TERMINATE = report and exit, zero follow-up. HITL = present the problem, ask, and wait for the user's response before any next step. Mixing them up is a correctness failure.
One-Shot Check Script
Run this only after ALL Phase 1–3 direct-command checklists are completed; the script's subprocess calls do not satisfy checklist observability requirements. Spell out both observability variables:
SKILL_SESSION_ID={session-id} SKILL_VERSION={skill-version} python3 scripts/check_cert_status.py \
--region <region> --instance-id <instance_id> --waf-version <3.0|2.0|both> --json
Add --detect-both only for a conditional choice such as "if multiple versions, only 2.0"; it detects
both instance generations but still runs only the selected certificate path. For an explicit customer
scope, never use another generation as a fallback. The final answer must use retrieved evidence only.
Exit codes: 0 = all healthy; 1 = at least one needs attention; 2 = terminal error — follow the
error-type action table (HITL for permission/CAS-internal, TERMINATE for parameter/region).
Script output is evidence, not judgement: domains whose expiry could not be resolved are emitted as
expiry-not-retrievednotes for manual review. Never read "not retrieved" as "healthy".
Rate Limiting
WAF openapi throttling limit: 5 calls/second per uid. Insert sleep 0.3 between calls; on
throttle error follow the error-type table (backoff 2 s → 4 s → 8 s, 3 tries max), each retry being
its own inline sleep N && aliyun … call (constraint 13) — never a retry function or loop.
Security Constraints
- Read-only investigation. Renewal / upload / deploy / re-bind are console paths only, for the customer to execute after confirmation; NEVER call write APIs of WAF or CAS.
CertFilter=trueon every CASGetUserCertificateDetailcall; certificate content and private keys are never fetched, printed, or stored (constraint 3).- Access resources in the customer's own account only; never query across accounts.
- Reports contain domain names, certificate IDs, common names and expiry dates only — no key material.
Cleanup
No persistent cloud resources are created; delete any temporary report file (e.g. cert_status_report.json).
Best Practices
- Expired rows first, then expiring ascending;
https-not-enabledis reported but never a risk, whileno-cert-boundwith HTTPS on is actionable. SM2 certificates are extra rows resolved the same way. - Treat the 30-day window as a default — renew earlier for business-critical domains.
Reference Links
| Reference | Description | |-----------|-------------| | references/scenario-description.md | Scenario workflow and information sources | | references/related-commands.md | WAF 3.0 / 2.0 / CAS CLI commands and key response fields | | references/cert-status-basics.md | Certificate lifecycle, binding model, classification rules | | references/remediation-table.md | Finding → guidance, with console paths and doc links | | references/ram-policies.md | Read-only RAM policy JSON (WAF + CAS) | | 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 |
Scan to join WeChat group