Skip to main content
Version: 2.0.0 (Latest)

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

BoundaryTrust model
Browser ↔ UIHuman 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 ↔ CoreService 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 objectsRuntime 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.

MechanismCode pathRole
Human sessionauthenticateTokenverify / decode JWTHuman authentication to Express; req.user.roles drives authorizeRoles.
Core callsapiService + stored account_tokenService 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 + empty users.jsonPOST /auth/initPOST /auth/login → register Cores with Core service-account.tokenGET /api/v1/status from 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/:coreId or 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) and PADAS_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

ControlImplementation 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 ingressNetwork policy / bind address; Core 8999 and UI listen port not on public Internet without proxy controls.
Rotate tokensCore /api/v1/auth/token/refresh + UI /auth/core-token/*; update automation stores.
Secure PADAS_HOME / PADAS_UI_HOMEOS permissions, separate disks, encrypted volumes where policy demands.
Use reverse proxyCentralize TLS, optional WAF, canonical X-Forwarded-* handling.
Monitor failed authCore 401 rates + lockout logs; UI loginRateLimiter on /auth/login; correlate with Monitoring incident windows.
Review runtime API exposureInventory who can reach /api/v1/* and UI routes.js surface from each VLAN.
Secure backupsRegistry + users.json + service-account.token contain operational secrets—encrypt at rest and restrict restore RBAC.

Operational security troubleshooting

SymptomLikely runtime cause
401 after Core changeStale token: UI account_token or automation not updated after Core refresh or grace expiry.
TLS trust mismatchUI JVM / Node CA store missing Core issuer; curl works with --cacert but product does not.
Browser cookie / session issuesJWT expired and refresh failed; refresh_token mismatch triggers removeUserToken path in authMiddleware.js.
Auth lockoutToo many bad Bearer attempts from one X-Forwarded-For IP at Core; or UI login rate limit.
Core API unreachableNetwork, TLS scheme, or Core down—distinct from 401.
Refresh failuresCore 429 refresh rate limit; UI /auth/core-token/refresh error payload from coreTokenController.js.
Expired certificatesRustls handshake failure on Core or UI/proxy front door—renew PEMs, reload process or proxy.
Reverse proxy auth/header problemsStripped Authorization to Core; malformed X-Forwarded-For breaking lockout or audits.

Deeper triage: Troubleshooting & Logs.


Security telemetry and monitoring

  • Failed auth attempts: Core logs + 401 spikes; UI login audit entries from logAudit in authController.js paths.
  • Token refresh activity: Core /auth/token/refresh responses; UI /auth/core-token/* JSON for operators.
  • Runtime API access patterns: combine GET /api/v1/metrics with padas.log windows 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.