Device posture policies
Posture policies enforce device-health requirements before a machine can access tagged resources. Out-of-compliance devices are auto-quarantined. This guide covers what signals are collected, how to write a policy, and how the remediation flow works.
Signals collected
The ztna agent reports these on every heartbeat (every 60 seconds):
E.g. Ubuntu 24.04.1 LTS, macOS 14.4.1, Windows 11 23H2.
LUKS2 (Linux), FileVault (macOS), BitLocker (Windows). Active state.
ufw, iptables, pf, Windows Firewall — any active host firewall.
clamav, XProtect, Defender, third-party AV. Active service required.
Auto-lock enabled + maximum idle minutes.
OS auto-update enabled.
Version of the ztna binary running.
Custom signals from external-posture integrations (Crowdstrike, SentinelOne).
Writing a posture policy
A policy is a named set of required signal values. Machines matching the policy's scope (by tag or group) must pass every requirement to be marked compliant.
{
"name": "strict-prod",
"scope": {
"tags": ["tag:prod", "tag:engineer"]
},
"requirements": {
"os_version_min": {
"linux": "22.04",
"darwin": "13.0",
"windows": "10.0.19041"
},
"disk_encryption": true,
"firewall": true,
"screen_lock": { "enabled": true, "max_idle_min": 10 },
"agent_version_min": "3.2.0"
},
"on_fail": "quarantine",
"grace_period_min": 30
} Enforcement
After every heartbeat, the backend evaluates the device against any matching policies.
- Compliant — all requirements pass. Machine is
online, normal ACL eval applies. - Non-compliant + grace period active — user is warned via dashboard + agent notification, but still connected.
- Non-compliant + grace expired —
on_failaction applies.
on_fail options:
Notify admin + user. No enforcement change.
Deny connections to tagged resources; allow tailnet connectivity.
Full isolation. No connections in or out. Can be lifted by admin or remediation.
Applying a policy
$ curl https://login.quickztna.com/api/db/posture_policies \
-H "Authorization: Bearer $QZ_API_KEY" \
-d '{
"rows": [{ /* policy JSON */ }],
"org_id": "org_9fX2kR"
}' Or in the dashboard: Device Security → Posture Policies → New.
Checking a device
$ ztna posture status
Device Posture · laptop-alex
─────────────────────────────
OS Version: Ubuntu 24.04.1 LTS ✓ (required: 22.04+)
Disk Encryption: LUKS2 (active) ✓
Firewall: ufw (enabled) ✓
Antivirus: clamav (active) ✓
Screen Lock: enabled (5min) ✓
Auto-Update: enabled ✓
Agent version: 3.2.0 ✓ (required: 3.2.0+)
Server verdict: COMPLIANT — all checks pass
Matched policy: strict-prod $ ztna machines list --filter posture=non_compliant
NAME IP VIOLATIONS GRACE
legacy-vm 100.64.1.55 os_version (20.04 < 22.04), agent (3.0.1) expired
prototype-01 100.64.1.88 disk_encryption, screen_lock 28 min left Remediation flow
When a policy fires:
- User sees in-dashboard notification + email with exact violations
- Dashboard shows "Remediation steps" —
sudo ufw enable, "enable FileVault in Settings", etc. - After remediation, user runs
ztna posture statusto self-verify - Next heartbeat (within 60s) reports fixed state — backend auto-unquarantines
# User sees dashboard: "Your device is quarantined because disk encryption is disabled."
$ sudo fdesetup enable # macOS — enable FileVault
# (reboot, enter password)
$ ztna posture status
Disk Encryption: FileVault (active) ✓
Server verdict: COMPLIANT
# User is automatically unquarantined at next heartbeat External posture sources
Pull signals from your existing EDR (Crowdstrike Falcon, SentinelOne) via /api/external-posture. The agent combines internal signals with external ones before the server evaluates.
$ curl https://login.quickztna.com/api/external-posture \
-H "Authorization: Bearer $QZ_API_KEY" \
-d '{
"action": "configure_source",
"org_id": "org_9fX2kR",
"provider": "crowdstrike",
"api_client_id": "...",
"api_secret": "...",
"sync_interval_min": 15
}' Using posture in ACL rules
Combine posture with ACL for a belt-and-braces approach. require_posture: true in a rule means "source must be compliant before this rule matches":
{
"name": "posture-gated-prod-access",
"src": "tag:engineer",
"dst": "tag:prod",
"proto": "tcp",
"ports": "22,443",
"require_posture": true
} Even if the source machine isn't quarantined, an ACL rule with require_posture denies the connection if posture is failing. Gives layered defence.
See also
- ACL policies — combining posture + tags
- Quarantine + unquarantine — the admin action behind auto-quarantine
- CLI: ztna posture status — what users see on their own device