Security
This page describes the security model of navin-manager. The binding reference is section 5 of
navin-manager/CONTRACT.md.
Sign in
| Source | Details |
|---|---|
| Local accounts | Passwords hashed with scrypt (cost NM_SCRYPT_N, 32768 by default). Policy: minimum length (12), four character classes, no username inside, history of the last 5 passwords, optional maximum age. |
| LDAP or Active Directory | Service bind, user search with an escaped filter, user bind, groups from memberOf or a group search, LDAPS or StartTLS with the bank CA. Group to role mappings are applied at every sign in. |
| OIDC (Keycloak, Entra ID) | Authorization code with PKCE S256, state and nonce stored hashed and single use, ID token checked against the JWKS (signature, issuer, audience, expiry, nonce). The groups claim maps to roles. Redirects go only to a relative path of the console. |
The initial account is navin, as on the platform. The server creates it at its first start with the initial
password of NM_ADMIN_PASSWORD (/etc/navin-manager/server.env): that password only serves the first sign in, the
console then asks for a personal password before it opens a session, and a restart never sets it again. On a local
install (sandbox) it is navin / navin; in production navin-manager check refuses a weak initial password and the
package writes a random one. Lost password: navin-manager reset-admin sets the initial password again, to change at
the next sign in, closes the sessions of the account and records it in the audit. Other administrators are created
from the Users page or with navin-manager create-admin --username <name> --password-stdin (password to change at the
first sign in).
Second factor. TOTP (RFC 6238, 30 seconds, 6 digits, one step of tolerance, a code is never accepted twice) and
10 single use recovery codes. The policy makes the second factor mandatory for roles (by default admin and
security_admin): users with such a role enroll at their next sign in.
Lockout and rate limits. After 5 failures (setting lockout_threshold) an account is locked for 15 minutes
(lockout_minutes). Sign in attempts are rate limited per address and per user name (HTTP 429 with Retry-After).
An unknown user name costs the same time as a known one.
Sessions and tokens
Sessions are stored on the server. The cookie nm_session is HttpOnly, Secure, SameSite=Strict. A session
ends after 30 minutes without activity or 12 hours in total (session_idle_minutes, session_absolute_hours).
Every modifying request with a session carries the header X-CSRF-Token. A password change ends the other sessions
of the user.
API tokens (Authorization: Bearer nmt_<id>_<secret>) are shown once, stored as sha256, expire, can be revoked and
can be restricted to a subset of the permissions of their owner. Use them for automation and for the Prometheus
service discovery.
Roles and permissions
| Role | Scope | Main rights |
|---|---|---|
admin | global | everything |
security_admin | global | users, authentication, audit, certificates |
cluster_admin | global or one cluster | hosts, install and operate services, configurations, alerts |
operator | global or one cluster | start, stop, restart, commands, logs, alerts |
viewer | global or one cluster | read only |
auditor | global | audit log and read only |
A binding of a role to one cluster never grants the global permissions (users, authentication, settings, connections, cluster creation). Every refusal is written to the audit log.
Secrets
Every secret (service passwords, identity provider secrets, connection passwords, agent secrets, CA key, payloads of
tasks that carry configuration files) is sealed with AES-256-GCM and the master key
(/etc/navin-manager/master.key, 32 random bytes, owned by navin-manager, mode 0600, created when the package is
installed or by navin-manager init-key; the server refuses a key readable by group or others). The API never
returns a secret: it shows {"secret": true, "set": true}. Configuration previews, diffs and task summaries mask
secrets. Keep a copy of the master key in the bank vault: without it the stored secrets cannot be read.
Vault and service consoles
The vault (page Administration, Vault, permission vault:manage) keeps the address, the login, the password and the
key of every installed service, sealed like the other secrets; only the name is stored in clear, and showing a
password (POST /api/v1/vault/entries/{id}/reveal) is audited.
- Every install generates its own passwords and keys (catalogue parameters with
generate): no password is shared between two clusters or two customers, and no service keeps a default password. - After every successful install or configuration apply, the Manager creates or refreshes the vault entry of the
service with the values now applied (
vault.syncis audited when a refresh fails).POST /api/v1/vault/importrefreshes the services installed before. - A field an administrator changes by hand is kept by the next refresh. The login, password and key of a console
whose credentials the service reads from its configuration at every start (HAProxy statistics, LiteLLM, SeaweedFS
admin, ClickHouse) change only through Change the password
(
POST /api/v1/clusters/{id}/consoles/{service}/credentials/rotate,configs:editandvault:manage): new configuration version, apply operation, then the vault. A password applied only at the first start or shared with other services (Keycloak, OpenSearch) is changed in the console of the service, then recorded in the vault.
The page Consoles (services:operate, operators and administrators) lists the local web interfaces of the installed
services. Each console is checked against four requirements: HTTPS, an internal DNS name (never localhost nor an
IP address), an authentication (its own sign-in, or the authenticating gateway declared by an administrator) and no
resource loaded from the Internet. On a production or preproduction cluster a console that fails a check cannot be
opened; elsewhere the checks are shown as warnings. Opening a console goes through
POST /api/v1/clusters/{id}/consoles/{service}/open, which is audited (console.open). An administrator with
cluster:manage publishes the internal address of a console behind the HTTPS gateway of the bank
(PUT .../consoles/{service}/access). The consoles of identities and secrets (Keycloak, OpenBao, OpenFGA)
are reserved to the holders of vault:manage: the others see them locked, without their address.
Audit
Every change and every refusal is an audit event. Events are chained by sha256 (each event stores the hash of the
previous one); GET /api/v1/audit/verify recomputes the chain and reports the first altered event. Exports in
NDJSON or CSV feed the SIEM of the bank. Audit events are never purged by the retention jobs.
Agents and hosts
- The agent opens every connection: managed hosts expose no port for the manager.
- Registration uses a bootstrap token (single cluster, expiring, limited number of uses, stored as sha256). The register command shows the sha256 fingerprint of the manager CA, which the agent checks before trusting it.
- The manager CA signs the agent certificate; the subject and the names come from the server, never from the request. In production the agent API requires that client certificate.
- Every agent request is also signed with HMAC-SHA256 and a timestamp (5 minutes window).
- The agent writes only below its allowed directories (
/etc/navin,/opt/navin,/var/lib/navin,/var/log/navin,/run/navin,navin-*systemd units and Quadlet files,90-navin-*sysctl and limits files). A symbolic link in the path of a write is refused, the final file is opened without following links. - Commands run with an absolute program path from the allowed list or from the managed directories. Values of sensitive environment variables are masked in logs and results.
- Downloads are checked against the sha256 of the mirror manifest and images against their digest.
- Host firewall (
firewall.open, firewalld or ufw): client facing ports are open to every source; the ports only the cluster uses (transport, peers, replication, gossip, bindings, Prometheus of the cluster, from the flow matrix) are open to the hosts of the cluster and the Manager only, through the firewalld ipsetnavin-<cluster>or one ufw rule per member, and closed to the other sources. The jobnetwork.firewall_memberssends the new member set to every host when a host joins or leaves (hardened installation).
Production checks
navin-manager check (also run by navin-manager serve) refuses to start in production without: TLS on both
listeners, client certificates for agents, the Secure cookie flag, a metrics token of at least 32 characters, a
scrypt cost of at least 16384, the master key, and a database URL with sslmode=require, verify-ca or
verify-full.
HTTP headers
The console is served with a strict Content Security Policy (default-src 'self', no inline script, frame-ancestors 'none'), X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer and, with TLS,
Strict-Transport-Security. API responses are never cached.