Skip to main content

Security

This page describes the security model of navin-manager. The binding reference is section 5 of navin-manager/CONTRACT.md.

Sign in​

SourceDetails
Local accountsPasswords 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 DirectoryService 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​

RoleScopeMain rights
adminglobaleverything
security_adminglobalusers, authentication, audit, certificates
cluster_adminglobal or one clusterhosts, install and operate services, configurations, alerts
operatorglobal or one clusterstart, stop, restart, commands, logs, alerts
viewerglobal or one clusterread only
auditorglobalaudit 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.sync is audited when a refresh fails). POST /api/v1/vault/import refreshes 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:edit and vault: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 ipset navin-<cluster> or one ufw rule per member, and closed to the other sources. The job network.firewall_members sends 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.