Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions plugins/common/opcua/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,18 @@ func (c ConnectionState) String() string {
}

type OpcUAClientConfig struct {
Endpoint string `toml:"endpoint"`
SecurityPolicy string `toml:"security_policy"`
SecurityMode string `toml:"security_mode"`
Certificate string `toml:"certificate"`
PrivateKey string `toml:"private_key"`
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"`
ClientTrace bool `toml:"client_trace"`
Endpoint string `toml:"endpoint"`
SecurityPolicy string `toml:"security_policy"`
SecurityMode string `toml:"security_mode"`
Certificate string `toml:"certificate"`
PrivateKey string `toml:"private_key"`
RemoteCertificate string `toml:"remote_certificate"`
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"`
ClientTrace bool `toml:"client_trace"`

OptionalFields []string `toml:"optional_fields"`
Workarounds OpcUAWorkarounds `toml:"workarounds"`
Expand Down Expand Up @@ -137,7 +138,7 @@ func (o *OpcUAClientConfig) Validate() error {
}

func (o *OpcUAClientConfig) validateCertificateConfiguration() error {
// If using None/None security, certificates are optional
// If using None/None security, client certificates are optional
if o.SecurityPolicy == "None" && o.SecurityMode == "None" {
return nil
}
Expand Down
47 changes: 47 additions & 0 deletions plugins/common/opcua/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,50 @@ func TestOpcUAClientSetupWorkarounds(t *testing.T) {
})
}
}

func TestRemoteCertificateValidation(t *testing.T) {
tests := []struct {
name string
securityPolicy string
securityMode string
remoteCertificate string
}{
{
name: "no remote certificate configured",
securityPolicy: "None",
securityMode: "None",
remoteCertificate: "",
},
{
name: "remote certificate path provided with None security",
securityPolicy: "None",
securityMode: "None",
remoteCertificate: "/etc/telegraf/server_cert.pem",
},
{
name: "remote certificate path provided with SignAndEncrypt",
securityPolicy: "Basic256Sha256",
securityMode: "SignAndEncrypt",
remoteCertificate: "/etc/telegraf/server_cert.pem",
},
{
name: "remote certificate path provided with auto security",
securityPolicy: "auto",
securityMode: "auto",
remoteCertificate: "/etc/telegraf/server_cert.pem",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := OpcUAClientConfig{
Endpoint: "opc.tcp://localhost:4840",
SecurityPolicy: tt.securityPolicy,
SecurityMode: tt.securityMode,
RemoteCertificate: tt.remoteCertificate,
}

require.NoError(t, config.Validate())
})
}
}
8 changes: 8 additions & 0 deletions plugins/common/opcua/opcua_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,14 @@ func (o *OpcUAClient) generateClientOpts(endpoints []*ua.EndpointDescription) ([
}

opts = append(opts, opcua.SecurityFromEndpoint(serverEndpoint, authMode))

// If a remote certificate is explicitly configured, use it to override
// the certificate from the endpoint. This allows trusting self-signed certificates.
if o.Config.RemoteCertificate != "" {
o.Log.Debugf("Using explicitly configured remote certificate from %s", o.Config.RemoteCertificate)
opts = append(opts, opcua.RemoteCertificateFile(o.Config.RemoteCertificate))
}

return opts, nil
}

Expand Down
15 changes: 15 additions & 0 deletions plugins/inputs/opcua/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ to use them.
## If key path is not supplied, self-signed cert and key will be generated.
# private_key = "/etc/telegraf/key.pem"

## Path to additional, explicitly trusted certificate for the remote endpoint
# remote_certificate = "/etc/telegraf/opcua_server_cert.pem"

## Authentication Method, one of "Certificate", "UserName", or "Anonymous". To
## authenticate using a specific ID, select 'Certificate' or 'UserName'
# auth_method = "Anonymous"
Expand Down Expand Up @@ -276,6 +279,18 @@ This example group configuration has three groups with two nodes each:
]
```

### Server Certificate Trust

When connecting to OPC UA servers with self-signed certificates using
secure modes (Sign or SignAndEncrypt), you need to explicitly trust the
server's certificate. Use the `remote_certificate` option to specify the
path to the server's certificate file.

Most OPC UA servers provide their certificate through their management interface
or configuration directory. Consult your OPC UA server's documentation to locate
the certificate, typically found in the server's PKI (Public Key Infrastructure)
directory. Alternatively, you can export the certificate using OPC UA client tools.

## Connection Service

This plugin actively reads to retrieve data from the OPC server.
Expand Down
3 changes: 3 additions & 0 deletions plugins/inputs/opcua/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
## If key path is not supplied, self-signed cert and key will be generated.
# private_key = "/etc/telegraf/key.pem"

## Path to additional, explicitly trusted certificate for the remote endpoint
# remote_certificate = "/etc/telegraf/opcua_server_cert.pem"

## Authentication Method, one of "Certificate", "UserName", or "Anonymous". To
## authenticate using a specific ID, select 'Certificate' or 'UserName'
# auth_method = "Anonymous"
Expand Down
5 changes: 4 additions & 1 deletion plugins/inputs/opcua_listener/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ to use them.
## Path to private key.pem. Required when security mode or policy isn't "None".
## If key path is not supplied, self-signed cert and key will be generated.
# private_key = "/etc/telegraf/key.pem"
#

## Path to additional, explicitly trusted certificate for the remote endpoint
# remote_certificate = "/etc/telegraf/opcua_server_cert.pem"

## Authentication Method, one of "Certificate", "UserName", or "Anonymous". To
## authenticate using a specific ID, select 'Certificate' or 'UserName'
# auth_method = "Anonymous"
Expand Down
5 changes: 4 additions & 1 deletion plugins/inputs/opcua_listener/sample.conf
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
## Path to private key.pem. Required when security mode or policy isn't "None".
## If key path is not supplied, self-signed cert and key will be generated.
# private_key = "/etc/telegraf/key.pem"
#

## Path to additional, explicitly trusted certificate for the remote endpoint
# remote_certificate = "/etc/telegraf/opcua_server_cert.pem"

## Authentication Method, one of "Certificate", "UserName", or "Anonymous". To
## authenticate using a specific ID, select 'Certificate' or 'UserName'
# auth_method = "Anonymous"
Expand Down
Loading