feat: add NATS NKey authentication support
Allow authentication to NATS using NKey seed files as an alternative to credentials files. NKeys use Ed25519 key pairs for authentication. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,7 @@ nix build
|
|||||||
| `--flake.nats.url` | `nats://localhost:4222` | NATS server URL |
|
| `--flake.nats.url` | `nats://localhost:4222` | NATS server URL |
|
||||||
| `--flake.nats.subject` | `nixos-exporter.remote-rev` | NATS subject for revision updates |
|
| `--flake.nats.subject` | `nixos-exporter.remote-rev` | NATS subject for revision updates |
|
||||||
| `--flake.nats.credentials-file` | | NATS credentials file (optional) |
|
| `--flake.nats.credentials-file` | | NATS credentials file (optional) |
|
||||||
|
| `--flake.nats.nkey-seed-file` | | NATS NKey seed file (optional) |
|
||||||
|
|
||||||
## NixOS Module Options
|
## NixOS Module Options
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@ services.prometheus.exporters.nixos = {
|
|||||||
url = "nats://localhost:4222";
|
url = "nats://localhost:4222";
|
||||||
subject = "nixos-exporter.remote-rev";
|
subject = "nixos-exporter.remote-rev";
|
||||||
credentialsFile = null; # Optional path to credentials file
|
credentialsFile = null; # Optional path to credentials file
|
||||||
|
nkeySeedFile = null; # Optional path to NKey seed file
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ type FlakeCollectorConfig struct {
|
|||||||
NATSURL string
|
NATSURL string
|
||||||
NATSSubject string
|
NATSSubject string
|
||||||
NATSCredentialsFile string
|
NATSCredentialsFile string
|
||||||
|
NATSNkeySeedFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// nixosVersionInfo holds the parsed output of nixos-version --json
|
// nixosVersionInfo holds the parsed output of nixos-version --json
|
||||||
@@ -107,7 +108,7 @@ func NewFlakeCollectorWithNATS(cfg FlakeCollectorConfig) (*FlakeCollector, error
|
|||||||
c.natsEnabled = true
|
c.natsEnabled = true
|
||||||
c.natsSubject = cfg.NATSSubject
|
c.natsSubject = cfg.NATSSubject
|
||||||
|
|
||||||
if err := c.connectNATS(cfg.NATSURL, cfg.NATSCredentialsFile); err != nil {
|
if err := c.connectNATS(cfg.NATSURL, cfg.NATSCredentialsFile, cfg.NATSNkeySeedFile); err != nil {
|
||||||
// Log warning but continue without NATS
|
// Log warning but continue without NATS
|
||||||
slog.Warn("Failed to connect to NATS, continuing without cache sharing", "error", err)
|
slog.Warn("Failed to connect to NATS, continuing without cache sharing", "error", err)
|
||||||
}
|
}
|
||||||
@@ -333,7 +334,7 @@ func getNixosVersionInfo() (*nixosVersionInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// connectNATS establishes connection to NATS server with auto-reconnect
|
// connectNATS establishes connection to NATS server with auto-reconnect
|
||||||
func (c *FlakeCollector) connectNATS(url, credentialsFile string) error {
|
func (c *FlakeCollector) connectNATS(url, credentialsFile, nkeySeedFile string) error {
|
||||||
opts := []nats.Option{
|
opts := []nats.Option{
|
||||||
nats.MaxReconnects(-1), // Infinite reconnects
|
nats.MaxReconnects(-1), // Infinite reconnects
|
||||||
nats.ReconnectWait(5 * time.Second),
|
nats.ReconnectWait(5 * time.Second),
|
||||||
@@ -363,6 +364,12 @@ func (c *FlakeCollector) connectNATS(url, credentialsFile string) error {
|
|||||||
|
|
||||||
if credentialsFile != "" {
|
if credentialsFile != "" {
|
||||||
opts = append(opts, nats.UserCredentials(credentialsFile))
|
opts = append(opts, nats.UserCredentials(credentialsFile))
|
||||||
|
} else if nkeySeedFile != "" {
|
||||||
|
opt, err := nats.NkeyOptionFromSeed(nkeySeedFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to load NKey seed file: %w", err)
|
||||||
|
}
|
||||||
|
opts = append(opts, opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
nc, err := nats.Connect(url, opts...)
|
nc, err := nats.Connect(url, opts...)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type Config struct {
|
|||||||
FlakeNATSURL string
|
FlakeNATSURL string
|
||||||
FlakeNATSSubject string
|
FlakeNATSSubject string
|
||||||
FlakeNATSCredentialsFile string
|
FlakeNATSCredentialsFile string
|
||||||
|
FlakeNATSNkeySeedFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func Parse() (*Config, error) {
|
func Parse() (*Config, error) {
|
||||||
@@ -32,6 +33,7 @@ func Parse() (*Config, error) {
|
|||||||
flag.StringVar(&cfg.FlakeNATSURL, "flake.nats.url", "nats://localhost:4222", "NATS server URL")
|
flag.StringVar(&cfg.FlakeNATSURL, "flake.nats.url", "nats://localhost:4222", "NATS server URL")
|
||||||
flag.StringVar(&cfg.FlakeNATSSubject, "flake.nats.subject", "nixos-exporter.remote-rev", "NATS subject for revision updates")
|
flag.StringVar(&cfg.FlakeNATSSubject, "flake.nats.subject", "nixos-exporter.remote-rev", "NATS subject for revision updates")
|
||||||
flag.StringVar(&cfg.FlakeNATSCredentialsFile, "flake.nats.credentials-file", "", "NATS credentials file (optional)")
|
flag.StringVar(&cfg.FlakeNATSCredentialsFile, "flake.nats.credentials-file", "", "NATS credentials file (optional)")
|
||||||
|
flag.StringVar(&cfg.FlakeNATSNkeySeedFile, "flake.nats.nkey-seed-file", "", "NATS NKey seed file (optional)")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
|||||||
3
main.go
3
main.go
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "0.3.0"
|
const version = "0.4.0"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfg, err := config.Parse()
|
cfg, err := config.Parse()
|
||||||
@@ -40,6 +40,7 @@ func main() {
|
|||||||
NATSURL: cfg.FlakeNATSURL,
|
NATSURL: cfg.FlakeNATSURL,
|
||||||
NATSSubject: cfg.FlakeNATSSubject,
|
NATSSubject: cfg.FlakeNATSSubject,
|
||||||
NATSCredentialsFile: cfg.FlakeNATSCredentialsFile,
|
NATSCredentialsFile: cfg.FlakeNATSCredentialsFile,
|
||||||
|
NATSNkeySeedFile: cfg.FlakeNATSNkeySeedFile,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to create flake collector", "error", err)
|
slog.Error("Failed to create flake collector", "error", err)
|
||||||
|
|||||||
@@ -58,6 +58,12 @@ in
|
|||||||
default = null;
|
default = null;
|
||||||
description = "Path to NATS credentials file.";
|
description = "Path to NATS credentials file.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nkeySeedFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
description = "Path to NATS NKey seed file.";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -133,6 +139,8 @@ in
|
|||||||
"--flake.nats.subject=${cfg.flake.nats.subject}"
|
"--flake.nats.subject=${cfg.flake.nats.subject}"
|
||||||
] ++ lib.optionals (cfg.flake.nats.enable && cfg.flake.nats.credentialsFile != null) [
|
] ++ lib.optionals (cfg.flake.nats.enable && cfg.flake.nats.credentialsFile != null) [
|
||||||
"--flake.nats.credentials-file=${cfg.flake.nats.credentialsFile}"
|
"--flake.nats.credentials-file=${cfg.flake.nats.credentialsFile}"
|
||||||
|
] ++ lib.optionals (cfg.flake.nats.enable && cfg.flake.nats.nkeySeedFile != null) [
|
||||||
|
"--flake.nats.nkey-seed-file=${cfg.flake.nats.nkeySeedFile}"
|
||||||
]);
|
]);
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "5s";
|
RestartSec = "5s";
|
||||||
|
|||||||
Reference in New Issue
Block a user