From bd5f6b7c7c904deeed623b67e1bf44ae8455efa7 Mon Sep 17 00:00:00 2001 From: Sven Rebhan <36194019+srebhan@users.noreply.github.com> Date: Tue, 21 Mar 2023 15:58:06 +0100 Subject: [PATCH] feat(common.opcua): Add support for secret-store secrets (#12863) --- plugins/common/opcua/client.go | 4 ++-- plugins/common/opcua/opcua_util.go | 23 ++++++++++--------- plugins/inputs/opcua/README.md | 9 ++++++++ plugins/inputs/opcua/opcua_test.go | 16 ++++--------- plugins/inputs/opcua_listener/README.md | 9 ++++++++ .../opcua_listener/opcua_listener_test.go | 4 ++-- .../inputs/opcua_listener/subscribe_client.go | 2 +- 7 files changed, 39 insertions(+), 28 deletions(-) diff --git a/plugins/common/opcua/client.go b/plugins/common/opcua/client.go index 22f20c845c7c8..3a844440d54b1 100644 --- a/plugins/common/opcua/client.go +++ b/plugins/common/opcua/client.go @@ -24,8 +24,8 @@ type OpcUAClientConfig struct { SecurityMode string `toml:"security_mode"` Certificate string `toml:"certificate"` PrivateKey string `toml:"private_key"` - Username string `toml:"username"` - Password string `toml:"password"` + Username config.Secret `toml:"username"` + Password config.Secret `toml:"password"` AuthMethod string `toml:"auth_method"` ConnectTimeout config.Duration `toml:"connect_timeout"` RequestTimeout config.Duration `toml:"request_timeout"` diff --git a/plugins/common/opcua/opcua_util.go b/plugins/common/opcua/opcua_util.go index cc1a8781fb386..040c2edf2d902 100644 --- a/plugins/common/opcua/opcua_util.go +++ b/plugins/common/opcua/opcua_util.go @@ -19,6 +19,7 @@ import ( "github.com/gopcua/opcua" "github.com/gopcua/opcua/debug" "github.com/gopcua/opcua/ua" + "github.com/influxdata/telegraf/config" ) // SELF SIGNED CERT FUNCTIONS @@ -288,42 +289,42 @@ func (o *OpcUAClient) generateClientOpts(endpoints []*ua.EndpointDescription) ([ return opts, nil } -func (o *OpcUAClient) generateAuth(a string, cert []byte, un, pw string) (ua.UserTokenType, opcua.Option, error) { - var err error - +func (o *OpcUAClient) generateAuth(a string, cert []byte, user, passwd config.Secret) (ua.UserTokenType, opcua.Option, error) { var authMode ua.UserTokenType var authOption opcua.Option switch strings.ToLower(a) { case "anonymous": authMode = ua.UserTokenTypeAnonymous authOption = opcua.AuthAnonymous() - case "username": authMode = ua.UserTokenTypeUserName - if un == "" { + var username, password []byte + if !user.Empty() { + var err error + username, err = user.Get() if err != nil { return 0, nil, fmt.Errorf("error reading the username input: %w", err) } + defer config.ReleaseSecret(username) } - if pw == "" { + if !passwd.Empty() { + var err error + password, err = passwd.Get() if err != nil { return 0, nil, fmt.Errorf("error reading the password input: %w", err) } + defer config.ReleaseSecret(password) } - - authOption = opcua.AuthUsername(un, pw) - + authOption = opcua.AuthUsername(string(username), string(password)) case "certificate": authMode = ua.UserTokenTypeCertificate authOption = opcua.AuthCertificate(cert) - case "issuedtoken": // todo: this is unsupported, fail here or fail in the opcua package? authMode = ua.UserTokenTypeIssuedToken authOption = opcua.AuthIssuedToken([]byte(nil)) - default: o.Log.Warnf("unknown auth-mode, defaulting to Anonymous") authMode = ua.UserTokenTypeAnonymous diff --git a/plugins/inputs/opcua/README.md b/plugins/inputs/opcua/README.md index e15f7de2f5bae..137cdebce385e 100644 --- a/plugins/inputs/opcua/README.md +++ b/plugins/inputs/opcua/README.md @@ -14,6 +14,15 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. [CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins +## Secret-store support + +This plugin supports secrets from secret-stores for the `username` and +`password` option. +See the [secret-store documentation][SECRETSTORE] for more details on how +to use them. + +[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets + ## Configuration ```toml @sample.conf diff --git a/plugins/inputs/opcua/opcua_test.go b/plugins/inputs/opcua/opcua_test.go index ca0cbb394d5f2..631e760caebaf 100644 --- a/plugins/inputs/opcua/opcua_test.go +++ b/plugins/inputs/opcua/opcua_test.go @@ -62,10 +62,6 @@ func TestGetDataBadNodeContainerIntegration(t *testing.T) { Endpoint: fmt.Sprintf("opc.tcp://%s:%s", container.Address, container.Ports[servicePort]), SecurityPolicy: "None", SecurityMode: "None", - Certificate: "", - PrivateKey: "", - Username: "", - Password: "", AuthMethod: "Anonymous", ConnectTimeout: config.Duration(10 * time.Second), RequestTimeout: config.Duration(1 * time.Second), @@ -128,10 +124,6 @@ func TestReadClientIntegration(t *testing.T) { Endpoint: fmt.Sprintf("opc.tcp://%s:%s", container.Address, container.Ports[servicePort]), SecurityPolicy: "None", SecurityMode: "None", - Certificate: "", - PrivateKey: "", - Username: "", - Password: "", AuthMethod: "Anonymous", ConnectTimeout: config.Duration(10 * time.Second), RequestTimeout: config.Duration(1 * time.Second), @@ -188,8 +180,8 @@ func TestReadClientIntegrationWithPasswordAuth(t *testing.T) { Endpoint: fmt.Sprintf("opc.tcp://%s:%s", container.Address, container.Ports[servicePort]), SecurityPolicy: "None", SecurityMode: "None", - Username: "peter", - Password: "peter123", + Username: config.NewSecret([]byte("peter")), + Password: config.NewSecret([]byte("peter123")), AuthMethod: "UserName", ConnectTimeout: config.Duration(10 * time.Second), RequestTimeout: config.Duration(1 * time.Second), @@ -293,8 +285,8 @@ use_unregistered_reads = true require.Equal(t, "/etc/telegraf/cert.pem", o.ReadClientConfig.Certificate) require.Equal(t, "/etc/telegraf/key.pem", o.ReadClientConfig.PrivateKey) require.Equal(t, "Anonymous", o.ReadClientConfig.AuthMethod) - require.Equal(t, "", o.ReadClientConfig.Username) - require.Equal(t, "", o.ReadClientConfig.Password) + require.True(t, o.ReadClientConfig.Username.Empty()) + require.True(t, o.ReadClientConfig.Password.Empty()) require.Equal(t, []input.NodeSettings{ { FieldName: "name", diff --git a/plugins/inputs/opcua_listener/README.md b/plugins/inputs/opcua_listener/README.md index 7841b89b346e8..19008aae8afb8 100644 --- a/plugins/inputs/opcua_listener/README.md +++ b/plugins/inputs/opcua_listener/README.md @@ -14,6 +14,15 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. [CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins +## Secret-store support + +This plugin supports secrets from secret-stores for the `username` and +`password` option. +See the [secret-store documentation][SECRETSTORE] for more details on how +to use them. + +[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets + ## Configuration ```toml @sample.conf diff --git a/plugins/inputs/opcua_listener/opcua_listener_test.go b/plugins/inputs/opcua_listener/opcua_listener_test.go index e86f95f4f21dc..96e8da41332b9 100644 --- a/plugins/inputs/opcua_listener/opcua_listener_test.go +++ b/plugins/inputs/opcua_listener/opcua_listener_test.go @@ -205,8 +205,8 @@ additional_valid_status_codes = ["0xC0"] require.Equal(t, "/etc/telegraf/cert.pem", o.SubscribeClientConfig.Certificate) require.Equal(t, "/etc/telegraf/key.pem", o.SubscribeClientConfig.PrivateKey) require.Equal(t, "Anonymous", o.SubscribeClientConfig.AuthMethod) - require.Equal(t, "", o.SubscribeClientConfig.Username) - require.Equal(t, "", o.SubscribeClientConfig.Password) + require.True(t, o.SubscribeClientConfig.Username.Empty()) + require.True(t, o.SubscribeClientConfig.Password.Empty()) require.Equal(t, []input.NodeSettings{ { FieldName: "name", diff --git a/plugins/inputs/opcua_listener/subscribe_client.go b/plugins/inputs/opcua_listener/subscribe_client.go index c51fda26effb9..a327b7f13e74f 100644 --- a/plugins/inputs/opcua_listener/subscribe_client.go +++ b/plugins/inputs/opcua_listener/subscribe_client.go @@ -141,7 +141,7 @@ func (o *SubscribeClient) processReceivedNotifications() { i := int(monitoredItemNotif.ClientHandle) oldValue := o.LastReceivedData[i].Value o.UpdateNodeValue(i, monitoredItemNotif.Value) - o.Log.Debugf("Data change notification: node %q value changed from %f to %f", + o.Log.Debugf("Data change notification: node %q value changed from %v to %v", o.NodeIDs[i].String(), oldValue, o.LastReceivedData[i].Value) o.metrics <- o.MetricForNode(i) }