Security Guide¶
This guide summarizes security-related settings and best practices when deploying Nexus GSLB.
Principles - Secure by default: HTTPS health checks verify TLS by default; GitOps requires signed commits when enabled. - Least privilege: limit credentials and subject permissions to the minimum required. - Defense in depth: mTLS for NATS, signed GitOps config, and restricted runtime privileges.
1) HTTP/HTTPS health checks
- Default behavior: when health.http.tls: true, TLS certificates are verified.
- Only set health.http.insecureSkipVerify: true for lab/testing or when using self-signed certs and you fully understand the risk.
- Prefer using proper certificates (internal CA or public CA) and correct http.host to match the cert.
Example (secure):
health:
type: http
port: 443
checkinterval: 10s
timeout: 2s
http:
path: "/healthz"
expectedstatus: 200
tls: true
insecureSkipVerify: false
2) GitOps signing and access
- gitops.requireSignature: true enforces signature verification on the latest commit checked out.
- gitops.allowedSigners restricts accepted signatures to a set of GPG key fingerprints.
- Deploy key: provide a read-only SSH key at gitops.auth.sshKeyPath; permissions should be 0600 and owned by the service user.
- Trust model: ensure the signer keys are trusted on hosts or rely on allowedSigners allowlist.
3) NATS and JetStream
- Use TLS with server authentication at minimum; prefer mTLS (client cert auth) or NATS accounts with JWT.
- Restrict subjects and KV permissions to the cluster namespace: gslb.<cluster>.*.
- Rotate client certificates and credentials regularly. Plan for CA rotation.
- Monitor gslbd_state_nats_connected and set alerts on disconnect.
4) Runtime privileges
- Binding to high ports (≥1024) avoids root. Default DNS port is 5353; if you must use port 53, either:
- run as root (not preferred), or
- grant cap_net_bind_service to the binary: setcap 'cap_net_bind_service=+ep' /usr/local/bin/gslbd and run as non-root.
- Limit file system permissions for /etc/gslb and any private keys.
5) Secrets and licensing
- Provide license secrets via environment variables when possible:
- GSLB_LICENSE_SECRET
- GSLB_LICENSE_KEY
- Use environment management in systemd (Environment=) or container secrets.
6) Supply chain and binaries - Build from source in a controlled CI/CD or use signed release artifacts (future work). - Pin container base images and scan them for vulnerabilities.
7) Logging and PII - Logs contain operational info (e.g., commit SHAs, signer fingerprints) but not sensitive payloads. Avoid logging credentials.
0) Authentication and user accounts
- Set GSLB_API_KEY (32-byte hex, openssl rand -hex 32) in the systemd EnvironmentFile before exposing the API. Without it, the daemon runs in dev mode — all requests are treated as system admin.
- Set GSLB_SECRET_KEY (also 32-byte hex) before enrolling any TOTP devices. The daemon will refuse to start if TOTP users exist and the key is absent.
- Store both values in /etc/gslb/env with chmod 600, owned by the service user. Reference it from the systemd unit with EnvironmentFile=/etc/gslb/env.
- Create named user accounts (tenant_admin, operator, viewer) instead of sharing the system API key. The system key is a break-glass credential, not a day-to-day login.
- Treat GSLB_API_KEY as a root password: rotate it if it is ever exposed, and restrict who knows it.
- Keep bcryptCost at 12 or higher in production.
See Authentication & User Management for full setup instructions.
Checklist
- [ ] TLS verified for HTTPS health checks (no insecureSkipVerify in prod)
- [ ] GitOps enabled with requireSignature: true and allowedSigners configured
- [ ] NATS uses TLS/mTLS; subjects restricted
- [ ] Non-root run or capability for port 53; secure file permissions
- [ ] License secrets provided via env/secrets manager
- [ ] GSLB_API_KEY set; named user accounts created; system key not used for day-to-day access
- [ ] GSLB_SECRET_KEY set before enrolling TOTP devices
- [ ] EnvironmentFile has chmod 600 and is owned by the service user
8) DNSSEC Pleiades signs DNS responses online using ECDSA P-256 (algorithm 13). KSK signs the DNSKEY RRset; ZSK signs all other RRsets.
Key generation:
# KSK
openssl ecparam -name prime256v1 -genkey -noout | \
openssl pkcs8 -topk8 -nocrypt -out /etc/gslb/ksk.pem
# ZSK
openssl ecparam -name prime256v1 -genkey -noout | \
openssl pkcs8 -topk8 -nocrypt -out /etc/gslb/zsk.pem
chmod 640 /etc/gslb/ksk.pem /etc/gslb/zsk.pem
chown root:gslbd /etc/gslb/ksk.pem /etc/gslb/zsk.pem
Configuration:
dnssec:
enabled: true
zone: "example.com."
ksk:
pemFile: "/etc/gslb/ksk.pem"
expiryDate: "2027-01-01"
zsk:
pemFile: "/etc/gslb/zsk.pem"
expiryDate: "2026-07-01"
signatureValidityDays: 7
Alternatively load keys from environment variables:
Key rotation:
1. Generate new ZSK; update config to point at new file.
2. Restart gslbd — new signatures use new ZSK immediately.
3. For KSK rotation, generate new KSK, export new DS record, submit to registrar, wait for TTL expiry, then restart.
4. Monitor gslbd_dnssec_key_days_remaining and alert before expiry.
DS record export:
NSEC3: denial-of-existence records are generated on-the-fly per RFC 5155 §7.1. No static NSEC3 chain is maintained.