We've been running Perimeter 81 for about 9 months now, and while the core ZTNA works as advertised, their admin panel's session reporting felt like a black box. I wanted something real-time that my team could glance at, especially during deployments or security audits.
So I built a live dashboard. The key was their decently documented API. It's RESTful, uses bearer tokens, and gives you access to session data, gateway status, and user activity. I pulled the data into a simple Flask app with a React frontend. The main goal was visibility: who's connected, from where, to which resources, and for how long.
Here's the core of the polling script that hits the P81 API every 30 seconds:
```python
import requests
import time
def fetch_active_sessions(api_token, account_id):
headers = {'Authorization': f'Bearer {api_token}'}
url = f'https://api.perimeter81.com/api/v1/accounts/{account_id}/sessions'
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return response.json().get('sessions', [])
except requests.exceptions.RequestException as e:
# Log to your monitoring system
print(f"API Error: {e}")
return []
# Then structure the data for the frontend, e.g., count by gateway, user, etc.
```
The dashboard now shows:
* Real-time active session count, broken down by gateway region.
* A list of users with active connections, including their source IP (anonymized last octet for our internal view).
* Which internal applications/resources are being accessed.
* Session duration, highlighting any long-lived connections that might need a forced refresh.
The whole thing took a weekend. It's not fancy, but it eliminated the constant "are people still connected?" questions during our zero-trust migration phases. The main gotcha was rate limiting—had to implement some basic caching. If you're looking to do something similar, start with their `/sessions` and `/gateways` endpoints.
Build once, deploy everywhere
Hitting an external API every 30 seconds from your own infra. That's a predictable cost that nobody models until the bill arrives.
What's your polling setup? A cron job on a t3.micro that's always on? Or did you containerize it and now it's a constantly running pod on a K8s node? That's 2,880 requests per day, per dashboard instance. If you're polling multiple endpoints or have this replicated for DR, you're already into the hundreds of thousands of monthly requests before you've served a single user-facing page.
The Flask/React app itself is probably overkill for internal dashboards. A static HTML page with a bit of JavaScript fetching from a serverless function (triggered by the poll, not polling itself) would cost pennies. Instead, teams end up with a perpetually running web server, an always-on database for "state," and then complain about their cloud spend.
Did you at least consider making the poller a Lambda/Cloud Function that writes to a cheap cache, and having the dashboard read from that?
pay for what you use, not what you reserve
Thirty-second polling introduces a state synchronization problem you haven't addressed. Your dashboard will present stale or missing data for any session that terminates between polls, which is critical for security audits. The API's session list is a point-in-time snapshot, not an event stream.
A more reliable method is to implement a simple event log. Augment your poller to diff the session list against the previous state, then push discrete connection/disconnection events to a small internal datastore, like SQLite or Redis. Your frontend should query your event log, not the raw API response. This gives you an audit trail and correct state representation.
Also, that bare `print` statement for errors is a problem. You need structured logging with severity levels piped to a monitoring system. Without metrics on your poller's health and API latency, you're creating a second black box.
Data first, decisions later.