Runtime operational security reference
This guide is the runtime security operations view of PADAS: trust boundaries between browser ↔ UI ↔ Core, the authentication surface each tier exposes, and deployment hardening choices that reduce runtime API exposure. It is implementation-aware—behaviour is tied to padas-core (padas-api Axum stack, auth_middleware, Rustls) and padas-ui (server/routes/routes.js, authenticateToken, authorizeRoles, handleToken.js), not generic security platitudes.
Related: Runtime configurations · Configuration & Runtime Engine · REST API Reference · Cores · Troubleshooting & Logs · Monitoring · Glossary · Users, roles & permissions · Quickstart: Core + UI
Trust boundaries and deployment model
| Boundary | Trust model |
|---|---|
| Browser ↔ UI | Human authentication to Node: POST /auth/login sets access_token / refresh_token HTTP-only cookies; subsequent authenticateToken verifies JWT against secret.json (ACCESS_SECRET / REFRESH_SECRET) and an in-memory whitelist (userTokenList.js). The browser never directly authenticates to Core for console flows. |
| UI ↔ Core | Service authentication: the UI process is a Core API client. Stored per-row account_token becomes Authorization: Bearer on outbound HTTPS to /api/v1/*. Runtime trust model: the UI server trusts Core only as far as TLS + that Bearer secret. |
| Core ↔ runtime objects | Runtime authorization on Core is binary for HTTP: valid Bearer (or auth disabled) gates the entire /api/v1/* surface—streams, tasks, connectors, reload, metrics. There is no per-UI-user ABAC inside padas-api. |
Separation of concerns: human authentication (who may open the console) is users.json + JWT. Service authentication (what the automation layer may do to engines) is service-account.token JSON on Core plus account_token in the UI registry. Token lifecycle events on either side cause runtime failures if operators do not update both stores when rotating.
UI bootstrap, RBAC, and operator profile
First-time UI administrator creation (POST /auth/init—no authenticateToken), JWT issuance via handleToken.js, route authorizeRoles(['admin','user']) matrices, and profile/password UX are documented in Users, roles & permissions. Treat /auth/init as part of ingress exposure: it remains mounted even after initialization (handler returns 409 when users.local is non-empty in userController.js).
Authentication and service accounts
Core: service-account Bearer (padas-core)
When [api.auth].enabled = true, ServiceAccountAuth is wired and Axum auth_middleware (padas-security, delegated from padas-api middleware.rs) wraps the embedded router when security_auth is Some (routes/mod.rs). Every route—including /api/v1/health, /metrics, /status—requires Authorization: Bearer <secret>; there is no anonymous bypass when auth is enabled.
Operational model: the Bearer string must match the active token field in JSON at [api.auth].service_account_token_file (default path pattern ./data/security/service-account.token under PADAS_HOME). save_token_with_metadata writes 0600 permissions and JSON only (token, expires_at epoch ms).
Token lifecycle: in-memory active token plus grace-period tokens after rotation; validate_token uses digest comparison. check_and_rotate_token / background task (when token_auto_generate) and POST /api/v1/auth/token/refresh move secrets forward; old tokens remain valid during grace—stale token behaviour for automation means any consumer still holding a rotated secret fails 401 once grace expires. Token compromise of the file or DB account_token grants full runtime API power equivalent to that Core row—rotate immediately and invalidate UI copies.
Automation implications: CI or scripts must read the same JSON token field the UI stores as account_token; after Core refresh, update automation secrets or UI rows or expect runtime failures on the next deploy/monitoring call.
curl -sS --tlsv1.2 --cacert /path/to/ca.pem \
-H "Authorization: Bearer YOUR_CORE_TOKEN" \
https://core.example.com:8999/api/v1/status
Core token introspection: GET /api/v1/auth/token/status. Rotation: POST /api/v1/auth/token/refresh (Bearer required; per-IP refresh rate limit in routes/system.rs / service_account/api.rs). Auth lockout: failed Bearer attempts increment per client IP derived from X-Forwarded-For / X-Real-IP; exceeding max_auth_attempts blocks even valid tokens until lockout_duration_secs elapses.
UI server: JWT session vs Core token
Backend mediation model: the browser trusts the UI origin and cookies. The UI trusts Core using server-side HTTP clients and account_token. authenticateToken (authMiddleware.js) reads req.cookies['access_token'], verifies with ACCESS_SECRET, and attaches req.user. authorizeRoles gates mutating and sensitive routes.js paths. handleToken.js issues and rotates JWT pairs on login and proactive refresh.
| Mechanism | Code path | Role |
|---|---|---|
| Human session | authenticateToken → verify / decode JWT | Human authentication to Express; req.user.roles drives authorizeRoles. |
| Core calls | apiService + stored account_token | Service authentication to Core; independent of browser—browser never directly authenticates to Core for product APIs. |
Core token maintenance routes (routes.js): GET /auth/core-token/status (+ authorizeRoles(['admin','user'])); POST /auth/core-token/refresh/:coreId and POST /auth/core-token/auto-refresh use authenticateToken only—any session role admin or user may trigger Core refresh handlers; there is no second authorizeRoles gate in the route table for those POSTs.
TLS and HTTPS
Core ([api.tls])
padas-api server.rs: [api.tls].enabled = true selects axum_server Rustls (RustlsConfig::from_pem_file on cert_file, key_file). false serves plain HTTP. API client validation behaviour is on the client side: Core does not install trust for outbound calls here—operators must align curl, UI JVM, and scrapers with the same certificate trust chain presented on 8999.
Self-signed operational realities: lab curl --insecure does not transfer trust to production browsers. TLS mismatch diagnostics: wrong scheme (http vs https), SNI/host mismatch, expired cert, or corporate MITM replacing chain—symptoms are TLS handshake errors before JSON.
[api.tls]
enabled = true
cert_file = "/var/lib/padas/etc/api.crt"
key_file = "/var/lib/padas/etc/api.key"
UI
Internal vs external TLS: dev http://localhost:5000 (server.js); production may wrap Node behind reverse proxy TLS termination. Browser trust vs server trust differ: the browser validates the UI certificate; the UI Node process validates Core when it calls https://core:8999. Reverse proxy deployments must forward Authorization, X-Forwarded-For, and X-Real-IP consistently or auth lockout and audit client IPs skew.
Runtime API exposure
Core
host = "0.0.0.0" binds the full /api/v1/* authentication surface (streams, tasks, connectors, query, system/reload, metrics). Auth-disabled Core ([api.auth].enabled = false) is dangerous outside isolated lab: any client on the network may mutate runtime state. There is no built-in IP allowlist in auth_middleware. Operational isolation: bind 127.0.0.1, place Core internal-only behind mesh/VPC, or front with reverse proxy + mTLS / network policy.
UI Express
routes.js exposes a large mutating API behind authenticateToken, but /auth/login, /auth/logout, /auth/init remain outside JWT—ingress restrictions must still block unauthenticated /auth/init from the Internet after bootstrap. auditMiddleware runs on mutating verbs for audit workflows (actor from token).
Operational security notes
- Bootstrap ordering: license →
secret.json+ emptyusers.json→POST /auth/init→POST /auth/login→ register Cores with Coreservice-account.token→GET /api/v1/statusfrom the UI host path (Quickstart: Core + UI). - Two token classes: JWT = human authentication to Node; Core Bearer = service authentication to the engine. Core rotation does not rewrite UI DB—use UI
/auth/core-token/refresh/:coreIdor edit the row. - Lockout correlation: Core Bearer failures use
X-Forwarded-For/X-Real-IP; mis-set proxies concentrate lockouts or hide attackers—validate reverse proxy implications before production. - Operational secrets:
PADAS_HOME(padas.toml,data/security/service-account.token, TLS PEMs) andPADAS_UI_HOME/data/security/(users.json,secret.json, UI TLS). Filesystem permissions and secure backups of those trees are part of security posture—restore drills must not publish tokens into ticketing plaintext.
Runtime hardening checklist
| Control | Implementation anchor |
|---|---|
| Enable TLS | [api.tls].enabled = true with real cert_file / key_file; terminate or passthrough consistently at ingress. |
| Enable auth | [api.auth].enabled = true; protect service_account_token_file. |
| Restrict ingress | Network policy / bind address; Core 8999 and UI listen port not on public Internet without proxy controls. |
| Rotate tokens | Core /api/v1/auth/token/refresh + UI /auth/core-token/*; update automation stores. |
Secure PADAS_HOME / PADAS_UI_HOME | OS permissions, separate disks, encrypted volumes where policy demands. |
| Use reverse proxy | Centralize TLS, optional WAF, canonical X-Forwarded-* handling. |
| Monitor failed auth | Core 401 rates + lockout logs; UI loginRateLimiter on /auth/login; correlate with Monitoring incident windows. |
| Review runtime API exposure | Inventory who can reach /api/v1/* and UI routes.js surface from each VLAN. |
| Secure backups | Registry + users.json + service-account.token contain operational secrets—encrypt at rest and restrict restore RBAC. |
Operational security troubleshooting
| Symptom | Likely runtime cause |
|---|---|
401 after Core change | Stale token: UI account_token or automation not updated after Core refresh or grace expiry. |
| TLS trust mismatch | UI JVM / Node CA store missing Core issuer; curl works with --cacert but product does not. |
| Browser cookie / session issues | JWT expired and refresh failed; refresh_token mismatch triggers removeUserToken path in authMiddleware.js. |
| Auth lockout | Too many bad Bearer attempts from one X-Forwarded-For IP at Core; or UI login rate limit. |
| Core API unreachable | Network, TLS scheme, or Core down—distinct from 401. |
| Refresh failures | Core 429 refresh rate limit; UI /auth/core-token/refresh error payload from coreTokenController.js. |
| Expired certificates | Rustls handshake failure on Core or UI/proxy front door—renew PEMs, reload process or proxy. |
| Reverse proxy auth/header problems | Stripped Authorization to Core; malformed X-Forwarded-For breaking lockout or audits. |
Deeper triage: Troubleshooting & Logs.
Security telemetry and monitoring
- Failed auth attempts: Core logs +
401spikes; UI login audit entries fromlogAuditinauthController.jspaths. - Token refresh activity: Core
/auth/token/refreshresponses; UI/auth/core-token/*JSON for operators. - Runtime API access patterns: combine
GET /api/v1/metricswithpadas.logwindows for suspicious connector or deploy traffic. - Monitoring correlations: EPS/drop anomalies coincident with auth errors often indicate mis-rotated tokens or overload—not “attacks” by default.
- Suspicious connector behaviour: high error rates after credential change—verify service authentication secrets for sink connectors vs Core Bearer confusion.
- Runtime anomaly investigation: use Monitoring first, then this document’s trust boundary table to decide which tier to fix.
Related pages
- Runtime configurations —
[api],[api.tls],[api.auth],[observability] - Configuration & Runtime Engine — engine + persistence context
- REST API Reference — Bearer usage,
curlpatterns, endpoints - Troubleshooting & Logs — TLS/auth/runtime triage
- Monitoring — security telemetry correlation with throughput
- Users, roles & permissions —
/auth/init, JWT,authorizeRoles - Cores —
account_tokenregistration and reachability - Glossary — Bearer, JWT session, token rotation, lockout terms