Administration
Security
This page explains how NGCP protects accounts, secrets, nodes and game servers, what you should do to harden an installation, and what is not done yet.
Secrets at rest
| What | How it is stored |
|---|---|
| Account passwords | Argon2id hashes (64 MiB, 3 passes), upgraded automatically when the parameters change |
| Session tokens, API keys, enrollment tokens | Only hashes are stored; the token is shown once |
| Two-step verification seeds | Sealed (AES-256-GCM) with the master key |
| Steam account passwords | Sealed; write-only through the API |
Game password variables (RCON, admin, join passwords) |
Sealed per service; write-only |
| Backup target passwords, private keys, secret keys | Sealed; write-only |
| Webhook signing secrets, SMTP password | Sealed; write-only |
| The internal certificate authority’s key and the agent-update signing key | Sealed in the database |
The master key (master.key next to controller.env, or NGCP_MASTER_KEY) unlocks all
sealed values. It is generated per installation by the setup and readable only by the
controller’s account (SYSTEM and Administrators on Windows). The controller refuses to start
without it. Back it up separately from the database: a database backup without the key
cannot be used to restore a working panel, and a key stolen together with the database exposes
every sealed secret. Key rotation tooling is not available yet.
Secrets are never written to logs. Steam passwords are masked in console output.
Connections
- Panel to nodes (AgentLink): gRPC over TLS 1.3 with client certificates on both sides. Each controller has its own internal certificate authority. A node’s certificate is bound to its node id, and the controller accepts only the current certificate of a node that has not been removed, so removing or re-enrolling a node revokes its old certificate at once.
- Enrollment: a one-time token (256-bit, stored hashed, valid 1 hour by default and at most 7 days) plus the CA hash. The agent checks the controller’s CA against the hash before it uses the token, so a wrong or spoofed controller never receives it. There is no “skip TLS verification” option. The agent’s private key is generated on the node and never sent.
- Agent updates: signed with an Ed25519 key whose public half the agent pinned at enrollment. The agent checks the signature before downloading and the SHA-256 after.
- Web and API: HTTP or HTTPS, your choice (TLS). Use HTTPS for anything outside a trusted network: session cookies, API keys and the one-line installers all depend on it.
- SFTP: SSH with an Ed25519 host key per node; the fingerprint is shown in the panel.
Game server isolation
- Every service runs as its own account (
ngcp_s<id>) that owns only its directory. Other services, the agent’s key and system files are not readable to it. This has been verified on Windows 11 and Ubuntu 24.04. - Processes run inside a Windows Job Object or a Linux cgroup with CPU, memory and process limits; stopping a service leaves no stray processes.
- The agent refuses any instruction whose account name is not an NGCP service account or whose
install directory is outside its services directory, so even a compromised controller cannot
make it run games as
root/Administratoror delete system folders. - SteamCMD runs as a separate node account (
ngcp_steam); game servers cannot read the cached Steam login. - Install scripts, hooks and scheduled scripts run as the service account with its limits, never as the agent. Only administrators can create scheduled scripts.
- Command lines are split into arguments before variables are filled in, so a variable value (for example a server name typed by a user) cannot add arguments to the game’s command line.
- Downloads in game definitions are HTTPS only and checked against published checksums; archives cannot write outside the install directory.
File access
The file manager, uploads, config forms and SFTP all go through one jail on the node:
- paths with
.., absolute paths, Windows drive letters, alternate data streams and device names are refused; - every access is opened relative to the service directory, so links and junctions cannot lead outside;
- deny rules are checked against the file’s real path after opening, so links and 8.3 short names cannot reach a denied file;
- archives cannot unpack outside the directory and links inside archives are skipped;
- quotas are checked before every write.
Web application
- Session cookies are
HttpOnly,SameSite=LaxandSecure(on HTTPS); every state-changing request also needs a CSRF token header. - A strict Content Security Policy (no inline scripts or styles),
X-Frame-Options: DENY,nosniff, a referrer policy and a permissions policy on every response; API answers are not cached. - The WebSocket accepts only same-origin connections, authenticates before the upgrade and re-checks the session every 30 seconds.
- Rate limits on sign-in (per IP), on authenticated callers and on anonymous endpoints.
- Lockout after repeated failed sign-ins, the admin IP allow-list, forced two-step verification for administrators (optional), and guards that stop you from locking yourself out.
- Resources you may not see answer “not found” rather than “forbidden”.
- The API documentation page is self-hosted and does not contact outside services.
Audit
Every change through the panel, the API and SFTP sign-ins is recorded with the account, the address and the details: sign-ins and failures, user and settings changes, service actions, console and RCON commands, file operations, backups, schedules and game definitions.
Hardening checklist
- Serve the panel over HTTPS (certificate files, or a reverse proxy with
NGCP_TRUSTED_PROXIES). - Back up the master key and the database, separately, and test a restore (Operations).
- Turn on two-step verification for your account, then Require two-step verification for admins.
- Set an admin IP allow-list if your administrators sign in from known addresses.
- Give people the lowest role that works; use per-user denies for exceptions. Use scoped, expiring API keys for integrations.
- Expose only what is needed: 443/8080 and 8443 on the controller; game ports and 2022 on nodes. Keep RCON ports closed (the agent uses them locally).
- Use a separate Steam account for servers.
- Pin the host key fingerprint on SFTP backup targets and use TLS for S3.
- Sign webhooks with a secret and verify the signature on the receiving side.
- Review the audit log for failed sign-ins and denied requests.
- Keep the controller and agents updated; update agents in a quiet hour, because their game servers restart.
- Leave Allow SFTP passwords for accounts with two-step verification off unless you need it.
Known limitations
- No certificate rotation or exportable revocation list for agent certificates yet (removal revokes immediately).
- No master-key rotation tooling yet.
- No automatic TLS certificates (ACME) yet.
- The installers and binaries are not code-signed yet.
- The admin IP list is an allow-list only; there is no deny-list.
- SFTP logins are cached on the node for 60 seconds, so a disabled account keeps SFTP access for up to a minute.
- Game config files can hold passwords (for example in ArmA’s
server.cfg); anyone with thefilespermission on that service can read them. - The one-line node installers verify package checksums published by the panel; they are as trustworthy as your connection to the panel.
- Linux seccomp / landlock sandboxing of game processes is not implemented.
- No software bill of materials (SBOM) is published yet.