From 0e017ab071e142408f30aaa64baf4a5c8fa06a33 Mon Sep 17 00:00:00 2001 From: Matt Lloyd Date: Sun, 27 Apr 2025 05:30:57 +0100 Subject: [PATCH] feat: support nats nkey seed auth (#21231) --- internal/config/notify/legacy.go | 4 +++ internal/config/notify/parse.go | 6 ++++ internal/event/target/nats.go | 10 ++++++ internal/event/target/nats_contrib_test.go | 33 +++++++++++++++++++ .../event/target/testdata/contrib/test.nkey | 1 + 5 files changed, 54 insertions(+) create mode 100644 internal/event/target/testdata/contrib/test.nkey diff --git a/internal/config/notify/legacy.go b/internal/config/notify/legacy.go index 9e8545a62..c72aff126 100644 --- a/internal/config/notify/legacy.go +++ b/internal/config/notify/legacy.go @@ -462,6 +462,10 @@ func SetNotifyNATS(s config.Config, natsName string, cfg target.NATSArgs) error Key: target.NATSToken, Value: cfg.Token, }, + config.KV{ + Key: target.NATSNKeySeed, + Value: cfg.NKeySeed, + }, config.KV{ Key: target.NATSCertAuthority, Value: cfg.CertAuthority, diff --git a/internal/config/notify/parse.go b/internal/config/notify/parse.go index 8765d23bc..c08606d4e 100644 --- a/internal/config/notify/parse.go +++ b/internal/config/notify/parse.go @@ -989,6 +989,11 @@ func GetNotifyNATS(natsKVS map[string]config.KVS, rootCAs *x509.CertPool) (map[s tokenEnv = tokenEnv + config.Default + k } + nKeySeedEnv := target.EnvNATSNKeySeed + if k != config.Default { + nKeySeedEnv = nKeySeedEnv + config.Default + k + } + queueDirEnv := target.EnvNATSQueueDir if k != config.Default { queueDirEnv = queueDirEnv + config.Default + k @@ -1025,6 +1030,7 @@ func GetNotifyNATS(natsKVS map[string]config.KVS, rootCAs *x509.CertPool) (map[s ClientCert: env.Get(clientCertEnv, kv.Get(target.NATSClientCert)), ClientKey: env.Get(clientKeyEnv, kv.Get(target.NATSClientKey)), Token: env.Get(tokenEnv, kv.Get(target.NATSToken)), + NKeySeed: env.Get(nKeySeedEnv, kv.Get(target.NATSNKeySeed)), TLS: env.Get(tlsEnv, kv.Get(target.NATSTLS)) == config.EnableOn, TLSSkipVerify: env.Get(tlsSkipVerifyEnv, kv.Get(target.NATSTLSSkipVerify)) == config.EnableOn, TLSHandshakeFirst: env.Get(tlsHandshakeFirstEnv, kv.Get(target.NATSTLSHandshakeFirst)) == config.EnableOn, diff --git a/internal/event/target/nats.go b/internal/event/target/nats.go index 56f4f91e6..c96833bc4 100644 --- a/internal/event/target/nats.go +++ b/internal/event/target/nats.go @@ -45,6 +45,7 @@ const ( NATSUsername = "username" NATSPassword = "password" NATSToken = "token" + NATSNKeySeed = "nkey_seed" NATSTLS = "tls" NATSTLSSkipVerify = "tls_skip_verify" NATSTLSHandshakeFirst = "tls_handshake_first" @@ -71,6 +72,7 @@ const ( NATSUserCredentials = "MINIO_NOTIFY_NATS_USER_CREDENTIALS" EnvNATSPassword = "MINIO_NOTIFY_NATS_PASSWORD" EnvNATSToken = "MINIO_NOTIFY_NATS_TOKEN" + EnvNATSNKeySeed = "MINIO_NOTIFY_NATS_NKEY_SEED" EnvNATSTLS = "MINIO_NOTIFY_NATS_TLS" EnvNATSTLSSkipVerify = "MINIO_NOTIFY_NATS_TLS_SKIP_VERIFY" EnvNatsTLSHandshakeFirst = "MINIO_NOTIFY_NATS_TLS_HANDSHAKE_FIRST" @@ -100,6 +102,7 @@ type NATSArgs struct { UserCredentials string `json:"userCredentials"` Password string `json:"password"` Token string `json:"token"` + NKeySeed string `json:"nKeySeed"` TLS bool `json:"tls"` TLSSkipVerify bool `json:"tlsSkipVerify"` TLSHandshakeFirst bool `json:"tlsHandshakeFirst"` @@ -178,6 +181,13 @@ func (n NATSArgs) connectNats() (*nats.Conn, error) { if n.Token != "" { connOpts = append(connOpts, nats.Token(n.Token)) } + if n.NKeySeed != "" { + nkeyOpt, err := nats.NkeyOptionFromSeed(n.NKeySeed) + if err != nil { + return nil, err + } + connOpts = append(connOpts, nkeyOpt) + } if n.Secure || n.TLS && n.TLSSkipVerify { connOpts = append(connOpts, nats.Secure(nil)) } else if n.TLS { diff --git a/internal/event/target/nats_contrib_test.go b/internal/event/target/nats_contrib_test.go index c04b1a91d..42a5f0609 100644 --- a/internal/event/target/nats_contrib_test.go +++ b/internal/event/target/nats_contrib_test.go @@ -19,6 +19,8 @@ package target import ( "testing" + "github.com/nats-io/nats-server/v2/server" + xnet "github.com/minio/pkg/v3/net" natsserver "github.com/nats-io/nats-server/v2/test" ) @@ -96,3 +98,34 @@ func TestNatsConnToken(t *testing.T) { } defer con.Close() } + +func TestNatsConnNKeySeed(t *testing.T) { + opts := natsserver.DefaultTestOptions + opts.Port = 14223 + opts.Nkeys = []*server.NkeyUser{ + { + // Not a real NKey + // Taken from https://docs.nats.io/running-a-nats-service/configuration/securing_nats/auth_intro/nkey_auth + Nkey: "UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4", + }, + } + s := natsserver.RunServer(&opts) + defer s.Shutdown() + + clientConfig := &NATSArgs{ + Enable: true, + Address: xnet.Host{ + Name: "localhost", + Port: (xnet.Port(opts.Port)), + IsPortSet: true, + }, + Subject: "test", + NKeySeed: "testdata/contrib/test.nkey", + } + + con, err := clientConfig.connectNats() + if err != nil { + t.Errorf("Could not connect to nats: %v", err) + } + defer con.Close() +} diff --git a/internal/event/target/testdata/contrib/test.nkey b/internal/event/target/testdata/contrib/test.nkey new file mode 100644 index 000000000..e75f2719b --- /dev/null +++ b/internal/event/target/testdata/contrib/test.nkey @@ -0,0 +1 @@ +SUACSSL3UAHUDXKFSNVUZRF5UHPMWZ6BFDTJ7M6USDXIEDNPPQYYYCU3VY \ No newline at end of file