Host Agents
Deploy the QNSP Host Agent to discover cryptographic assets across your server fleet and report them to the QNSP platform.
Host Agents
The QNSP Host Agent is a lightweight CLI daemon that discovers cryptographic assets on your servers — SSH keys, TLS certificates, PKCS#12/JKS keystores, and active TLS endpoints — and reports them to the QNSP platform for inventory, exposure analysis, and PQC migration planning.
Host Agents are one of the two primary discovery modes in QNSP:
- Cloud/API connectors for managed providers with usable APIs
- QNSP agents for private, self-hosted, host-local, cluster-local, and on-prem environments
Use agents when the assets are not fully reachable through provider APIs or when you need evidence from inside the customer environment.
Prerequisites
- Node.js 20 or later
- An active QNSP tenant
host-agent-ingestionfeature enabled for your tenant (contact your account team if not enabled)tenant_adminrole to register agents
Quick Start
In the migration journey, agents support the Connect and Discover stages. They do not replace application cutover. Migration is only complete once production trust dependencies are consumed from QNSP services and continuously validated by QNSP.
1. Register an agent
In the QNSP portal, navigate to Crypto Posture → Host Agents → Register Agent.
Give the agent a name (e.g. web-01-prod) and click Register Agent. You will receive:
- Agent ID — a UUID identifying this agent
- Agent Secret — a 64-character hex string shown once only. Store it securely.
Alternatively, register via the API:
curl -sS -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "x-qnsp-tenant-id: $TENANT_ID" \
-d '{"name": "web-01-prod"}' \
https://api.qnsp.cuilabs.io/proxy/crypto/v1/agents
Response:
{
"agent": {
"id": "<agent-uuid>",
"name": "web-01-prod",
"status": "active",
"labels": {},
"lastSeenAt": null,
"createdAt": "2026-03-06T00:00:00.000Z",
"updatedAt": "2026-03-06T00:00:00.000Z"
},
"secret": "<64-char-hex-secret>",
"warning": "Store this secret securely. It will not be shown again."
}
2. Install the agent
npm install -g @qnsp/agent
Requires Node.js 20+. The package installs the qnsp-agent binary globally.
3. Configure the agent
Run the interactive setup wizard:
qnsp-agent configure
Or set environment variables directly:
export QNSP_AGENT_ID=<agent-uuid>
export QNSP_AGENT_SECRET=<64-char-hex-secret>
export QNSP_ENDPOINT=https://api.qnsp.cuilabs.io
export QNSP_TENANT_ID=<tenant-uuid>
Or create a config file at ~/.qnsp-agent/config.env:
QNSP_AGENT_ID=<agent-uuid>
QNSP_AGENT_SECRET=<64-char-hex-secret>
QNSP_ENDPOINT=https://api.qnsp.cuilabs.io
QNSP_TENANT_ID=<tenant-uuid>
4. Run a scan
# Run once and exit
qnsp-agent run
# Run continuously on the configured interval (default: 5 minutes)
qnsp-agent daemon
Configuration Reference
| Variable | Required | Default | Description |
|---|---|---|---|
QNSP_AGENT_ID |
✅ | — | Agent UUID from the QNSP portal |
QNSP_AGENT_SECRET |
✅ | — | 64-char hex secret from registration |
QNSP_ENDPOINT |
✅ | — | https://api.qnsp.cuilabs.io |
QNSP_TENANT_ID |
✅ | — | Your tenant UUID |
QNSP_SCAN_PATHS |
❌ | /etc/ssl,/etc/pki,/etc/ssh,/home,/root,... |
Comma-separated paths to scan |
QNSP_INTERVAL_SECS |
❌ | 300 |
Report interval in daemon mode (30–86400) |
QNSP_LOG_LEVEL |
❌ | info |
silent, error, warn, info, debug |
QNSP_HOSTNAME |
❌ | os.hostname() |
Override the reported hostname |
What the Agent Discovers
| Asset Type | Examples |
|---|---|
| SSH private keys | id_rsa, id_ecdsa, id_ed25519, *.key |
| X.509 certificates | *.pem, *.crt, *.cer, *.der |
| PKCS#12 keystores | *.p12, *.pfx |
| JKS keystores | *.jks, *.keystore |
| JWT signing keys | Files matching jwt*.pem, signing*.pem |
| TLS endpoints | Active TLS listeners on common ports (443, 8443, etc.) |
For each asset, the agent reports: type, file path, algorithm, key size (where applicable), expiry date (for certificates), subject/issuer (for certificates), and a SHA-256 fingerprint.
Running as a System Service
systemd (Linux)
[Unit]
Description=QNSP Host Agent
After=network.target
[Service]
ExecStart=/usr/local/bin/qnsp-agent daemon
EnvironmentFile=/etc/qnsp-agent/config.env
Restart=always
RestartSec=30
User=qnsp-agent
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now qnsp-agent
launchd (macOS)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>io.cuilabs.qnsp-agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/qnsp-agent</string>
<string>daemon</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>QNSP_AGENT_ID</key> <string>YOUR_AGENT_ID</string>
<key>QNSP_AGENT_SECRET</key> <string>YOUR_AGENT_SECRET</string>
<key>QNSP_ENDPOINT</key> <string>https://api.qnsp.cuilabs.io</string>
<key>QNSP_TENANT_ID</key> <string>YOUR_TENANT_ID</string>
</dict>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
Agent Status Values
| Status | Meaning |
|---|---|
active |
Agent is registered and can submit reports |
disabled |
Agent is temporarily suspended — reports will be rejected |
revoked |
Agent access is permanently revoked — cannot be re-activated |
Security Model
The agent authenticates each report using HMAC-SHA256:
- The bootstrap secret is never stored in plaintext on the server. The server stores
SHA-256(secret)as the HMAC key. - For each report, the agent computes:
HMAC-SHA256(SHA-256(secret), timestamp + "." + nonce + "." + SHA-256(body)) - The server verifies the signature, checks the timestamp is within ±300 seconds, and enforces nonce uniqueness (anti-replay).
- Reports are rejected if the agent is
disabledorrevoked.
The agent secret is shown once at registration. If lost, rotate it via Crypto Posture → Host Agents → Rotate Secret or the API:
curl -sS -X POST \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "x-qnsp-tenant-id: $TENANT_ID" \
https://api.qnsp.cuilabs.io/proxy/crypto/v1/agents/<agent-id>/rotate
CLI Commands
qnsp-agent run Scan the host and submit a report, then exit
qnsp-agent daemon Run continuously on the configured interval
qnsp-agent configure Interactive setup wizard
qnsp-agent status Print current configuration (no secrets printed)
qnsp-agent version Print version
qnsp-agent help Print help
Troubleshooting
Invalid agent configuration — One or more required environment variables are missing or invalid. Run qnsp-agent status to see the current config (secrets are not printed).
Report rejected (401) — The agent secret is wrong or the agent ID does not exist. Re-register or rotate the secret.
Report rejected (403) — The host-agent-ingestion feature is not enabled for your tenant, or the agent belongs to a different tenant.
Agent is not active — The agent has been disabled or revoked. Re-enable it in the portal or register a new agent.
Nonce already used (replay detected) — The same request was submitted twice within 10 minutes. This is a no-op — the first submission was accepted.
Timestamp outside acceptable range — The system clock on the agent host is more than 5 minutes out of sync. Sync the clock with NTP.