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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/style.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: uncrustify
run: /ros_entrypoint.sh ament_uncrustify rmw_zenoh_cpp/
run: /ros_entrypoint.sh ament_uncrustify rmw_zenoh_cpp/ zenoh_security_tools/
- name: cpplint
run: /ros_entrypoint.sh ament_cpplint rmw_zenoh_cpp/
run: /ros_entrypoint.sh ament_cpplint rmw_zenoh_cpp/ zenoh_security_tools/
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ For example, if another `Zenoh router` is listening on IP address `192.168.1.1`

Then, start the `Zenoh router` after setting the `ZENOH_ROUTER_CONFIG_URI` environment variable to the absolute path of the modified config file.

### Security

Security is available in `rmw_zenoh` by means of access control, authentication and encryption.
The [zenoh_security_tools](./zenoh_security_tools/) package contains a script to generate Zenoh configs with security configured along with documentation on its usage.

### Logging

The core of Zenoh is implemented in Rust and uses a logging library that can be configured via a `RUST_LOG` environment variable.
Expand Down Expand Up @@ -221,7 +226,7 @@ Note that composable nodes should *never* call `rclcpp::shutdown()`, as the comp

For more details, see https://github.com/ros2/rmw_zenoh/issues/170.

### rmw_zenoh is incompatible between Humble and newer distributions.
### rmw_zenoh is incompatible between Humble and newer distributions.

Since Iron, ROS 2 introduced type hashes for messages and `rmw_zenoh` includes these type hashes in the Zenoh keyexpressions it constructs for data exchange. While participants will be discoverable, communication between Humble and newer distributions will fail, resulting in messages being silently dropped.

Expand Down
51 changes: 51 additions & 0 deletions zenoh_security_tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.8)
project(zenoh_security_tools)

# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
# todo(Yadunund): Remove rmw dependency after https://github.com/ros2/rmw/pull/400 is merged.
find_package(rmw REQUIRED)
find_package(rmw_security_common REQUIRED)
find_package(tinyxml2_vendor REQUIRED)
find_package(TinyXML2 REQUIRED)
find_package(zenoh_cpp_vendor REQUIRED)

add_executable(generate_configs
src/main.cpp
src/config_generator.cpp
)
target_link_libraries(generate_configs PRIVATE
nlohmann_json::nlohmann_json
rcpputils::rcpputils
rcutils::rcutils
rmw::rmw
rmw_security_common::rmw_security_common_library
tinyxml2::tinyxml2
zenohcxx::zenohc
)

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()


install(
TARGETS generate_configs
DESTINATION lib/${PROJECT_NAME}
)

ament_package()
178 changes: 178 additions & 0 deletions zenoh_security_tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# zenoh_security_tools

The `zenoh_security_tools` package contains the `generate_configs` executable which generates Zenoh session config files with access control, authentication and encryption parameters based on policies and keystores generated using [sros2](https://github.com/ros2/sros2).

## Usage
```bash
ros2 run zenoh_security_tools generate_configs -h

Generate Zenoh session configs with security artifacts.

Options:
-h,--help Print this help message and exit
-p,--policy TEXT REQUIRED The path to the Access Control Policy file.
-e,--enclaves TEXT The directory with the security enclaves for the various nodes in the policy file.
-d,--ros-domain-id UINT REQUIRED The ROS Domain ID.
-c,--session-config TEXT REQUIRED The path to the Zenoh session config file.
-r,--router-config TEXT REQUIRED The path to the Zenoh router config file.

```

## Example of configuring security rmw_zenoh

The process of setting up security is very similar to [this tutorial](https://docs.ros.org/en/rolling/Tutorials/Advanced/Security/Introducing-ros2-security.html) but instead of relying on security environment variables and passing enclaves to nodes, we'll
pass Zenoh session configs with the desired security parameters configured to `rmw_zenoh`.
These modified session configs are generated using the tool above.

### Setup

The steps below will walk us through running rmw_zenoh with security enabled for a simple talker-lister system.

#### First create a directory for security artifacts and configs that will be generated.

```bash
mkdir ~/sros2_demo
```

#### Generate a keystore

```bash
cd ~/sros2_demo
ros2 security create_keystore demo_keystore
```

#### Generate the certificates for authentication and encryption

Generate security files for the `talker` and `listener` nodes, and the `zenohd` router respectively.

```bash
ros2 security create_enclave demo_keystore /talker_listener/talker
ros2 security create_enclave demo_keystore /talker_listener/listener
ros2 security create_enclave demo_keystore /talker_listener/zenohd
```

#### Generate the policy.xml for access control

Launch zenohd
```bash
ros2 run rmw_zenoh_cpp rmw_zenohd
```

Launch the listener
```bash
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
ros2 run demo_nodes_cpp listener
```

Launch the talker
```bash
export RMW_IMPLEMENTATION=rmw_zenoh_cpp
ros2 run demo_nodes_cpp talker
```

Now run the policy generator from sros2

```bash
ros2 security generate_policy policy_listener_talker.xml
```

Finally, terminate all processes.

## Try access control

Generate security configs without enclaves (only access control).

```bash
ros2 run zenoh_security_tools generate_configs \
--policy policy_listener_talker.xml \
--router-config <path to default router config>/DEFAULT_RMW_ZENOH_ROUTER_CONFIG.json5 \
--session-config <path to default session config>/DEFAULT_RMW_ZENOH_SESSION_CONFIG.json5 \
--ros-domain-id 0
```
This will generate Zenoh session config files for each node in the `policy_listener_talker.xml` file.

#### Run the talker with the new config file

```bash
export ZENOH_SESSION_CONFIG_URI=talker.json5
ros2 run demo_nodes_cpp talker
[INFO] [1740601932.350808475] [talker]: Publishing: 'Hello World: 1'
[INFO] [1740601933.350487483] [talker]: Publishing: 'Hello World: 2'
```

#### Run the listener with the new config file
```bash
export ZENOH_SESSION_CONFIG_URI=listener.json5
ros2 run demo_nodes_cpp listener
...
[INFO] [1740602312.492840958] [listener]: I heard: [Hello World: 1]
[INFO] [1740602313.492200366] [listener]: I heard: [Hello World: 2]
```

You can validate access control by remapping the `/chatter` topic which should result in no messages being published.


```bash
export ZENOH_SESSION_CONFIG_URI=talker.json5
ros2 rmw_zenoh_cpp rmw_zenohd
```

```bash
export ZENOH_SESSION_CONFIG_URI=talker.json5
ros2 run demo_nodes_cpp talker --ros-args -r chatter:=new_topic
```

```bash
export ZENOH_SESSION_CONFIG_URI=listener.json5
ros2 run demo_nodes_cpp listener --ros-args -r chatter:=new_topic
...
# listener should not receive anything
```

## Try access control, authentication and encryption

This time we generate the configs with authentication and encryption configured using the enclaves generated by sros2.

```bash
ros2 run zenoh_security_tools generate_configs \
--policy policy_listener_talker.xml \
--router-config <path to default router config>/DEFAULT_RMW_ZENOH_ROUTER_CONFIG.json5 \
--session-config <path to default session config>/DEFAULT_RMW_ZENOH_SESSION_CONFIG.json5 \
--ros-domain-id 0
--enclaves ~/sros2_demo/demo_keystore/enclaves/talker_listener
```

> [!NOTE]
The executable assumes that the `~/sros2_demo/demo_keystore/enclaves/talker_listener` directory contains folders with names matching node names defined in the `policy_listener_talker.xml` with the security files present.

Start the zenoh router with the `zenohd.json` config file.
```bash
export ZENOH_ROUTER_CONFIG_URI=zenohd.json5
ros2 rmw_zenoh_cpp rmw_zenohd
```

Start the talker

```bash
export ZENOH_SESSION_CONFIG_URI=talker.json5
ros2 rmw_zenoh_cpp rmw_zenohd
```

Start the listener without setting the session config.
```bash
ros2 run demo_nodes_cpp listener
```

The listener will not receive any messages.

Restart the listener with the session config.

```bash
export ZENOH_SESSION_CONFIG_URI=listener.json5
ros2 run demo_nodes_cpp listener
...
[INFO] [1740602312.492840958] [listener]: I heard: [Hello World: 10]
[INFO] [1740602313.492200366] [listener]: I heard: [Hello World: 11]
```

The messages are received by the listener.
26 changes: 26 additions & 0 deletions zenoh_security_tools/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>zenoh_security_tools</name>
<version>0.5.0</version>
<description>This package generates config files to enforce security with Zenoh</description>
<maintainer email="alejandro@openrobotics.org">Alejandro Hernanadez</maintainer>
<license>Apache License 2.0</license>


<build_depend>nlohmann-json-dev</build_depend>

<depend>rcpputils</depend>
<depend>rcutils</depend>
<depend>rmw</depend>
<depend>rmw_security_common</depend>
<depend>tinyxml2_vendor</depend>
<depend>zenoh_cpp_vendor</depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
Loading
Loading