Skip to content

Security

Myxo's concern is the boundary between processes. Authenticating your users and authorizing what they do remains your application's job.

Calls between processes

Calls between processes are not authenticated: whoever reaches a listener can call every operation of the services behind it. The defaults keep listeners out of reach:

Listener Who can reach it
unix:PATH the application's user alone: the socket's mode is 0600; a directory the runtime makes is 0700
http://..., default bind this machine, on 127.0.0.1
http://... on Kubernetes the application's own pods, by a network policy

So keep these true:

  • Prefer Unix sockets on one host.
  • Set bind to another address only behind a firewall or a network policy, since /rpc and /readyz answer there. myxo check warns about such a process.
  • Check that your cluster's network plugin enforces network policies.
  • Expose only the public port through your proxy or ingress.

Secrets

Keep them out of the layout: on Kubernetes the layout travels in a ConfigMap. Write ${DATABASE_URL} and let the platform supply the value:

Target Where secrets go
systemd /etc/NAME/env, mode 0600, read by the units
Hop3 hop3 env set; the PostgreSQL addon injects DATABASE_URL
Kubernetes the secret NAME-env

myxo export writes no value from the environment into env.example or the manifests.

Processes that parse untrusted files

Mark them privileges = "reduced", and keep the parsing out of the request, on the queue:

Target What it applies
systemd a read-only system, no home, private devices, no capabilities, a system-call filter, and restricted namespaces and address families
Kubernetes no root (uid 10001), no new privileges, no capabilities, a read-only root filesystem, the runtime's default system calls, and a scratch volume as TMPDIR
Hop3 nothing: the export refuses unless --without-sandbox

Kubernetes' context was checked in a running pod. On systemd, only the system-call filter was checked, since OrbStack's containers turn parts of the sandbox off. Check it on your own machine.

Messages

A malformed message that reaches a listener answers Invalid, status 422, with no call to the service: the runtime decodes it against the operation's type first. Field values are your service's to validate.

Events and streams

Push sends every event of the given types to whoever connects, so check authorization in front of it, and keep private data out of those events. Events stay readable in the database for an hour once handled.