Security¶
This page is deliberately blunt about what DockSight protects today and what it does not. Deploy accordingly.
Current limitations¶
Read this section before exposing DockSight to an untrusted network.
Agent connections are unauthenticated
The /agents WebSocket endpoint accepts any connection that reaches it. An
attacker who can reach the platform can register as an agent, appear in your
dashboard, and receive container commands intended for a real host.
Token authentication is the top security item on the
Roadmap. Until it lands, treat network reachability
of /agents as the trust boundary: keep the platform on a private network,
behind a VPN, or restrict /agents by source IP at your proxy.
TLS is supported but not enforced
If you install an agent with an http:// URL, the session is ws:// —
plaintext. Nothing warns you at runtime. Every message, including container
names, log contents and command results, crosses the network in the clear.
Use https:// platform URLs so agents negotiate wss://.
No authorization model
There are no users, roles or scopes for agent operations yet. Access to the dashboard is access to every managed host.
The Docker socket¶
This is the most important thing to understand about running an agent.
Access to the Docker socket is equivalent to root on the host. Anyone who can
talk to /var/run/docker.sock can start a container that mounts / and
therefore read or write any file on the machine, regardless of container
isolation.
The agent runs as root and reads the socket directly. That is a deliberate
trade-off, and it is worth being explicit about what it means:
| Consequence | Detail |
|---|---|
| The agent is a high-value target | Compromising it is equivalent to compromising the host |
| Platform commands are powerful | The platform can start, stop and restart any container on the host |
| Isolation does not help | No container boundary protects a host whose socket is being used |
What DockSight does to limit exposure:
- The socket never leaves the host. It is read locally over a Unix socket; the Docker API is never published to the network. This is the primary reason the agent exists at all.
- The agent exposes no inbound port. There is nothing to connect to.
- The command surface is narrow. The agent implements a fixed set of message types — list, inspect, start, stop, restart, log streaming — rather than proxying arbitrary Docker API calls.
Adding a user to the docker group grants root
This is a Docker property, not a DockSight one, but it surprises people:
usermod -aG docker alice is effectively alice ALL=(ALL) NOPASSWD: ALL.
Identity¶
Each agent generates a UUID v4 on first connection and persists it at
/etc/docksight-agent/identity.json (mode 0600).
What identity is today: a stable name so the platform recognises a host across restarts, upgrades and reinstalls.
What identity is not today: a credential. It is not secret, not verified, and
not proof of anything. Anyone who can reach /agents can claim any UUID.
That is precisely what token authentication will change: registration will require a secret issued by the platform, and identity will become a claim the platform can verify.
Never copy identity.json between machines
Two agents sharing one UUID means the platform sees a single host whose facts flip between two machines — and commands land on whichever connected most recently.
Credentials on disk¶
The platform installer generates credentials with crypto/rand — never
math/rand, whose output is reconstructible from a few samples and would make
a JWT signing key forgeable.
| File | Mode | Contents |
|---|---|---|
/opt/docksight/.env |
0600 |
Database password, JWT secret |
/etc/docksight-agent/config.yaml |
0640 |
Platform URL, socket path |
/etc/docksight-agent/identity.json |
0600 |
Agent UUID |
Generated values are 48 random bytes rendered as 64 base64url characters. The
alphabet matters: A–Z a–z 0–9 - _ contains nothing a shell, a compose file or a
PostgreSQL connection string would treat as syntax, so a password can never
break the file it lands in.
Why .env is never regenerated¶
Re-running the installer leaves an existing .env untouched. PostgreSQL bakes
the password into its data volume at first boot; regenerating
POSTGRES_PASSWORD on an upgrade would lock the platform out of its own
database, and a new JWT_SECRET would invalidate every session. The check is
performed with O_CREATE|O_EXCL rather than "stat then write", so two concurrent
installs cannot both decide to write.
Reading them back¶
.env is 0600 and root-owned, so sudo cat is required — and docker compose
must also run as root. Running Compose as a non-root user in the docker group
means it cannot read .env, every variable interpolates empty, and Postgres
refuses to start with a blank password. Compose reports that only as
warning: The "POSTGRES_PASSWORD" variable is not set.
Platform isolation¶
graph LR
I[Internet] -->|only published port| N[nginx :2002]
N --> W[web]
N --> S[server]
S --> P[(postgres)]
S --> R[(redis)]
postgresandredispublish no ports. They are reachable only from the internaldocksight-networkbridge.webandserverpublish no ports either; nginx is the sole entry point.- Internal services are addressed by container name on a dedicated bridge network, not through the host.
The practical consequence: a port scan of the platform host finds one open port.
Terminate TLS in front
DockSight ships nginx configured for plain HTTP on 2002. For anything
beyond a private network, put a TLS-terminating proxy in front (or extend
the shipped nginx config with certificates) and use https:// for the
dashboard and agent URLs.
Container isolation¶
DockSight does not sandbox the containers it manages — it observes and controls them through Docker. Standard Docker security practice still applies to your workloads:
- Avoid
--privilegedand unnecessary capability grants. - Do not bind-mount the Docker socket into application containers.
- Prefer read-only root filesystems and non-root users in images.
The platform's own stack follows the parts of this that apply: no service mounts the Docker socket, and only nginx is exposed. The agent is the sole component that touches Docker, and it runs on the host, not in a container.
Supply chain¶
Releases are downloaded from the GitHub Releases API over HTTPS. Two properties of the installer are worth knowing:
Archive extraction is path-traversal guarded. A tar entry named
../../etc/cron.d/x or /etc/passwd is rejected rather than written. Since
installs run as root, an unguarded extractor would let a tampered release write
anywhere on the host. Symlink entries are skipped for the same reason.
Binaries are replaced atomically. New binaries are staged next to their
destination and moved into place with a rename, so an interrupted install cannot
leave a half-written executable on PATH.
What is not done yet:
- No checksum verification of downloaded assets.
- No signature verification.
- No pinning of the release host.
If you need those today, download assets manually, verify them out of band, and install from a local path.
Hardening checklist¶
For a deployment beyond a trusted private network:
- Put the platform behind TLS and use
https://platform URLs everywhere - Restrict
/agentsat the proxy — source IP allow-list or mTLS — until token authentication ships - Keep the platform off the public internet, or behind a VPN
- Treat every agent host as root-equivalent to the platform's reach
- Limit who can read
/opt/docksight/.env - Back up the database volume (
postgres-data) and.envtogether — the password in one must match the volume in the other - Watch
journalctl -u docksight-agentfor unexpected reconnect churn
Reporting a vulnerability¶
Please do not open a public issue for security problems. See Contributing for how to make private contact.