On-prem SIEM relay
The cloud cannot reach a SIEM appliance inside your network, so the relay runs on a box on your LAN, pulls device and tamper events outbound over HTTPS with an API key, and forwards each one to your SIEM as a CEF record over syslog. Nothing inbound from the internet is required.
Prerequisites
- An always-on Windows box on your LAN with Windows PowerShell 5.1 or later
- Outbound HTTPS from that box to siem.permitusb.com
- A PermitUSB API key with the events:read scope, created on the API keys page. It is shown once, so copy it then
1. Download
From the API keys page, download PermitUSB-SIEM-Relay.ps1 and the sample relay-config.json.sample onto the relay box, for example into C:\PermitUSB\.
The relay is EV code-signed by JJMK Studios, LLC, so Windows runs it under a RemoteSigned or AllSigned execution policy without the Mark-of-the-Web block, and no Unblock-File step is needed. Confirm the signature before trusting it:
Get-AuthenticodeSignature C:\PermitUSB\PermitUSB-SIEM-Relay.ps1It is an ASCII-only PowerShell script, so you can open it in any editor and review exactly what it does before running it.
2. Configure
Copy the sample to relay-config.json beside the script and fill it in:
{
"ApiBaseUrl": "https://siem.permitusb.com",
"SyslogHost": "10.0.0.50",
"SyslogPort": 514,
"SyslogProtocol": "udp",
"SyslogBindAddress": null,
"PollIntervalSeconds": 30
}| Setting | What it does |
|---|---|
| ApiBaseUrl | Your PermitUSB base URL. |
| SyslogHost and SyslogPort | Your SIEM’s syslog listener. |
| SyslogProtocol | udp, tcp or tls. TLS validates the server against the machine trust store: import an internal CA there rather than disabling validation. |
| SyslogBindAddress | Optional. On a multi-homed relay box, the local source IP to send syslog from. It pins only the syslog egress, not the outbound poll, and an unbindable address logs a warning and falls back to the default source rather than dropping events. |
| PollIntervalSeconds, BatchSize, StatePath | Optional. Defaults are 30, 200, and a cursor file beside the script. |
3. Test it
Run a single batch and exit, to confirm connectivity and that records land in your SIEM. A bad or revoked key exits with an authentication error, and a syslog outage backs off without advancing the cursor, so nothing is lost.
powershell -NoProfile -ExecutionPolicy Bypass -File .\PermitUSB-SIEM-Relay.ps1 -OnceTo see exactly what the relay would forward before you have a SIEM listening, add -Preview. It prints each CEF record to the console, sends nothing, and does not save the cursor, so it never disturbs a real relay. The syslog settings are not required for a preview.
powershell -NoProfile -ExecutionPolicy Bypass -File .\PermitUSB-SIEM-Relay.ps1 -Preview -OnceIf it prints nothing, your cursor is already caught up. Set SinceIso in the config, or point StatePath at a throwaway file, to replay history.
4. Run it continuously
Without -Once the relay loops forever. Register it as a scheduled task that runs at startup as SYSTEM and restarts on failure:
schtasks /Create /TN "PermitUSB SIEM Relay" /SC ONSTART /RU SYSTEM /RL HIGHEST ^
/TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\PermitUSB\PermitUSB-SIEM-Relay.ps1 -ConfigPath C:\PermitUSB\relay-config.json"The -ExecutionPolicy Bypass argument applies only to that invocation. The relay keeps a cursor in its state file, so a restart resumes where it left off. Delivery is at-least-once, so dedupe SIEM-side on the CEF externalId, which is the PermitUSB event id.
Linux with systemd
Prefer a service on a Linux box to a script on Windows? Download the relay for your CPU architecture from the API keys page, unpack it, and run the installer:
tar xzf relay-linux-arm64.tar.gz
sudo bash install.shThat installs a static binary to /usr/local/bin, an unprivileged permitusb-relay service account, and a systemd unit. Put your API key in /etc/permitusb-relay/relay.env and the syslog destination in /etc/permitusb-relay/config.json, then dry-run and enable:
sudo bash -c 'set -a; . /etc/permitusb-relay/relay.env; \
permitusb-siem-relay -config /etc/permitusb-relay/config.json -preview -once'
sudo systemctl enable --now permitusb-siem-relay
journalctl -u permitusb-siem-relay -fSame config shape and CEF output as the Windows relay. Systemd handles start-at-boot and restart-on-failure, and there is no TLS setup to do.
What gets forwarded
Every device-control and security event, as CEF, with stable signature IDs you can alert on:
| Signature IDs | Meaning |
|---|---|
| 1001 / 1002 / 1003 | Device connected, disconnected, and re-blocked by the reconciler after a re-enable. |
| 2001-2004 | The enforcement verdict: allowed (2001), blocked (2002, Warning), audited (2004). Code 2003 is reserved and not emitted in this release. |
| 3001-3004 | Tamper attempt (Warning), then suspected, reported and user-allowed HID injection. |
| 4001-4005 | Policy stale (Warning), kernel enforcement unavailable (Error), agent uninstalled or endpoint decommissioned (Warning), agent upgrade failed (Warning) or interrupted. |
| 5001-5003 | Protection paused by a user (Warning), resumed, and resume sweep failed (Error), meaning a device admitted during the pause may still be enabled. |
The relay drains both feeds automatically, device events and tamper or policy events, with no extra configuration. If your SIEM applies a severity floor, note that routine allow and connect events are below Warning, while blocks, tamper, HID injection, protection pauses and failed resume sweeps are Warning or above and survive a Warning-and-above filter.
Updating
On Windows, download the script again and replace the copy on the relay box. Your relay-config.json and state file are untouched.
On Linux, download the new tarball for your architecture, unpack it, re-run the installer, then restart the service. The installer overwrites the binary and the systemd unit but keeps your config, your API key and the cursor state.
tar xzf relay-linux-arm64.tar.gz
sudo bash install.sh
sudo systemctl restart permitusb-siem-relaySomething missing or wrong here? Tell us. Documentation gaps get filled fast.



