Giter Site home page Giter Site logo

sros2's Introduction

Context

SROS2 CI codecov

This package provides the tools and instructions to use ROS 2 on top of DDS-Security. The security feature is tested across platforms (Linux, macOS, and Windows) as well as across different languages (C++ and Python).

This package has been tested against eProsima FastDDS, Eclipse CycloneDDS and RTI Connext. If you want to run the demo using RTI Connext Secure you will need a license for it and you will need to install it.

These Tutorials are written for the latest state of the repository. If you are using an older ROS 2 distribution please refer to the tutorials on the branch named after the distribution, e.g. for Crystal: https://github.com/ros2/sros2/blob/crystal/README.md

Try SROS2 on Linux

Try SROS2 on MacOS

Try SROS2 on Windows

sros2's People

Contributors

aalon avatar ahcorde avatar asorbini avatar borisboutillier avatar clalancette avatar codebot avatar cottsay avatar dhood avatar dirk-thomas avatar emersonknapp avatar fujitatomoya avatar hidmic avatar ivanpauno avatar j-rivero avatar jacobperron avatar keisukeshima avatar kyrofa avatar marcoag avatar mikaelarguedas avatar mjcarroll avatar nuclearsandwich avatar paudrow avatar pbaughman avatar ross-desmond avatar ruffsl avatar skucheria avatar sloretz avatar tfoote avatar wjwwood avatar yadunund avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sros2's Issues

Easy way to generate artifacts for all nodes in policy file

Feature request

Opening this ticket for feedback on the approach before starting implementation

Feature description

Provide a Python verb as well as CMake way of generating artifacts for all nodes listed in the policies file.

Context:

We can now have an automatically generated policies file for a ROS system (generate_permissions).
To generate artifacts for a set of nodes in the system we can use ros2_secure_node.
However this requires to explicitly list the nodes to create security artifacts for, which will result in a long handwritten macro call for a non-trivial (e.g. 50 nodes) system.

Problems it will solve:
  • CMake changes: writing exhaustive list of nodes by hand for CMake macro call
  • Python verb: A way to generate artifacts for all nodes without having to type many commands or create a CMake package

Implementation considerations

We could implement the feature in CMake and in Python.
In CMake: we could add an ALL option to the macro, in which case it would generate artifacts for the nodes listed under NODES and all the nodes present in the policy file.

In Python: we could provide a new verb e.g. autogenerate_artifacts that would require a policy file and optionnaly take a keystore path. It would create a keystore if needed and then generate keys and permissions for all the nodes listed in the policies file.

I'm planning on starting with the Python verb and then the CMake changes.

@ross-desmond @ruffsl any feedback on the approach will be very appreciated :)

Security Profile Library for AppArmor

Many software projects releasing for Linux ship with included AppArmor profiles to secure their applications at runtime. To enable ROS package developers to succinctly write and maintain similar app policies, I previously wrote an AppArmor library to pre-configure default tuneables and incluable permission abstractions to simplify authored profiles.

I’d like to suggest we package this AppArmor library for release in SROS2; perhaps calling sros_apparmor? This package would mainly serve as a delivery mechanism to install the necessary include files in /etc/apparmor.d/. Downstream ROS2 package developers could cite sros_apparmor as a runtime dependency so that the customer profiles they install to /etc/apparmor.d/ could include the required permission abstractions.


Background

AppArmor ("Application Armor") is a Linux kernel security module that allows the system administrator to restrict programs' capabilities with per-program profiles. Profiles can allow capabilities like network access, raw socket access, and the permission to read, write, or execute files on matching paths. AppArmor supplements the traditional Unix discretionary access control (DAC) model by providing mandatory access control (MAC).
https://wikipedia.org/wiki/AppArmor

I initially started a profile library appstration for AppArmor back with SROS1. However, given the library had to be manually installed, adoption in ROS1 was rather limited:

https://github.com/ros-infrastructure/apparmor_profiles
http://wiki.ros.org/SROS/Tutorials/AppArmorAndROS

Progress

I’ve recently been updating the library for ROS2, and have cpp and python nodes working while under enforced profiles, such as this for the demo node examples shown here:
ros-infrastructure/apparmor_profiles#6

# opt.ros.distro.lib.demo_nodes_cpp
include <tunables/global>
include <tunables/ros>

profile demo_nodes_cpp/talker @{ROS_INSTALL_LIB}/demo_nodes_cpp/talker {
  include <ros/base>
  include <ros/node>
}

profile demo_nodes_cpp/listener @{ROS_INSTALL_LIB}/demo_nodes_cpp/listener {
  include <ros/base>
  include <ros/node>
}

Next steps

Going forward, I’d like to add more permission abstractions for other ROS2 primitives events, like process signal handling between launch tools or allowing shared memory access between nodes, while at the same time auditing the existing policy footprint: to verify which rulesets are truly necessary and where we may want to relax restrictions to generalize for common use case patterns. Iterating further by writing more example profiles for the rest of the ROS2 demos might useful for unearthing any remaining conor cases. I’d apprchate help from folks who may also be familiar either AppArmor debuging or testing advanced ROS2 features.

While rewriting the library, it may also be a good opportunity to re-license the tunables and abstraction files to coincide with the rest of ROS2’s development.

I’d like to eventually host this AppArmor library here with the rest of the sros2 packages, so that downstream users can redaly install it and build on top of it. Perhaps packaging the installer (mostly copying files to /etc/apparmor.d/) using CMake would be enough of a start?

Implementation of online arbiter in SROS2?

I am very interested in the proposal of adding access control into ROS. In particular, I find the "online arbiter" concept in the design proposal from the SROS website quite interesting and would like to research more on it. I am wondering if the online arbiter has been implemented in the current SROS/SROS2 code base. I looked at the ros_comm repo (sros branch) but could not find relevant code pieces for the online arbiter. If not yet, is there any plan to implement the online arbiter concept in SROS2?

Please help clarify/share if any guy know more details. Thanks !

test_policy_to_permissions failing

Bug report

I'm having some trouble with the test_policy_to_permissions - but just today. It's been fine for months:

test/test_policy_to_permissions.py:33: in test_policy_to_permissions
    policy_xsd = etree.XMLSchema(etree.parse(policy_xsd_path))
src/lxml/xmlschema.pxi:86: in lxml.etree.XMLSchema.__init__
    ???
E   lxml.etree.XMLSchemaParseError: attribute use (unknown), attribute 'ref': The QName value '{http://www.w3.org/XML/1998/namespace}base' does not resolve to a(n) attribute declaration., line 34
- generated xml file: /path_to_workspace/build/sros2/pytest.xml -

I don't know as much about XML as I should, but I think the issue is in sros2/policy/schemas/policy.xsd

    <xs:import namespace="http://www.w3.org/XML/1998/namespace"
               schemaLocation="http://www.w3.org/2001/03/xml.xsd" />

I can't navigate to https://www.w3.org/2001/03/xml.xsd right now, and the test is failing. I can see that this should be a page by looking at the google 'cached pages' link. I'm pretty sure it's trying to fetch this schema from the internet and failing because the page is offline right now.

Would it be appropriate to copy this schema somewhere locally so our unit tests don't stop working if/when we can't access www.w3.org?

Required Info:

  • Operating System:

NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"

  • Installation type:

    • from source
  • Version or commit hash:

  • DDS implementation:

  • Client library (if applicable):

Steps to reproduce issue

This happens when we do colcon test. You can also do it pretty easily in an ipython window:

from lxml import etree
etree.XMLSchema(etree.parse('/path_to_sros2/sros2/sros2/policy/schemas/policy.xsd'))

Unable to write random state

https://github.com/ros2/sros2/blob/master/SROS2_Windows.md

On windows 10 using the binaries from https://ci.ros2.org/view/packaging/job/packaging_windows/1043/

Running

ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker

Results in a message unable to write 'random state'. What does this message mean? Is it an error that should be looked at?

Full output

C:\dev\sros2_demo>ros2 security create_keystore demo_keys
Namespace(ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x00000006FC4299E8>, _verb=<sros2.verb.create_keystore.CreateKeystoreVerb object at 0x00000006FCBC3710>, **{' command': 'security', ' verb': 'create_keystore'})
directory already exists: demo_keys
creating CA file: demo_keys\ca_conf.cnf
creating ECDSA param file: demo_keys\ecdsaparam
running command in path [None]: openssl ecparam -name prime256v1 > demo_keys\ecdsaparam
creating new CA key/cert pair
running command in path [None]: openssl req -nodes -x509 -days 3650 -newkey ec:demo_keys\ecdsaparam -keyout demo_keys\ca.key.pem -out demo_keys\ca.cert.pem -config demo_keys\ca_conf.cnf
Generating a 256 bit EC private key
unable to write 'random state'
writing new private key to 'demo_keys\ca.key.pem'
-----
creating governance file: demo_keys\governance.xml
creating signed governance file: demo_keys\governance.p7s
running command in path [None]: openssl smime -sign -in demo_keys\governance.xml -text -out demo_keys\governance.p7s -signer demo_keys\ca.cert.pem -inkey demo_keys\ca.key.pem
unable to write 'random state'
all done! enjoy your keystore in demo_keys
cheers!

C:\dev\sros2_demo>ros2 security create_key demo_keys talker
Namespace(NAME='talker', ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x0000007194CBA978>, _verb=<sros2.verb.create_key.CreateKeyVerb object at 0x0000007195453710>, **{' command': 'security', ' verb': 'create_key'})
creating key for node name: talker
creating ECDSA param file: demo_keys\talker\ecdsaparam
running command in path [None]: openssl ecparam -name prime256v1 > demo_keys\talker\ecdsaparam
creating key and cert request
running command in path [demo_keys]: openssl req -nodes -new -newkey ec:talker\ecdsaparam -config talker\request.cnf -keyout talker\key.pem -out talker\req.pem
Generating a 256 bit EC private key
unable to write 'random state'
writing new private key to 'talker\key.pem'
-----
creating cert
running command in path [demo_keys]: openssl ca -batch -create_serial -config ca_conf.cnf -days 3650 -in talker\req.pem -out talker\cert.pem
Using configuration from ca_conf.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4096 (0x1000)
        Validity
            Not Before: Jun 22 18:30:43 2018 GMT
            Not After : Jun 19 18:30:43 2028 GMT
        Subject:
            commonName                = talker
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
Certificate is to be certified until Jun 19 18:30:43 2028 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
unable to write 'random state'
running command in path [None]: openssl smime -sign -in demo_keys\talker\permissions.xml -text -out demo_keys\talker\permissions.p7s -signer demo_keys\ca.cert.pem -inkey demo_keys\ca.key.pem
unable to write 'random state'

Replace openssl subprocess calls with python cryptography library

Currently, the sros2 api makes subprocess calls to the systems OpenSSL CLI for generating public/private x509 key pairs and signing for SMIME. This is a bit hacky, as it relies upon the OpenSSL CLI to be consistent across runtime targets, making it quite fragile should the CLI or implicit defaults change. Instead, we should seek to use a proper cryptography library API so we may have finer control over key material provisioning and error handling for the user.

For example, users wishing to use Connext for DDS Security must swap the environment to point to a version of OpenSSL shipped by RTI. As RTI’s OpenSSL installer does not fully configure the CLI, as it does instead for the shared library, nor does the install respect the system config defaults for OpenSSL; this results in warnings produced by the RTI OpenSSL CLI binary that are susiquentl silenced by sros2 use of subprocess, obscuring potential errors or deviating crypto settings.


Background

cryptography is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic standard library". cryptography includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and key derivation functions.
https://cryptography.io

By far, my favorite python library for this is cryptography, which has a pythonic API, excellent documentation, and readily available for most targets. This what I also used back for SROS1 when developing its keyserver:
https://github.com/ros/ros_comm/blob/f95b4a5de2acb4fb53f0e9a4cff47dcef928eac5/tools/rosgraph/src/rosgraph/key_helper.py

Progress

While sros2 CLI was still in its early stages, I previously prototyped a more advanced keystore workspace tool called Keymint, again using the python cryptography library:

https://github.com/keymint/keymint_keymake/tree/adc38e07ce5f16d6ba4b36294d7d2e8a361153f0/keymint_keymake/pki

This allowed me to abstract a bit more allowing users to finally configure the asymmetric key algorithm/size/format, CA hierarchy, period of validity and expiration, file protection, etc. I’d like to port over most of these features directly into sros2, but would like to just start by swapping out the subprocess calls and establishing cryptography as a primary depency.

The only road bump is foresee is that of supporting SMIME signatures when notarizing DDS Security governance and permission documents. As of writing, the cryptography library doesn’t yet seem to have a simple API for producing smime signature. This has been an open ticket for a while:

pyca/cryptography#1621

For Keyment, I worked out out this by using M2Crypto for this one purpose instead, allow me to replicate the same valid SMIME signatures in pure-ish python. However M2Crypto isn’t as simple to install (this may have improved since I last checked a year ago), and its API is more like OpenSSL (think: giant hairball):

https://github.com/keymint/keymint_keymake/blob/adc38e07ce5f16d6ba4b36294d7d2e8a361153f0/keymint_keymake/smime/sign.py

Still, I think we can avoid M2Crypto as a dependency if we temporarily drop down a little into the backend API and add some wrappers around the lowevel interfaces for SMIME signing:

https://stackoverflow.com/questions/52780716/signing-s-mime-content-from-python

Cannot CTRL + C non-secure listener if secure publisher is publishing

Bug report

Required Info:

Steps to reproduce issue

First confirm that CTRL + c works if no secure publishers are publishing

$ ros2 run demo_nodes_py listener
Traceback (most recent call last):
  File "C:\dev\ros2-windows\lib\demo_nodes_py\listener-script.py", line 11, in <module>
    load_entry_point('demo-nodes-py==0.4.0', 'console_scripts', 'listener')()
  File "C:\dev\ros2-windows\Lib\site-packages\demo_nodes_py\topics\listener.py", line 40, in main
    rclpy.spin(node)
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\__init__.py", line 108, in spin
    executor.spin_once()
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\executors.py", line 519, in spin_once
    handler, entity, node = self.wait_for_ready_callbacks(timeout_sec=timeout_sec)
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\executors.py", line 505, in wait_for_ready_callbacks
    return next(self._cb_iter)
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\executors.py", line 411, in _wait_for_ready_callbacks
    _rclpy.rclpy_wait(wait_set, timeout_nsec)
KeyboardInterrupt

In another terminal start talker with security enabled

set ROS_SECURITY_ROOT_DIRECTORY=%cd%/demo_keys
set ROS_SECURITY_ENABLE=true
set ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_py talker

Restart the listener and try to interrupt it by pressing CTRL + c.

$ ros2 run demo_nodes_py listener

Expected behavior

listener would be interrupted when CTRL + c is hit

Actual behavior

listener does not respond to CTRL + c events at all. Process must be killed using task manager.

Additional information

ros2 run demo_nodes_cpp listener does not show the same behavior. I have not tested with other RMW implementations.

Foxy support

Security demos work on Ubuntu Bionic but fail on Focal.
This ticket is to aggregate findings about what need to change ahead of Foxy release.

Current state:

Code to test talker listener
docker run -it --rm osrf/ros2:nightly
source /opt/ros/foxy/setup.bash 
mkdir ~/sros2_demo
cd ~/sros2_demo
export ROS_SECURITY_ROOT_DIRECTORY=~/sros2_demo/demo_keys
export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys /talker
ros2 security create_key demo_keys /listener
ros2 launch demo_nodes_cpp talker_listener.launch.xml 


  • FastRTPS fails: Likely due to a lack of support of OpenSSL 1.1.1d, asked at eProsima/Fast-DDS#1087
    • FastRTPS own Security examples without any ROS or sros2 involved already fail
Error message
[talker-1] 2020-03-23 15:26:26.045 [SECURITY_AUTHENTICATION Error] OpenSSL library cannot set peer (/home/jenkins-agent/workspace/packaging_linux/ws/src/eProsima/Fast-RTPS/src/cpp/security/authentication/PKIDH.cpp:1041) -> Function on_process_handshake
  • CycloneDDS fails: maybe openSSL support ?
    - not sure how to do standalone security testing for Cyclone

Works as of eclipse-cyclonedds/cyclonedds#446

  • RTI Connext: works: connext ships it's own (EOL...) OpenSSL 1.0.2 (support hypothesis of OpenSSL version being the culprit)

OpenSSL version:

If it was an openSSL version support issue, rolling distributions like Windows and Macos should have allowed us to catch it earlier..

Windows is using 1.0.2u apparently, https://github.com/ros2/ci/blob/3ec2369bd0ddc04e80b9fadab272abcd46e08b64/windows_docker_resources/Dockerfile.msvc2019#L20 so it's normal it didnt catch any error

on MacOS there seem to be tests failing for a long time, need to track down if it worked with openssl 1.1.1 at some point

Talker crashes when it tries to publish on a topic it doesn't have permission to use

Bug report

Required Info:

Steps to reproduce issue

Policy file: https://raw.githubusercontent.com/ros2/sros2/ardent/examples/sample_policy.yaml

md C:\dev\sros2_demo
md C:\dev\sros2_demo\demo_keys
REM copy policy file as policies.yaml into demo_keys
cd C:\dev\sros2_demo
set RANDFILE=C:\dev\sros2_demo\.rnd

ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker
ros2 security create_key demo_keys listener
ros2 security create_permission demo_keys talker demo_keys/policies.yaml
ros2 security create_permission demo_keys listener demo_keys/policies.yaml

REM Launch the c++ talker
set ROS_SECURITY_ROOT_DIRECTORY=%cd%/demo_keys
set ROS_SECURITY_ENABLE=true
set ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_cpp talker /chatter:=/something/else

REM next try rclpy
ros2 run demo_nodes_py talker /chatter:=/something/else

Expected behavior

Processes would exit with a non-zero return code

Actual behavior

Processes seem to crash (Windows dialog pops up saying process crashed)

Additional information

python talker manages to print a traceback before crashing

>ros2 run demo_nodes_py talker /chatter:=/something/else
Traceback (most recent call last):
  File "C:\dev\ros2-windows\lib\demo_nodes_py\talker-script.py", line 11, in <module>
    load_entry_point('demo-nodes-py==0.4.0', 'console_scripts', 'talker')()
  File "C:\dev\ros2-windows\Lib\site-packages\demo_nodes_py\topics\talker.py", line 46, in main
    node = Talker()
  File "C:\dev\ros2-windows\Lib\site-packages\demo_nodes_py\topics\talker.py", line 28, in __init__
    self.pub = self.create_publisher(String, 'chatter')
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\node.py", line 115, in create_publisher
    self.handle, msg_type, topic, qos_profile.get_c_qos_profile())
RuntimeError: Failed to create publisher: create_publisher() could not create publisher, at C:\J\workspace\packaging_windows\ws\src\ros2\rmw_fastrtps\rmw_fastrtps_cpp\src\rmw_publisher.cpp:132, at C:\J\workspace\packaging_windows\ws\src\ros2\rcl\rcl\src\rcl\publisher.c:173
[SECURITY

Finer control over security artifacts compared to ROS_SECURITY_ROOT_DIRECTORY

Having additional environment variables to point the rmw dds layer towards specific security artifacts, i.e. in vious independent paths, would be helpful in that users wouldn't have to duplicate files like the permission authority public CA certificate into every 'ROS_SECURITY_ROOT_DIRECTORY' directory for each node identity.

This would be helpful for the keymint project, but also in general just to reduce the chance of relaying on a voided CA file for security just because you lost track of an revoked CA certificate somewhere, or free user to choose descriptive filenames as they please.

Last time I tried to be cute and auto generate symbolic links in the file system to point to a single CA on disk, the dds implementation is was testing, RTI Connext, did not acknowledge the links and failed to load the assets. And perhaps justly so, as symbolic linking can itself be a security concern.

I'd suggest checking additional environment variables that could be set to overload the default path to read the assets from, one for each core Secure DDS artifact: identity_ca, permissions_ca, private_key, identity_certificate, governance, and permissions.

This way users could also ensure that identity_ca and permissions_ca are not set to the same public certificate, given the assets they sign often have separate life cycles. Presently this is not possible given SROS2 uses ROS_SECURITY_ROOT_DIRECTORY to load the hardcoded file ca.cert.pem for both CA roles.

Also, perhaps there should be a password environment variable that SROS2 should check to dcypher the private key if encrypted on disk.

Resolve schema file hosting

Based on discussion from #84.

sros2 could be updated to get the schema files from OMG or download.ros.org instead of storing a copy in this repository

sros2 specific schema such as the policy schema should also be stored somewhere like download.ros.org and be referenced in the generated policy files

Policy to permissions test is failing

Bug report

Required Info:

  • Operating System:
    • Ubuntu 18.04 LTS
  • Installation type:
    • From source
  • Version or commit hash:
  • DDS implementation:
    • Fast-RTPS

Steps to reproduce issue

colcon test --event-handlers=console_direct+ --packages-select sros2 --pytest-args ' -k policy_to_permissions' ' -vv'

Expected behavior

Test passes.

Actual behavior

Test fails ```sh __________________________ test_policy_to_permissions __________________________ test/test_policy_to_permissions.py:57: in test_policy_to_permissions assert actual == expected E assert '\n\n' == '\n \n\n' E - E + E E E CN=/talker E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/talker/describe_parametersRequest E rq/talker/get_parameter_typesRequest E rq/talker/get_parametersRequest E rq/talker/list_parametersRequest E rq/talker/set_parametersRequest E rq/talker/set_parameters_atomicallyRequest E rr/talker/describe_parametersReply E rr/talker/get_parameter_typesReply E rr/talker/get_parametersReply E rr/talker/list_parametersReply E rr/talker/set_parametersReply E rr/talker/set_parameters_atomicallyReply E rt/chatter E rt/parameter_events E rt/rosout E E E E E rq/talker/describe_parametersRequest E rq/talker/get_parameter_typesRequest E rq/talker/get_parametersRequest E rq/talker/list_parametersRequest E rq/talker/set_parametersRequest E rq/talker/set_parameters_atomicallyRequest E rr/talker/describe_parametersReply E rr/talker/get_parameter_typesReply E rr/talker/get_parametersReply E rr/talker/list_parametersReply E rr/talker/set_parametersReply E rr/talker/set_parameters_atomicallyReply E rt/clock E rt/parameter_events E E E E DENY E E E CN=/listener E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/listener/describe_parametersRequest E rq/listener/get_parameter_typesRequest E rq/listener/get_parametersRequest E rq/listener/list_parametersRequest E rq/listener/set_parametersRequest E rq/listener/set_parameters_atomicallyRequest E rr/listener/describe_parametersReply E rr/listener/get_parameter_typesReply E rr/listener/get_parametersReply E rr/listener/list_parametersReply E rr/listener/set_parametersReply E rr/listener/set_parameters_atomicallyReply E rt/parameter_events E rt/rosout E E E E E rq/listener/describe_parametersRequest E rq/listener/get_parameter_typesRequest E rq/listener/get_parametersRequest E rq/listener/list_parametersRequest E rq/listener/set_parametersRequest E rq/listener/set_parameters_atomicallyRequest E rr/listener/describe_parametersReply E rr/listener/get_parameter_typesReply E rr/listener/get_parametersReply E rr/listener/list_parametersReply E rr/listener/set_parametersReply E rr/listener/set_parameters_atomicallyReply E rt/chatter E rt/clock E rt/parameter_events E E E E DENY E E E CN=/add_two_ints_server E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/add_two_ints_server/describe_parametersRequest E rq/add_two_ints_server/get_parameter_typesRequest E rq/add_two_ints_server/get_parametersRequest E rq/add_two_ints_server/list_parametersRequest E rq/add_two_ints_server/set_parametersRequest E rq/add_two_ints_server/set_parameters_atomicallyRequest E rr/add_two_intsReply E rr/add_two_ints_server/describe_parametersReply E rr/add_two_ints_server/get_parameter_typesReply E rr/add_two_ints_server/get_parametersReply E rr/add_two_ints_server/list_parametersReply E rr/add_two_ints_server/set_parametersReply E rr/add_two_ints_server/set_parameters_atomicallyReply E rt/parameter_events E rt/rosout E E E E E rq/add_two_intsRequest E rq/add_two_ints_server/describe_parametersRequest E rq/add_two_ints_server/get_parameter_typesRequest E rq/add_two_ints_server/get_parametersRequest E rq/add_two_ints_server/list_parametersRequest E rq/add_two_ints_server/set_parametersRequest E rq/add_two_ints_server/set_parameters_atomicallyRequest E rr/add_two_ints_server/describe_parametersReply E rr/add_two_ints_server/get_parameter_typesReply E rr/add_two_ints_server/get_parametersReply E rr/add_two_ints_server/list_parametersReply E rr/add_two_ints_server/set_parametersReply E rr/add_two_ints_server/set_parameters_atomicallyReply E rt/clock E rt/parameter_events E E E E DENY E E E CN=/add_two_ints_client E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/add_two_intsRequest E rq/add_two_ints_client/describe_parametersRequest E rq/add_two_ints_client/get_parameter_typesRequest E rq/add_two_ints_client/get_parametersRequest E rq/add_two_ints_client/list_parametersRequest E rq/add_two_ints_client/set_parametersRequest E rq/add_two_ints_client/set_parameters_atomicallyRequest E rr/add_two_ints_client/describe_parametersReply E rr/add_two_ints_client/get_parameter_typesReply E rr/add_two_ints_client/get_parametersReply E rr/add_two_ints_client/list_parametersReply E rr/add_two_ints_client/set_parametersReply E rr/add_two_ints_client/set_parameters_atomicallyReply E rt/parameter_events E rt/rosout E E E E E rq/add_two_ints_client/describe_parametersRequest E rq/add_two_ints_client/get_parameter_typesRequest E rq/add_two_ints_client/get_parametersRequest E rq/add_two_ints_client/list_parametersRequest E rq/add_two_ints_client/set_parametersRequest E rq/add_two_ints_client/set_parameters_atomicallyRequest E rr/add_two_intsReply E rr/add_two_ints_client/describe_parametersReply E rr/add_two_ints_client/get_parameter_typesReply E rr/add_two_ints_client/get_parametersReply E rr/add_two_ints_client/list_parametersReply E rr/add_two_ints_client/set_parametersReply E rr/add_two_ints_client/set_parameters_atomicallyReply E rt/clock E rt/parameter_events E E E E DENY E E E CN=/minimal_action_server E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/minimal_action_server/describe_parametersRequest E rq/minimal_action_server/get_parameter_typesRequest E rq/minimal_action_server/get_parametersRequest E rq/minimal_action_server/list_parametersRequest E rq/minimal_action_server/set_parametersRequest E rq/minimal_action_server/set_parameters_atomicallyRequest E rr/fibonacci/_action/cancel_goalReply E rr/fibonacci/_action/get_resultReply E rr/fibonacci/_action/send_goalReply E rt/fibonacci/_action/feedback E rt/fibonacci/_action/status E rr/minimal_action_server/describe_parametersReply E rr/minimal_action_server/get_parameter_typesReply E rr/minimal_action_server/get_parametersReply E rr/minimal_action_server/list_parametersReply E rr/minimal_action_server/set_parametersReply E rr/minimal_action_server/set_parameters_atomicallyReply E rt/parameter_events E rt/rosout E E E E E rq/fibonacci/_action/cancel_goalRequest E rq/fibonacci/_action/get_resultRequest E rq/fibonacci/_action/send_goalRequest E rq/minimal_action_server/describe_parametersRequest E rq/minimal_action_server/get_parameter_typesRequest E rq/minimal_action_server/get_parametersRequest E rq/minimal_action_server/list_parametersRequest E rq/minimal_action_server/set_parametersRequest E rq/minimal_action_server/set_parameters_atomicallyRequest E rr/minimal_action_server/describe_parametersReply E rr/minimal_action_server/get_parameter_typesReply E rr/minimal_action_server/get_parametersReply E rr/minimal_action_server/list_parametersReply E rr/minimal_action_server/set_parametersReply E rr/minimal_action_server/set_parameters_atomicallyReply E rt/clock E rt/parameter_events E E E E DENY E E E CN=/minimal_action_client E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/fibonacci/_action/cancel_goalRequest E rq/fibonacci/_action/get_resultRequest E rq/fibonacci/_action/send_goalRequest E rq/minimal_action_client/describe_parametersRequest E rq/minimal_action_client/get_parameter_typesRequest E rq/minimal_action_client/get_parametersRequest E rq/minimal_action_client/list_parametersRequest E rq/minimal_action_client/set_parametersRequest E rq/minimal_action_client/set_parameters_atomicallyRequest E rr/minimal_action_client/describe_parametersReply E rr/minimal_action_client/get_parameter_typesReply E rr/minimal_action_client/get_parametersReply E rr/minimal_action_client/list_parametersReply E rr/minimal_action_client/set_parametersReply E rr/minimal_action_client/set_parameters_atomicallyReply E rt/parameter_events E rt/rosout E E E E E rq/minimal_action_client/describe_parametersRequest E rq/minimal_action_client/get_parameter_typesRequest E rq/minimal_action_client/get_parametersRequest E rq/minimal_action_client/list_parametersRequest E rq/minimal_action_client/set_parametersRequest E rq/minimal_action_client/set_parameters_atomicallyRequest E rr/fibonacci/_action/cancel_goalReply E rr/fibonacci/_action/get_resultReply E rr/fibonacci/_action/send_goalReply E rt/fibonacci/_action/feedback E rt/fibonacci/_action/status E rr/minimal_action_client/describe_parametersReply E rr/minimal_action_client/get_parameter_typesReply E rr/minimal_action_client/get_parametersReply E rr/minimal_action_client/list_parametersReply E rr/minimal_action_client/set_parametersReply E rr/minimal_action_client/set_parameters_atomicallyReply E rt/clock E rt/parameter_events E E E E DENY E E E CN=/admin E E 2013-10-26T00:00:00 E 2023-10-26T22:45:30 E E E E 0 E E E E rq/add_two_intsRequest E rq/admin/describe_parametersRequest E rq/admin/get_parameter_typesRequest E rq/admin/get_parametersRequest E rq/admin/list_parametersRequest E rq/admin/set_parametersRequest E rq/admin/set_parameters_atomicallyRequest E rq/fibonacci/_action/cancel_goalRequest E rq/fibonacci/_action/get_resultRequest E rq/fibonacci/_action/send_goalRequest E rr/add_two_intsReply E rr/admin/describe_parametersReply E rr/admin/get_parameter_typesReply E rr/admin/get_parametersReply E rr/admin/list_parametersReply E rr/admin/set_parametersReply E rr/admin/set_parameters_atomicallyReply E rr/fibonacci/_action/cancel_goalReply E rr/fibonacci/_action/get_resultReply E rr/fibonacci/_action/send_goalReply E rt/fibonacci/_action/feedback E rt/fibonacci/_action/status E rt/chatter E rt/parameter_events E rt/rosout E E E E E rq/add_two_intsRequest E rq/admin/describe_parametersRequest E rq/admin/get_parameter_typesRequest E rq/admin/get_parametersRequest E rq/admin/list_parametersRequest E rq/admin/set_parametersRequest E rq/admin/set_parameters_atomicallyRequest E rq/fibonacci/_action/cancel_goalRequest E rq/fibonacci/_action/get_resultRequest E rq/fibonacci/_action/send_goalRequest E rr/add_two_intsReply E rr/admin/describe_parametersReply E rr/admin/get_parameter_typesReply E rr/admin/get_parametersReply E rr/admin/list_parametersReply E rr/admin/set_parametersReply E rr/admin/set_parameters_atomicallyReply E rr/fibonacci/_action/cancel_goalReply E rr/fibonacci/_action/get_resultReply E rr/fibonacci/_action/send_goalReply E rt/fibonacci/_action/feedback E rt/fibonacci/_action/status E rt/chatter E rt/clock E rt/parameter_events E E E E DENY E E E ```

Additional information

Test failure can be seen in CI as well, see https://ci.ros2.org/job/ci_linux/6268/, https://ci.ros2.org/job/ci_linux-aarch64/2691/ and https://ci.ros2.org/job/ci_osx/5150/.

windows nightly release build has a new test failure

Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/local/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 601, in run
    testMethod()
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/site-packages/nose/failure.py", line 39, in runTest
    raise self.exc_val.with_traceback(self.tb)
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/site-packages/nose/loader.py", line 418, in loadTestsFromName
    addr.filename, addr.module)
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/site-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/site-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/imp.py", line 234, in load_module
    return load_source(name, filename, file)
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/venv/lib/python3.6/imp.py", line 172, in load_source
    module = _load(spec)
  File "<frozen importlib._bootstrap>", line 675, in _load
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "/Users/osrf/jenkins/workspace/nightly_osx_debug/ws/src/ros2/sros2/sros2/verb/create_key.py", line 21, in <module>
    from ros2pkg.verb import VerbExtension
ModuleNotFoundError: No module named 'ros2pkg'

-- http://ci.ros2.org/job/nightly_win_rel/465/testReport/nose.failure/Failure/runTest/

Allow ROS2 CLI to support Security

The ROS2 CLI utilizes a node_name_suffix to ensure an unique node name by including the process's pid:

https://github.com/ros2/ros2cli/blob/e5f67d0e0362462644a5530094fac43af84ca938/ros2cli/ros2cli/node/direct.py#L36-L38

This makes it difficult to provide any CLI the necessary root dir for its security artifacts at runtime.
I see a few solutions:

  1. passing an argument to the cli to drop the use of its node_name_suffix, however the loss of a unique FQN could bing unintended consequences.
  2. Add support for providing the exact path to the node_secure_root directory. This could be done by pre checking a new security environment variable that would take precedence over ROS_SECURITY_ROOT_DIRECTORY , e.g: ROS_SECURITY_NODE_DIRECTORY?

I like 2) as it would allow users to override the normal root lookup when using any CLI or debugging nodes with separate temporary credentials provisioned with super privileges, e.g "*" permissions for all topics.

SROS2 Keystore Proposal

I'd like to refactor the SROS2 keystore and CLI to accommodate a more streamlined features set that is also scalable to a larger number of keys, as well as being a little more agnostic to the secure transport. Below is a proposed outline of a new CLI building on top from the current ros2 secure subcommand behavior:

ros2 secure

keystore

auto

Automatically initialize, build, create, and sign keystore in one command

  • -c --config
  • -g, --governance
  • -p, --policy
  • -n, --namespace
  • -f, --force
  • -n, --namespace

init

Initializes only the keystore folder and root CAs

  • -c --config
  • -f, --force

build

Builds keystore; regenerating and distributes governance

  • -g, --governance
  • -f, --force
  • -u, --unsigned

create

Create keystore entry for given namespace

  • -p, --policy
  • -f, --force
  • -u, --unsigned
  • -n, --namespace

sign

Sign keystore entry for given namespace

  • -f, --force
  • -r, --recursive
  • -n, --namespace

remove

Remove keystore entry for given namespace

  • -r, --recursive
  • -n, --namespace

Legend

  • -c --config
    • path to general config file given CLI context
    • overrides system defaults
  • -g, --governance
    • path to specific governance config
    • overrides system defaults
  • -p, --policy
    • path to specific policy config
    • overrides system defaults
  • -n, --namespace
    • namespaces to be applied
  • -f, --force
    • force ignore and overwrite existing files
  • -r, --recursive
    • recursive operation upon the namespace context
  • -u, --unsigned
    • signatures are not automatically applied

Storage

I'd also like to suggest a standard layout for the default keystore layout on disk. Later we could probably play around with different types of secure keystore data structures and the like, but for now a simple nested directory should serve as a good start. This also has the added benefit of being simple to translate keystore read permissions to only certain authorized ros2 process given suitable apparmor profiles.

The proposed layout is as follows:

$ tree keystore_root/
keystore_root/        # Keystore root directory
├── governance.cnf    # Governance config
├── keystore.cnf      # Keystore config
├── permissions.cnf   # Permissions config
├── participants      # Participants root namespace subtree
│   └── namespace
│       └── here
│           ├── listener
│           │   ├── cert.pem
│           │   ├── governance.cert.pem -> ../../../../public/governance.cert.pem
│           │   ├── governance.p7s -> ../../../../shared/governance.p7s
│           │   ├── key.pem
│           │   ├── permissions.cert.pem -> ../../../../public/permissions.cert.pem
│           │   ├── permissions.p7s
│           │   ├── permissions.xml
│           │   └── req.pem
│           └── talker
│               ├── cert.pem            # namespace/here/talker public certificate
│               ├── governance.cert.pem -> ../../../../public/governance.cert.pem
│               ├── governance.p7s -> ../../../../shared/governance.p7s
│               ├── key.pem             # namespace/here/talker private key
│               ├── permissions.cert.pem -> ../../../../public/permissions.cert.pem
│               ├── permissions.p7s     # namespace/here/talker permissions singed
│               ├── permissions.xml     # namespace/here/talker permissions file
│               └── req.pem             # namespace/here/talker certificate request
├── private
│   ├── governance.key.pem      # Governance CA private key
│   ├── governance.xml          # Governance file
│   └── permissions.key.pem     # Permissions CA private key
├── public
│   ├── governance.cert.pem     # Governance CA public certificate
│   └── permissions.cert.pem    # Permissions CA public certificate
└── shared
    └── governance.p7s          # Governance singed

With in root directory of the keystore are several config files and a set of specifically name folders. The configuration files are not specific, and may vary given the middleware transport/vendor, or customization file of the user. However a default naming scheme should be established to at least support implicit referencing when using CLI, given a default keystore structure.

The participants folder serves as the root of the namespace subtree in which the participant resources are nested and organized. This makes it simple for participants to lookup runtime certificates and secrets, while also permitting users to manage and orchestrate those resources in manner that mirrors the runtime computation graph.

The private and public folders are used to segregate resources that are sensitive or not within the keystore. The shared folder surveys as a special directory for resources that must be distributed among participants, but are not necessary public outside the keystore.

Resources within the public and shared directories could be soft linked to created entries in the participants subtree. This helps ensure all participants have up-to-date instances of common resources, reduces the duplicate files on disk, and benefits from OS page caching. This also still enabling more advanced users overwrite and customize the structure.

In practice with respect to the keystore, secure ros2 runtime process should only be granted read permissions for the exact namespace directory given the participants (also not recursive), the public folder for necessary CA certificates, and the shared folder for common resources within the secure system. In addition, only the public folder should be given read access to non ros2 related process, i.e. for a signed certificate revocation list inside that may require public hosting.

Remarks

Namespace collisions

One potential hazard with the participants subtree mimicking the namespace hierarchy is that participant namespaces could collide with resource file names, i.e. a folder and file can not share the same name within the same parent directory. However given that ros2 prevents the inclusion of periods . within the a node's namespaces, this issue should be avoidable given that all resources/files within keystore should be denoted with a file extension, e.g. .pem or .p7s, et cetera.

Another issue may be that two participants of the same namespace can not immediately have a separate set of keys or resources. This could be alleviated by resigning to use separate keystores for such use cases, but does not seem ideal. However, as with ros1, I expect ros2 may expect users to service only one node per absolute namespace, and utilize topics as the primary means of overlap or redundancy.

Then again when configured, ros1 was able assigned participants a unique node namespace through a combination of starttime date and PID number. It is not immediately clear how such anonymizing capabilities could be achieved here; also perhaps such anonymization would fundamentally work against our secure design principles.

Implementation agnostic

One goal I'd like for this effort is to be agnostic to the exact secure transport, such that if ros2 where to come around and support in addition to Secure DDS, but also in the future say gRPC or dps-for-iot, that the a new sros2 plugin could be written and invoked under the hood to enable all the secret and token handling for whatever may come.

Obviously this is quite ambitious, and perhaps the whole security ecosystem for such future transports may be drastically different. However it is my guess that given ros2's classic pub/sub approach, the roles between subjects and objects in an Access Control Matrix, and longstanding duality of public key cryptography, my hope is that much of this design will sufficiently generalize and translate naturally.

[ERROR] [rcl]: Failed to fini publisher for node: 1

Bug report

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • from source
  • Version or commit hash:
    • Eloquent
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • rcl, rmw_fastrtps_shared_cpp

Steps to reproduce issue

cd ~/sros2_demo
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys /talker
ros2 security create_key demo_keys /listener
export ROS_SECURITY_ROOT_DIRECTORY=~/sros2_demo/demo_keys
export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_cpp talker

Expected behavior

talker node running and sending msg out.

Actual behavior

[INFO] [rcl]: Found security directory: /home/claire/sros2_demo/demo_keys/talker

>>> [rcutils|error_handling.c:107] rcutils_set_error_state()
This error state is being overwritten:

  'This Fast-RTPS version doesn't have the security libraries
Please compile Fast-RTPS using the -DSECURITY=ON CMake option, at /home/claire/ros2_ws/src/ros2/rmw_fastrtps/rmw_fastrtps_shared_cpp/src/rmw_node.cpp:330, at /home/claire/ros2_ws/src/ros2/rcl/rcl/src/rcl/node.c:336'

with this new error message:

  'rcl node's rmw handle is invalid, at /home/claire/ros2_ws/src/ros2/rcl/rcl/src/rcl/node.c:485'

rcutils_reset_error() should be called after error handling to avoid this.
<<<
[ERROR] [rcl]: Failed to fini publisher for node: 1
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  failed to initialize rcl node: rcl node's rmw handle is invalid, at /home/claire/ros2_ws/src/ros2/rcl/rcl/src/rcl/node.c:485

might also just be due to my failure in building rmw_fastrtps_shared_cpp, verifying...

Rename generate_permissions to generate_policies?

When trying to use the ros2 security generate_permissions based only on the help message:

ros2 security generate_permissions -h
usage: ros2 security generate_permissions [-h] POLICY_FILE_PATH

Generate permissions

positional arguments:
  POLICY_FILE_PATH  path of the permission yaml file

I was surprised by the behavior.

What I understood the verb was doing: "Generate permissions based on a YAML policy file"

Actual behavior: "Look at the ROS graph and generate a YAML policy file but no permission files"

I suggest renaming the verb to reduce ambiguity and add a more complete help message than "Generate permissions".

@ross-desmond @ruffsl please let me know if this makes sense and/or if you have any suggestion on the approach (I opened #78 with the suggested change)

Integration for DDS Security Builtin Logging Plugin

When designing, auditing, or monitoring security policies for complex applications, comprised of many internal and external interfaces, as with distributed computation graphs in ROS2, feedback in form of security event logging can provide valuable insight into potential misconfigurations or abnormalities during development, testing, and deployment.

To further improve our security assistive tooling for SROS2, it would be pertinent to integrate security event logging to facilitate advanced features such as: Log-driven profile generation of access control policies, interoperability testing between multiple integrated systems, as well as continuous monitoring for security abnormalities. To an extent, much of this may be readily achievable by leveraging existing DDS Security Builtin Logging Plugin Interfaces.


Background

The Logging plugin provides the capability to log all security events, including expected behavior and all security violations or errors. The goal is to create security logs that can be used to support audits. The rest of the security plugins will use the logging API to log events.

The Logging plugin will add an ID to the log message that uniquely specifies the DomainParticipant. It will also add a time-stamp to each log message.

The Logging API has two options for collecting log data. The first is to log all events to a local file for collection and storage. The second is to distribute log events securely over DDS.

Section 8.6.1, DDS Security specification (v1.4)
https://www.omg.org/spec/DDS-SECURITY/About-DDS-SECURITY

The DDS Security specification from OMG defines 5 Service Plugin Interfaces:

Table 43 – Summary of the Builtin Plugins

SPI Plugin Name Description
Authentication DDS:Auth:PKI-DH Uses PKI with a pre-configured shared Certificate Authority
AccessControl DDS:Access:Permissions Permissions document signed by shared Certificate Authority
Cryptography DDS:Crypto:AES-GCM-GMAC AES-GCM for encryption. AES-GMAC for message authentication
DataTagging* DDS:Tagging:DDS_Discovery Send Tags via Endpoint Discovery
Logging* DDS:Logging:DDS_LogTopic Logs security events to a dedicated DDS Log Topic

(*) denotes that default implementations for SPI is optional

The most notable SPI here being that for Logging, as explained in sections 8.6, and 9.6 in the DDS Security spec. These sections detail the plugin model, parameter options, message IDL, and runtime behavior. A conforming logging plugin essently captures and records security events that may crop up at runtime in other security plugins, along with helpful identifying contexts to triage the event.

Recorded events may either be distributed by writing them to disk locally via log file, or publishing them over the DDS network, specifically over the topic name DDS:Security:LogTopic, with the following governance setting:

<topic_rule>
  <topic_expression> DDS:Security:LogTopic</topic_expression>
  <enable_discovery_protection>FALSE</enable_discovery_protection>
  <enable_read_access_control>TRUE</enable_read_access_control>
  <enable_write_access_control>FALSE</enable_write_access_control>
  <metadata_protection_kind>SIGN</metadata_protection_kind>
  <data_protection_kind>ENCRYPT</data_protection_kind>
</topic_rule>

The above rule states that any DomainParticipant with permission necessary to join the DDS Domain shall be allowed to write the BuiltinLoggingTopic but in order to read the BuiltinLoggingTopic the DomainParticipant needs to have a grant for the BuiltinLoggingTopic in its permissions document. (Section 9.6)

Progress

This was something originally I had started in SROS1 (distributed security logging, no DDS plugins), but found the ROS1 logging mechneme deficient of rich context that would render such events debuggable for large graphs, nor did it have the message structure to interject supplementary context. Additionally, the all or nothing of TLS hindered SROS1’s ability securely introspect distributed events from nodes failing to join the network to begin with.

The Logging SPI in DDS Security largely resolves these issues, via granular governance settings, structured IDL formats, abstraction over distribution (be it via files or topics), and perhaps most importantly a standard interface to introspect the internal state of the accompanying security plugins.

However, from my interpretation, while the specification is explicit in what supplementary context must be included given the message IDL, it's still a bit handwavy with respect to what the Free-form message string should contain, or how its formatted. I also suspect the meat of the info we’d like to parse out will reside therein, e.g:

  • QoS and topic-name that was denied due to insufficient permissions?
  • Requested permission type that was denied (read, write, relay)?
  • Invalid certificate how (expired validity, broken CA chain, void signature)?

I haven’t yet tested any Logging plugins from DDS vendors, primarily as I don’t think Fast-RTPS shipps with a default plugin implementation given Logging is listed as optional plugin. I’m not so sure Fast-RTPS even has a logging SPI so that we could write our own plugin. Also, given that RTI recently released a newer version, I’ve been stalling until ROS2 compiles with Connext v6.0 before I commit any more time investigating the state of logging there. Does anyone know the progress for Security Logging SPI on Opensplice (Vortex or I guess Cyclone now?). My fear is that each vinder will have some quirky way of conveying the same info, like they already do with warning messages, making the inferencing downstream tedious.

Perhaps some readily addressable tasks for improving integration could include supporting more advance governance.xml file templating, as we’ll have to amend it to include the relevant permissions for DDS:Security:LogTopic topic when uses wish to distribute log events over DDS. Another task could be investigating the logfile format, as parsing/translating static log files seems a bit less involved than subscribing to raw DDS topics and IDL. However, any parsing interfaces in exposing security events for downstream tooling, e.g. log-driven profile generation, should probably be abstract enough for both file or network stream sources.

check_openssl_version fails despite openssl being installed

Bug report

Required Info:

Steps to reproduce issue

  1. Follow instructions here to install openssl https://github.com/ros2/ros2/wiki/Windows-Install-Binary
  2. Run command from this tutorial https://github.com/ros2/sros2/blob/master/SROS2_Windows.md
    • ros2 security create_keystore demo_keys

Expected behavior

No traceback

Actual behavior

C:\dev\ros2\sros2_demo>ros2 security create_keystore demo_keys
Namespace(ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x0000004348FEE9E8>, _verb=<sros2.verb.create_keystore.CreateKeystoreVerb object at 0x000000434935B940>, **{' command': 'security', ' verb': 'create_keystore'})
directory already exists: demo_keys
found CA conf file, not writing a new one!
creating ECDSA param file: demo_keys\ecdsaparam
Traceback (most recent call last):
  File "C:\dev\ros2\Scripts\ros2-script.py", line 11, in <module>
    load_entry_point('ros2cli==0.0.0', 'console_scripts', 'ros2')()
  File "C:\dev\ros2\Lib\site-packages\ros2cli\cli.py", line 64, in main
    rc = extension.main(parser=parser, args=args)
  File "C:\dev\ros2\Lib\site-packages\sros2\command\security.py", line 34, in main
    return extension.main(args=args)
  File "C:\dev\ros2\Lib\site-packages\sros2\verb\create_keystore.py", line 33, in main
    success = create_keystore(args)
  File "C:\dev\ros2\Lib\site-packages\sros2\api\__init__.py", line 184, in create_keystore
    create_ecdsa_param_file(ecdsa_param_path)
  File "C:\dev\ros2\Lib\site-packages\sros2\api\__init__.py", line 112, in create_ecdsa_param_file
    check_openssl_version(openssl_executable)
  File "C:\dev\ros2\Lib\site-packages\sros2\api\__init__.py", line 39, in check_openssl_version
    stdout=subprocess.PIPE, stderr=subprocess.PIPE
  File "C:\Python36\lib\subprocess.py", line 403, in run
    with Popen(*popenargs, **kwargs) as process:
  File "C:\Python36\lib\subprocess.py", line 707, in __init__
    restore_signals, start_new_session)
  File "C:\Python36\lib\subprocess.py", line 992, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified

Additional information

C:\dev\ros2\sros2_demo>openssl
'openssl' is not recognized as an internal or external command,
operable program or batch file.

C:\dev\ros2\sros2_demo>start openssl

C:\dev\ros2\sros2_demo>where openssl
C:\OpenSSL-Win64\bin\openssl.exe
C:\dev\ros2\sros2_demo>echo %PATH%
C:\dev\ros2\Scripts;C:\dev\ros2\bin;C:\Python36\Scripts\;C:\Python36\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Windows Kits\8.1\Windows Performance Toolkit\;C:\dev\opencv-2.4.13.2-vc14.VS2015;C:\ProgramData\chocolatey\bin;C:\ProgramData\chocolatey\lib\tinyxml2\lib;C:\OpenSSL-Win64\bin\

C:\dev\ros2\sros2_demo>echo %OPENSSL_CONF%
C:\OpenSSL-Win64\bin\openssl.cfg

Extend the access control tutorial to show how it works

The current access control "tutorial" only shows how to use an existing set of policies.
It should be extended to show that:

  • trying to publish/subscribe to something not defined in the policies results in denied access
  • how to modify policies and regrenerate the permissions for a given node

SROS2 fails to use the DOMAIN_ID

Bug report The error message is not explicit enough

Nodes fails to run with security enabled using non-zero DOMAIN_ID.

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • binaries
  • Version or commit hash:
    • ros-dashing-sros2/bionic,now 0.7.1-1bionic.20191016.193121 amd64 [installed]
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • rclcpp and rclpy

Steps to reproduce issue

Generate security and start a node with a DOMAIN ID

cd ~
mkdir -p store
ros2 security create_keystore store
ros2 security create_key store /talker
export ROS_SECURITY_ROOT_DIRECTORY=~/store
export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce
export ROS_DOMAIN_ID=10
ros2 run demo_nodes_cpp talker
# As well as the python node
ros2 run demo_nodes_py talker

Expected behavior

The node starts with a different multicast port computed from the ROS_DOMAIN_ID value.

Actual behavior

The rclcpp node crashes with non zero DOMAIN_ID.

[INFO] [rcl]: Found security directory: /home/alexis/store/talker
2019-11-05 11:30:09.008 [SECURITY Error] Error checking creation of local writer 93.eb.4b.d1.65.cd.79.ea.c1.e2.f1.59|0.0.1.3 (Not found topic access rule for topic rt/rosout (/tmp/binarydeb/ros-dashing-fastrtps-1.8.2/src/cpp/security/accesscontrol/Permissions.cpp:1065))
 -> Function register_local_writer
2019-11-05 11:30:09.008 [PARTICIPANT Error] Problem creating associated Writer -> Function createPublisher
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  failed to initialize rcl node: create_publisher() could not create publisher, at /tmp/binarydeb/ros-dashing-rmw-fastrtps-cpp-0.7.6/src/rmw_publisher.cpp:175, at /tmp/binarydeb/ros-dashing-rcl-0.7.7/src/rcl/publisher.c:171

The rclpy node crashes with non zero DOMAIN_ID.

[INFO] [rcl]: Found security directory: /home/alexis/store/talker
2019-11-05 11:32:12.663 [SECURITY Error] Error checking creation of local writer 93.eb.4b.d1.65.cd.e4.19.eb.8e.c3.36|0.0.1.3 (Not found topic access rule for topic rt/rosout (/tmp/binarydeb/ros-dashing-fastrtps-1.8.2/src/cpp/security/accesscontrol/Permissions.cpp:1065))
 -> Function register_local_writer
2019-11-05 11:32:12.663 [PARTICIPANT Error] Problem creating associated Writer -> Function createPublisher
Traceback (most recent call last):
  File "/opt/ros/dashing/lib/demo_nodes_py/talker", line 11, in <module>
    load_entry_point('demo-nodes-py==0.7.9', 'console_scripts', 'talker')()
  File "/opt/ros/dashing/lib/python3.6/site-packages/demo_nodes_py/topics/talker.py", line 41, in main
    node = Talker()
  File "/opt/ros/dashing/lib/python3.6/site-packages/demo_nodes_py/topics/talker.py", line 24, in __init__
    super().__init__('talker')
  File "/opt/ros/dashing/lib/python3.6/site-packages/rclpy/node.py", line 152, in __init__
    node_name, namespace, self._context.handle, cli_args, use_global_arguments))
RuntimeError: Unknown error creating node: create_publisher() could not create publisher, at /tmp/binarydeb/ros-dashing-rmw-fastrtps-cpp-0.7.6/src/rmw_publisher.cpp:175, at /tmp/binarydeb/ros-dashing-rcl-0.7.7/src/rcl/publisher.c:171

Fix

The security keys depend on the DOMAIN_ID. Thus ROS_DOMAIN_ID has to be defined before creating the keys.

cd ~
mkdir -p store
export ROS_SECURITY_ROOT_DIRECTORY=~/store
export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce
export ROS_DOMAIN_ID=10
ros2 security create_keystore store
ros2 security create_key store /talker
ros2 run demo_nodes_cpp talker
# As well as the python node
ros2 run demo_nodes_py talker

Should services servers require both publish & subscribe access to own Request/Reply?

While developing on keymint, I attempted to use the same semantic access control profile that I had successfully used in ROS2 Ardent, with the addition of some new subsystem services such as set_parameters_atomically. However, this proved insufficient, and through closer inspection using RTI Connext Administration Console, I realised a new change in where ROS2 Bouncy nodes appear to be both publishing and subscribing to all of their own service level DDS topics:

image

IMO, this seem unwarranted given that a service server should not also require client level access, doing so would unecessarly widen the scope of the subject's (service host) access control policy and make it furtherly difficult to enforce asymmetric API access. If there is a good reason why this elevated access requirement for ROS service host has been introduced into Bouncy but was absent from Ardent, I'd be curious to know.

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • binaries
  • Version or commit hash:
    • ros-bouncy-sros2/bionic,now 0.5.0-0bionic.20180720.000732 amd64 [installed]
    • rti-connext-dds-5.3.1/bionic,bionic,now 5.3.1-nc.x64Linux3gcc5.4.0+2 amd64 [installed,automatic]
    • ros-bouncy-fastrtps/bionic,now 1.6.0-5bionic.20180719.223049 amd64 [installed]
  • DDS implementation:
    • rmw_connext_cpp
    • rmw_fastrtps_cpp
  • Client library (if applicable):
    • rclcpp

Steps to reproduce issue

Using the following symantec policy profile, I'd expect the granting the /talker node serving the service /talker/describe_parameters with execute permission would sufficient, i.e. permission to subscribe to Request and publish to Reply; as opposed to call permission, i.e. permission to publish to Request and subscribe to Reply.

Expected comarmor profile.xml
<?xml version="1.0" encoding="UTF-8"?>

<profiles xmlns:xi="http://www.w3.org/2001/XInclude">
    <profile name="My Talker Profile">
        <attachment>/talker</attachment>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/chatter</attachment>
            </attachments>
            <permissions>
                <ros_publish/>
            </permissions>
        </ros_topic>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/parameter_events</attachment>
            </attachments>
            <permissions>
                <ros_publish/>
                <ros_subscribe/>
            </permissions>
        </ros_topic>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/clock</attachment>
            </attachments>
            <permissions>
                <ros_subscribe/>
            </permissions>
        </ros_topic>

        <ros_service qualifier="ALLOW">
            <attachments>
                <attachment>/talker/describe_parameters</attachment>
                <attachment>/talker/get_parameter_types</attachment>
                <attachment>/talker/get_parameters</attachment>
                <attachment>/talker/list_parameters</attachment>
                <attachment>/talker/set_parameters</attachment>
                <attachment>/talker/set_parameters_atomically</attachment>
            </attachments>
            <permissions>
                <ros_execute/>
            </permissions>
        </ros_service>
    </profile>

    <profile name="My Listener Profile">
        <attachment>/listener</attachment>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/chatter</attachment>
            </attachments>
            <permissions>
                <ros_subscribe/>
            </permissions>
        </ros_topic>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/parameter_events</attachment>
            </attachments>
            <permissions>
                <ros_publish/>
                <ros_subscribe/>
            </permissions>
        </ros_topic>

        <ros_topic qualifier="ALLOW">
            <attachments>
                <attachment>/clock</attachment>
            </attachments>
            <permissions>
                <ros_subscribe/>
            </permissions>
        </ros_topic>

        <ros_service qualifier="ALLOW">
            <attachments>
                <attachment>/listener/describe_parameters</attachment>
                <attachment>/listener/get_parameter_types</attachment>
                <attachment>/listener/get_parameters</attachment>
                <attachment>/listener/list_parameters</attachment>
                <attachment>/listener/set_parameters</attachment>
                <attachment>/listener/set_parameters_atomically</attachment>
            </attachments>
            <permissions>
                <ros_execute/>
            </permissions>
        </ros_service>
    </profile>
</profiles>

See here for more of an detailed example: https://github.com/ruffsl/ros2_docker_demos/tree/master/sros2

Expected behavior

The following permission.xml is the expected minimally permission needed (using the comarmor profile from above), where publish access is granted to Reply topics and subscribe access is given to Request topics for a given service server.

Expected minimal permissions.xml
<?xml version="1.0" encoding="utf-8"?>
<dds>
  <permissions>
    <grant name="talker">
      <subject_name>CN=talker</subject_name>
      <validity>
        <not_before>2013-10-26T00:00:00</not_before>
        <not_after>2023-10-26T22:45:30</not_after>
      </validity>
      <allow_rule>
        <domains>
          <id>0</id>
        </domains>
        <publish>
          <topics>
            <topic>rt/chatter</topic>
            <topic>rt/parameter_events</topic>
            <topic>rr/talker/describe_parametersReply</topic>
            <topic>rr/talker/get_parameter_typesReply</topic>
            <topic>rr/talker/get_parametersReply</topic>
            <topic>rr/talker/list_parametersReply</topic>
            <topic>rr/talker/set_parametersReply</topic>
            <topic>rr/talker/set_parameters_atomicallyReply</topic>
          </topics>
        </publish>
        <subscribe>
          <topics>
            <topic>rt/parameter_events</topic>
            <topic>rt/clock</topic>
            <topic>rq/talker/describe_parametersRequest</topic>
            <topic>rq/talker/get_parameter_typesRequest</topic>
            <topic>rq/talker/get_parametersRequest</topic>
            <topic>rq/talker/list_parametersRequest</topic>
            <topic>rq/talker/set_parametersRequest</topic>
            <topic>rq/talker/set_parameters_atomicallyRequest</topic>
          </topics>
        </subscribe>
      </allow_rule>
      <default>DENY</default>
    </grant>
  </permissions>
</dds>

Actual behavior

The following permission.xml presently works when service Request/Reply topics are all given both publish and subscribe access.

Presently needed permissions.xml
<?xml version="1.0" encoding="utf-8"?>
<dds>
  <permissions>
    <grant name="talker">
      <subject_name>CN=talker</subject_name>
      <validity>
        <not_before>2013-10-26T00:00:00</not_before>
        <not_after>2023-10-26T22:45:30</not_after>
      </validity>
      <allow_rule>
        <domains>
          <id>0</id>
        </domains>
        <publish>
          <topics>
            <topic>rt/chatter</topic>
            <topic>rt/parameter_events</topic>
            <topic>rq/talker/describe_parametersRequest</topic>
            <topic>rq/talker/get_parameter_typesRequest</topic>
            <topic>rq/talker/get_parametersRequest</topic>
            <topic>rq/talker/list_parametersRequest</topic>
            <topic>rq/talker/set_parametersRequest</topic>
            <topic>rq/talker/set_parameters_atomicallyRequest</topic>
            <topic>rr/talker/describe_parametersReply</topic>
            <topic>rr/talker/get_parameter_typesReply</topic>
            <topic>rr/talker/get_parametersReply</topic>
            <topic>rr/talker/list_parametersReply</topic>
            <topic>rr/talker/set_parametersReply</topic>
            <topic>rr/talker/set_parameters_atomicallyReply</topic>
          </topics>
        </publish>
        <subscribe>
          <topics>
            <topic>rt/parameter_events</topic>
            <topic>rt/clock</topic>
            <topic>rr/talker/describe_parametersReply</topic>
            <topic>rr/talker/get_parameter_typesReply</topic>
            <topic>rr/talker/get_parametersReply</topic>
            <topic>rr/talker/list_parametersReply</topic>
            <topic>rr/talker/set_parametersReply</topic>
            <topic>rr/talker/set_parameters_atomicallyReply</topic>
            <topic>rq/talker/describe_parametersRequest</topic>
            <topic>rq/talker/get_parameter_typesRequest</topic>
            <topic>rq/talker/get_parametersRequest</topic>
            <topic>rq/talker/list_parametersRequest</topic>
            <topic>rq/talker/set_parametersRequest</topic>
            <topic>rq/talker/set_parameters_atomicallyRequest</topic>
          </topics>
        </subscribe>
      </allow_rule>
      <default>DENY</default>
    </grant>
  </permissions>
</dds>

Additional information

The DDS implementation rmw_fastrtps_cpp still appears to fail at runtime startup when using the same security artifacts that otherwise work fine with rmw_connext_cpp:

Update I tested this again in a container, and seems to be working like rmw_connext_cpp, so perhaps I've messed with rmw_fastrtps_cpp on my host install.

$ export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
$ ros2 run demo_nodes_cpp talker
[SECURITY Error] Error validating the local participant identity. () -> Function init
[RTPS_PARTICIPANT Error] Cannot create participant due to security initialization error -> Function createParticipant
[PARTICIPANT Error] Problem creating RTPSParticipant -> Function createParticipant
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  failed to initialize rcl node: create_node() could not create participant, at /tmp/binarydeb/ros-bouncy-rmw-fastrtps-cpp-0.5.1/src/rmw_node.cpp:91, at /tmp/binarydeb/ros-bouncy-rcl-0.5.1/src/rcl/node.c:336

Failure to create participant using rmw_connext_cpp

Bug report

Required Info:

Steps to reproduce issue

md C:\dev\sros2_demo
cd C:\dev\sros2_demo
set RANDFILE=C:\dev\sros2_demo\.rnd
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker
ros2 security create_key demo_keys listener
set ROS_SECURITY_ROOT_DIRECTORY=%cd%/demo_keys
set ROS_SECURITY_ENABLE=true
set ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_cpp talker

Expected behavior

talker should begin publishing

Actual behavior

>ros2 run demo_nodes_py talker
RTI Data Distribution Service Evaluation License issued to OSRF (OSRF01) [email protected] For non-production use only.
Expires on 5-Nov-2018 See www.rti.com for more information.
[CREATE Participant]RTIOsapiLibrary_open:error opening library nddssecurity.dll
[CREATE Participant]DDS_DomainParticipantTrustPlugins_initialize:!failed to load library
[CREATE Participant]DDS_DomainParticipant_createI:!create builtin trust plugins support
[CREATE Participant]DDS_DomainParticipantFactory_create_participant_disabledI:!create participant
DDSDomainParticipant_impl::create_disabledI:!create participant
DDSDomainParticipant_impl::createI:!create participant
DomainParticipantFactory_impl::create_participant():!create failure creating participant
Traceback (most recent call last):
  File "C:\dev\ros2-windows\lib\demo_nodes_py\talker-script.py", line 11, in <module>
    load_entry_point('demo-nodes-py==0.4.0', 'console_scripts', 'talker')()
  File "C:\dev\ros2-windows\Lib\site-packages\demo_nodes_py\topics\talker.py", line 46, in main
    node = Talker()
  File "C:\dev\ros2-windows\Lib\site-packages\demo_nodes_py\topics\talker.py", line 26, in __init__
    super().__init__('talker')
  File "C:\dev\ros2-windows\Lib\site-packages\rclpy\node.py", line 69, in __init__
    node_name, namespace, cli_args, use_global_arguments)
RuntimeError: Unknown error creating node: failed to create participant, at C:\J\workspace\packaging_windows\ws\src\ros2\rmw_connext\rmw_connext_shared_cpp\src\node.cpp:255, at C:\J\workspace\packaging_windows\ws\src\ros2\rcl\rcl\src\rcl\node.c:336

Additional information

Found while testing https://github.com/ros2/sros2/blob/master/SROS2_Windows.md

I'm not sure if security with connext is supposed to work on windows. The cell was originally grey'd out on the sheet, but the tutorial itself does mention setting RMW_IMPLEMENTATION to rmw_connext_cpp.

[sros2_cmake] generate_policy fails to provide policies for talker / listener

Bug report

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • from source
  • Version or commit hash:
    • crystal patch2 for all repos
    • master for sros2 (8165d7f)
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • rclpy

Steps to reproduce issue

Terminal 1

ros2 run demo_nodes_py talker

Terminal 2

ros2 run demo_nodes_py listener

Terminal 3
After the two nodes exchanged multiple messages (~30 seconds)

ros2 security generate_policy foo.xml

Expected behavior

foo.xml contains policies for the talker and listener nodes, including all default node rules + the chatter topic (publish for talker and subscribe for listener)

Actual behavior

foo.xml doesnt have any rules for the talker

<policy version="0.1.0">
  <profiles>
    <profile node="listener" ns="/">
      <services reply="ALLOW">
        <service>~describe_parameters</service>
        <service>~get_parameter_types</service>
        <service>~get_parameters</service>
        <service>~list_parameters</service>
        <service>~set_parameters</service>
        <service>~set_parameters_atomically</service>
      </services>
      <topics subscribe="ALLOW">
        <topic>chatter</topic>
      </topics>
      <topics publish="ALLOW">
        <topic>parameter_events</topic>
        <topic>rosout</topic>
      </topics>
    </profile>
    <profile node="talker" ns="/"/>
  </profiles>
</policy>

Additional information

ros2 node info provides the expected list of topics / services for the /talker node

# ros2 node info /talker 
/talker
  Subscribers:

  Publishers:
    /chatter: std_msgs/String
    /parameter_events: rcl_interfaces/ParameterEvent
    /rosout: rcl_interfaces/Log
  Services:
    /talker/describe_parameters: rcl_interfaces/DescribeParameters
    /talker/get_parameter_types: rcl_interfaces/GetParameterTypes
    /talker/get_parameters: rcl_interfaces/GetParameters
    /talker/list_parameters: rcl_interfaces/ListParameters
    /talker/set_parameters: rcl_interfaces/SetParameters
    /talker/set_parameters_atomically: rcl_interfaces/SetParametersAtomically

@ruffsl @ross-desmond @jacobperron FYI

Unnecessary `/` before node name in tutorial

Bug report

Required Info:

  • Operating System:
    • Ubuntu 16.04
  • Installation type:
    • Build from source
  • Version or commit hash:
    • 0.6.2
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • Doesn't apply

Steps to reproduce issue

While following the steps in the tutorial, I failed to execute these commands:

$ ros2 security create_key demo_keys /talker
Namespace( command='security',  verb='create_key', NAME='/talker', ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x7f8c8d1395c0>, _verb=<sros2.verb.create_key.CreateKeyVerb object at 0x7f8c8ce26ef0>)
bad character in requested key name: /talker

It'll succeed if I changed the last parameter(key name, aka ROS node name) to talker. Looks like the / is unnecessary.

ros2 security create_permission should abort when a policy file does not exist

Bug report

Required Info:

  • Operating System:
    • Windows 10
  • Installation type:
    • binaries
  • Version or commit hash:
    • Ardent patch 2
  • DDS implementation:
    • Fast-RTPS
  • Client library (if applicable):
    • N/A

Steps to reproduce issue

md C:\dev\ros2\sros2_demo
cd C:\dev\ros2\sros2_demo
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker
ros2 security create_permission demo_keys talker this_policy_file_does_not_exist.yaml

Expected behavior

ros2 security create_permission should refuse to continue if the policy file does not exist.

Actual behavior

The policy file is overwritten with permissions that allow everything. stdout from the command is indistinguishable from a run with a real policy file

create_key fails to create keystore (Crystal pre-release)

Bug report

Required Info:

Steps to reproduce issue

$ ros2 security create_key demo_keys listener                         
Namespace(NAME='listener', ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x7f0faa574b38>, _verb=<sros2.verb.create_key.CreateKeyVerb object at 0x7f0fa63d0550>, **{' command': 'security', ' verb': 'create_key'})
root path is not a valid keystore: demo_keys

Expected behavior

Command should be successful

Actual behavior

Command fails

Tutorial permissions not working

Bug report

Required Info:

  • Operating System:
    • Ubuntu Bionic
  • Installation type:
    • source
  • Version or commit hash:
  • DDS implementation:
    • N/A
  • Client library (if applicable):
    • N/A

Steps to reproduce issue

Follow the SROS2_Linux Tutorial until Access control section

or

$ docker run -it --rm ros:crystal
apt update && apt upgrade -y && apt install -y curl ros-crystal-demo-nodes-cpp ros-crystal-demo-nodes-py ros-crystal-sros2 
mkdir ~/sros2_demo && cd ~/sros2_demo
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker
ros2 security create_key demo_keys listener
curl -sk https://raw.githubusercontent.com/ros2/sros2/master/examples/sample_policy.yaml -o ./demo_keys/policies.yaml
ros2 security create_permission demo_keys talker demo_keys/policies.yaml

Expected behavior

Generate permission.xml files and be able to use access control

Actual behavior

Fails to create permission files.

Additional information

Error1
Traceback (most recent call last):
  File "/opt/ros/crystal/bin/ros2", line 11, in <module>
    load_entry_point('ros2cli==0.6.3', 'console_scripts', 'ros2')()
  File "/opt/ros/crystal/lib/python3.6/site-packages/ros2cli/cli.py", line 69, in main
    rc = extension.main(parser=parser, args=args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/command/security.py", line 37, in main
    return extension.main(args=args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/verb/create_permission.py", line 44, in main
    success = create_permission(args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/api/__init__.py", line 522, in create_permission
    permissions_dict = get_permissions(name, policy_file_path)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/api/__init__.py", line 500, in get_permissions
    return graph['nodes'][name]
KeyError: 'nodes'

Reason: the url https://raw.githubusercontent.com/ros2/sros2/master/examples/sample_policy.yaml is broken, the file is now at https://raw.githubusercontent.com/ros2/sros2/sros2/master/examples/sample_policy.yaml

Error2 (using the updated URL)
ros2 security create_permission demo_keys talker demo_keys/policies.yaml
Namespace(NAME='talker', POLICY_FILE_PATH='demo_keys/policies.yaml', ROOT='demo_keys', _command=<sros2.command.security.SecurityCommand object at 0x7f67d0927860>, _verb=<sros2.verb.create_permission.CreatePermissionVerb object at 0x7f67cbccbdd8>, **{' command': 'security', ' verb': 'create_permission'})
key_dir demo_keys/talker
while scanning a simple key
  in "demo_keys/policies.yaml", line 30, column 9
could not find expected ':'
  in "demo_keys/policies.yaml", line 31, column 7

The file is invalid yaml format.
The file is missing whitespaces line 30 and 36

Error3(using valid yaml file)
Traceback (most recent call last):
  File "/opt/ros/crystal/bin/ros2", line 11, in <module>
    load_entry_point('ros2cli==0.6.3', 'console_scripts', 'ros2')()
  File "/opt/ros/crystal/lib/python3.6/site-packages/ros2cli/cli.py", line 69, in main
    rc = extension.main(parser=parser, args=args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/command/security.py", line 37, in main
    return extension.main(args=args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/verb/create_permission.py", line 44, in main
    success = create_permission(args)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/api/__init__.py", line 524, in create_permission
    create_permission_file(permissions_path, name, domain_id, permissions_dict)
  File "/opt/ros/crystal/lib/python3.6/site-packages/sros2/api/__init__.py", line 425, in create_permission_file
    service_dict = permissions_dict['services']
KeyError: 'services'

@ross-desmond @jacobperron Is there another policy file to use for the Linux tutorial ?

I will try the code and tutorial from #72 to see if the issue is resolved with the xml version

Update
I got the tutorial working using #72 + #80

Use security enclaves

Feature request

Feature description

Tracking issue for changes started in #177.
Design document: ros2/design#274

Implementation considerations

  • Update policy schema with contexts (#177)
  • Update policy transforms for DDS (#177)
  • Update keystore layout with pubic, private, contexts sub folders (#177)
  • Update existing tests and downstream packages (#177)


  • Update policy auto generation (#203).
  • Make use of context name validation, instead of using namespace validation for it. Requires ros2/rclpy#528.
  • Update documentation (#201)
  • Support for metadata and type attribute
    • e.g. associating profiles to domains, validity times, singing CA
    • may need more thought, could look back at keymint for config patterns
  • Fix security directory lookup for '/' security contexts ros2/rcl#609
  • Add security context introspection ros2/rclpy#538

SROS2 leaks node information, regardless of rtps_protection_kind setup

Bug report

Connected to https://github.com/ros2/sros2/pull/171/files. After this patch one wold expect that node information isn't disclosed anymore but testing led to a different result. I'm not that experienced with sros2 at this point so I might be missing something? Ping to @mikaelarguedas and @ruffsl.

  • Operating System:
    • OS X 10.14.3
    • Ubuntu 18.04
  • Installation type:
    • from sources
  • Version or commit hash:
  • DDS implementation:
    • FastRTPS
  • Client library (if applicable):
    • rclpy

Steps to reproduce issue

Change defaults set rtps_protection_kind to encrypt and recreate keys.

https://asciinema.org/a/yuGkBlaPC33wqL4qABRlgxBkd

Expected behavior

Communications are encrypted for third parties (without credentials) in the network, node information isn't disclosed.

Actual behavior

Node information is still disclosed. Even after applying https://github.com/ros2/sros2/pull/171/files , rebuilding sros2 and regenerating the keys.

Additional information

Auto generation interface for Access Control Profiles

Formulating access control profiles for large or complex ROS applications that satisfy principles of least privilege is at a present manual endeavor for robotics. Given the tedium of such tasks and the rigor it demands to be fully effective, instances of human error become both more probable and problematic; as accidental over provisioning of permissions presents issues in system security, while under provisioning may similarly effect system stability.

To ease the development of complete and correct access control, automated tooling for profile generation must be developed. Such tooling could consume system measurements such as security event logs or discovery traffic to assist in accurately profiling all permissions required. Subsequently, the acquired permission model could then be exported into profile formats used in SROS2 keystore tooling; e.g. a CLI exposing an interactive session for amending work-in-progress profiles by prompting the user about discrepancies between the existing xml policy file vs. the acquired model.


Background

SROS1 provides a varying degree of run-time modes, including audit, enforce and complain, again borrowing feature designs from AppArmor. This provides developers a method to auto generate, or amend profiles through granular logging of access events and violation attempts.

“SROS1: Using and Developing Secure ROS1 Systems”
https://doi.org/10.1007/978-3-319-91590-6_11

Auto generation of profiles was used in SROS1 to simplify the bootstrapping process for enabling fine-grained API access control over ROS1. As ROS1 was centralized with respect to the master node, roscore was extended to support several run-time modes; specifically an audit mode that could amend any work-in-progress profile to include missing permission for API accesses observed during training time. This profile was then used in conjunction with a keyserver process the provisioned the certificates and tokens in keystore accordingly.

Security of robotics systems, as well as of the related middleware infrastructures, is a critical issue for industrial and domestic IoT, and it needs to be continuously assessed throughout the whole development lifecycle... In this work, we introduce a framework for procedural provisioning access control policies for robotic software, as well as for verifying the compliance of generated transport artifacts and decision point implementations.

“Procedurally Provisioned Access Control for Robotic Systems”
https://doi.org/10.1109/IROS.2018.8594462

In later work, some of this bootstrapping was reproduced for ROS2 to assist in the automation for the verification and testing of security artifacts used for secure transports. Specifically, given decentralized networking of ROS2 with DDS, observed discovery traffic during training time was substituted to train the model of necessary API permission.

Both approaches made efforts to streamline and fortify access control development via greater automation. The future works of both also detail areas of improvement in regards to developer interfaces, citing AppArmor aa-genprof CLI as a particularly useful example tool pattern to adopt for ROS policy development.

The aa-genprof utility is CLI that provides users with an interactive session to create and/or amend application security profiles. By running an application in audit mode, aa-genprof sequently prompts the user on each new and unaccounted security issue such as missing permissions or policy imports by displaying both the observed security violation in concert with the appropriate excerpt in the present profile along with several choices of applicable amendments to resolve or ignore the violation. I’d recommend trying out the utility yourself to get a better feel for the profile development workflow.

http://manpages.ubuntu.com/manpages/bionic/man8/aa-genprof.8.html

Similarly, the aa-logprof utility provides a equivalent and consistent interface for using event measurements from log files rather than a running audit mode process:

http://manpages.ubuntu.com/manpages/bionic/man8/aa-logprof.8.html

Screen capture of aa-logprof

$ sudo aa-logprof
Reading log entries from /var/log/syslog.
Updating AppArmor profiles in /etc/apparmor.d.
Complain-mode changes:

Profile:     ros/rosmaster
Access mode: receive
Signal:      int
Peer:        ros/roslaunch

 [1 - signal receive set=int peer=ros/roslaunch,]
(A)llow / [(D)eny] / (I)gnore / Audi(t) / Abo(r)t / (F)inish
Adding signal receive set=int peer=ros/roslaunch, to profile.

...

= Changed Local Profiles =

The following local profiles were changed. Would you like to save them?

 [1 - ros/rosout]
  2 - ros/talker_listener_py 
  3 - ros/rosmaster 
(S)ave Changes / Save Selec(t)ed Profile 
[(V)iew Changes] View Changes b/w / (C)lean profiles / Abo(r)t
Writing updated profile for ros/rosmaster.
Writing updated profile for ros/rosout.
Writing updated profile for ros/talker_listener_py.

Progress

With the addition of the new policy markup format in #72 , it is now redeadly simple to write composable sub profiles. Using XInclude schema in XML, profiles and permission may be broken into separate files for reuse or versioning and subsequently imported as needed. This allows for sharing of common permission primitives across different node profiles, reducing the chances of duplicated errors or divergent policy behaviors.

For automated tools to appropriately amend or constructively suggest changes to policies under audit, the underlying structure of the composed profiles must be conveyed. Parsers supporting XInclude can reconstruct the entire DOM of the policy, along with annotations of expanded includes via xml:base denoting the relative URI imported. Thus for instances where promoted feedback from the user necessitates alterations to a nested permission or profile, the tool may trace back the URI to determine the files to modify.

Original policy file

<?xml version="1.0" encoding="UTF-8"?>
<policy version="0.1.0"
  xmlns:xi="http://www.w3.org/2001/XInclude">
  <profiles>
    <profile ns="/" node="talker">
      <xi:include href="common/node.xml"
        xpointer="xpointer(/profile/*)"/>
      <topics publish="ALLOW" >
        <topic>chatter</topic>
      </topics>
    </profile>
</policy>

Expanded policy DOM

<policy version="0.1.0">
  <profiles>
    <profile node="talker" ns="/">
      <services reply="ALLOW" xml:base="common/node/parameters.xml">
        <service>~describe_parameters</service>
        <service>~get_parameter_types</service>
        <service>~get_parameters</service>
        <service>~list_parameters</service>
        <service>~set_parameters</service>
        <service>~set_parameters_atomically</service>
      </services>
      <topics subscribe="ALLOW" xml:base="common/node/parameters.xml">
        <topic>parameter_events</topic>
      </topics>
      <topics publish="ALLOW" xml:base="common/node/parameters.xml">
        <topic>parameter_events</topic>
      </topics>
      <topics publish="ALLOW" xml:base="common/node/log.xml">
        <topic>rosout</topic>
      </topics>
      <topics subscribe="ALLOW" xml:base="common/node/time.xml">
        <topic>clock</topic>
      </topics>
      <topics publish="ALLOW">
        <topic>chatter</topic>
      </topics>
    </profile>
  </profiles>
</policy>

For the interactive interface and generation API, we could probably start by taking a look at AppArmor code base for the same respective utilities, as they are simalay written in python. However, given the custom markup for AppArmor profile language, the library design exhibits a number of quirks to accommodate the less structured format. Still, I’d like to replicate the CLI frontend experience, or at least abstract the API to support equivalent GUI tools as well.

https://gitlab.com/apparmor/apparmor/tree/master/utils/apparmor

Example CLI interface

$ ros2 security logprof
Reading log entries from /home/user/.ros/log/
Updating SROS profiles in /home/user/.ros/sros.d/
Complain-mode changes:

Profile:     ros/wheatley
Access mode: publish
Topic:       /chatter/foo


 [1 - topic /chatter/foo p,]
(A)llow / [(D)eny] / (I)gnore / Audi(t) / Abo(r)t / (F)inish

Adding topic to profile:
<topics publish="ALLOW">
  <topic>/chatter/foo</topic>
</topics>

...

= Changed Local Profiles =

The following local profiles were changed. Would you like to save them?

 [1 - ros/wheatley]
  2 - ros/listener 
  3 - ros/navigation2 
(S)ave Changes / Save Selec(t)ed Profile 
[(V)iew Changes] View Changes b/w / (C)lean profiles / Abo(r)t
Writing updated profile for ros/listener.
Writing updated profile for ros/navigation2.
Writing updated profile for ros/wheatley.

Finally, with respect to measurements for permission modeling, the acquisition of which has proposed in #110 via Integration with DDS Security builtin logging plugin. However, supporting additional measurements source alternative to log events, such as DDS discovery data mentioned above, may prove much quicker to implement. For example, in the Procedurally Provisioned Access Control publication above, this was done simply via an XML transform between RTI Connext DDS discovery export format to SROS2 policy file.

Node crashes without showing an error message

Bug report

Required Info:

Steps to reproduce issue

Follow https://github.com/ros2/sros2/blob/master/SROS2_Windows.md tutorial.
After having configuring the command prompt for using security (with or without Authentication), run any other example not related to talker/listener. e.g.:

ros2 run intra_process_demo cyclic_pipeline

Expected behavior

It should show a nice error.

Actual behavior

It's finished without saying nothing.

Additional information

Doing echo %errorlevel% returns -1.
I don't know if this is the known behavior of it's a bug.
If it's known, it would be nice to at least show an error message.

Minimal permission set for a talker and listener pair in the demo_cpp example

I'm trying to determine the minimal set of permissions for a talker and listener pair in the demo_cpp example in order to evaluate keymint's provisioning of permissions. I've checked the discovery data, and I looks like I've added everything they'd need in the permissions document, but apparently I've missed something the client library is needing, as this inevitably causes the failure in creating the DDS participant.

Bug report

Required Info:

  • Operating System:
    • Ubuntu 16.04
  • Installation type:
  • Version or commit hash:
  • DDS implementation:
    • RTI Connext
  • Client library (if applicable):
    • rclcpp

Steps to reproduce issue

I've made a simple example that can quickly be create using keymint_tools. See the example section in the repo README for more details: https://github.com/keymint/keymint_tools#example

You can also find the resulting keystore here: https://github.com/ruffsl/keymint_ws/tree/7783f87783e27efcee80be7f6189ded1bce5869e
For example. here is the permissions file for the talker before signing:
https://github.com/ruffsl/keymint_ws/blob/7783f87783e27efcee80be7f6189ded1bce5869e/build/talker/permissions.xml

Expected behavior

From looking at the discovery data, we can collect the number of resources advertised. I'd expect collpacing this back down into the permissions files would be sufficient, but perhaps there are some requested resources from the client library to the dds vender that are not being advertised during a non-secure session, or are not captured by my DDS session monitor under secure sessions without access control.

For good measure, one can simple add this XML snippet to the beginning of the allow_rule for the grant specific to the node within the keymint package source, then rebuild the keymint package and all will work as expected. However, this use of wildcarding nullifies what we are trying to achieve here.

                <publish>
                    <topics>
                        <topic>*</topic>
                    </topics>
                    <partitions>
                        <partition>*</partition>
                    </partitions>
                </publish>
                <subscribe>
                    <topics>
                        <topic>*</topic>
                    </topics>
                    <partitions>
                        <partition>*</partition>
                    </partitions>
                </subscribe>

Actual behavior

If attempting to use the keystore files as is, you'll get this error noting the creation of the participant has failed due to the RTI_Security_AccessControl_check_create_datawriter:endpoint recognizing that the policy is insufficient for resources requested by the client library.

$ ros2 run demo_nodes_cpp talker
RTI_Security_AccessControl_check_create_datawriter:endpoint not allowed: no rule found; default DENY
DDS_DomainParticipantTrustPlugins_getLocalDataWriterSecurityState:!security function check_create_datawriter
DDS_DataWriter_create_presentation_writerI:ERROR: Failed to get local datawriter security state
DDS_DataWriter_createI:!create PRESPsWriter
DDS_Publisher_create_datawriter_disabledI:!create DataWriter
DDSDataWriter_impl::createI:!create writer
initialize:!create DataWriter
connext::details::EntityUntypedImpl::initialize:!failed (see previous errors)

>>> [rcutils|error_handling.c:155] rcutils_set_error_state()
This error state is being overwritten:

  'C++ exception during construction of Requester, at /home/ruffsl/ws/ros2/ardent/build_isolated/rcl_interfaces/rosidl_typesupport_connext_cpp/rcl_interfaces/srv/dds_connext/get_parameters__type_support.cpp:98'

with this new error message:

  'failed to create requester, at /home/ruffsl/ws/ros2/ardent/src/ros2/rmw_connext/rmw_connext_cpp/src/rmw_client.cpp:139'

rcutils_reset_error() should be called after error handling to avoid this.
<<<
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  could not create client: failed to create requester, at /home/ruffsl/ws/ros2/ardent/src/ros2/rmw_connext/rmw_connext_cpp/src/rmw_client.cpp:139, at /home/ruffsl/ws/ros2/ardent/src/ros2/rcl/rcl/src/rcl/client.c:152

Additional information

Here is a record of the decoverydata captured for the talker listener cpp demo. I've provided a simple script to collapse the topics and partitions access by each participant for clarity. The resources listed are what I've incorporated into the minimal permissions keystore example linked above.

https://gist.github.com/ruffsl/d914f68342f616c361d7f44b7332e6ae

It would be nice if the error message return some context for the failed creation of the participant.
E.g. what resources were attempted before failure, and which specifically resulted in insufficient privileges.

Should nodes crash when it tries to access a resource it doesn't have permission to use?

Feature request

Inspired by #57

Feature description

This may seem silly, but let me ask: Should users always expect a ROS2 node to crash when it tries to access a topic, service, or etc. that is has insufficient permissions for? I guess one might see the act of not fatally crashing as a dangerous case of a silent failure, but I was thinking that trying to recover and issuing a error/warning could be beneficial for a few reasons:

  • Facilitate more feedback about insufficient premissioning:
    • This would allow the node to issue more warnings about other permission related issues, rather than just crashing after the first among many left to encounter during startup. An example use case: log all errors/warnings after a practice run to use for later when fixing/updating access control policies.
  • Intentionally revoke partial access to specific resources
    • When using a public binary package, the user may have good reason to not provide all permissions first requested by the node. Either the user knows the requested permission to be superfluous and not applicable to the rest of the system, or wishes to isolate or avoid the node from interacting with the system is such a way. Necessitating an all-or-nothing permission model might be too inflexible, much like Android's older app permission dialogs.

Implementation considerations

Perhaps something like an audit mode like in AppArmor audit mode could be set through the runtime envoirment, allowing the rcl layer to negotate how to proceed, and weather to just give the application a fake handeler of what it requested given the DDS security layer errored on the datawriter/reader inilization call. Perhaps this might be technically impractical, or resulting ill defined behavior undesirable.

Guard against creating keys for empty and whitespace only names

Bug report

Required Info:

  • Operating System:
    • Ubuntu 18.04
  • Installation type:
    • Debian pkgs
  • Version or commit hash:
    • 0.7.0
  • DDS implementation:
    • Connext
  • Client library (if applicable):
    • N/A

Steps to reproduce issue

Create a keystore:

ros2 security create_keystore /tmp/ks

Try creating a key with an empty name:

ros2 security create_key /tmp/ks /

Try creating a key with a name containing only whitespace

ros2 security create_key /tmp/ks "/ "

Expected behavior

Graceful error messages in both cases.

Actual behavior

The empty name results in the following output:

creating key for identity: '/'
Traceback (most recent call last):
  File "/opt/ros/dashing/bin/ros2", line 11, in <module>
    load_entry_point('ros2cli==0.7.0', 'console_scripts', 'ros2')()
  File "/opt/ros/dashing/lib/python3.6/site-packages/ros2cli/cli.py", line 69, in main
    rc = extension.main(parser=parser, args=args)
  File "/opt/ros/dashing/lib/python3.6/site-packages/sros2/command/security.py", line 37, in main
    return extension.main(args=args)
  File "/opt/ros/dashing/lib/python3.6/site-packages/sros2/verb/create_key.py", line 34, in main
    success = create_key(args.ROOT, args.NAME)
  File "/opt/ros/dashing/lib/python3.6/site-packages/sros2/api/__init__.py", line 439, in create_key
    shutil.copyfile(keystore_governance_path, dest_governance_path)
  File "/usr/lib/python3.6/shutil.py", line 104, in copyfile
    raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
shutil.SameFileError: '/tmp/ks/governance.p7s' and '/tmp/ks/./governance.p7s' are the same file

The whitespace name succeeds. I don't think this should be a valid name.

Bionic: FastRTPS security tests fail

On Bionic default openssl/libssl is 1.1.0:

With Connext

no support for 1.1.0 so we need to install custom version of 1.0.2 provided by RTI

With FastRTPS: it fails with "Invalid CA error".

Combinations tested:

  • ca generated with 1.0.2(used in the tests) and fastrtps using SSL 1.1.0 runtime libs: fail
  • ca generated with 1.1.0 and fastrtps using SSL 1.1.0 runtime libs: fail
  • manually remove openssl/libssl 1.1.0 and install libssl and openssl 1.0.2 and generate certificates by hand: WORKS

Path forward

As I don't see forcing the use of openssl 1.0.2 as a viable path forward for bionic (as it conflicts with the system one and will force people to uninstall a ton of stuff), we need to figure out how to tweak certificate and key generation in sros2 to allow that use case.
A lead to explore is that is looks that our certificates are SSLv1 and fail, certs used in Fast-RTPS testing are SSLv3 and pass.

related to ros2/ros2#481

What does distribute_key do?

Calling ros2 security distribute_key demo_keys output.fastrtps.keystore on windows 10 results in no output on stdout. I'm not sure what it does. Guessing from the help text, I might expect that the result is a file named output.fastrtps.keystore which contains previously created keys, but I don't see any new files.

problem with ros2cli

I just setup the latest ros2.repos on my Windows desktop at home and when I run an unrelated ros2cli command I get an error from the create_permission verb in this repository:

C:\Windows\System32>ros2 topic list
Traceback (most recent call last):
  File "C:\dev\ros2\install\bin\ros2-script.py", line 11, in <module>
    load_entry_point('ros2cli==0.0.0', 'console_scripts', 'ros2')()
  File "C:\dev\ros2\install\Lib\site-packages\ros2cli\cli.py", line 44, in main
    hide_extensions=['extension_points', 'extensions'])
  File "C:\dev\ros2\install\Lib\site-packages\ros2cli\command\__init__.py", line 111, in add_subparsers
    command_parser, '{cli_name} {name}'.format_map(locals()))
  File "C:\dev\ros2\install\Lib\site-packages\sros2\command\security.py", line 26, in add_arguments
    add_subparsers(parser, cli_name, '_verb', verb_extensions)
  File "C:\dev\ros2\install\Lib\site-packages\ros2cli\command\__init__.py", line 111, in add_subparsers
    command_parser, '{cli_name} {name}'.format_map(locals()))
  File "C:\dev\ros2\install\Lib\site-packages\sros2\verb\create_permission.py", line 40, in add_arguments
    allowednames=('yaml'), directories=False)
TypeError: FilesCompleter() got an unexpected keyword argument 'allowednames'

test_generate_policy fails on Windows

Bug report

Required Info:

  • Operating System:
    • Windows
  • Installation type:
    • source
  • Version or commit hash:
    • master

The test was introduced in #122.

It has been consistently failing the nightly Windows debug and release builds, e.g.

Output:

Error Message
AssertionError: assert 0 != 0  +  where 0 = <function main at 0x000002670D3A3C80>(argv=['security', 'generate_policy', 'C:\\WINDOWS\\TEMP\\tmpwsfvjedi\\test-policy.xml'])  +    where <function main at 0x000002670D3A3C80> = cli.main
Stacktrace
test\sros2\commands\security\verbs\test_generate_policy.py:67: in test_generate_policy_no_nodes
    assert cli.main(argv=[
E   AssertionError: assert 0 != 0
E    +  where 0 = <function main at 0x000002670D3A3C80>(argv=['security', 'generate_policy', 'C:\\WINDOWS\\TEMP\\tmpwsfvjedi\\test-policy.xml'])
E    +    where <function main at 0x000002670D3A3C80> = cli.main

What are the default settings for access control? Seems to allow all by default.

On a windows 10 binary installation using https://ci.ros2.org/view/packaging/job/packaging_windows/1043/ it looks like a listener who's access control policy has not been set is able to listen to a talker whos access policy has been set. I'm wondering if this is the expected behavior. I would have thought the default would be to restrict access to a topic

REM Create keys and policy for talker / listener
ros2 security create_keystore demo_keys
ros2 security create_key demo_keys talker
ros2 security create_key demo_keys listener
ros2 security create_permission demo_keys talker demo_keys/policies.yaml
REM did not create permissions for listener
REM ros2 security create_permission demo_keys listener demo_keys/policies.yaml

REM run talker where current directory is sros2_demo
set ROS_SECURITY_ROOT_DIRECTORY=%cd%/demo_keys
set ROS_SECURITY_ENABLE=true
set ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_cpp talker

REM in another terminal run the listener
set ROS_SECURITY_ROOT_DIRECTORY=%cd%/demo_keys
set ROS_SECURITY_ENABLE=true
set ROS_SECURITY_STRATEGY=Enforce
ros2 run demo_nodes_py listener

REM the listener receives messages from the talker. Is the default policy to allow all communication?

Request service permissions should be included in generated policies

Feature request

Opening this ticket for feedback on the approach before starting implementation

Feature description

Improve the generate_policy verb to ensure service permissions for request are accounted for.

Context:

As mentioned in #91 (review) , policy files that auto generated by the generate_policy verb do not provision sufficient permissions for services, and instead only provision reply permissions when determined necessary via quiring the ros2 graph API.

Problems it will solve:
  • Startime failures: nodes may otherwise crash at runtime when failing to initialize a client due to insufficient privileges.
  • Runtime failures: nodes may also fail when remote servers refuse to accept requests from initialized client interfaces

Implementation considerations

This derives from the fact that the present ros2 graph API does not provide an interface to query for what services a node is assuming the client role. Although expanding the ros2 graph API could resolve this absence of information, in general a larger issue remains in that client interfaces may be temporally created, and thus harder to observe via a singular snapshot observation of the graph's current state. Alternate methods for modeling access control policies, such as inferring requirements from log event files like in AppArmor, could prove more complete in generating sufficient permissions for a target application.

Any feedback on the approach will be very appreciated :)

[documentation] Update documentation to use security with connext

follow-up of #16
Now that Connext 5.3 ships with security plugins and is tested on all platform we should update (or merge?) the readmes for each platform.
We should also remember to highlight that on MacOS, the location of the openssl libraries has to be appended to the DYLD_LIBRARY_PATH

SROS2 documentation and design documents

Are there any design documents or documentation files about SROS2? I am able to follow the tutorials, but I do not understand how is that what I am doing enables secure communication between topics. For example, the first part of the tutorial makes me set

export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce

However, what would happen if I set ROS_SECURITY_STRATEGY, but I set ROS_SECURITY_STRATEGY=false? What are the other option values of the latter environmental variable?

Another example. After completing the first part of the tutorial, it says

These nodes will be communicating using authentication and encryption!

What exactly enabled authentication between the nodes? What enabled message encryption? Is the topic encrypted? How can I enable only authentication and not encryption?

Nodes should consider FQN path when searching for own secure root

Nodes should expand node_secure_root using local_namespace so that unique secure configuration files in the secure root directory may be passed to namespaced nodes. Given namespacing often necessitates special modification to security credentials, a node with a alternate namespace may not inherently be capable of reusing security credentials with another node of the same name.

E.g.
Nodes /talker and /foo/talker may require require separate security permission given one may published to /chatter and the other to /foo/chatter; not to mention the additional sub system topics and services that may be affected by the namespace prefixing.

Tentative workaround:
ruffsl/rcl#1

If this sounds reasonable, I could clean up and PR my patches above.

Install and register policy files via ament_index

It would be convenient to have CMake infrastructure for installing SROS policy files for a given package that could then be discovered by other packages for use as part of their security policy.

I would envision that this would include installing the policy files to some known location (probably the package share directory), and then registering those policies with the ament_index.

Provide some granularity for individual topic protection

Feature request

Feature description

While DDS allows to pick any protection kind for the topics and associated discovery, it is currently not exposed by sros2 that uses a static governance file. Currently all data / discovery / liveliness is encrypted by default.
Generating the governance file at the same time as generating the permission files would allow to pick the type of protection desired on a per-topic basis.

Implementation considerations

Modifying the SROS2 policy format to take an extra attribute protection for each topic/service/action list would allow to specify that information and leverage it to generate governance topic rules accordingly.
Then create a governance.xsl template that would create an governance file with a TopicRule for each topic specified in the policy.

Trade-offs:

Providing full granularity of the governance parameters will be cumbersome and complex for maintainers to support and for users to use. At which point writing it by hand may be easier. The goal here would be to allow users to specify the protection of their topic in the high level policy file and generate a consistent set of governance/permission.
Example of node configuration:

  • use some signed topics
  • use some encrypted topics
  • only authenticated nodes
  • signed metatraffic (see below)

Some parameters apply to the participant globally and will impact the usefulness of setting other parameters on a per topic basis, some specific use-cases to explore (very sparse list):

  • if a node/participant has any non-encrypted topics:
    • setting rtps_protection_kind to ENCRYPT, would require the node to perform heavy cryptographic operations for all the rtps traffic. -> keeping the default as SIGN
    • If meta-traffic is encrypted (discovery / liveliness) the node needs to perform heavy operation as well: change the default to SIGN for all nodes?

This is a draft to gather initial feedback, if the approach seems sensible, the use cases to consider and trade-offs can be expanded later on.

Example of policy and governance files

Policy:

<policy version="0.1.0"
  xmlns:xi="http://www.w3.org/2001/XInclude">
  <profiles>
    <profile ns="/" node="admin">
      <xi:include href="common/node.xml"
        xpointer="xpointer(/profile/*)"/>
      <actions call="ALLOW" execute="ALLOW">
        <action>fibonacci</action>
      </actions>
      <services reply="ALLOW" request="ALLOW" protection="SIGN">
        <service>add_two_ints</service>
      </services>
      <topics publish="ALLOW" subscribe="ALLOW" protection="ENCRYPT">
        <topic>chatter</topic>
      </topics>
    </profile>
  </profiles>
</policy>

Governance:

<?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/20170901/omg_shared_ca_governance.xsd">
    <domain_access_rules>
        <domain_rule>
            <domains>
              <id>0</id>
            </domains>
            <allow_unauthenticated_participants>false</allow_unauthenticated_participants>
            <enable_join_access_control>true</enable_join_access_control>
            <discovery_protection_kind>SIGN</discovery_protection_kind>
            <liveliness_protection_kind>SIGN</liveliness_protection_kind>
            <rtps_protection_kind>SIGN</rtps_protection_kind>
            <topic_access_rules>
                <topic_rule>
                    <topic_expression>rt/chatter</topic_expression>
                    <enable_discovery_protection>true</enable_discovery_protection>
                    <enable_liveliness_protection>true</enable_liveliness_protection>
                    <enable_read_access_control>true</enable_read_access_control>
                    <enable_write_access_control>true</enable_write_access_control>
                    <metadata_protection_kind>SIGN</metadata_protection_kind>
                    <data_protection_kind>ENCRYPT</data_protection_kind>
                </topic_rule>
                <topic_rule>
                    <topic_expression>rq/add_two_ints_Request</topic_expression>
                    <enable_discovery_protection>true</enable_discovery_protection>
                    <enable_liveliness_protection>true</enable_liveliness_protection>
                    <enable_read_access_control>true</enable_read_access_control>
                    <enable_write_access_control>true</enable_write_access_control>
                    <metadata_protection_kind>SIGN</metadata_protection_kind>
                    <data_protection_kind>SIGN</data_protection_kind>
                </topic_rule>
                <topic_rule>
                    <topic_expression>rr/add_two_ints_Reply</topic_expression>
                    <enable_discovery_protection>true</enable_discovery_protection>
                    <enable_liveliness_protection>true</enable_liveliness_protection>
                    <enable_read_access_control>true</enable_read_access_control>
                    <enable_write_access_control>true</enable_write_access_control>
                    <metadata_protection_kind>SIGN</metadata_protection_kind>
                    <data_protection_kind>SIGN</data_protection_kind>
                </topic_rule>
                <topic_rule>
                    <topic_expression>*</topic_expression>
                    <enable_discovery_protection>true</enable_discovery_protection>
                    <enable_liveliness_protection>true</enable_liveliness_protection>
                    <enable_read_access_control>true</enable_read_access_control>
                    <enable_write_access_control>true</enable_write_access_control>
                    <metadata_protection_kind>SIGN</metadata_protection_kind>
                    <data_protection_kind>SIGN</data_protection_kind>
                </topic_rule>
            </topic_access_rules>
        </domain_rule>
    </domain_access_rules>
</dds>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.