Skip to main content
Version: 0.2.0 (Latest)

Runtime operational security reference

This guide is the runtime security operations view of PADAS: trust boundaries between the browser, Padas UI (the console), and the Motion Engine (console: Cores; tree: core/); the authentication surface each tier exposes; and deployment hardening choices that reduce runtime API exposure.

Related: Motion Engine TOML · Configuration & Runtime Engine · REST API Reference · Cores · Troubleshooting & Logs · Monitoring · Glossary · Users, roles & permissions · Run a sample pipeline


Trust boundaries and deployment model​

BoundaryTrust model
Browser ↔ consoleOperator login via POST /auth/login sets HTTP-only access_token / refresh_token cookies. Subsequent console API calls require a valid session signed with secrets in {PADAS_UI_HOME}/data/security/secret.json. The browser never directly authenticates to the engine for console workflows.
console ↔ engineService authentication: after enrollment, the console calls the engine over HTTPS using OAuth credentials stored on the engine host during enroll. Operators register host and port only in Cores—no token paste.
engine ↔ runtime objectsThe engine protects its HTTP API with TLS and authentication configured in padas.toml. The console uses the enrolled service identity for deploy and monitoring.

Separation of concerns: Operator login (who may open the console) uses console user accounts and session cookies. Service authentication (console to engine) is established by enrollment before you register a Core row. Direct engine API scripts (no console) may use separate engine API credentials—see Troubleshooting & Logs.


Padas UI bootstrap, RBAC, and operator profile​

First-time console administrator creation (POST /auth/init), session cookies, role checks (admin / user), and profile/password UX are documented in Users, roles & permissions. Treat /auth/init as part of ingress exposure: it remains reachable after initialization (returns 409 Conflict when a local user already exists).


Authentication and service accounts​

Motion Engine API auth​

Default (after enrollment): the engine validates OAuth S2S JWTs via [core.auth.server] (JWKS / issuer from the console AS, typically :9000). Callers send:

Authorization: Bearer <access_token>

Mint tokens with POST https://<ui-host>:9000/api/v1/auth/token (grant_type=client_credentials, aud=padas-core, scopes such as core:read / core:write). Use the enrolled Core client_id and secret under $PADAS_HOME/core/data/security/<client_id>.client.secret.

export PADAS_HOME=/opt/padas
UI=https://ui.example.com:9000
CORE=https://core.example.com:8999
CLIENT_ID=<enrolled-core-client-id>
SECRET=$(sudo cat "$PADAS_HOME/core/data/security/${CLIENT_ID}.client.secret")
CA="$PADAS_HOME/core/etc/certs/install-ca.crt"

TOKEN=$(curl -sS --cacert "$CA" -X POST "$UI/api/v1/auth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${SECRET}" \
--data-urlencode "aud=padas-core" \
--data-urlencode "scope=core:read" \
| python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))")

curl -sS --cacert "$CA" -H "Authorization: Bearer $TOKEN" \
"$CORE/api/v1/status"

Prometheus / metrics scrapers use the same JWT path against GET /api/v1/metrics — see Monitoring → External Prometheus scrape. Create a reader client in the console (Settings → Service clients or Services → Cores → Add reader client): grant-ready, core:read only, not Core enroll. Copy the secret once; do not put enroll credentials on the scraper host.

warning

data/security/service-account.token is not valid while S2S inbound auth is active. Scrapers and scripts that still send that opaque Bearer get 401 Unauthorized. That is expected, not an engine outage.

Loopback probes: GET /api/v1/health, /ready, and /metrics may omit JWT when the client is 127.0.0.1 / ::1. Remote callers always need a JWT when S2S is configured.

Legacy opt-in (migration only): opaque service-account inbound (ServiceAccountAuth, POST /api/v1/auth/token/refresh) works only when [core.auth.legacy].enabled = true and S2S inbound is not configured. If [core.auth.server] is set (normal enrolled appliance), enabling legacy is ignored — JWT remains the only inbound path. Do not disable enrollment just to revive the old token for Prometheus.

PathWhenCredential
S2S JWT (default)Enrolled Core / [core.auth.server] presentConsole AS client_credentials → Bearer JWT
Legacy service accountExplicit [core.auth.legacy] and no S2S server blockservice-account.token + refresh API
Auth offLab onlyNo Bearer (dangerous on non-loopback binds)

console: operator session vs engine access​

Mediation model: the browser trusts the console origin and session cookies. The console reaches the engine using credentials from enrollment—not a token the operator types into Cores.

MechanismRole
Operator sessionLogin and role checks gate console pages and mutating actions.
Engine callsAfter enrollment, deploy and monitoring use the S2S service identity on the engine host. The browser never calls the engine directly for product workflows.

TLS and HTTPS​

Motion Engine ([api.tls])​

When [api.tls].enabled = true, the engine serves HTTPS with cert_file and key_file. When false, the engine serves plain HTTP. API client validation is on the client side: the engine does not install trust for outbound calls—align curl, the console, and scrapers with the certificate 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"

console​

Default packaged listen is HTTPS on port 9000 (see local-config.json under {PADAS_UI_HOME}/etc/). Production may terminate TLS at a reverse proxy instead. Browser trust vs server trust differ: the browser validates the console certificate; the console process validates the engine when it calls https://core:8999. Reverse proxy deployments must forward cookies, Authorization (if used upstream), X-Forwarded-For, and X-Real-IP consistently or auth lockout and audit client IPs skew.


Runtime API exposure​

Motion Engine​

host = "0.0.0.0" binds the full /api/v1/* surface (streams, tasks, connectors, query, system/reload, metrics). An auth-disabled engine ([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. Operational isolation: bind 127.0.0.1, place the engine internal-only behind mesh/VPC, or front it with reverse proxy + mTLS / network policy.

console​

Mutating console routes require a valid operator session. /auth/login, /auth/logout, and /auth/init are outside the session gate—ingress restrictions must block unauthenticated /auth/init from the public Internet after bootstrap. Mutating API calls are audited (actor from session).


Operational security notes​

  • Bootstrap ordering: license → console admin setup → login → Services → Cores (create + enroll) → verify from the console host (Cores → Verification).
  • Two identity layers: operator login = who may use the console; enrollment = how the console may call the engine.
  • Lockout correlation: Engine 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: Motion Engine tree under $PADAS_HOME/core/ (padas.toml in etc/, enroll *.client.secret, TLS PEMs, optional legacy service-account.token) and PADAS_UI_HOME/data/security/ (users.json, secret.json, console TLS, data/security/s2s/ enroll registry). Platform $PADAS_HOME is /opt/padas. Filesystem permissions and secure backups of those trees are part of security posture—restore drills must not publish secrets into ticketing plaintext.

Runtime hardening checklist​

ControlOperator action
Enable TLSEngine [api.tls].enabled = true with real PEMs; console HTTPS or proxy termination consistent end-to-end.
Enable authPrefer enrolled [core.auth.server] (S2S JWT). Protect enroll *.client.secret files. Use legacy [core.auth.legacy] only for migration stragglers without S2S.
Restrict ingressNetwork policy / bind address; engine 8999 and console 9000 (or proxy front door) not on public Internet without controls.
Rotate credentialsRotate S2S client secrets via console admin / re-enroll. Legacy POST /api/v1/auth/token/refresh only when legacy inbound is active. If console deploy auth fails, re-enroll or restart the engine after enroll.
Secure $PADAS_HOME / PADAS_UI_HOMEOS permissions on the platform root (/opt/padas), the engine tree (core/), and the console tree (ui/); separate disks, encrypted volumes where policy demands.
Use reverse proxyCentralize TLS, optional WAF, canonical X-Forwarded-* handling.
Monitor failed authEngine 401 rates + lockout logs; console login rate limits on /auth/login; correlate with Monitoring incident windows.
Review runtime API exposureInventory who can reach engine /api/v1/* and console mutating routes from each VLAN.
Secure backupsRegistry DB, users.json, enroll material (*.client.secret, install CA), and any leftover service-account.token contain operational secrets—encrypt at rest and restrict restore RBAC.

Operational security troubleshooting​

SymptomLikely runtime cause
401 with service-account.tokenS2S inbound is active; opaque legacy token is rejected. Mint a JWT from the console AS (aud=padas-core) — Monitoring → Prometheus scrape.
401 after engine changeEnrollment incomplete, engine not restarted after enroll, stale client secret, or wrong aud/scope. Re-run enrollment or confirm engine [core.auth.server].
TLS trust mismatchThe console or curl missing the install / engine CA; curl --cacert works but console does not—align trust store with enroll install-ca.crt.
Browser cookie / session issuesJWT expired and refresh failed; blocked cookies or wrong console origin.
Auth lockoutToo many bad Bearer attempts from one X-Forwarded-For IP at the engine; or console login rate limit.
Engine API unreachableNetwork, TLS scheme, or engine down—distinct from 401.
Deploy returns auth errorsEnroll incomplete or engine not restarted—see Installation — padas-motion.
Engine token refresh failuresLegacy /api/v1/auth/token/refresh 429 rate limit — only relevant when [core.auth.legacy] is the active inbound path.
Expired certificatesTLS handshake failure on the engine or console/proxy front door—renew PEMs, reload process or proxy.
Reverse proxy auth/header problemsStripped headers to the engine; malformed X-Forwarded-For breaking lockout or audits.

Deeper triage: Troubleshooting & Logs.


Security telemetry and monitoring​

  • Failed auth attempts: Engine logs + 401 spikes; console login audit entries.
  • Token mint activity: Console AS POST /api/v1/auth/token (S2S). Legacy engine /api/v1/auth/token/refresh only when legacy inbound is enabled.
  • Runtime API access patterns: combine GET /api/v1/metrics with engine log windows for suspicious connector or deploy traffic; external scrapers should use JWT — Prometheus scrape.
  • Monitoring correlations: EPS/drop anomalies coincident with auth errors often indicate enrollment misconfiguration or overload—not “attacks” by default.
  • Suspicious connector behaviour: high error rates after credential change—distinguish connector secrets from engine Bearer vs console enroll paths.
  • Runtime anomaly investigation: use Monitoring first, then this document’s trust boundary table to decide which tier to fix.