Getting error trying to connect to Ignition OPC UA Server with security Basic256Sha256

Hi everybody,

I am trying to connect to the internal Ignition OPC UA-Server via python script with the opcua library.

I changed the 'Bind Address' to 0.0.0.0 and exposed the tag browsers. I also restarted after. I also trusted my certificate under the "Security" tab in the OPC UA options. Here is my code:

from opcua import Client
from opcua import ua

def main():
    server_url = "opc.tcp://server-hostname:62541/discovery"
    client = Client(server_url)

    # Sicherheitseinstellungen
    client.set_security_string("Basic256Sha256,SignAndEncrypt,my_certificate.der,my_private_key.pem")
    client.application_uri = "urn:example:client"

    # Benutzeranmeldeinformationen setzen
    client.set_user("user")
    client.set_password("password")

    try:
        # Verbindung zum Server herstellen
        client.connect()
        print("Connected to the OPC UA Server.")

        # Führen Sie hier Ihre OPC UA-Operationen aus
        # Beispiel: Lesen eines Wertes
        node = client.get_node("ns=urn:inductiveautomation:ignition:opcua:tags;s=[Tag-Provider-Name]/Folder1/Folder2/Folder3/Tag-Name")
        value = node.get_value()
        print("Node value:", value)

    finally:
        # Trennen der Verbindung zum Server
        client.disconnect()
        print("Disconnected from the OPC UA Server.")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("Program interrupted by the user. Exiting...")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")

I am always getting this error:

exception calling callback for <Future at 0x285de932790 state=cancelled>
Traceback (most recent call last):

...

concurrent.futures._base.CancelledError
An unexpected error occurred: [WinError 10038] An operation related to an object that is not a socket

Also in Ignition in the logs, I find the following entries:

I also found this github issue where another person has mentioned its problem with this connecting to Ignition OPC UA: concurrent.futures._base.CancelledError upon open_secure_channel attempt · Issue #1155 · FreeOpcUa/python-opcua · GitHub

Thanks in advance for any help :slight_smile:

Has your client's certificate showed up in the OPC UA > Security > Server tab yet for you to mark as trusted?

1 Like

Sorry for being too slow :smiley: just edited it: Yes i trusted it.

Can you copy/paste the full text of that error message from the Ignition logs? (click the "+" to expand and get the full stack trace)

Following Error under "UascServerAsymmetricHandler":

org.eclipse.milo.opcua.stack.core.UaException: no matching endpoint found: transportProfile=TCP_UASC_UABINARY, endpointUrl=opc.tcp://server-name:62541/discovery, securityPolicy=Basic256Sha256, securityMode=SignAndEncrypt

at org.eclipse.milo.opcua.stack.server.transport.uasc.UascServerAsymmetricHandler.lambda$openSecureChannel$3(UascServerAsymmetricHandler.java:397)

at java.base/java.util.Optional.orElseThrow(Unknown Source)

at org.eclipse.milo.opcua.stack.server.transport.uasc.UascServerAsymmetricHandler.openSecureChannel(UascServerAsymmetricHandler.java:387)

at org.eclipse.milo.opcua.stack.server.transport.uasc.UascServerAsymmetricHandler.lambda$sendOpenSecureChannelResponse$1(UascServerAsymmetricHandler.java:298)

at org.eclipse.milo.opcua.stack.core.channel.SerializationQueue.lambda$encode$0(SerializationQueue.java:52)

at org.eclipse.milo.opcua.stack.core.util.ExecutionQueue$Task.run(ExecutionQueue.java:119)

at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.base/java.lang.Thread.run(Unknown Source)

I was also checking the endpoint settings:

And I checked the certificate of the Ignition OPC UA-Server for the host name.

Right, so this means your client is trying to open a secured connection to the wrong endpoint.

There is a discovery endpoint at opc.tcp://host:62541/discovery. It accepts unsecured connections and implements the discovery services. The endpoints it returns contain URLs that point to the session endpoint at opc.tcp://host:62541 (no /discovery).

If your client / client library can't correctly use the endpoint URLs returned in the GetEndpoints response then it won't be able to connect.

I've found that on order to connect broken clients like this to Ignition you have to enable the "None" security policy in the server and then point the client directly at the session endpoint instead.

1 Like

Ok so it only works without security that way? Are there other python libraries that are known of working together with security?

There's only two Python libraries AFAIK, the deprecated one you're using, and its replacement GitHub - FreeOpcUa/opcua-asyncio: OPC UA library for python >= 3.7

But they don't seem very responsive when I report issues: Browsing for HasTypeDefinition references is broken · Issue #1529 · FreeOpcUa/opcua-asyncio · GitHub

1 Like

Ok thanks, I'll give it a shot with this library. Security is a key part of this project, so I cannot set the SecurityPolicy to None.

Thanks for the fast replies :slight_smile: I'll give an update asap.

I am also getting a similiar error with UAExpert from Unified Automation (GUI client from an industrial context):

image

Trying asyncio / asyncua then.

With UaExpert use the "Custom Discovery" workflow, don't just type in the endpoint information.

image

1 Like

Bit of a late response but I recently ran into exactly this same problem: need to connect to ignition via the opcua python library with proper security enabled in Ignition.

You have almost everything but are missing the server's security cert, and the server url for the actual endpoint should not be .../discovery (as was already mentioned).

You can get the server's cert by downloading it from the ignition web portal or you can do an endpoint discovery and get it that way.

discovery_client = Client(url="opc.tcp://localhost:12345/discovery")
# endpoints is a list of EndpointDescriptions
endpoints = await discovery_client.connect_and_get_server_endpoints()

client = Client(url="opc.tcp://localhost:12345")
await client.set_security(
    SecurityPolicyBasic256Sha256,
    certificate="path/to/client/cert",
    private_key="path/to/client/key",
    mode=ua.MessageSecurityMode.SignAndEncrypt,
    # array index of the appropriate endpoint although I suspect the server cert will be the same for all of them
    server_certificate=endpoints[0].ServerCertificate
)
client.set_user("someuser")
client.set_password("somepassword")

This works for me, I see you are using the set_security_string form which I haven't tried, I'd guess you just append the raw contents of ServerCertificate

1 Like