Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Security model

taktwerk has four surfaces a network can reach: the OPC UA server, the http connector, taktwerk serve and SSH to devices. Client connectors reach out to a PLC or a plant data system with credentials from the environment or a file. The project file holds no secret: inline passwords are refused; a rest login body takes them as ${NAME} from the environment.

surfacelistens onwho may readwho may writetransport security
OPC UA server0.0.0.0:4840 by defaultevery accepted identityidentities with write access; outputs neverOPC UA sign, sign-encrypt
http connector127.0.0.1:8480 by defaultanyone who reaches itbearer token, with writes = truenone: loopback or a trusted network
taktwerk serveloopback onlythe local user’s browserbearer tokennone: loopback only
devicesthe device’s SSH serverthe login userthe login user; root for unitsSSH

OPC UA server

Open by default: anonymous, writable, no encryption, all interfaces, so any client on a closed machine network is a UI. On any other network:

  • bind endpoint to one interface;
  • anonymous = false, or anonymous_write = false for read-only anonymous sessions;
  • users with passwords from password_env or password_file, write = false for viewers;
  • security = ["sign-encrypt"] and the policies to offer; client certificates are trusted only from <pki_dir>/trusted/ unless trust_client_certs.

A user’s password on a "none" endpoint is encrypted with the server certificate, the values are not. Inputs and tunables are writable to identities with write access, through UserAccessLevel; outputs and system signals are read-only for everyone. Every write passes the image’s type, length and range checks; a refused tunable write is logged in events.csv. Keys in OPC UA server.

http connector

  • Reading needs no credentials. Writes and stop need writes = true and Authorization: Bearer <token>: TAKTWERK_HTTP_TOKEN, else a fresh token written to token_file (default $XDG_RUNTIME_DIR/taktwerk/http-<port>.token, mode 0600) and removed at shutdown.
  • No TLS. It listens on loopback by default; keep it there or on a network you trust.
  • On loopback a request is refused (403) unless its Host is a loopback address or localhost and no browser marks it cross-site (Sec-Fetch-Site), so a web page the operator opens cannot reach the engine through DNS rebinding.

On a device the bundle’s unit serves it on a loopback port with the token in the bundle’s env file; a host reaches it through an SSH port forward and reads the token over SSH.

taktwerk serve

  • Listens on loopback only; another address is refused.
  • A token (TAKTWERK_SERVE_TOKEN, else generated and printed in the URL’s fragment) is needed to check a project (it loads model libraries), start and stop runs, write values, shut down, and for every request that changes a device. Requests that change a device are refused when CI is set.
  • The same Host and Sec-Fetch-Site checks as the http connector.
  • Runs start without the project’s connectors unless asked, so the workbench talks to no plant by accident.
  • Passwords for SSH logins, sudo or su stay in memory until serve exits or the device’s session is forgotten; nothing is written to disk.

Devices

  • Every control call is an SSH exec, every file an SFTP transfer, the live view an SSH port forward: SSH authenticates and encrypts.
  • Host keys are pinned at the first verify and checked on every connection; a changed key is refused until it is pinned again (device verify --accept-host-key).
  • Logins use an SSH agent, key files, or a password asked for and never stored. devices.toml holds no secret.
  • The login user owns the install root; only unit changes and creating a missing root run as root, through the device’s privilege (none, sudo, su).
  • Secrets for the engine (password_env, token_env, TAKTWERK_HTTP_TOKEN) live in the bundle’s env file on the device, mode 600, which a deploy never rewrites.
  • Every mutating command is a dry run without --yes, and --yes is refused when CI is set.

See Deploying to devices.

Client connectors

  • opcua-client: security = "sign" or "sign-encrypt" (Basic256Sha256), credentials from password_env or password_file, server certificates trusted only from <pki_dir>/trusted/ unless trust_server_certs.
  • rest: plain HTTP only; https:// is refused. For a server that requires TLS, put a TLS proxy beside the engine. Credentials from the environment (Auth).
  • Both write to a plant only when the project says writes = "on", or for one run run --write <id>; "dry-run" logs what they would write (Dry run).

What taktwerk does not do

  • Models run in the engine’s process, with its privileges; a package is trusted code.
  • The engine is not a safety controller: the PLC owns the safe state (the safety contract).
  • No TLS on the http connector, serve or rest.