Security hardening: input validation, secrets protection, NATS auth
Config injection prevention: - Add FQDN validation for domain names (RFC 1123) in Register/Update — rejects newlines, spaces, shell metacharacters that could inject into HAProxy/dnsmasq configs - Add backend address validation (valid host:port format, valid IP or hostname, port 1-65535). DNS-only backends allow bare IPs. - Add header key/value validation — keys must be HTTP token chars only, values must not contain newlines or NULs - Add WireGuard peer name validation (alphanumeric + hyphens + underscores) - Add defense-in-depth domain validation in certbot Provision() Secrets protection: - Remove ?raw=true bypass on GET /api/v1/secrets — secrets are now always redacted in API responses regardless of query parameters - Update test to verify redaction cannot be bypassed NATS authentication: - Generate random auth token on first startup, store in secrets.yaml - Pass token to embedded NATS server via Authorization option - Internal client connects with the same token - External NATS clients (Wild Cloud) must now authenticate Security headers: - Add X-Content-Type-Options: nosniff - Add X-Frame-Options: DENY - Add Cache-Control: no-store
This commit is contained in:
@@ -37,8 +37,9 @@ type Server struct {
|
||||
|
||||
// Config for the embedded NATS server.
|
||||
type Config struct {
|
||||
Port int // listen port (default 4222)
|
||||
DataDir string // JetStream storage directory
|
||||
Port int // listen port (default 4222)
|
||||
DataDir string // JetStream storage directory
|
||||
AuthToken string // require this token for client connections (empty = no auth)
|
||||
}
|
||||
|
||||
// Start launches the embedded NATS server with JetStream and creates
|
||||
@@ -52,9 +53,11 @@ func Start(cfg Config) (*Server, error) {
|
||||
Port: cfg.Port,
|
||||
JetStream: true,
|
||||
StoreDir: cfg.DataDir,
|
||||
// Quiet logging — NATS logs at its own level
|
||||
NoLog: true,
|
||||
NoSigs: true,
|
||||
NoLog: true,
|
||||
NoSigs: true,
|
||||
}
|
||||
if cfg.AuthToken != "" {
|
||||
opts.Authorization = cfg.AuthToken
|
||||
}
|
||||
|
||||
ns, err := natsserver.NewServer(opts)
|
||||
@@ -87,7 +90,11 @@ func Start(cfg Config) (*Server, error) {
|
||||
slog.Info("NATS JetStream server started", "port", cfg.Port, "dataDir", cfg.DataDir)
|
||||
|
||||
// Connect as internal client
|
||||
nc, err := nats.Connect(ns.ClientURL())
|
||||
connectOpts := []nats.Option{}
|
||||
if cfg.AuthToken != "" {
|
||||
connectOpts = append(connectOpts, nats.Token(cfg.AuthToken))
|
||||
}
|
||||
nc, err := nats.Connect(ns.ClientURL(), connectOpts...)
|
||||
if err != nil {
|
||||
ns.Shutdown()
|
||||
return nil, fmt.Errorf("connecting to embedded NATS: %w", err)
|
||||
|
||||
Reference in New Issue
Block a user