Using the OPC UA DDS Gateway¶
License Management¶
Both the gateway and the “client” library make use of floating licenses, which synchronize with an external floating license server. Each license can allow for 1 to many concurrent executions on different systems.
Each time a gateway instance is started an activations counter gets incremented, and each time it stops, this activation is released. In case of gateway, or library-using application crash you should wait for … s for an automatic release of the activation. If you can’t wait, simply reach your neoliant.cryptlex.app portal, where you can can release the activation yourself.
Gateway
During the first execution of the Gateway, you’ll be asked if you want to run it as a 10-days trial or if you want to activate a license.
- Trial mode
Simply choose the option “1” for a 10-days trial full-featured version of the Gateway. At the end of this trial, you’ll be asked to enter a license key, in order to activate the a paid license allowing you to use the Gateway, either in its “Expose” version or in its “Complete” version.
- Activating the license
During the first execution of the Gateway, thanks to option “2”, or at the end of the trial period, you can enter the license key associated with your paid license.
Applications using the “client” services library
DDS applications can interact directly with OPC UA services thanks the libopcddsservices.so shared library, which is available with the “Complete” version of the Gateway, or as a standalone library in the “Interact” product, if you already own an OPC UA Gateway.
To use this library, you should call the following functions first in order to activate the associated license :
- Trial mode
In trial mode, you can use the following code snippet in order to trigger a 10-days trial version of the library. You’ll be able to run it on only one system, but you can have several applications using it and running in parrallel on the same system.
#include "libopcddsservices/headers/LicenseManager.h" int main( int argc, char * argv[] ) { LicenseManager licenseManager; licenseManager.ActivateTrial(); // Code of your DDS application licenseManager.DeactivateLicense(); }
- Activating the license
5CC778-ED6999-4E8D9E-E54511-AA8913-D50A45 Once you have acquired a paid license for the OPC UA - DDS Services library, you can use it in a given number of systems. In order to activate this license you should call the following functions first, before any other call to the library members.
#include "libopcddsservices/headers/LicenseManager.h" int main( int argc, char * argv[] ) { LicenseManager licenseManager; licenseManager.SetLicenseKey ( "{License key string}" ); // should ideally be called only once licenseManager.ActivateLicense(); // Code of your DDS application licenseManager.DeactivateLicense(); }
Configuration¶
Introduction¶
The whole OPC UA - DDS Gateway configuration follows the standard established by the Object Management Group. The additional configuration files are mainly used to setup state of the art security on the OPC UA and DDS networks, as well as managing the logs of the Gateway.
The configuration files are all present in the gateway-[version].AppImage.home directory.
XML Gateway Configuration¶
The main configuration file is “opcdds_config.xml”, which follows the recommandations of the OMG, and should follow the schema described in the accompanying normative XSD files in the same directory. It is build upon the DDS Consolidated XML Syntax [DDS-XML], which provides all the necessary constructs to specify DDS resources in XML.
You can run the following command to validate your XML file before starting the Gateway :
xmllint --schema dds-opcua_definitions.xsd ./opcdds_config.xml --noout
Since this implementation concerns only the OPC UA - DDS Bridge, the XML configuration of the Gateway shall comply with the following structure :
<dds>
<types>
<qos_libraries>
<ddsopcua_gateway>
<opcua_connection>
<domain_participant>
<opcua_to_dds_bridge>
<service_set>
<subscription>
<opcua_input>
<dds_output>
<mapping>
<assignment>
Let’s get into more details :
- <dds> :
Root element. Is the entry point of the OPC UA - DDS Gateway configuration.
- <types> :
Defines types that DomainParticipants may register to create Topics for writing DDS data.
On the DDS side of the OPC UA - DDS Bridge, the OPC UA - DDS gateway defines so-called “DdsOutputs” that are responsible for writing data on a given Topic. As for every Topic in DDS, one should associate a dedicated date Type to it and that Type should have been registered by the DomainParticipant. DDS ensures data contracts thanks to this approach.
You can define DDS types that will be used in the DDS Outputs of the Gateway and whose Topics will be written upon OPC UA MonitoredItems notification updates. Those are types that DomainParticipants may register to create Topics for reading or writing DDS data. <types> defines DDS types that are required to create DDS Outputs according to the users’ interests and the mapping rules (see below).
- <qos_libraries> :
Organizes QoS Profiles with QoS Policies that may be used to specify behavior of the DDS entities instantiated by the Gateway.
- <ddsopcua_gateway>
Configures the OPC UA - DDS Gateway. A <ddsopcua_gateway> configuration may refer to types and qos_libraries specified in the configuration file. Moreover, it may define opcua_connections, opcua_servers, domain_participants, and opcua_to_dds_bridges.
- <opcua_connection> :
Defines a connection of the OPC UA - DDS Gateway to an OPC UA server. When referenced from a service_set or subscription configuration in the context of an OPC UA to DDS Bridge, the Gateway will instantiate an OPC UA Client capable of connecting to the specified Server according to the specified configuration.
An OPC UA/DDS Gateway configuration may contain multiple opcua_connection definitions.
- <domain_participant> :
Configures a DomainParticipant, which provides the entry point for OPC UA to DDS Bridge to operate in a DDS Domain. The same DomainParticipant definition may be used by different bridges.
An OPC UA - DDS Gateway configuration may contain multiple domain_participantdefinitions.
- <opcua_to_dds_bridge> :
Configures an OPC UA to DDS Bridge, which exposes the AddressSpace of one or more OPC UA Servers to DDS applications.
An OPC UA - DDS Gateway configuration may contain multiple opcua_to_dds_bridge definitions.
- <service_set> :
Exposes selected OPC UA Services from an OPC UA Server to DDS applications by creating equivalent DDS Services using RPC over DDS.
An OPC UA to DDS Bridge may include multiple service_set definitions to expose Service Sets from different OPC UA Servers to DDS applications.
- <subscription> :
Defines OPC UA Inputs (Subscriptions to different MonitoredItems — DataItems and EventItems — in OPC UA Servers) and DDS Outputs (DataWriters associated to DDS Topics) and provides the ability to map DataItems or EventItems from different OPC UA Inputs to fields of Topics associated with DDS Outputs.
An OPC UA to DDS Bridge may include multiple subscription definitions.
- <opcua_input> :
Configures a Subscription to an OPC UA Client and a set of MonitoredItems — DataItems or EventItems — using an opcua_connection definition.
A subscription may contain different opcua_input definitions to allow combining information from different Inputs in one or more DDS Outputs.
- <dds_output> :
Configures a DDS DataWriter capable of publishing a Topic in the context of an already defined domain_participant. The definition of a dds_output does not trigger any publication; for that to happen, users shall specify mappings and assignments of elements in an OPC UA Input to fields of the Topic associated with an OPC UA Output.
A subscription may contain different dds_output definitions.
- <mapping> :
Maps DataItems and EventItems from an OPC UA Input to fields of one or more DDS Outputs.
A subscription shall contain a single mapping definition. In other words, only one mapping section can appear under a subscription element.
- <assignment> :
Assigns DataItems, EventFields from an EventItem, or a constant values to fields of the Topic associated with a DDS Output. Each assignment is therefore bound to a specific DDS Output. A reference to an OPC UA Input under the subscription is also required. The referred OPC UA Input is used as the default input for all the MonitoredItems being assigned (DataItems or EventFields); however, in the mapping of specific fields, users are allowed to override the default OPCUA Input by referencing a different Input from the subscription. This enables combining information from different OPC UA Inputs into a single DDS Output.
A mapping definition may contain multiple assignments — as many as DDS Outputs under the parent subscription definition.
Security¶
In this version of the OPC UA - DDS Gateway, security is on by default and there is no way to run without it, thus ensuring the highest security standards on the data passing through the Gateway. Not only is the data encrypted, but the Gateway requires strong authentication on the OPC servers. On the DDS side, the Gateway requires certificates to subscribe and publish on the appropriate DDS domains.
- OPC UA
The OPC UA server that comes with the demo, and the gateway, are using a self-signed Idendity CA certificate. In production, you should request an SSL certificate from a CA like Verisign, by sending them a Certificate Signing Request.
In order to establish a secured connection in betwwen the OPC UA - DDS gateway and the surrounding OPC UA servers one should provide at least the following artefacts :
- An Identity CA Certificate and its private key
- On the OPC UA server side :
- An Identity Certificate and its private key
- Authentication using user name and password activated
- On the OPC UA - DDS gateway side :
- An Identity Certificate and its private key, issued by the same Identity CA
The configuration of the security of the OPC UA connection between the OPC UA - DDS gateway and the surrounding OPC UA servers can be found in gateway-[version].AppImage.home/security/OPC/security.cfg
This configuration file stores all the required information, described in the following fields. All the fields are mandatory.
- certificateTrustListLocation : points to the directory that contains … This folder is relative to the $HOME directory. Can be an empty folder.
- certificateRevocationListLocation : Not supported yet.
- issuersCertificateLocation : points to the directory that contains the certificates stored by official certificate issuers, commonly “/etc/ssl/certs” on a Debian or derivative.
These fields are followed by a “security” section that contains a serverConnections list. For each OPC UA server connection, the OPC UA - DDS gateway offers the following entries :
- connectionName : should be the same as the one used in the OPC UA - DDS gateway configuration opcdds_config.xml
- securityPolicy : can be one of “None”, “Basic128Rsa15”, “Basic256”, “Basic256Sha256”
- messageSecurityMode : can be one of “None”, “Sign”, “SignAndEncrypt” (recommended)
- authenticationMode : can be one of “UsernamePassword” (recommended). During the connection to an OPC UA server, the gateway scans the different endpoints exposed by the server and ensures the safest connection.
- userName : the user name used for authenticating on this OPC UA server
- password : the password used for authenticating on this OPC UA server
- certificate : the certificate representing the gateway, a self-signed certificate is provided with the demo, this should never be used in production !
- key : the public key associated with the previous certificate
FOR DEVELOPMENT PURPOSES ONLY !
If you want to setup a secured connection using your own self-signed certificate :
- Creating your own self-signed CA certificate for securing the OPC UA - DDS gateway to OPC UA servers :
$ cd config/security/OPC //or wherever should this certificate be. But you should point to it when using it for signing the identity certificates
$ mkdir ca
$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out ca/ca.key
$ openssl req -new -x509 -days 3600 -key ca/ca.key -subj "/CN=devteam CA/O=neoliant.com" -out ca/ca.crt //you can place what you need in the CN and O fields
$ openssl x509 -in ca/ca.crt -inform pem -out ca/ca.crt.der -outform der
- On the OPC UA server side, create a server certificate, signed using the previously created CA certificate, so as to encrypt the connection with the gateway :
The following commands should be run on the OPC UA server system.
$ mkdir server
$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server/server.key
$ openssl rsa -in server/server.key -inform pem -out server/server.key.der -outform der
$ openssl req -new -sha256 -key server/server.key -subj "/C=FR/O=your-company.com/CN=opctestserver" -out server/server.csr # you can place what you wish in C, O and CN variables.
Then create a server/exts.txt file :
[v3_ca]
subjectAltName=DNS:localhost,IP:127.0.0.1,URI:urn:OPC.server.application
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth,clientAuth,codeSigning
You can add more DNS or IP entries. You can set a proper Application URI, identical to the one set in the configuration of the server. Then sign the certificate signing request (csr), providing the fresly created exts.txt file :
$ openssl x509 -days 3600 -req -in server/server.csr -extensions v3_ca -extfile server/exts.txt -CAcreateserial -CA ca/ca.crt -CAkey ca/ca.key -out server/server.crt
Finally, convert the certificate to the .der format :
$ openssl x509 -in server/server.crt -inform pem -out server/server.crt.der -outform der
This certificate server.crt.der and its private key server.key.der must be loaded by the OPC UA server.
Additionaly, for authentication purposes, anonymous logins must be disabled on the server side, and a username / password login must be enabled.
- Creating an identity certificate for the OPC UA - DDS gateway, using the previously generated CA certificate :
$ cd config/security/OPC
$ mkdir gateway
$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out gateway/gateway.key
$ openssl rsa -in gateway/gateway.key -inform pem -out gateway/gateway.key.der -outform der
$ openssl req -new -sha256 -key gateway/gateway.key -subj "/C=FR/O=neoliant.com/CN=OPC UA - DDS Gateway" -out gateway/gateway.csr
Then create a gateway/exts.txt file :
[v3_ca]
subjectAltName=DNS:localhost,IP:127.0.0.1,URI:urn:Neoliant:OPCUA-DDS Gateway
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth,clientAuth,codeSigning
You can add more DNS or IP entries. You cannot change the application URI. Then sign the certificate signing request (csr), providing the freshly created exts.txt file :
$ openssl x509 -days 3600 -req -in gateway/gateway.csr -extensions v3_ca -extfile gateway/exts.txt -CAcreateserial -CA ca/ca.crt -CAkey ca/ca.key -out gateway/gateway.crt
Finally, convert the certificate to the .der format :
$ openssl x509 -in gateway/gateway.crt -inform pem -out gateway/gateway.crt.der -outform der
Make sure gateway-[version].AppImage.home/config/security/OPC/gateway contains gateway.crt.der as well as gateway.key.der before starting it.
Connect UaExpert client to the OPC UA server, an empty revocation list is necessary…
- DDS
Let consider a DDS Domain on which you want to publish and subscribe data to and from the OPC UA - DDS Gateway. For this Domain we’ll need the following artefacts :
- Identity CA Certificate
- Permissions CA Certificate (may be the same as Identity CA)
- Governance document
- signed by Permissions CA using its private key
Then for the OPC UA - DDS Gateway, we’ll need :
- Identity Certificate and its Private key
- issued by Identity CA
- Permissions document
- Contains a “subject name” which matches the participant certificate’s Subject
- Signed by Permissions CA using its private key
And of course the same for each DDS Application using this Domain.
So let’s get into practice. First, One should create a self-signed Identity CA Certificate :
We start by creating a private key :
$ cd gateway-[version].AppImage.home/security/DDS/certs/identity
$ openssl genrsa -out identity_ca_private_key.pem 2048
Then provide an appropriate .cnf configuration file for openssl like the one available at the OpenDDS repository and adapt the [ req_distinguished_name ] to your situation.
$ wget https://raw.githubusercontent.com/objectcomputing/OpenDDS/master/tests/security/certs/identity/identity_ca_openssl.cnf
$ nano identity_ca_openssl.cnf
Finally we can generate the certificate :
$ openssl req -config ./identity_ca_openssl.cnf -new -key identity_ca_private_key.pem -out ca.csr
$ openssl x509 -req -days 3650 -in ca.csr -signkey identity_ca_private_key.pem -out identity_ca_cert.pem
We’ll create a separate Permissions CA Certificate in the same way :
$ cd ../permissions
$ cp ../identity/identity_ca_openssl.cnf . # and edit it
$ openssl genrsa -out permissions_ca_private_key.pem 2048
$ openssl req -config ./identity_ca_openssl.cnf -new -key permissions_ca_private_key.pem -out ca.csr
$ openssl x509 -req -days 3650 -in ca.csr -signkey permissions_ca_private_key.pem -out permissions_ca_cert.pem
We finally take care of the domain by providing a signed xml governance document. For details regarding governance.xml and permissions.xml, we encourage the read of OpenDDS-3.15 documentation. For instance, governance.xml may look like :
<?xml version="1.0" encoding="UTF-8"?>
<!--
Illustrates DDS Security is an extension of DDS. It is still possible to
run applications without any protection.
-->
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../schema/omg_shared_ca_governance.xsd">
<domain_access_rules>
<!-- Domain 4 is an "protected domain." That is, only applications that
can authenticate and have proper permissions can join it. -->
<domain_rule>
<domains>
<id>4</id>
</domains>
<allow_unauthenticated_participants>false</allow_unauthenticated_participants>
<enable_join_access_control>false</enable_join_access_control>
<discovery_protection_kind>NONE</discovery_protection_kind>
<liveliness_protection_kind>NONE</liveliness_protection_kind>
<rtps_protection_kind>NONE</rtps_protection_kind>
<topic_access_rules>
<topic_rule>
<topic_expression>*</topic_expression>
<enable_discovery_protection>false</enable_discovery_protection>
<enable_liveliness_protection>false</enable_liveliness_protection>
<enable_read_access_control>false</enable_read_access_control>
<enable_write_access_control>false</enable_write_access_control>
<metadata_protection_kind>NONE</metadata_protection_kind>
<data_protection_kind>NONE</data_protection_kind>
</topic_rule>
</topic_access_rules>
</domain_rule>
</domain_access_rules>
</dds>
This can be signed using :
$ openssl smime -sign -in governance.xml -text -out governance_signed.p7s -signer certs/permissions/permissions_ca_cert.pem -inkey certs/permissions/permissions_ca_private_key.pem
This file should reside in gateway-[version].AppImage.home/security/DDS
OK, let now generate the artefacts that are needed per application joining this DDS Domain. We’ll consider the gateway, the approach is exactly the same for all the DDS applications based on OpenDDS and joining this Domain.
$ cd gateway-[version].AppImage.home/security/DDS/certs/identity
$ openssl genrsa -out gateway_private_key.pem 2048
$ openssl req -new -key gateway_private_key.pem -out gateway.csr //and answer a few questions
$ openssl x509 -req -in gateway.csr -CA identity_ca_cert.pem -CAkey identity_ca_private_key.pem -CAcreateserial -out gateway_cert.pem -days 500 -sha256
Then look into the generated certificate with the following command :
$ openssl req -in gateway.csr -noout -text
or
$ openssl x509 -noout -in gateway_cert.pem -subject
Edit the permissions_gateway.xml file and change the subject to the one given with the previous command. You might have the following gateway_permissions.xml file :
<?xml version="1.0" encoding="utf-8"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS-SECURITY/20160303/omg_shared_ca_permissions.xsd">
<permissions>
<grant name="GatewayPermission">
<subject_name>C = FR, L = Paris, O = Neoliant, emailAddress = info@neoliant.com</subject_name>
<validity>
<!-- Format is CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] in GMT -->
<not_before>2015-09-15T01:00:00</not_before>
<not_after>2025-09-15T01:00:00</not_after>
</validity>
<allow_rule>
<domains>
<id>4</id>
</domains>
<publish>
<topics>
<topic>*</topic>
</topics>
</publish>
<subscribe>
<topics>
<topic>*</topic>
</topics>
</subscribe>
</allow_rule>
<default>DENY</default>
</grant>
</permissions>
</dds>
Finally, sign this file using the Permissions CA certificate :
$ openssl smime -sign -in permissions_gateway.xml -text -out permissions_gateway_signed.p7s -signer certs/permissions/permissions_ca_cert.pem -inkey certs/permissions/permissions_ca_private_key.pem
This file should reside in gateway-[version].AppImage.home/security/DDS
To sum up, in order to properly and securely start on DDS, the OPC UA - DDS Gateway requires the following files :
- In gateway-[version].AppImage.home/security/DDS/certs/identity : gateway_cert.pem, gateway_private_key.pem and identity_ca_cert.pem
- In gateway-[version].AppImage.home/security/DDS/certs/permissions : permissions_ca_cert.pem
- In gateway-[version].AppImage.home/security/DDS : governance_signed.p7s and permissions_gateway_signed.p7s
Logs Management¶
More DDS Configuration¶
QoS, rtps-udp.ini, switching to tcp, using the relay, …
Execution¶
Switch to the directory where you unpacked the OPC UA - DDS Gateway and simply execute :
$ ./gateway-[version].AppImage