Claude
Skills
Sign in
Back

zpa-audit-baseline-compliance

Included with Lifetime
$97 forever

Read-only audit of a ZPA tenant against the Zscaler ZPA Baseline Recommendations v1.0 document. Inventories app connector groups, server groups, application segments, access policy rules, forwarding policy rules, timeout policy rules, and (when available) LSS configs, then scores ~26 configuration-only checks across 7 categories and renders an interactive Zscaler-styled web report (single-file HTML, plus an optional .jsx component) — searchable, filterable by category, severity, and security framework (NIST SP 800-53 Rev. 5 and CIS Critical Security Controls v8), with per-finding evidence, remediation, and framework citations suitable as supporting evidence for SOC 2, FedRAMP, ISO 27001, and NIST CSF assessments, and printable to PDF from the browser. Use when an administrator asks to audit ZPA against best practices, run a baseline-compliance review, get a ZPA health check, gather compliance evidence, or see how their tenant compares to the recommended baseline. NEVER mutates the tenant — read-only.

Design

What this skill does


# ZPA: Audit Baseline Compliance

## Keywords

zpa audit, zpa best practices, zpa baseline, zpa health check, zpa compliance review, baseline recommendations, zpa configuration audit, zpa policy audit, connector group audit, zpa hardening, zpa review, security baseline check, ZPA Baseline Recommendations v1.0

## Overview

Audit a ZPA tenant's configuration against the **Zscaler ZPA Baseline Recommendations v1.0** document. This skill is **fully read-only** — it inventories the tenant via existing list/get MCP tools, scores each finding against the baseline doc, and renders the result as a **standalone Zscaler-styled web report** (a single self-contained HTML file). A matching React component (`ZpaAuditReport.jsx`) is also generated for teams that want to embed the same view in an existing portal.

**Use this skill when:** An administrator asks to audit their ZPA tenant against best practices, run a baseline-compliance review, get a "ZPA health check", or see how their configuration compares to the recommended baseline.

---

## Hard constraints — what this skill does not do

1. **No writes.** Only `zpa_list_*` and `zpa_get_*` tools. Never call `zpa_create_*`, `zpa_update_*`, or `zpa_delete_*`.
2. **No telemetry checks.** ZPA does not expose live connector CPU/memory/throughput, app probe results, session counts, or LSS log delivery health. Checks that require runtime data are **not silently skipped** — they are listed in the report's "Cannot Audit" section so the user knows what's missing and can request new APIs later.
3. **Configuration-only.** Every check evaluates a field on a resource the API returns. Heuristic checks (e.g. naming-pattern matches for "sensitive" / "lss" / "discovery") are clearly marked as heuristic in the report.
4. **No external network calls from the report at view time.** The HTML file embeds all findings inline; the only runtime external loads are the Tailwind/React/Babel CDN scripts needed to render it. (For air-gapped environments, see "Offline mode" in Step 4.)

---

## Workflow

### Step 1: Confirm scope

Before running anything, confirm with the administrator:

- **Scope:** full audit (all categories) or a single category (Connectors, Server Groups, Segments, Access Policy, Forwarding Policy, Timeout Policy, LSS).
- **Microtenant:** if the tenant uses microtenants, ask which one to inventory (default: the parent tenant). This is an inventory-scope decision only; it is not stored in the audit JSON or shown on the report.

If the user asked a generic "audit my ZPA tenant" question, default to **full audit, parent tenant** and proceed without further questions.

> **The skill does not record a tenant identifier in the report.** The vanity domain, customer ID, and cloud realm live in the Zscaler MCP server's authentication context (env vars / config at server startup) and are not returned by any `zpa_list_*` / `zpa_get_*` tool — and rather than inviting the agent to guess (or compose strings from email addresses, file names, or `zscaler_check_connectivity` output), the report header simply omits tenant identity. The audit timestamp and inventory line are enough to identify a given run.

---

### Step 2: Inventory the tenant (read-only)

**Claude Desktop pre-step (deferred tool loading).** Claude Desktop lazy-loads MCP tool schemas via `tool_search` and refuses to invoke a tool whose schema isn't cached yet (you'll see *"`<tool>` has not been loaded yet. Call tool_search first"*). Before the inventory, prime the cache with a single search so all the read tools below are loaded in one shot:

```text
tool_search(query="zpa list connectors server groups segments policy rules lss")
```

If you skip this and call `zpa_list_lss_configs` (or any other tool) directly, the first call will fail with the *"not loaded yet"* error, you'll have to retry, and one inventory tool may end up silently skipped. This pre-step is a no-op on Cursor and Gemini CLI but is required on Claude Desktop / Cowork.

Then call these tools in parallel where possible. Capture the full result of each:

```text
zpa_list_app_connector_groups()
zpa_list_app_connectors()
zpa_list_server_groups()
zpa_list_segment_groups()
zpa_list_application_segments()
zpa_list_access_policy_rules()
zpa_list_forwarding_policy_rules()
zpa_list_timeout_policy_rules()
zpa_list_lss_configs()
zpa_list_lss_log_types()      # used to verify baseline log-feed coverage
```

**Pagination:** if any list returns the maximum page size (typically 500), paginate with `page_size=500, page=N` until exhausted. The audit is incomplete on a partial inventory.

**Errors:** if a tool returns an error (e.g. service disabled, missing scope, or the *"not loaded yet"* deferred-loading error), record the category as "Cannot Audit — API error" with the error message and continue with the rest. **Do not abort the whole audit.** For *"not loaded yet"*, retry the same tool once after running the `tool_search` pre-step above; if it still fails, mark the category as "Cannot Audit" and move on.

**Inventory transparency:** the inventory string you build here gets embedded into the report as a one-line summary so the admin can see which categories were actually fetched. Build it like:

> *Inventoried: 4 connector groups, 12 server groups, 30 application segments, 1 access rule, 0 forwarding rules, 2 timeout rules, 0 LSS configs.*

**LSS specifics:** the LSS API is **configuration-only** (returns LSS config records and the metadata catalogs). It cannot tell you whether logs are actually flowing to the SIEM, dropping, or arriving late — that's an out-of-band, SIEM-side observation. The audit can only verify configuration shape; live delivery health is in the "Cannot Audit" section.

---

### Step 3: Score the findings

Apply each check below to the inventory. Each finding has:

- **`id`** — short stable identifier (e.g. `acg-n-plus-one`)
- **`category`** — one of: `Connectors`, `ServerGroups`, `Segments`, `AccessPolicy`, `ForwardingPolicy`, `TimeoutPolicy`, `LSS`, `CannotAudit`
- **`severity`** — `critical`, `warning`, `info`, or `cannotAudit`
- **`title`** — one-line human summary
- **`evidence`** — short list of resource names / IDs that triggered the finding (max 10; truncate longer lists with `…and N more`)
- **`docRef`** — page or section in the baseline doc (e.g. `§Health Reporting Recommendations, page 23`)
- **`remediation`** — one or two sentences pointing the user at the right fix (often: "use the `zpa/<other-skill>` skill")
- **`heuristic`** — `true` if the check relies on naming patterns rather than a definitive field
- **`frameworks`** — optional object with `nist80053r5` and `cisV8` arrays of control identifiers. **Use the lookup table in [Step 3a — Framework mapping](#step-3a--framework-mapping) verbatim**; do not invent or generalize citations. Omit the field entirely (or both arrays empty) if the check has no high-confidence mapping — `acg-geo-coords` is the only check intentionally left unmapped.

> **Important:** every finding the report emits must be one of the IDs below. Do not invent new IDs; if a check does not apply, omit the finding entirely (the report only shows triggered findings — no "passes" section).

#### App Connector Group checks

| ID | Severity | Check |
|---|---|---|
| `acg-n-plus-one` | warning | Each AC group has ≥ 2 connectors (N+1 minimum). Flag groups with 0 or 1. |
| `acg-geo-coords` | info | AC groups have non-empty `latitude` / `longitude` for geo-routing. |
| `acg-version-drift` | warning | Each connector's `current_version` matches `expected_version`. |
| `acg-cert-expiring` | warning | Connector enrollment certificates expiring in <30 days. Use `enrollment_cert.valid_to_in_epoch_sec` if exposed. |
| `acg-enclave-isolation` | warning (heuristic) | AC groups whose name matches `*sensitive*`, `*enclave*`, `*pci*`, `*hr*`, `*finance*` are referenced by **only** "enclave-style" server groups (no broad SGs). |
| `acg-lss-isolation` | warning (heuristic) | AC group whose 

Related in Design