design icon indicating copy to clipboard operation
design copied to clipboard

Security | Access Control Policy Format

Open ruffsl opened this issue 6 years ago • 3 comments

This issue serves to track ideas for specifying the policy format to be used for access control in SROS2. Ideally this specification should be extensible enough to convey all necessary permissions or access rights, say in a traditional access control matrix where the rows are subjects/users (i.e., nodes), the columns are objects/resources (i.e., topics, services, parameters). Additionally, it would be advantageous if the format translated easily to metafiles used by other secure middleware transports (i.e., DDS Secure's builtin plugins), but is not necessarily too confirmative to inhibit being a common format among transports vinders.

Some ideal qualities for such a format may also include:

  • human readable
    • format should be clear and concise
    • otherwise may prove difficult to audit or debug
  • machine parsable
    • consumable for metafile auto generation
    • importing and exporting should preserve original structure
  • expressive power
    • suitable for defining all fundamental SROS2 governance
    • capable of extension for future security transport plugins

Additional, there are some aspects of the standard we may wish to decide on as well:

  • file format
    • what text based structure should be used (e.g., JSON, XML, YAML, custom)
  • regular expressions
    • how should alias or globbing be permitted (e.g., POSIX, Regex, AppArmor, other)
  • templating
    • should the format support any arbitrary tempting (e.g., via empy, jinja)

ruffsl avatar Sep 02 '17 06:09 ruffsl

To kick start off on my own questions, I'd like to bring up some previous ideas from SROS1.

During the initial development of SROS1, I started creating an Apparmor Profile Library for ROS, as well a few base examples in it use for adding Mandatory Access Control to ROS's process runtime:

Example Apparmor Policy Profile for ROS

#include <tunables/global>
#include <tunables/ros>

/opt/ros/kinetic/bin/rosmaster {
  #include <ros/base>
  #include <ros/node>
  #include <ros/python>

  @{ROS_INSTALL_BIN}/rosmaster rix,
}

/opt/ros/kinetic/share/rospy_tutorials/001_talker_listener/listener.py {
  #include <ros/base>
  #include <ros/node>
  #include <ros/python>

  @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/listener.py r,
}

/opt/ros/kinetic/share/rospy_tutorials/001_talker_listener/talker.py {
  #include <ros/base>
  #include <ros/node>
  #include <ros/python>

  @{ROS_INSTALL_SHARE}/rospy_tutorials/001_talker_listener/talker.py r,
}

Some aspects about the Apparmor syntax I like are:

  • Supports MAC
    • Permissions are explicit
  • Path Globbing
    • To define scopes
  • Importing
    • #include rules for reuse
  • Parsable format
    • Help autogenerate profiles
  • Human readable
    • Auditing & debugging clarity

The file format for Apparmor Policy Profiles has its own style, and so it's own custom parser, but I think translates fairly well:

Example SROS policy syntax

#include global_rule
/namespace
{
  #include local_role
  resource /scope masks
}

Such a syntax incorporates few nice properties:

  • Profiles are applied to node Namespaces
  • Namespace matched nodes incur those Profiles
  • Profiles are composed of resource access Rules
  • Rules specify resource type, scope, role, and permissions the policy allows or denies

So for ROS1 or ROS2, the number of applicable masks could include:

Resource Mask Permission
Parameters r Read
Parameters w Write
Topics s Subscribe
Topics p Publish
Services c Call
Services x Execute

Given these, an SROS policy profile for a node named:

  • wheatley
  • wheatley/apple

permits read access to the parameter:

  • /use_sim_time,

permits publishing to topics like:

  • /chatter
  • /chatter42
  • /chatter/apple

permits executing the services:

  • /wheatley/get_loggers
  • /wheatley/set_logger_level

but denies everything else,
explicitly including the publishing of topics:

  • /chatter/foo
  • or anything ending with e-stop

Example SROS policy profile

#include <ros/system>
/wheatley{,/apple}
{
  #include <ros/node>
  param /use_sim_time r,
  topic /chatter{,/**} p,
  deny topic /chatter/foo p,
  deny topic /**/e-stop p,
  service /wheatley/get_loggers x,
  service /wheatley/set_logger_level x,
}

In the above example we can see:

  • Resource types make a rule explicit to a specific resource
  • Scope defines the globbing namespace for the permission
  • Permissions are specified via masks, masks are also resource explicit
  • Deny is used to revoke permissions, superseding any applicable allow

Some related issues I see with this includes:

  • Custom Parser
    • We'd need to somewhat fork components of Apparmor's parser
    • Luckily Apparmor ships with this in its system python library
  • Globing
    • SROS1 used namespace globing for both nodes and resources
    • This worked by embedding the expanded regex into the metafiles
    • However DDS Security only supports POSIX so resource strings are restricted
  • Namespacing
    • ROS2 namespace syntax supports resource definitions
    • E.g. rostopic:///foo/bar
    • perhaps separate resource arg in rule line is redundant?
    • and explicit omission of resource could enable shorthand masking
    • E.g. /wheatley/** rwspcx
    • but that might also make auditing not as straight forward
  • Imports
    • Not sure how global or local imports should interact?
    • local imported rules could be appended
    • could there be functionality to support context substitution?
    • E.g. syntax to perpend local rule with the node namespace matched by policy expression
  • Translation
    • Generating metafiles for plugins may desire additional context
    • Plugins like those built in DDS Security
    • I.e. what topics should be encrypted, or only signed?
    • This might be more of a workflow issue

ruffsl avatar Sep 02 '17 06:09 ruffsl

After having a chat with @ZJohnny offline, I think we've come up with a few more refined ideas about some related issues I mentioned in my previous post.

For imports, apparmor merely adds to the subset of rules applied within the scope. I think this is quite intuitive and I see no immediate issue maintaining this behavior in SROS as well.

For inheriting context, this may be specifically useful in the case where a user would like to succinctly describe a permission in relation to the namespace of the affected node. For the SROS policy syntax, the plan so far is to bind subjects/nodes to policies that restrict access to objects/resources. This is done by globbing the node namespace to define the scope of the policy. This policy profile is eventually fully expanded before embedding it into the various metafiles used by the specific vendor or transport. So during this expansion process, we resolve the relative paths.

Example <ros/node> policy import

# Include basic node abstractions and resources needed for ros nodes

param /use_sim_time r,
service ~/get_loggers x,
service ~/set_logger_level x,
topic ~/rosout p,

Example SROS policy profile

/talker
{
  #include <ros/node>
  topic /chatter p,
}

Another interesting feature this brings up is the use of Tunables, a mechanism for tuning your configuration without having to adjust your profiles. They might also be useful, but we can hold on this and the host of other apparmor related features until we are more confident that apparmor mandatory access control syntax is what we'd like to go for.

ruffsl avatar Sep 05 '17 23:09 ruffsl

For the translation of policies into metafiles, I'm still not sure how we should convey governance related attributes, such that may be used on the QOS related governance files for Secure DDS, i.e whether a topic should be encrypted or signed, etc. Another question is if they should be supported at all, or if this would be outside the scope of the generic policy syntax we sich to define in SROS.

My feeling is that this some of these plugin related features could be considered core attributes you'd want to be able to describe, such a sign or encrypt. However I'm not sure of a good boundary to determine whether an attribute is too transport specific, e.g. tags or partitions. But if the description of the security attributes is data centric, and fits well with ROS2's main target protocol, DDS, I don't think it would be to bad to enable optional rule modifiers to enable this, e.g:

/talker
{
  #include <ros/node>
  encrypt topic /foo p,
  sign topic /bar p,
}

Although, this could complicate the translation process, necessitating more contextual passing and expansion into the metafiles. For example, if a topic namespace is cited twice in two different rules, but with different modifiers, then the translation of the topic's definition into the Secure DDS governances file may be ill-defined given the contradictory occurrences. Or this could result in contradictory governance files given different node namespaces, which could be non obvious to debug.

One last idea I have is if such specific features or modifiers could be captured by a separate file, so a degree of separation between transport security and access control policy could be clearly defined, but yet enable a translation plugin that would consume both file types jointly to produce the desired custom metafiles. This somewhat already resembles the behavior of the separate governance and permission file structure in Secure DDS.

ruffsl avatar Sep 06 '17 00:09 ruffsl