From 0c2f3be36a6eb5ca970bc24bc4df60e194b0e796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Fri, 10 Jan 2025 14:56:20 +0100 Subject: [PATCH 1/4] Added Zenoh secutiry configuration package MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- zenoh_security_configuration/README.md | 1 + zenoh_security_configuration/package.xml | 16 + .../resource/zenoh_security_configuration | 0 zenoh_security_configuration/setup.cfg | 4 + zenoh_security_configuration/setup.py | 31 ++ .../templates/router.json5 | 499 ++++++++++++++++++ .../zenoh_security_configuration/__init.py__ | 0 .../zenoh_security_configuration.py | 121 +++++ 8 files changed, 672 insertions(+) create mode 100644 zenoh_security_configuration/README.md create mode 100644 zenoh_security_configuration/package.xml create mode 100644 zenoh_security_configuration/resource/zenoh_security_configuration create mode 100644 zenoh_security_configuration/setup.cfg create mode 100644 zenoh_security_configuration/setup.py create mode 100644 zenoh_security_configuration/templates/router.json5 create mode 100644 zenoh_security_configuration/zenoh_security_configuration/__init.py__ create mode 100644 zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py diff --git a/zenoh_security_configuration/README.md b/zenoh_security_configuration/README.md new file mode 100644 index 00000000..5ab09479 --- /dev/null +++ b/zenoh_security_configuration/README.md @@ -0,0 +1 @@ +# zenoh security configuration diff --git a/zenoh_security_configuration/package.xml b/zenoh_security_configuration/package.xml new file mode 100644 index 00000000..3f6c03c5 --- /dev/null +++ b/zenoh_security_configuration/package.xml @@ -0,0 +1,16 @@ + + + + zenoh_security_configuration + 0.3.0 + This package generates zenoh secutiry configurations + Alejandro Hernanadez + Apache License 2.0 + + python3-jsonschema + python3-yaml + + + ament_python + + diff --git a/zenoh_security_configuration/resource/zenoh_security_configuration b/zenoh_security_configuration/resource/zenoh_security_configuration new file mode 100644 index 00000000..e69de29b diff --git a/zenoh_security_configuration/setup.cfg b/zenoh_security_configuration/setup.cfg new file mode 100644 index 00000000..40748208 --- /dev/null +++ b/zenoh_security_configuration/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/zenoh_security_configuration +[install] +install_scripts=$base/lib/zenoh_security_configuration diff --git a/zenoh_security_configuration/setup.py b/zenoh_security_configuration/setup.py new file mode 100644 index 00000000..35c02461 --- /dev/null +++ b/zenoh_security_configuration/setup.py @@ -0,0 +1,31 @@ +import os +from glob import glob +from setuptools import setup + +package_name = 'zenoh_security_configuration' + +setup( + name=package_name, + version='0.3.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + [os.path.join('resource', package_name)]), + (os.path.join('share', package_name), ['package.xml']), + (os.path.join('share', package_name, 'templates'), + glob('templates/*.json5')), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='alejandro', + maintainer_email='alejandro@openrobotics.org', + description='This package generates zenoh secutiry configurations', + license='Apache License 2.0', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'zenoh_security_configuration = \ + zenoh_security_configuration.zenoh_security_configuration:main' + ], + }, +) diff --git a/zenoh_security_configuration/templates/router.json5 b/zenoh_security_configuration/templates/router.json5 new file mode 100644 index 00000000..a9eaf935 --- /dev/null +++ b/zenoh_security_configuration/templates/router.json5 @@ -0,0 +1,499 @@ +/// This file attempts to list and document available configuration elements. +/// For a more complete view of the configuration's structure, check out `zenoh/src/config.rs`'s `Config` structure. +/// Note that the values here are correctly typed, but may not be sensible, so copying this file to change only the parts that matter to you is not good practice. +{ + /// The identifier (as unsigned 128bit integer in hexadecimal lowercase - leading zeros are not accepted) + /// that zenoh runtime will use. + /// If not set, a random unsigned 128bit integer will be used. + /// WARNING: this id must be unique in your zenoh network. + // id: "1234567890abcdef", + + /// The node's mode (router, peer or client) + mode: "router", + + /// Which endpoints to connect to. E.g. tcp/localhost:7447. + /// By configuring the endpoints, it is possible to tell zenoh which router/peer to connect to at startup. + /// For TCP/UDP on Linux, it is possible additionally specify the interface to be connected to: + /// E.g. tcp/192.168.0.1:7447#iface=eth0, for connect only if the IP address is reachable via the interface eth0 + connect: { + /// timeout waiting for all endpoints connected (0: no retry, -1: infinite timeout) + /// Accepts a single value (e.g. timeout_ms: 0) + /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }). + timeout_ms: { router: -1, peer: -1, client: 0 }, + + /// The list of endpoints to connect to. + /// Accepts a single list (e.g. endpoints: ["tcp/10.10.10.10:7447", "tcp/11.11.11.11:7447"]) + /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/10.10.10.10:7447"], peer: ["tcp/11.11.11.11:7447"] }). + /// + /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html + endpoints: [ + // "/
" + ], + + /// Global connect configuration, + /// Accepts a single value or different values for router, peer and client. + /// The configuration can also be specified for the separate endpoint + /// it will override the global one + /// E.g. tcp/192.168.0.1:7447#retry_period_init_ms=20000;retry_period_max_ms=10000" + + /// exit from application, if timeout exceed + exit_on_failure: { router: false, peer: false, client: true }, + /// connect establishing retry configuration + retry: { + /// initial wait timeout until next connect try + period_init_ms: 1000, + /// maximum wait timeout until next connect try + period_max_ms: 4000, + /// increase factor for the next timeout until nexti connect try + period_increase_factor: 2, + }, + }, + + /// Which endpoints to listen on. E.g. tcp/0.0.0.0:7447. + /// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers, + /// peers, or client can use to establish a zenoh session. + /// For TCP/UDP on Linux, it is possible additionally specify the interface to be listened to: + /// E.g. tcp/0.0.0.0:7447#iface=eth0, for listen connection only on eth0 + listen: { + /// timeout waiting for all listen endpoints (0: no retry, -1: infinite timeout) + /// Accepts a single value (e.g. timeout_ms: 0) + /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }). + timeout_ms: 0, + + /// The list of endpoints to listen on. + /// Accepts a single list (e.g. endpoints: ["tcp/[::]:7447", "udp/[::]:7447"]) + /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/[::]:7447"], peer: ["tcp/[::]:0"] }). + /// + /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html + endpoints: [ + "tls/localhost:7447" + ], + + /// Global listen configuration, + /// Accepts a single value or different values for router, peer and client. + /// The configuration can also be specified for the separate endpoint + /// it will override the global one + /// E.g. tcp/192.168.0.1:7447#exit_on_failure=false;retry_period_max_ms=1000" + + /// exit from application, if timeout exceed + exit_on_failure: true, + /// listen retry configuration + retry: { + /// initial wait timeout until next try + period_init_ms: 1000, + /// maximum wait timeout until next try + period_max_ms: 4000, + /// increase factor for the next timeout until next try + period_increase_factor: 2, + }, + }, + + /// Configure the scouting mechanisms and their behaviours + scouting: { + /// In client mode, the period in milliseconds dedicated to scouting for a router before failing. + timeout: 3000, + /// In peer mode, the maximum period in milliseconds dedicated to scouting remote peers before attempting other operations. + delay: 500, + /// The multicast scouting configuration. + multicast: { + /// Whether multicast scouting is enabled or not + /// + /// ROS setting: disable multicast discovery by default + enabled: false, + /// The socket which should be used for multicast scouting + address: "224.0.0.224:7446", + /// The network interface which should be used for multicast scouting + interface: "auto", // If not set or set to "auto" the interface if picked automatically + /// The time-to-live on multicast scouting packets + ttl: 1, + /// Which type of Zenoh instances to automatically establish sessions with upon discovery on UDP multicast. + /// Accepts a single value (e.g. autoconnect: ["router", "peer"]) + /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }). + /// Each value is a list of: "peer", "router" and/or "client". + autoconnect: { router: [], peer: ["router", "peer"] }, + /// Whether or not to listen for scout messages on UDP multicast and reply to them. + listen: true, + }, + /// The gossip scouting configuration. + gossip: { + /// Whether gossip scouting is enabled or not + enabled: true, + /// When true, gossip scouting information are propagated multiple hops to all nodes in the local network. + /// When false, gossip scouting information are only propagated to the next hop. + /// Activating multihop gossip implies more scouting traffic and a lower scalability. + /// It mostly makes sense when using "linkstate" routing mode where all nodes in the subsystem don't have + /// direct connectivity with each other. + multihop: false, + /// Which type of Zenoh instances to automatically establish sessions with upon discovery on gossip. + /// Accepts a single value (e.g. autoconnect: ["router", "peer"]) + /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }). + /// Each value is a list of: "peer", "router" and/or "client". + autoconnect: { router: [], peer: ["router", "peer"] }, + }, + }, + + /// Configuration of data messages timestamps management. + timestamping: { + /// Whether data messages should be timestamped if not already. + /// Accepts a single boolean value or different values for router, peer and client. + /// + /// ROS setting: PublicationCache which is required for transient_local durability + /// only works when time-stamping is enabled. + enabled: { router: true, peer: true, client: true }, + /// Whether data messages with timestamps in the future should be dropped or not. + /// If set to false (default), messages with timestamps in the future are retimestamped. + /// Timestamps are ignored if timestamping is disabled. + drop_future_timestamp: false, + }, + + /// The default timeout to apply to queries in milliseconds. + queries_default_timeout: 10000, + + /// The routing strategy to use and it's configuration. + routing: { + /// The routing strategy to use in routers and it's configuration. + router: { + /// When set to true a router will forward data between two peers + /// directly connected to it if it detects that those peers are not + /// connected to each other. + /// The failover brokering only works if gossip discovery is enabled. + /// ROS setting: disabled by default because it serves no purpose when each peer connects directly to all others, + /// and it introduces additional management overhead and extra messages during system startup. + peers_failover_brokering: false, + }, + /// The routing strategy to use in peers and it's configuration. + peer: { + /// The routing strategy to use in peers. ("peer_to_peer" or "linkstate"). + mode: "peer_to_peer", + }, + }, + + // /// The declarations aggregation strategy. + // aggregation: { + // /// A list of key-expressions for which all included subscribers will be aggregated into. + // subscribers: [ + // // key_expression + // ], + // /// A list of key-expressions for which all included publishers will be aggregated into. + // publishers: [ + // // key_expression + // ], + // }, + + // /// The downsampling declaration. + // downsampling: [ + // { + // /// A list of network interfaces messages will be processed on, the rest will be passed as is. + // interfaces: [ "wlan0" ], + // /// Data flow messages will be processed on. ("egress" or "ingress") + // flow: "egress", + // /// A list of downsampling rules: key_expression and the maximum frequency in Hertz + // rules: [ + // { key_expr: "demo/example/zenoh-rs-pub", freq: 0.1 }, + // ], + // }, + // ], + + // /// Configure access control (ACL) rules + // access_control: { + // /// [true/false] acl will be activated only if this is set to true + // "enabled": false, + // /// [deny/allow] default permission is deny (even if this is left empty or not specified) + // "default_permission": "deny", + // /// Rule set for permissions allowing or denying access to key-expressions + // "rules": + // [ + // { + // /// Id has to be unique within the rule set + // "id": "rule1", + // "messages": [ + // "put", "delete", "declare_subscriber", + // "query", "reply", "declare_queryable", + // ], + // "flows":["egress","ingress"], + // "permission": "allow", + // "key_exprs": [ + // "test/demo" + // ], + // }, + // { + // "id": "rule2", + // "messages": [ + // "put", "delete", "declare_subscriber", + // "query", "reply", "declare_queryable", + // ], + // "flows":["ingress"], + // "permission": "allow", + // "key_exprs": [ + // "**" + // ], + // }, + // ], + // /// List of combinations of subjects. + // /// + // /// If a subject property (i.e. username, certificate common name or interface) is empty + // /// it is interpreted as a wildcard. Moreover, a subject property cannot be an empty list. + // "subjects": + // [ + // { + // /// Id has to be unique within the subjects list + // "id": "subject1", + // /// Subjects can be interfaces + // "interfaces": [ + // "lo0", + // "en0", + // ], + // /// Subjects can be cert_common_names when using TLS or Quic + // "cert_common_names": [ + // "example.zenoh.io" + // ], + // /// Subjects can be usernames when using user/password authentication + // "usernames": [ + // "zenoh-example" + // ], + // /// This instance translates internally to this filter: + // /// (interface="lo0" && cert_common_name="example.zenoh.io" && username="zenoh-example") || + // /// (interface="en0" && cert_common_name="example.zenoh.io" && username="zenoh-example") + // }, + // { + // "id": "subject2", + // "interfaces": [ + // "lo0", + // "en0", + // ], + // "cert_common_names": [ + // "example2.zenoh.io" + // ], + // /// This instance translates internally to this filter: + // /// (interface="lo0" && cert_common_name="example2.zenoh.io") || + // /// (interface="en0" && cert_common_name="example2.zenoh.io") + // }, + // { + // "id": "subject3", + // /// An empty subject combination is a wildcard + // }, + // ], + // /// The policies list associates rules to subjects + // "policies": + // [ + // /// Each policy associates one or multiple rules to one or multiple subject combinations + // { + // /// Rules and Subjects are identified with their unique IDs declared above + // "rules": ["rule1"], + // "subjects": ["subject1", "subject2"], + // }, + // { + // "rules": ["rule2"], + // "subjects": ["subject3"], + // }, + // ] + //}, + + /// Configure internal transport parameters + transport: { + unicast: { + /// Timeout in milliseconds when opening a link + accept_timeout: 10000, + /// Maximum number of zenoh session in pending state while accepting + accept_pending: 100, + /// Maximum number of sessions that can be simultaneously alive + max_sessions: 1000, + /// Maximum number of incoming links that are admitted per session + max_links: 1, + /// Enables the LowLatency transport + /// This option does not make LowLatency transport mandatory, the actual implementation of transport + /// used will depend on Establish procedure and other party's settings + /// + /// NOTE: Currently, the LowLatency transport doesn't preserve QoS prioritization. + /// NOTE: Due to the note above, 'lowlatency' is incompatible with 'qos' option, so in order to + /// enable 'lowlatency' you need to explicitly disable 'qos'. + /// NOTE: LowLatency transport does not support the fragmentation, so the message size should be + /// smaller than the tx batch_size. + lowlatency: false, + /// Enables QoS on unicast communications. + qos: { + enabled: true, + }, + /// Enables compression on unicast communications. + /// Compression capabilities are negotiated during session establishment. + /// If both Zenoh nodes support compression, then compression is activated. + compression: { + enabled: false, + }, + }, + /// WARNING: multicast communication does not perform any negotiation upon group joining. + /// Because of that, it is important that all transport parameters are the same to make + /// sure all your nodes in the system can communicate. One common parameter to configure + /// is "transport/link/tx/batch_size" since its default value depends on the actual platform + /// when operating on multicast. + /// E.g., the batch size on Linux and Windows is 65535 bytes, on Mac OS X is 9216, and anything else is 8192. + multicast: { + /// JOIN message transmission interval in milliseconds. + join_interval: 2500, + /// Maximum number of multicast sessions. + max_sessions: 1000, + /// Enables QoS on multicast communication. + /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility. + qos: { + enabled: false, + }, + /// Enables compression on multicast communication. + /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility. + compression: { + enabled: false, + }, + }, + link: { + /// An optional whitelist of protocols to be used for accepting and opening sessions. If not + /// configured, all the supported protocols are automatically whitelisted. The supported + /// protocols are: ["tcp" , "udp", "tls", "quic", "ws", "unixsock-stream", "vsock"] For + /// example, to only enable "tls" and "quic": protocols: ["tls", "quic"], + /// + /// Configure the zenoh TX parameters of a link + protocols: @(protocols), + tx: { + /// The resolution in bits to be used for the message sequence numbers. + /// When establishing a session with another Zenoh instance, the lowest value of the two instances will be used. + /// Accepted values: 8bit, 16bit, 32bit, 64bit. + sequence_number_resolution: "32bit", + /// Link lease duration in milliseconds to announce to other zenoh nodes + lease: 10000, + /// Number of keep-alive messages in a link lease duration. If no data is sent, keep alive + /// messages will be sent at the configured time interval. + /// NOTE: In order to consider eventual packet loss and transmission latency and jitter, + /// set the actual keep_alive interval to one fourth of the lease time: i.e. send + /// 4 keep_alive messages in a lease period. Changing the lease time will have the + /// keep_alive messages sent more or less often. + /// This is in-line with the ITU-T G.8013/Y.1731 specification on continuous connectivity + /// check which considers a link as failed when no messages are received in 3.5 times the + /// target interval. + keep_alive: 4, + /// Batch size in bytes is expressed as a 16bit unsigned integer. + /// Therefore, the maximum batch size is 2^16-1 (i.e. 65535). + /// The default batch size value is the maximum batch size: 65535. + batch_size: 65535, + /// Each zenoh link has a transmission queue that can be configured + queue: { + /// The size of each priority queue indicates the number of batches a given queue can contain. + /// NOTE: the number of batches in each priority must be included between 1 and 16. Different values will result in an error. + /// The amount of memory being allocated for each queue is then SIZE_XXX * BATCH_SIZE. + /// In the case of the transport link MTU being smaller than the ZN_BATCH_SIZE, + /// then amount of memory being allocated for each queue is SIZE_XXX * LINK_MTU. + /// If qos is false, then only the DATA priority will be allocated. + size: { + control: 1, + real_time: 1, + interactive_high: 1, + interactive_low: 1, + data_high: 2, + data: 4, + data_low: 4, + background: 4, + }, + /// Congestion occurs when the queue is empty (no available batch). + congestion_control: { + /// Behavior pushing CongestionControl::Drop messages to the queue. + drop: { + /// The maximum time in microseconds to wait for an available batch before dropping a droppable message if still no batch is available. + wait_before_drop: 1000, + }, + /// Behavior pushing CongestionControl::Block messages to the queue. + block: { + /// The maximum time in microseconds to wait for an available batch before closing the transport session when sending a blocking message + /// if still no batch is available. + wait_before_close: 5000000, + }, + }, + /// Perform batching of messages if they are smaller of the batch_size + batching: { + /// Perform adaptive batching of messages if they are smaller of the batch_size. + /// When the network is detected to not be fast enough to transmit every message individually, many small messages may be + /// batched together and sent all at once on the wire reducing the overall network overhead. This is typically of a high-throughput + /// scenario mainly composed of small messages. In other words, batching is activated by the network back-pressure. + enabled: true, + /// The maximum time limit (in ms) a message should be retained for batching when back-pressure happens. + time_limit: 1, + }, + }, + }, + /// Configure the zenoh RX parameters of a link + rx: { + /// Receiving buffer size in bytes for each link + /// The default the rx_buffer_size value is the same as the default batch size: 65535. + /// For very high throughput scenarios, the rx_buffer_size can be increased to accommodate + /// more in-flight data. This is particularly relevant when dealing with large messages. + /// E.g. for 16MiB rx_buffer_size set the value to: 16777216. + buffer_size: 65535, + /// Maximum size of the defragmentation buffer at receiver end. + /// Fragmented messages that are larger than the configured size will be dropped. + /// The default value is 1GiB. This would work in most scenarios. + /// NOTE: reduce the value if you are operating on a memory constrained device. + max_message_size: 1073741824, + }, + /// Configure TLS specific parameters + tls: { + /// Path to the certificate of the certificate authority used to validate either the server + /// or the client's keys and certificates, depending on the node's mode. If not specified + /// on router mode then the default WebPKI certificates are used instead. + root_ca_certificate: null, + /// Path to the TLS listening side private key + listen_private_key: "/home/ahcorde/sros2_demo/tls/localhost/key.pem", + /// Path to the TLS listening side public certificate + listen_certificate: "/home/ahcorde/sros2_demo/tls/localhost/cert.pem", + /// Enables mTLS (mutual authentication), client authentication + enable_mtls: false, + /// Path to the TLS connecting side private key + connect_private_key: null, + /// Path to the TLS connecting side certificate + connect_certificate: null, + // Whether or not to verify the matching between hostname/dns and certificate when connecting, + // if set to false zenoh will disregard the common names of the certificates when verifying servers. + // This could be dangerous because your CA can have signed a server cert for foo.com, that's later being used to host a server at baz.com. + // If you want your ca to verify that the server at baz.com is actually baz.com, let this be true (default). + verify_name_on_connect: true, + }, + }, + /// Shared memory configuration. + /// NOTE: shared memory can be used only if zenoh is compiled with "shared-memory" feature, otherwise + /// settings in this section have no effect. + shared_memory: { + /// A probing procedure for shared memory is performed upon session opening. To enable zenoh to operate + /// over shared memory (and to not fallback on network mode), shared memory needs to be enabled also on the + /// subscriber side. By doing so, the probing procedure will succeed and shared memory will operate as expected. + /// + /// ROS setting: disabled by default until fully tested + enabled: false, + }, + auth: { + /// The configuration of authentication. + /// A password implies a username is required. + usrpwd: { + user: null, + password: null, + /// The path to a file containing the user password dictionary + dictionary_file: null, + }, + pubkey: { + public_key_pem: null, + private_key_pem: null, + public_key_file: null, + private_key_file: null, + key_size: null, + known_keys_file: null, + }, + }, + }, + + /// Configure the Admin Space + /// Unstable: this configuration part works as advertised, but may change in a future release + adminspace: { + /// Enables the admin space + enabled: true, + /// read and/or write permissions on the admin space + permissions: { + read: true, + write: false, + }, + }, + +} diff --git a/zenoh_security_configuration/zenoh_security_configuration/__init.py__ b/zenoh_security_configuration/zenoh_security_configuration/__init.py__ new file mode 100644 index 00000000..e69de29b diff --git a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py new file mode 100644 index 00000000..02eaa248 --- /dev/null +++ b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py @@ -0,0 +1,121 @@ +# Copyright 2025 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse +import em +from io import StringIO +import os +import pathlib +import sys +from ament_index_python.packages import get_package_share_directory + +class ZenohSecutiryConfigGenerator: + """ZenohSecutiryConfigGenerator generates Zenoh secutiry configurations.""" + + def __init__(self): + """ + Construct NEXUSConfigGenerator. + """ + self.zenoh_cfg_file_extension = "json5" + + def generate_router_config(self, data): + try: + output = StringIO() + interpreter = em.Interpreter( + output=output, + options={ + em.BUFFERED_OPT: True, + em.RAW_OPT: True, + }, + ) + + template_path = pathlib.Path(os.path.join( + get_package_share_directory("zenoh_security_configuration"), + "templates", + "router.json5" + )) + + + with template_path.open('r') as h: + template_content = h.read() + interpreter.string(template_content, locals=data) + return output.getvalue() + except: + print('lol') + finally: + if interpreter is not None: + interpreter.shutdown() + interpreter = None + + def generate_zenoh_config(self, output_dir, router_config, encoding: str = 'utf-8'): + """ + Generate Zenoh bridge configs and output to directory 'output_dir'. + + Parameters + ---------- + output_dir : str + Output directory for Zenoh configurations + + """ + write_filepath = os.path.join( + output_dir, "router" + "." + + self.zenoh_cfg_file_extension, + ) + output_file = pathlib.Path(write_filepath) + print(f"Generated Zenoh secutiry configuration at {write_filepath}") + if output_file.exists(): + existing_content = output_file.read_text(encoding=encoding) + if existing_content == router_config: + return + elif output_file.parent: + os.makedirs(str(output_file.parent), exist_ok=True) + + output_file.write_text(router_config, encoding=encoding) + +def main(argv=sys.argv): + """Entrypoint.""" + parser = argparse.ArgumentParser( + description="Generate Zenoh configurations from a NEXUS Network \ + and REDF Configuration", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument( + "-o", + "--output", + required=True, + type=str, + help="Output directory for Zenoh bridge configurations", + ) + + parser.add_argument( + "-p", + "--protocols", + nargs='*', + required=False, + choices=["tcp", "tls"], + default=['tls'], + help="Protocols chooices", + ) + + args = parser.parse_args(argv[1:]) + + data = {'protocols': args.protocols} + + zenoh_sec_gen = ZenohSecutiryConfigGenerator() + router_config = zenoh_sec_gen.generate_router_config(data) + zenoh_sec_gen.generate_zenoh_config(args.output, router_config) + +if __name__ == "__main__": + main(sys.argv) From 6cdfbe12545d5b8b5a9f1234bb1bcefca00d987b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Mon, 20 Jan 2025 18:48:21 +0100 Subject: [PATCH 2/4] Added peer template and config key and cert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- zenoh_security_configuration/README.md | 59 ++ .../templates/peer.json5 | 572 ++++++++++++++++++ .../templates/router.json5 | 16 +- .../zenoh_security_configuration.py | 137 ++++- 4 files changed, 762 insertions(+), 22 deletions(-) create mode 100644 zenoh_security_configuration/templates/peer.json5 diff --git a/zenoh_security_configuration/README.md b/zenoh_security_configuration/README.md index 5ab09479..08fcea79 100644 --- a/zenoh_security_configuration/README.md +++ b/zenoh_security_configuration/README.md @@ -1 +1,60 @@ # zenoh security configuration + +### Configure the router + +```bash +ros2 run zenoh_security_configuration zenoh_security_configuration \ + -o zenoh_config \ + -t router \ + --listen_endpoint="tls/localhost:7447" \ + --protocols=tls \ + paths \ + --root_ca_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/public/ca.cert.pem \ + --listen_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/key.pem \ + --connect_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/key.pem \ + --connect_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/cert.pem \ + --listen_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/cert.pem +``` + +Using enclaves generated with `ros2 security create_enclave` + +```bash +ros2 run zenoh_security_configuration zenoh_security_configuration \ + -o zenoh_config \ + -t router \ + --listen_endpoint="tls/localhost:0" \ + --protocols=tls \ + enclave \ + --enclave_path /home/ahcorde/sros2_demo/demo_keystore_zenoh \ + --enclave_name /zenoh +``` + +### Configure a Peer + +```bash +ros2 run zenoh_security_configuration zenoh_security_configuration \ + -o zenoh_config \ + -t peer \ + --listen_endpoint="tls/localhost:0" \ + --protocols=tls \ + paths \ + --root_ca_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/public/ca.cert.pem \ + --listen_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/key.pem \ + --connect_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/key.pem \ + --connect_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/cert.pem \ + --listen_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/cert.pem +``` + +Using enclaves generated with `ros2 security create_enclave` + + +```bash +ros2 run zenoh_security_configuration zenoh_security_configuration \ + -o zenoh_config \ + -t peer \ + --listen_endpoint="tls/localhost:0" \ + --protocols=tls \ + enclave \ + --enclave_path /home/ahcorde/sros2_demo/demo_keystore_zenoh \ + --enclave_name /talker_listener/talker +``` diff --git a/zenoh_security_configuration/templates/peer.json5 b/zenoh_security_configuration/templates/peer.json5 new file mode 100644 index 00000000..49a2d8e4 --- /dev/null +++ b/zenoh_security_configuration/templates/peer.json5 @@ -0,0 +1,572 @@ +/// This file attempts to list and document available configuration elements. +/// For a more complete view of the configuration's structure, check out `zenoh/src/config.rs`'s `Config` structure. +/// Note that the values here are correctly typed, but may not be sensible, so copying this file to change only the parts that matter to you is not good practice. +{ + /// The identifier (as unsigned 128bit integer in hexadecimal lowercase - leading zeros are not accepted) + /// that zenoh runtime will use. + /// If not set, a random unsigned 128bit integer will be used. + /// WARNING: this id must be unique in your zenoh network. + // id: "1234567890abcdef", + + /// The node's mode (router, peer or client) + mode: "peer", + + /// Which endpoints to connect to. E.g. tcp/localhost:7447. + /// By configuring the endpoints, it is possible to tell zenoh which router/peer to connect to at startup. + /// + /// For TCP/UDP on Linux, it is possible additionally specify the interface to be connected to: + /// E.g. tcp/192.168.0.1:7447#iface=eth0, for connect only if the IP address is reachable via the interface eth0 + /// + /// It is also possible to specify a priority range and/or a reliability setting to be used on the link. + /// For example `tcp/localhost?prio=6-7;rel=0` assigns priorities "data_low" and "background" to the established link. + /// + /// For TCP and TLS links, it is possible to specify the TCP buffer sizes: + /// E.g. tcp/192.168.0.1:7447#so_sndbuf=65000;so_rcvbuf=65000 + connect: { + /// timeout waiting for all endpoints connected (0: no retry, -1: infinite timeout) + /// Accepts a single value (e.g. timeout_ms: 0) + /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }). + timeout_ms: { router: -1, peer: -1, client: 0 }, + + /// The list of endpoints to connect to. + /// Accepts a single list (e.g. endpoints: ["tcp/10.10.10.10:7447", "tcp/11.11.11.11:7447"]) + /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/10.10.10.10:7447"], peer: ["tcp/11.11.11.11:7447"] }). + /// + /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html + /// + /// ROS setting: By default connect to the Zenoh router on localhost on port 7447. + endpoints: [ + "@(connect_endpoint)" + ], + + /// Global connect configuration, + /// Accepts a single value or different values for router, peer and client. + /// The configuration can also be specified for the separate endpoint + /// it will override the global one + /// E.g. tcp/192.168.0.1:7447#retry_period_init_ms=20000;retry_period_max_ms=10000" + + /// exit from application, if timeout exceed + exit_on_failure: { router: false, peer: false, client: true }, + /// connect establishing retry configuration + retry: { + /// initial wait timeout until next connect try + period_init_ms: 1000, + /// maximum wait timeout until next connect try + period_max_ms: 4000, + /// increase factor for the next timeout until nexti connect try + period_increase_factor: 2, + }, + }, + + /// Which endpoints to listen on. E.g. tcp/0.0.0.0:7447. + /// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers, + /// peers, or client can use to establish a zenoh session. + /// + /// For TCP/UDP on Linux, it is possible additionally specify the interface to be listened to: + /// E.g. tcp/0.0.0.0:7447#iface=eth0, for listen connection only on eth0 + /// + /// It is also possible to specify a priority range and/or a reliability setting to be used on the link. + /// For example `tcp/localhost?prio=6-7;rel=0` assigns priorities "data_low" and "background" to the established link. + /// + /// For TCP and TLS links, it is possible to specify the TCP buffer sizes: + /// E.g. tcp/192.168.0.1:7447#so_sndbuf=65000;so_rcvbuf=65000 + listen: { + /// timeout waiting for all listen endpoints (0: no retry, -1: infinite timeout) + /// Accepts a single value (e.g. timeout_ms: 0) + /// or different values for router, peer and client (e.g. timeout_ms: { router: -1, peer: -1, client: 0 }). + timeout_ms: 0, + + /// The list of endpoints to listen on. + /// Accepts a single list (e.g. endpoints: ["tcp/[::]:7447", "udp/[::]:7447"]) + /// or different lists for router, peer and client (e.g. endpoints: { router: ["tcp/[::]:7447"], peer: ["tcp/[::]:0"] }). + /// + /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html + /// + /// ROS setting: By default accept incoming connections only from localhost (i.e. from colocalized Nodes). + /// All communications with other hosts are routed by the Zenoh router. + endpoints: [ + "@(listen_endpoint)" + ], + + /// Global listen configuration, + /// Accepts a single value or different values for router, peer and client. + /// The configuration can also be specified for the separate endpoint + /// it will override the global one + /// E.g. tcp/192.168.0.1:7447#exit_on_failure=false;retry_period_max_ms=1000" + + /// exit from application, if timeout exceed + exit_on_failure: true, + /// listen retry configuration + retry: { + /// initial wait timeout until next try + period_init_ms: 1000, + /// maximum wait timeout until next try + period_max_ms: 4000, + /// increase factor for the next timeout until next try + period_increase_factor: 2, + }, + }, + /// Configure the session open behavior. + open: { + /// Configure the conditions to be met before session open returns. + return_conditions: { + /// Session open waits to connect to scouted peers and routers before returning. + /// When set to false, first publications and queries after session open from peers may be lost. + connect_scouted: true, + /// Session open waits to receive initial declares from connected peers before returning. + /// Setting to false may cause extra traffic at startup from peers. + declares: true, + }, + }, + /// Configure the scouting mechanisms and their behaviours + scouting: { + /// In client mode, the period in milliseconds dedicated to scouting for a router before failing. + timeout: 3000, + /// In peer mode, the maximum period in milliseconds dedicated to scouting remote peers before attempting other operations. + delay: 500, + /// The multicast scouting configuration. + multicast: { + /// Whether multicast scouting is enabled or not + /// + /// ROS setting: disable multicast discovery by default + enabled: false, + /// The socket which should be used for multicast scouting + address: "224.0.0.224:7446", + /// The network interface which should be used for multicast scouting + interface: "auto", // If not set or set to "auto" the interface if picked automatically + /// The time-to-live on multicast scouting packets + ttl: 1, + /// Which type of Zenoh instances to automatically establish sessions with upon discovery on UDP multicast. + /// Accepts a single value (e.g. autoconnect: ["router", "peer"]) + /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }). + /// Each value is a list of: "peer", "router" and/or "client". + autoconnect: { router: [], peer: ["router", "peer"] }, + /// Whether or not to listen for scout messages on UDP multicast and reply to them. + listen: true, + }, + /// The gossip scouting configuration. + gossip: { + /// Whether gossip scouting is enabled or not + enabled: true, + /// When true, gossip scouting information are propagated multiple hops to all nodes in the local network. + /// When false, gossip scouting information are only propagated to the next hop. + /// Activating multihop gossip implies more scouting traffic and a lower scalability. + /// It mostly makes sense when using "linkstate" routing mode where all nodes in the subsystem don't have + /// direct connectivity with each other. + multihop: false, + /// Which type of Zenoh instances to automatically establish sessions with upon discovery on gossip. + /// Accepts a single value (e.g. autoconnect: ["router", "peer"]) + /// or different values for router, peer and client (e.g. autoconnect: { router: [], peer: ["router", "peer"] }). + /// Each value is a list of: "peer", "router" and/or "client". + autoconnect: { router: [], peer: ["router", "peer"] }, + }, + }, + + /// Configuration of data messages timestamps management. + timestamping: { + /// Whether data messages should be timestamped if not already. + /// Accepts a single boolean value or different values for router, peer and client. + /// + /// ROS setting: PublicationCache which is required for transient_local durability + /// only works when time-stamping is enabled. + enabled: { router: true, peer: true, client: true }, + /// Whether data messages with timestamps in the future should be dropped or not. + /// If set to false (default), messages with timestamps in the future are retimestamped. + /// Timestamps are ignored if timestamping is disabled. + drop_future_timestamp: false, + }, + + /// The default timeout to apply to queries in milliseconds. + queries_default_timeout: 10000, + + /// The routing strategy to use and it's configuration. + routing: { + /// The routing strategy to use in routers and it's configuration. + router: { + /// When set to true a router will forward data between two peers + /// directly connected to it if it detects that those peers are not + /// connected to each other. + /// The failover brokering only works if gossip discovery is enabled. + peers_failover_brokering: true, + }, + /// The routing strategy to use in peers and it's configuration. + peer: { + /// The routing strategy to use in peers. ("peer_to_peer" or "linkstate"). + mode: "peer_to_peer", + }, + }, + + // /// Overwrite QoS options for Zenoh messages by key expression (ignores Zenoh API QoS config for overwritten values) + // qos: { + // /// Overwrite QoS options for PUT and DELETE messages + // publication: [ + // { + // /// PUT and DELETE messages on key expressions that are included by these key expressions + // /// will have their QoS options overwritten by the given config. + // key_exprs: ["demo/**", "example/key"], + // /// Configurations that will be applied on the publisher. + // /// Options that are supplied here will overwrite the configuration given in Zenoh API + // config: { + // congestion_control: "block", + // priority: "data_high", + // express: true, + // reliability: "best_effort", + // allowed_destination: "remote", + // }, + // }, + // ], + // }, + + // /// The declarations aggregation strategy. + // aggregation: { + // /// A list of key-expressions for which all included subscribers will be aggregated into. + // subscribers: [ + // // key_expression + // ], + // /// A list of key-expressions for which all included publishers will be aggregated into. + // publishers: [ + // // key_expression + // ], + // }, + + // /// The downsampling declaration. + // downsampling: [ + // { + // /// A list of network interfaces messages will be processed on, the rest will be passed as is. + // interfaces: [ "wlan0" ], + // /// Data flow messages will be processed on. ("egress" or "ingress") + // flow: "egress", + // /// A list of downsampling rules: key_expression and the maximum frequency in Hertz + // rules: [ + // { key_expr: "demo/example/zenoh-rs-pub", freq: 0.1 }, + // ], + // }, + // ], + + // /// Configure access control (ACL) rules + // access_control: { + // /// [true/false] acl will be activated only if this is set to true + // "enabled": false, + // /// [deny/allow] default permission is deny (even if this is left empty or not specified) + // "default_permission": "deny", + // /// Rule set for permissions allowing or denying access to key-expressions + // "rules": + // [ + // { + // /// Id has to be unique within the rule set + // "id": "rule1", + // "messages": [ + // "put", "delete", "declare_subscriber", + // "query", "reply", "declare_queryable", + // "liveliness_token", "liveliness_query", "declare_liveliness_subscriber", + // ], + // "flows":["egress","ingress"], + // "permission": "allow", + // "key_exprs": [ + // "test/demo" + // ], + // }, + // { + // "id": "rule2", + // "messages": [ + // "put", "delete", "declare_subscriber", + // "query", "reply", "declare_queryable", + // ], + // "flows":["ingress"], + // "permission": "allow", + // "key_exprs": [ + // "**" + // ], + // }, + // ], + // /// List of combinations of subjects. + // /// + // /// If a subject property (i.e. username, certificate common name or interface) is empty + // /// it is interpreted as a wildcard. Moreover, a subject property cannot be an empty list. + // "subjects": + // [ + // { + // /// Id has to be unique within the subjects list + // "id": "subject1", + // /// Subjects can be interfaces + // "interfaces": [ + // "lo0", + // "en0", + // ], + // /// Subjects can be cert_common_names when using TLS or Quic + // "cert_common_names": [ + // "example.zenoh.io" + // ], + // /// Subjects can be usernames when using user/password authentication + // "usernames": [ + // "zenoh-example" + // ], + // /// This instance translates internally to this filter: + // /// (interface="lo0" && cert_common_name="example.zenoh.io" && username="zenoh-example") || + // /// (interface="en0" && cert_common_name="example.zenoh.io" && username="zenoh-example") + // }, + // { + // "id": "subject2", + // "interfaces": [ + // "lo0", + // "en0", + // ], + // "cert_common_names": [ + // "example2.zenoh.io" + // ], + // /// This instance translates internally to this filter: + // /// (interface="lo0" && cert_common_name="example2.zenoh.io") || + // /// (interface="en0" && cert_common_name="example2.zenoh.io") + // }, + // { + // "id": "subject3", + // /// An empty subject combination is a wildcard + // }, + // ], + // /// The policies list associates rules to subjects + // "policies": + // [ + // /// Each policy associates one or multiple rules to one or multiple subject combinations + // { + // /// Rules and Subjects are identified with their unique IDs declared above + // "rules": ["rule1"], + // "subjects": ["subject1", "subject2"], + // }, + // { + // "rules": ["rule2"], + // "subjects": ["subject3"], + // }, + // ] + //}, + + /// Configure internal transport parameters + transport: { + unicast: { + /// Timeout in milliseconds when opening a link + open_timeout: 10000, + /// Timeout in milliseconds when accepting a link + accept_timeout: 10000, + /// Maximum number of zenoh session in pending state while accepting + accept_pending: 100, + /// Maximum number of sessions that can be simultaneously alive + max_sessions: 1000, + /// Maximum number of incoming links that are admitted per session + max_links: 1, + /// Enables the LowLatency transport + /// This option does not make LowLatency transport mandatory, the actual implementation of transport + /// used will depend on Establish procedure and other party's settings + /// + /// NOTE: Currently, the LowLatency transport doesn't preserve QoS prioritization. + /// NOTE: Due to the note above, 'lowlatency' is incompatible with 'qos' option, so in order to + /// enable 'lowlatency' you need to explicitly disable 'qos'. + /// NOTE: LowLatency transport does not support the fragmentation, so the message size should be + /// smaller than the tx batch_size. + lowlatency: false, + /// Enables QoS on unicast communications. + qos: { + enabled: true, + }, + /// Enables compression on unicast communications. + /// Compression capabilities are negotiated during session establishment. + /// If both Zenoh nodes support compression, then compression is activated. + compression: { + enabled: false, + }, + }, + /// WARNING: multicast communication does not perform any negotiation upon group joining. + /// Because of that, it is important that all transport parameters are the same to make + /// sure all your nodes in the system can communicate. One common parameter to configure + /// is "transport/link/tx/batch_size" since its default value depends on the actual platform + /// when operating on multicast. + /// E.g., the batch size on Linux and Windows is 65535 bytes, on Mac OS X is 9216, and anything else is 8192. + multicast: { + /// JOIN message transmission interval in milliseconds. + join_interval: 2500, + /// Maximum number of multicast sessions. + max_sessions: 1000, + /// Enables QoS on multicast communication. + /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility. + qos: { + enabled: false, + }, + /// Enables compression on multicast communication. + /// Default to false for Zenoh-to-Zenoh-Pico out-of-the-box compatibility. + compression: { + enabled: false, + }, + }, + link: { + /// An optional whitelist of protocols to be used for accepting and opening sessions. If not + /// configured, all the supported protocols are automatically whitelisted. The supported + /// protocols are: ["tcp" , "udp", "tls", "quic", "ws", "unixsock-stream", "vsock"] For + /// example, to only enable "tls" and "quic": protocols: ["tls", "quic"], + /// + /// Configure the zenoh TX parameters of a link + protocols: @(protocols), + tx: { + /// The resolution in bits to be used for the message sequence numbers. + /// When establishing a session with another Zenoh instance, the lowest value of the two instances will be used. + /// Accepted values: 8bit, 16bit, 32bit, 64bit. + sequence_number_resolution: "32bit", + /// Link lease duration in milliseconds to announce to other zenoh nodes + lease: 10000, + /// Number of keep-alive messages in a link lease duration. If no data is sent, keep alive + /// messages will be sent at the configured time interval. + /// NOTE: In order to consider eventual packet loss and transmission latency and jitter, + /// set the actual keep_alive interval to one fourth of the lease time: i.e. send + /// 4 keep_alive messages in a lease period. Changing the lease time will have the + /// keep_alive messages sent more or less often. + /// This is in-line with the ITU-T G.8013/Y.1731 specification on continuous connectivity + /// check which considers a link as failed when no messages are received in 3.5 times the + /// target interval. + keep_alive: 4, + /// Batch size in bytes is expressed as a 16bit unsigned integer. + /// Therefore, the maximum batch size is 2^16-1 (i.e. 65535). + /// The default batch size value is the maximum batch size: 65535. + batch_size: 65535, + /// Each zenoh link has a transmission queue that can be configured + queue: { + /// The size of each priority queue indicates the number of batches a given queue can contain. + /// NOTE: the number of batches in each priority must be included between 1 and 16. Different values will result in an error. + /// The amount of memory being allocated for each queue is then SIZE_XXX * BATCH_SIZE. + /// In the case of the transport link MTU being smaller than the ZN_BATCH_SIZE, + /// then amount of memory being allocated for each queue is SIZE_XXX * LINK_MTU. + /// If qos is false, then only the DATA priority will be allocated. + size: { + control: 1, + real_time: 1, + interactive_high: 1, + interactive_low: 1, + data_high: 2, + data: 4, + data_low: 4, + background: 4, + }, + /// Congestion occurs when the queue is empty (no available batch). + congestion_control: { + /// Behavior pushing CongestionControl::Drop messages to the queue. + drop: { + /// The maximum time in microseconds to wait for an available batch before dropping a droppable message if still no batch is available. + wait_before_drop: 1000, + /// The maximum deadline limit for multi-fragment messages. + max_wait_before_drop_fragments: 50000, + }, + /// Behavior pushing CongestionControl::Block messages to the queue. + block: { + /// The maximum time in microseconds to wait for an available batch before closing the transport session when sending a blocking message + /// if still no batch is available. + wait_before_close: 5000000, + }, + }, + /// Perform batching of messages if they are smaller of the batch_size + batching: { + /// Perform adaptive batching of messages if they are smaller of the batch_size. + /// When the network is detected to not be fast enough to transmit every message individually, many small messages may be + /// batched together and sent all at once on the wire reducing the overall network overhead. This is typically of a high-throughput + /// scenario mainly composed of small messages. In other words, batching is activated by the network back-pressure. + enabled: true, + /// The maximum time limit (in ms) a message should be retained for batching when back-pressure happens. + time_limit: 1, + }, + }, + }, + /// Configure the zenoh RX parameters of a link + rx: { + /// Receiving buffer size in bytes for each link + /// The default the rx_buffer_size value is the same as the default batch size: 65535. + /// For very high throughput scenarios, the rx_buffer_size can be increased to accommodate + /// more in-flight data. This is particularly relevant when dealing with large messages. + /// E.g. for 16MiB rx_buffer_size set the value to: 16777216. + buffer_size: 65535, + /// Maximum size of the defragmentation buffer at receiver end. + /// Fragmented messages that are larger than the configured size will be dropped. + /// The default value is 1GiB. This would work in most scenarios. + /// NOTE: reduce the value if you are operating on a memory constrained device. + max_message_size: 1073741824, + }, + /// Configure TLS specific parameters + tls: { + /// Path to the certificate of the certificate authority used to validate either the server + /// or the client's keys and certificates, depending on the node's mode. If not specified + /// on router mode then the default WebPKI certificates are used instead. + root_ca_certificate: "@(root_ca_certificate)", + /// Path to the TLS listening side private key + listen_private_key: "@(listen_private_key)", + /// Path to the TLS listening side public certificate + listen_certificate: "@(listen_certificate)", + /// Enables mTLS (mutual authentication), client authentication + enable_mtls: true, + /// Path to the TLS connecting side private key + connect_private_key: "@(connect_private_key)", + /// Path to the TLS connecting side certificate + connect_certificate: "@(connect_certificate)", + // Whether or not to verify the matching between hostname/dns and certificate when connecting, + // if set to false zenoh will disregard the common names of the certificates when verifying servers. + // This could be dangerous because your CA can have signed a server cert for foo.com, that's later being used to host a server at baz.com. + // If you want your ca to verify that the server at baz.com is actually baz.com, let this be true (default). + verify_name_on_connect: false, + // Whether or not to close links when remote certificates expires. + // If set to true, links that require certificates (tls/quic) will automatically disconnect when the time of expiration of the remote certificate chain is reached + // note that mTLS (client authentication) is required for a listener to disconnect a client on expiration + close_link_on_expiration: false, + /// Optional configuration for TCP system buffers sizes for TLS links + /// + /// Configure TCP read buffer size (bytes) + // so_rcvbuf: 123456, + /// Configure TCP write buffer size (bytes) + // so_sndbuf: 123456, + }, + // // Configure optional TCP link specific parameters + // tcp: { + // /// Optional configuration for TCP system buffers sizes for TCP links + // /// + // /// Configure TCP read buffer size (bytes) + // // so_rcvbuf: 123456, + // /// Configure TCP write buffer size (bytes) + // // so_sndbuf: 123456, + // } + }, + /// Shared memory configuration. + /// NOTE: shared memory can be used only if zenoh is compiled with "shared-memory" feature, otherwise + /// settings in this section have no effect. + shared_memory: { + /// A probing procedure for shared memory is performed upon session opening. To enable zenoh to operate + /// over shared memory (and to not fallback on network mode), shared memory needs to be enabled also on the + /// subscriber side. By doing so, the probing procedure will succeed and shared memory will operate as expected. + /// + /// ROS setting: disabled by default until fully tested + enabled: false, + }, + auth: { + /// The configuration of authentication. + /// A password implies a username is required. + usrpwd: { + user: null, + password: null, + /// The path to a file containing the user password dictionary + dictionary_file: null, + }, + pubkey: { + public_key_pem: null, + private_key_pem: null, + public_key_file: null, + private_key_file: null, + key_size: null, + known_keys_file: null, + }, + }, + }, + + /// Configure the Admin Space + /// Unstable: this configuration part works as advertised, but may change in a future release + adminspace: { + /// Enables the admin space + enabled: true, + /// read and/or write permissions on the admin space + permissions: { + read: true, + write: false, + }, + }, + +} diff --git a/zenoh_security_configuration/templates/router.json5 b/zenoh_security_configuration/templates/router.json5 index a9eaf935..3dc4fd1b 100644 --- a/zenoh_security_configuration/templates/router.json5 +++ b/zenoh_security_configuration/templates/router.json5 @@ -66,7 +66,7 @@ /// /// See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html endpoints: [ - "tls/localhost:7447" + "@(listen_endpoint)" ], /// Global listen configuration, @@ -435,22 +435,22 @@ /// Path to the certificate of the certificate authority used to validate either the server /// or the client's keys and certificates, depending on the node's mode. If not specified /// on router mode then the default WebPKI certificates are used instead. - root_ca_certificate: null, + root_ca_certificate: "@(root_ca_certificate)", /// Path to the TLS listening side private key - listen_private_key: "/home/ahcorde/sros2_demo/tls/localhost/key.pem", + listen_private_key: "@(listen_private_key)", /// Path to the TLS listening side public certificate - listen_certificate: "/home/ahcorde/sros2_demo/tls/localhost/cert.pem", + listen_certificate: "@(listen_certificate)", /// Enables mTLS (mutual authentication), client authentication - enable_mtls: false, + enable_mtls: true, /// Path to the TLS connecting side private key - connect_private_key: null, + connect_private_key: "@(connect_private_key)", /// Path to the TLS connecting side certificate - connect_certificate: null, + connect_certificate: "@(connect_certificate)", // Whether or not to verify the matching between hostname/dns and certificate when connecting, // if set to false zenoh will disregard the common names of the certificates when verifying servers. // This could be dangerous because your CA can have signed a server cert for foo.com, that's later being used to host a server at baz.com. // If you want your ca to verify that the server at baz.com is actually baz.com, let this be true (default). - verify_name_on_connect: true, + verify_name_on_connect: false, }, }, /// Shared memory configuration. diff --git a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py index 02eaa248..4d0d22aa 100644 --- a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py +++ b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py @@ -25,11 +25,11 @@ class ZenohSecutiryConfigGenerator: def __init__(self): """ - Construct NEXUSConfigGenerator. + Construct ZenohConfigGenerator. """ self.zenoh_cfg_file_extension = "json5" - def generate_router_config(self, data): + def generate_router_config(self, data, zenoh_type): try: output = StringIO() interpreter = em.Interpreter( @@ -43,22 +43,21 @@ def generate_router_config(self, data): template_path = pathlib.Path(os.path.join( get_package_share_directory("zenoh_security_configuration"), "templates", - "router.json5" + zenoh_type + ".json5" )) - with template_path.open('r') as h: template_content = h.read() interpreter.string(template_content, locals=data) return output.getvalue() - except: - print('lol') + except Exception as e: + print(e) finally: if interpreter is not None: interpreter.shutdown() interpreter = None - def generate_zenoh_config(self, output_dir, router_config, encoding: str = 'utf-8'): + def generate_zenoh_config(self, output_dir, router_config, zenoh_type, encoding: str = 'utf-8'): """ Generate Zenoh bridge configs and output to directory 'output_dir'. @@ -69,7 +68,7 @@ def generate_zenoh_config(self, output_dir, router_config, encoding: str = 'utf- """ write_filepath = os.path.join( - output_dir, "router" + "." + output_dir, zenoh_type + "." + self.zenoh_cfg_file_extension, ) output_file = pathlib.Path(write_filepath) @@ -86,10 +85,12 @@ def generate_zenoh_config(self, output_dir, router_config, encoding: str = 'utf- def main(argv=sys.argv): """Entrypoint.""" parser = argparse.ArgumentParser( - description="Generate Zenoh configurations from a NEXUS Network \ - and REDF Configuration", + description="Generate Zenoh security configurations", formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) + subparsers = parser.add_subparsers(help='help for subcommand', dest="subcommand") + parser_path = subparsers.add_parser('paths', help='Use path') + parser_enclave = subparsers.add_parser('enclave', help='Use enclave directory') parser.add_argument( "-o", @@ -99,6 +100,24 @@ def main(argv=sys.argv): help="Output directory for Zenoh bridge configurations", ) + parser.add_argument( + "-l", + "--listen_endpoint", + required=False, + type=str, + default ="tls/localhost:7447", + help="The list of endpoints to listen on (See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)", + ) + + parser.add_argument( + "-c", + "--connect_endpoint", + required=False, + type=str, + default ="tls/localhost:7447", + help="The list of endpoints to connect to. (See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)", + ) + parser.add_argument( "-p", "--protocols", @@ -109,13 +128,103 @@ def main(argv=sys.argv): help="Protocols chooices", ) - args = parser.parse_args(argv[1:]) + parser.add_argument( + "-t", + "--type", + type=str, + required=True, + choices=["router", "peer"], + default=['router'], + help="Set router or peer", + ) - data = {'protocols': args.protocols} + parser_path.add_argument( + "--root_ca_certificate", + type=str, + required=True, + default='', + help="Path to the certificate of the certificate authority used to validate " \ + "either the server or the client's keys and certificates" + ) + + parser_path.add_argument( + "--listen_private_key", + type=str, + required=True, + default='', + help="Path to the TLS listening side private key" + ) + + parser_path.add_argument( + "--listen_certificate", + type=str, + required=True, + default='', + help="Path to the TLS listening side public certificate" + ) + + parser_path.add_argument( + "--connect_private_key", + type=str, + required=True, + default='', + help="Path to the TLS connecting side private key" + ) + + parser_path.add_argument( + "--connect_certificate", + type=str, + required=True, + default='', + help="Path to the TLS connecting side certificate" + ) + + parser_enclave.add_argument( + "--enclave_path", + type=str, + required=True, + default='', + help="Enclave path" + ) + + parser_enclave.add_argument( + "--enclave_name", + type=str, + required=True, + default='', + help="Enclave name" + ) + + args = parser.parse_args(argv[1:]) + if args.enclave_name is not None: + if args.enclave_name[0] == '/': + args.enclave_name = args.enclave_name[1:] + root_ca_certificate = os.path.join(args.enclave_path, "public", "ca.cert.pem") + listen_private_key = os.path.join(args.enclave_path, "enclaves", args.enclave_name, "key.pem") + listen_certificate = os.path.join(args.enclave_path, "enclaves", args.enclave_name, "cert.pem") + connect_private_key = listen_private_key + connect_certificate = listen_certificate + else: + root_ca_certificate = args.root_ca_certificate + listen_private_key = args.listen_private_key + listen_certificate = args.listen_certificate + connect_private_key = args.connect_private_key + connect_certificate = args.connect_certificate + + data = { + 'protocols': args.protocols, + 'listen_endpoint': args.listen_endpoint, + 'connect_endpoint': args.connect_endpoint, + 'root_ca_certificate': root_ca_certificate, + 'listen_private_key': listen_private_key, + 'listen_certificate': listen_certificate, + 'connect_private_key': connect_private_key, + 'connect_certificate': connect_certificate, + } zenoh_sec_gen = ZenohSecutiryConfigGenerator() - router_config = zenoh_sec_gen.generate_router_config(data) - zenoh_sec_gen.generate_zenoh_config(args.output, router_config) + router_config = zenoh_sec_gen.generate_router_config(data, args.type) + zenoh_sec_gen.generate_zenoh_config(args.output, router_config, args.type) if __name__ == "__main__": main(sys.argv) From 3c1d7b925760cd29ab5b70519831f0e62561f5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Hern=C3=A1ndez=20Cordero?= Date: Mon, 20 Jan 2025 18:58:32 +0100 Subject: [PATCH 3/4] make linters hapy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alejandro Hernández Cordero --- zenoh_security_configuration/package.xml | 4 + zenoh_security_configuration/setup.py | 3 +- .../test/test_flake8.py | 23 ++++ .../test/test_xmllint.py | 23 ++++ .../zenoh_security_configuration.py | 110 ++++++++++-------- 5 files changed, 111 insertions(+), 52 deletions(-) create mode 100644 zenoh_security_configuration/test/test_flake8.py create mode 100644 zenoh_security_configuration/test/test_xmllint.py diff --git a/zenoh_security_configuration/package.xml b/zenoh_security_configuration/package.xml index 3f6c03c5..6a2893b9 100644 --- a/zenoh_security_configuration/package.xml +++ b/zenoh_security_configuration/package.xml @@ -10,6 +10,10 @@ python3-jsonschema python3-yaml + ament_flake8 + ament_xmllint + python3-pytest + ament_python diff --git a/zenoh_security_configuration/setup.py b/zenoh_security_configuration/setup.py index 35c02461..58566a16 100644 --- a/zenoh_security_configuration/setup.py +++ b/zenoh_security_configuration/setup.py @@ -1,5 +1,6 @@ -import os from glob import glob +import os + from setuptools import setup package_name = 'zenoh_security_configuration' diff --git a/zenoh_security_configuration/test/test_flake8.py b/zenoh_security_configuration/test/test_flake8.py new file mode 100644 index 00000000..b9042824 --- /dev/null +++ b/zenoh_security_configuration/test/test_flake8.py @@ -0,0 +1,23 @@ +# Copyright 2019 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_flake8.main import main +import pytest + + +@pytest.mark.flake8 +@pytest.mark.linter +def test_flake8(): + rc = main(argv=[]) + assert rc == 0, 'Found errors' diff --git a/zenoh_security_configuration/test/test_xmllint.py b/zenoh_security_configuration/test/test_xmllint.py new file mode 100644 index 00000000..ca32830a --- /dev/null +++ b/zenoh_security_configuration/test/test_xmllint.py @@ -0,0 +1,23 @@ +# Copyright 2019 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ament_xmllint.main import main +import pytest + + +@pytest.mark.linter +@pytest.mark.xmllint +def test_xmllint(): + rc = main(argv=['.']) + assert rc == 0, 'Found errors' diff --git a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py index 4d0d22aa..dd3ef467 100644 --- a/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py +++ b/zenoh_security_configuration/zenoh_security_configuration/zenoh_security_configuration.py @@ -13,21 +13,22 @@ # limitations under the License. import argparse -import em from io import StringIO import os import pathlib import sys + from ament_index_python.packages import get_package_share_directory +import em + + class ZenohSecutiryConfigGenerator: """ZenohSecutiryConfigGenerator generates Zenoh secutiry configurations.""" def __init__(self): - """ - Construct ZenohConfigGenerator. - """ - self.zenoh_cfg_file_extension = "json5" + """Construct ZenohConfigGenerator.""" + self.zenoh_cfg_file_extension = 'json5' def generate_router_config(self, data, zenoh_type): try: @@ -41,9 +42,9 @@ def generate_router_config(self, data, zenoh_type): ) template_path = pathlib.Path(os.path.join( - get_package_share_directory("zenoh_security_configuration"), - "templates", - zenoh_type + ".json5" + get_package_share_directory('zenoh_security_configuration'), + 'templates', + zenoh_type + '.json5' )) with template_path.open('r') as h: @@ -57,7 +58,8 @@ def generate_router_config(self, data, zenoh_type): interpreter.shutdown() interpreter = None - def generate_zenoh_config(self, output_dir, router_config, zenoh_type, encoding: str = 'utf-8'): + def generate_zenoh_config(self, output_dir, router_config, + zenoh_type, encoding: str = 'utf-8'): """ Generate Zenoh bridge configs and output to directory 'output_dir'. @@ -68,11 +70,11 @@ def generate_zenoh_config(self, output_dir, router_config, zenoh_type, encoding: """ write_filepath = os.path.join( - output_dir, zenoh_type + "." + output_dir, zenoh_type + '.' + self.zenoh_cfg_file_extension, ) output_file = pathlib.Path(write_filepath) - print(f"Generated Zenoh secutiry configuration at {write_filepath}") + print(f'Generated Zenoh security configuration at {write_filepath}') if output_file.exists(): existing_content = output_file.read_text(encoding=encoding) if existing_content == router_config: @@ -82,117 +84,120 @@ def generate_zenoh_config(self, output_dir, router_config, zenoh_type, encoding: output_file.write_text(router_config, encoding=encoding) + def main(argv=sys.argv): """Entrypoint.""" parser = argparse.ArgumentParser( - description="Generate Zenoh security configurations", + description='Generate Zenoh security configurations', formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) - subparsers = parser.add_subparsers(help='help for subcommand', dest="subcommand") + subparsers = parser.add_subparsers(help='Help for subcommand', dest='subcommand') parser_path = subparsers.add_parser('paths', help='Use path') parser_enclave = subparsers.add_parser('enclave', help='Use enclave directory') parser.add_argument( - "-o", - "--output", + '-o', + '--output', required=True, type=str, - help="Output directory for Zenoh bridge configurations", + help='Output directory for Zenoh bridge configurations', ) parser.add_argument( - "-l", - "--listen_endpoint", + '-l', + '--listen_endpoint', required=False, type=str, - default ="tls/localhost:7447", - help="The list of endpoints to listen on (See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)", + default='tls/localhost:7447', + help='The list of endpoints to listen on. ' + + '(See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)', ) parser.add_argument( - "-c", - "--connect_endpoint", + '-c', + '--connect_endpoint', required=False, type=str, - default ="tls/localhost:7447", - help="The list of endpoints to connect to. (See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)", + default='tls/localhost:7447', + help='The list of endpoints to connect to. ' + + '(See https://docs.rs/zenoh/latest/zenoh/config/struct.EndPoint.html)', ) parser.add_argument( - "-p", - "--protocols", + '-p', + '--protocols', nargs='*', required=False, - choices=["tcp", "tls"], + choices=['tcp', 'tls'], default=['tls'], - help="Protocols chooices", + help='Protocols chooices', ) parser.add_argument( - "-t", - "--type", + '-t', + '--type', type=str, required=True, - choices=["router", "peer"], + choices=['router', 'peer'], default=['router'], - help="Set router or peer", + help='Set router or peer', ) parser_path.add_argument( - "--root_ca_certificate", + '--root_ca_certificate', type=str, required=True, default='', - help="Path to the certificate of the certificate authority used to validate " \ - "either the server or the client's keys and certificates" + help='Path to the certificate of the certificate authority used' + + "to validate either the server or the client's keys and certificates" ) parser_path.add_argument( - "--listen_private_key", + '--listen_private_key', type=str, required=True, default='', - help="Path to the TLS listening side private key" + help='Path to the TLS listening side private key' ) parser_path.add_argument( - "--listen_certificate", + '--listen_certificate', type=str, required=True, default='', - help="Path to the TLS listening side public certificate" + help='Path to the TLS listening side public certificate' ) parser_path.add_argument( - "--connect_private_key", + '--connect_private_key', type=str, required=True, default='', - help="Path to the TLS connecting side private key" + help='Path to the TLS connecting side private key' ) parser_path.add_argument( - "--connect_certificate", + '--connect_certificate', type=str, required=True, default='', - help="Path to the TLS connecting side certificate" + help='Path to the TLS connecting side certificate' ) parser_enclave.add_argument( - "--enclave_path", + '--enclave_path', type=str, required=True, default='', - help="Enclave path" + help='Enclave path' ) parser_enclave.add_argument( - "--enclave_name", + '--enclave_name', type=str, required=True, default='', - help="Enclave name" + help='Enclave name' ) args = parser.parse_args(argv[1:]) @@ -200,9 +205,11 @@ def main(argv=sys.argv): if args.enclave_name is not None: if args.enclave_name[0] == '/': args.enclave_name = args.enclave_name[1:] - root_ca_certificate = os.path.join(args.enclave_path, "public", "ca.cert.pem") - listen_private_key = os.path.join(args.enclave_path, "enclaves", args.enclave_name, "key.pem") - listen_certificate = os.path.join(args.enclave_path, "enclaves", args.enclave_name, "cert.pem") + root_ca_certificate = os.path.join(args.enclave_path, 'public', 'ca.cert.pem') + listen_private_key = os.path.join(args.enclave_path, 'enclaves', + args.enclave_name, 'key.pem') + listen_certificate = os.path.join(args.enclave_path, 'enclaves', + args.enclave_name, 'cert.pem') connect_private_key = listen_private_key connect_certificate = listen_certificate else: @@ -226,5 +233,6 @@ def main(argv=sys.argv): router_config = zenoh_sec_gen.generate_router_config(data, args.type) zenoh_sec_gen.generate_zenoh_config(args.output, router_config, args.type) -if __name__ == "__main__": + +if __name__ == '__main__': main(sys.argv) From 6f2add0848f6618723da6d2960fc73bbd1753728 Mon Sep 17 00:00:00 2001 From: Alejandro Hernandez Cordero Date: Thu, 30 Jan 2025 15:38:41 +0100 Subject: [PATCH 4/4] updated README.md Signed-off-by: Alejandro Hernandez Cordero --- zenoh_security_configuration/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/zenoh_security_configuration/README.md b/zenoh_security_configuration/README.md index 08fcea79..60c1e1ac 100644 --- a/zenoh_security_configuration/README.md +++ b/zenoh_security_configuration/README.md @@ -9,11 +9,11 @@ ros2 run zenoh_security_configuration zenoh_security_configuration \ --listen_endpoint="tls/localhost:7447" \ --protocols=tls \ paths \ - --root_ca_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/public/ca.cert.pem \ - --listen_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/key.pem \ - --connect_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/key.pem \ - --connect_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/cert.pem \ - --listen_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/zenohd/cert.pem + --root_ca_certificate ~/sros2_demo/demo_keystore/public/ca.cert.pem \ + --listen_private_key ~/sros2_demo/demo_keystore/enclaves/zenohd/key.pem \ + --connect_private_key ~/sros2_demo/demo_keystore/enclaves/zenohd/key.pem \ + --connect_certificate ~/sros2_demo/demo_keystore/enclaves/zenohd/cert.pem \ + --listen_certificate ~/sros2_demo/demo_keystore/enclaves/zenohd/cert.pem ``` Using enclaves generated with `ros2 security create_enclave` @@ -22,10 +22,10 @@ Using enclaves generated with `ros2 security create_enclave` ros2 run zenoh_security_configuration zenoh_security_configuration \ -o zenoh_config \ -t router \ - --listen_endpoint="tls/localhost:0" \ + --listen_endpoint="tls/localhost:7447" \ --protocols=tls \ enclave \ - --enclave_path /home/ahcorde/sros2_demo/demo_keystore_zenoh \ + --enclave_path ~/sros2_demo/demo_keystore \ --enclave_name /zenoh ``` @@ -38,11 +38,11 @@ ros2 run zenoh_security_configuration zenoh_security_configuration \ --listen_endpoint="tls/localhost:0" \ --protocols=tls \ paths \ - --root_ca_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/public/ca.cert.pem \ - --listen_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/key.pem \ - --connect_private_key /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/key.pem \ - --connect_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/cert.pem \ - --listen_certificate /home/ahcorde/sros2_demo/demo_keystore_zenoh/enclaves/listener/cert.pem + --root_ca_certificate ~/sros2_demo/demo_keystore/public/ca.cert.pem \ + --listen_private_key ~/sros2_demo/demo_keystore/enclaves/listener/key.pem \ + --connect_private_key ~/sros2_demo/demo_keystore/enclaves/listener/key.pem \ + --connect_certificate ~/sros2_demo/demo_keystore/enclaves/listener/cert.pem \ + --listen_certificate ~/sros2_demo/demo_keystore/enclaves/listener/cert.pem ``` Using enclaves generated with `ros2 security create_enclave` @@ -55,6 +55,6 @@ ros2 run zenoh_security_configuration zenoh_security_configuration \ --listen_endpoint="tls/localhost:0" \ --protocols=tls \ enclave \ - --enclave_path /home/ahcorde/sros2_demo/demo_keystore_zenoh \ + --enclave_path ~/sros2_demo/demo_keystore \ --enclave_name /talker_listener/talker ```