MiravoMiravo

Security

Network exposure defaults, unauthenticated protocol endpoints, writable members, and Docker port binding for Miravo.

Miravo is a simulator for development, testing, and demos. Run it on a laptop, a CI runner, or an isolated lab network. Do not expose it to the internet or to a production OT network.

Bind defaults

ListenerDefault bindOpt in to remote access
Admin API and Console127.0.0.1:8080--admin-host or MIRAVO_ADMIN_HOST
Embedded MQTT broker127.0.0.1:1883--mqtt-host, MIRAVO_MQTT_HOST, or template protocols.mqtt.host
OPC UA127.0.0.1:4840--opcua-host, MIRAVO_OPCUA_HOST, or template protocols.opcua.host
Modbus TCP127.0.0.1:1502--modbus-host, MIRAVO_MODBUS_HOST, or template protocols.modbus.host

Set a host to 0.0.0.0 to listen on every interface, or to a specific interface address.

What the endpoints do not protect

  • OPC UA accepts anonymous sessions. Its endpoints use a self-signed certificate, so signing and encryption do not restrict who can connect.
  • Modbus TCP has no authentication. Any client that reaches the port can read and write.
  • The embedded MQTT broker has no authentication or TLS. Any client can subscribe and publish.
  • Members with readwrite access accept writes over Modbus and OPC UA. MQTT is publish-only. A remote client can change simulated setpoints and states.
  • The admin API uses Basic Auth. The default password is admin. Set MIRAVO_ADMIN_PASSWORD before binding it beyond loopback.

Docker

The image binds the admin API and all protocol listeners to 0.0.0.0 inside the container, so published ports work. Control exposure on the host side with the port mapping:

ports:
  - "127.0.0.1:1883:1883"
  - "127.0.0.1:8080:8080"

A bare -p 1883:1883 publishes on every host interface. Use the 127.0.0.1: prefix unless you want LAN access.

Secrets

No command takes a secret as a flag value, because flag values leak into shell history and process listings.

  • Litmus Edge API token: set LITMUS_EDGE_API_TOKEN for le apply and le cleanup, or save it in a target. le target add and le target update read it from stdin with --api-token-stdin, and le target add asks through a hidden prompt on a terminal when the flag is omitted.
  • External MQTT broker password: set MIRAVO_MQTT_PASSWORD. start has no password flag. The username and password are never written to the saved state file; set MIRAVO_MQTT_USERNAME too. If it is missing at the next start, restore refuses to enable the MQTT adapter instead of connecting without it, and startup leaves MQTT off unless you pass an explicit --mqtt-* flag.
  • Saved targets, including their tokens, live in ~/.miravo/integrations/targets.json. le target inspect masks the token unless you pass --show-token.
printf %s "$LE_TOKEN" | miravo le target add --label demo --hostname 10.0.0.20 --source-hostname 172.17.0.1 --api-token-stdin

Checklist

  1. Keep the default loopback binds unless another machine must connect.
  2. Place exposed instances on an isolated network or behind a firewall that limits source addresses.
  3. Change MIRAVO_ADMIN_PASSWORD when the admin API is reachable by others.
  4. Treat writable members as open to every client on that network.
  5. Pass secrets through environment variables or stdin, never as flag values.

Outbound traffic

Miravo has no telemetry. The CLI makes one optional request: an update check against the GitHub Releases API.

  • Interactive terminal runs only. Skipped when stdout or stderr is not a TTY, when CI is set, with --quiet, with JSON output, and for completion.
  • At most once every 24 hours. The result is cached in ~/.miravo/state/update-check.json.
  • Sends an HTTPS request to api.github.com with a miravo/<version> user agent. It sends no other data.
  • Disable with MIRAVO_NO_UPDATE_CHECK=1. The Docker image sets it by default.

Was this page useful?

Last updated on