Policies in Kanzi Connect

Policies in Kanzi Connect control the ability of a Kanzi Connect Client to access the data and methods of a service offered by a Kanzi Connect Server. Kanzi Connect loads policies from a policy file defined in the YAML format. By default a Kanzi Connect Server looks for a file named policy.yaml in the current directory of the service application. You can set the location of the file in the Kanzi Connect Server configuration file connect_server_config.xml. See Kanzi Connect Server configuration.

The policies are defined with respect to the service descriptions of the Kanzi Connect services. See Kanzi Connect services.

During startup the Kanzi Connect Server reads the file and reports errors and omissions in coverage of the policy with respect to the included policies.

The policy enforcement operates in these modes:

  • Erroneous. In case of errors Kanzi Connect does not enforce the policies. In the Technology Preview releases of Kanzi Connect the system continues operating, but without performing policy operations. In the official release of Kanzi Connect errors in policies cause the Kanzi Connect Server to quit.

  • Notify. Policy decisions are reported normally, but not enforced. The operation is permitted, but Kanzi Connect writes negative decisions to the service log. Use this mode for debugging.

  • Enforced. Kanzi Connect fully enforces polices.

You can use the configuration file to set either Notify or Enforced mode.

A limited set of policy features is available with remote services, because the remote services themselves already limit the access to their internals better than a policy can.

Note

Modification of the policy file requires restarting the Kanzi Connect server.

Policy descriptions

Policies are defined in a single YAML format policy file, which defines policies for all operations. A policy file is an ordered list of individual policy statements, where the order resolves possible conflicts: latter statements override the earlier statements. This is an example policy file that controls connection to a service, policy.yaml:

# Lines starting with the hash sign (#) are comments and you can include them
# anywhere in the policy file.
- globals: "Globals for policies for Kanzi Connect"
  subject: connect
  ipblacklist: ["192.168.10.128"]
  peerwhitelist: ["Unknown"]
  ipwhitelist: ["192.168.10.1", "192.168.10.2"]
  evaluator: kz_server
- tag: "TCP connection"
  subject: connect
  tags: ["tcp"]
  conditions:
      - condition: connect.coreservice.connection.runtime-data.peer.type == "connect.bearer.tcp"
  evaluator: kz_server
- name: "Allow connect to server via ssl from known sources"
  subject: connect.coreservice.connection
  operation: connect
  conditions:
      - condition: connect.coreservice.connection.runtime-data.peer.role == "Server"
      - condition: connect.coreservice.connection.runtime-data.peer.id |> peerwhitelist
      - condition: connect.coreservice.connection.runtime-data.peer.addr |> ipwhitelist
      - condition: connect.coreservice.connection.runtime-data.peer.type == "connect.bearer.ssl"
  decision: pass
  evaluator: kz_server
- name: "No connect to server via tcp"
  subject: connect.coreservice.connection
  operation: connect
  conditions:
      - condition: tcp
  decision: deny
  evaluator: kz_server
- name: "An exception to allow TCP from localhost (latter overrides earlier)"
  subject: connect.coreservice.connection
  operation: connect
  localhosts: ["127.0.0.1"]
  conditions:
      - condition: tcp
      - condition: connect.coreservice.connection.runtime-data.peer.addr |> localhosts
  decision: pass
  evaluator: kz_server

This file has four policy statements, individual elements in the YAML list. Each list item is denoted by leading - and indentation. Kanzi Connect policies have these types of policy statements available:

  • Global statement can define named list values that other statements, which come later in the file, can reference. There is no limit on the number or position of global statements, but it is useful to have a single global statement in the beginning. Attempting to redefine a list value name later is a syntax error.

  • Regular policy statement can also define local list values, but it must have conditions and a decision, which are not in global statements. The scope of a statement is the combination of its operation and subject.

  • Tag statement defines a tag which is a name that you can use as a single condition statement in other policy statements. The tag holds if all of the conditions in the statement hold. There are no decision or operation associated with a tag statement. They are used to define shorthand names for a number of conditions to avoid replicating them in policy statements. The policy is checked for circular tag dependencies and if found, they are reported as errors at server startup.

  • Traffic shaping policies, which enable controlling the relative priorities of connected clients, pausing the network and disconnecting clients. Kanzi Connect evaluates these policies differently than the other policies. See Traffic shaping statements.

The elements of the policy statement are:

  • log element, adding log: on to any statement sets the evaluation of that statement to be logged to the server log. For statements that hold (all conditions evaluate to true), Kanzi Connect logs only the name of the policy. If a condition in the logged statement does not hold, Kanzi Connect logs that failing condition and the values. This is useful for debugging the policies, to check which policy statements are triggered and which values of identifiers are used. Extra logging decreases performance, so do not use logging in production. Logging pertains to the evaluation of conditions, not the verdict itself. In case of a condition that evaluates to false, the log contains the statement as well as the resolved runtime values.

  • name a human readable name for this policy, reported along with the policy decision. For global statements this is globals and for tags this is tag.

  • subject identifies the resource, method, data or event which this policy statement should control. This may be service specific or it may be one of the fixed internal Connect specific subjects, described later. Note that this subject string pertains to all other subjects for which this is a prefix of. For example, policies defined for connect.service are evaluated (for the same operation) also for subjects such as connect.service.engine.method.set_clutch or connect.service.engine.runtime-data.engine.gear because connect.service is a string prefix of these.

  • operation is the operation targeted at the subject. May be one of: connect,``write``, call, or read.

  • conditions contains a sequence of expressions that should all evaluate to true for this policy statement to produce the decision. The expressions are or form (identifier comparison (literal|reference) tagname), where

    • identifier is a name of a subject as described in item 2 above.

    • comparison can be

      • Equality (==) or inequality (!=)

      • Arithmetic comparisons (>,<, >=,<=), for strings these are interpreted as string prefixes. For example,"abc" < "abcde" evaluates to true.

      • Element inclusion (|>) and negated inclusion (!>) for a named list (not a literal)

    • literal is a numeric or string literal

    • reference is a name of a list value that has been defined either in this statement or in a global statement.

    • tagname is a name that has been defined in the tags part of a tag statement. It can only be used on its own in a condition, it cannot be compared with anything.

  • decision the result when all conditions evaluate to true, either deny or pass. Only relevant for regular policy statements.

  • named list, of form name: [literal1,literal2,...] defines a name associated with a list of literals. This name can be referred to in the decision expressions. Names in a normal policy statement are visible within that statement, names in global statements are visible for all policy statements that come later in the file.

  • tags of form [name1,name2,...] defines a list of tag names which hold when the conditions are all true. This acts as a shorthand to avoid retyping the same conditions in multiple statements. Multiple tags are allowed, but in practice single item is enough for most cases.

  • evaluator uninterpreted, enables offloading the policy decisions to be computed by some other entity. For example, this allows centralized management of connections by the Kanzi Connect infrastructure rather than the actual service implementation which can be on a very limited device.

Regular policy evaluation is triggered by Kanzi Connect and the subject and operation are fed to the policy system which produces a result: either a pass or fail, which is default if no other results are found. All of the policies that match with the subject and operation are evaluated, but only one result is reported. This is the latest definition in the file, regardless of how many other policies produced a result. This also at the same time resolves any conflicts, two policies producing different decisions for the same operation: the latter policy wins. Kanzi Connect evaluates the traffic shaping policies for all connected clients after service operation after 100 millisecond period. See Traffic shaping statements.

To further illustrate the syntax of the policy subjects and conditions, consider the following two related, but artificial policy statements over non-core services. The subject and part of the conditions refer to different services in different “namespaces”, implemented by different services.

name: "Remote call gear up"
subject: connect.service.cluster.method.gear_up
operation: call
whitelist: ["128.0.0.1","128.0.0.2"]
conditions:
  - condition: connect.coreservice.connection.runtime-data.peer.addr |> whitelist
  - condition: connect.coreservice.connection.runtime-data.peer.type == "connect.bearer.tcp"
  - condition: connect.service.cluster.runtime-data.gear < 10
decision: pass
evaluator: third
name: "Direct set of gear only over ssl and when engine temperature is low"
subject: connect.service.cluster.runtime-data.gear
operation: write
whitelist: ["128.0.0.1","128.0.0.2"]
conditions:
  - condition: connect.coreservice.connection.runtime-data.peer.addr |> whitelist
  - condition: connect.coreservice.connection.runtime-data.peer.type == "connect.bearer.ssl"
  - condition: connect.service.obd2.runtime-data.engine_coolant_temp < 30
  - condition: connect.service.obd2.runtime-data.engine_oil_temp < 30
  - condition: connect.service.cluster.runtime-data.rpm == 0
decision: pass
evaluator: third

The first one pertains to calling a method gear_up in the cluster service, when connecting over TCP from a known source and when the current gear is less than 10. The subject and the conditions are according to the cluster_interface.xml description. The second policy statement allows writing directly to the gear data only when connecting using SSL from a known host and when the available obd2 temperature data indicates that the engine is not running and that the RPM is at 0.

Traffic shaping statements

Traffic shaping policy statements reside in the same policy.yaml file, but Kanzi Connect evaluates them differently and they allow controlling the prioritization of the clients and flow control of the traffic. Here is an example traffic shaping statement:

- performance: "Performance policy test"
  subject: client
  log: on
  conditions:
      - condition: connect.diagnostics.client.name != "Control Panel"
      - condition: connect.diagnostics.client.tx_messages > 10
  effect: stopnetwork 10000
  period: 100
  evaluator: kz_server

These are much like the regular statements, but these elements are different:

  • performance indicates this to be a traffic shaping statement

  • subject can currently only be client

  • effect can be one of:

    • stopnetwork <milliseconds> stops reading from the socket for the set amount of time in milliseconds. Use this in case of congestion to temporarily stop all communications with a client. Depending on the client implementation and the underlying platform, this can cause the client to disconnect. Value -1 sets this permanently.

    • demote <milliseconds> reduces the priority of the client for the set amount of time. Value -1 sets this permanently.

    • promote <milliseconds> increases the priority of the client for the set amount of time. Value -1 sets this permanently.

  • disconnect disconnects the client.

  • period must be present but is not used.

This policy statement is evaluated for all connected clients and if all of the conditions in a performance statement hold, then the effect is put to a queue and after Kanzi Connect iterates all clients, it evaluates the effects. You have to make sure that policies do not produce conflicting effects. Kanzi Connect prints the effects to the log, and in case of a timeout, it also logs the passing of the timeout and the return to the previous state.

Like in other policies, you can use runtime values and these performance related runtime values with connect.diagnostics prefix are available, but only for performance statements:

  • connect.diagnostics.client.conn_time the time a client has been connected in seconds

  • connect.diagnostics.client.latency_avg average latency in milliseconds

  • connect.diagnostics.client.rx_total total number of bytes received by a client

  • connect.diagnostics.client.tx_total total number of bytes sent by a client

  • connect.diagnostics.client.rx_messages number of messages received by a client

  • connect.diagnostics.client.tx_messages number of messages sent by a client

  • connect.diagnostics.client.rx_messages_per_second number of messages per second received by a client

  • connect.diagnostics.client.tx_messages_per_second number of messages per second sent by a client

  • connect.diagnostics.client.name name of the connecting client

  • connect.diagnostics.client.addr IP address of the connecting client

  • connect.diagnostics.client.id unique ID of the connecting client

  • connect.diagnostics.client.conntype type of connection of the connecting client

Policy basics and an example for connection management

This section:

  • Explains stepwise generation of a policy file.

  • Introduces the basic syntax of the policy description,.

  • Explains how Kanzi Connect evaluates policies.

This section assumes that:

  • All modifications are done to a single default policy file policy.yaml that the server can access, either by having the policy.yaml file in the working directory or specifying it in the configuration file.

  • You have a working Kanzi Connect Server and Control Panel client. Use release builds for both. The debug builds generate more log information. The server must be working in advisory mode and the relevant service description XML files must be available.

This section outlines a development flow for the policies: we run the policies in the notify mode, Kanzi Connect will warn about coverage of polices over services and by default report denials for method calls and value writes. The aim is to gradually build a policy file that covers all services and their methods.

If you do not use a configuration file, Kanzi Connect is by default in the Notify mode and no changes are necessary. If you use a configuration file, set the mode to Notify as this example shows.

<policy>
   <attribute name="filename" value="policy.yaml" type="removethis_file" />
   <!-- Possible modes: inactive.. comment: this mode is not mentioned in the list above., notify, enforce -->
  <attribute name="mode" value="notify" />
</policy>

The simplest policy file is as follows:

- globals: "Globals for policies under Kanzi Connect"
  subject: connect
  evaluator: kz_server

This contains only the common information for all the subsequent policy statements and does not do anything. When you start the Kanzi Connect Server, the server output looks similar to the example output below. The order of different services and their subject can be different.

...
INF [           policycontext] Checking policies for Connect.Service.System
WRN [           policycontext] Subject connect.service.system.runtime-data.demo.fuel not covered by any policy
WRN [           policycontext] Subject connect.service.system.runtime-data.demo.temperature not covered by any policy
...

Use this configuration to list all available policies on this server and the policy subjects, that the service has. The policies handle the operations over these policy subjects. Note the correspondence between these and the service description XML in system_interface.xml:

<service name="system" namespace="kanzi" description="System interface">
  ...
  <runtime-data>
    <demo>
      <temperature type="int" writable="1" />
      ...
      <fuel type="int" writable="1" />
      ...
    </demo>
  </runtime-data>
</service>

The prefix connect.service is common, but the rest are formed in a straightforward manner by traversing the XML graph and separating the names with dots.

The default policy is to deny any operations, any client attempting call methods or read data will be denied by default as there are no policies. If the policy engine is running in notify mode, the denials are only reported, but not enforced for all operations.

In order allow all calls for system service, the following policy statement can be added to the policy file. The crucial part is the subject line that specifies the service as connect.service.system.

- name: "Default allow for calling System"
  subject: connect.service.system
  operation: call
  conditions:
      - condition: true
  decision: pass
  evaluator: kz_server

Restarting the Kanzi Connect Server does not cause a warning when checking for policies for the Connect.Service.System, while Kanzi Connect issues warnings for other services. You can add a similar policy statement to all other services by replacing the subject line and name accordingly:

  • connect.service.cluster

  • connect.service.media

  • connect.service.sensor

  • connect.service.obd2

  • connect.service.media_testability

  • connect.service.httpvirtualfile

  • connect.service.connection

  • connect.service.diagnostics

  • connect.service.content

  • connect.service.input

  • connect.service.service

After you add a policy statement for these services and restart the Kanzi Connect Server, Kanzi Connect does not issue warnings for the policy coverage. You can now run the ControlPanel client application.

You can limit the connections that are allowed by the Kanzi Connect Server. When you add this statement, Kanzi Connect Server prevents all connections that use unencrypted TCP connections:

- name: "No connect to cluster server using TCP"
  subject: connect.service.connection
  operation: connect
  conditions:
      - condition: connect.service.connection.runtime-data.peer.type == "connect.bearer.tcp"
  decision: deny
  evaluator: kz_server

Note that the operation is connect while previous operations were calls. The negative decision is indicated by deny. The condition refers to a data value that you can compare to strings. You can be even more exclusive this way:

- condition: connect.service.connection.runtime-data.peer.type != "connect.bearer.ssl"

However, both require a policy statement with an explicit pass decision for SSL.

Note that the evaluator is not effective, but that it must be present.

Running the Kanzi Connect Server and then ControlPanel client again returns this message in the Kanzi Connect Server log:

INF [ policycontext] Deny (notify) connect(connect.service.connection)/1186 us /2:No connect to cluster server via tcp

The deny message contains the name of the policy. In order to allow TCP connections from known IP addresses, insert this policy statement after the above statement:

- name: "Exception: Can connect using TCP from localhost."
  subject: connect.service.connection
  operation: connect
  conditions:
      - condition: connect.service.connection.runtime-data.peer.type == "connect.bearer.tcp"
      - condition: connect.service.connection.runtime-data.peer.addr |>  locals
  decision: pass
  evaluator: kz_server

Add to the globals statement:

locals: ["127.0.0.1"]

This introduces a mechanism for checking that a value, in this case connect.service.connection.runtime-data.peer.addr, is in a named set of values, in this case locals, which is a set of one. Restart the Kanzi Connect Server and the ControlPanel and note that this time there is no deny log message when connecting. Note also that the policy statement that is lexicographically later in the policy file has precedence over the earlier ones. here both of the policy statements are valid at the same time, but the latter one is chosen for the decision.

This way it is possible to define another policy that forbids all connections from blacklisted IP addresses. Add another list to globals:

blacklist: ["192.168.0.1","192.168.0.2"]

and another policy statement below the earlier ones:

- name: "Block all IP connections from known bad hosts."
  subject: connect.service.connection
  operation: connect
  conditions:
      - condition: connect.service.connection.runtime-data.peer.addr |>  blacklist
  decision: deny
  evaluator: kz_server

The two set operators are |> (“in set”) and !> (“not in set”).

In order to cover all of the connection related service calls, add thus policy statement:

- name: "Allow calling of identify, could also open all calls."
  subject: connect.service.connection.method.identify
  operation: call
  conditions:
      - condition: true
  decision: pass
  evaluator: kz_server

Policy example for service data

For now the only data values have been under connect.service.connection but they can refer to other values as well. This example shows how to combine values across different services in policies, here policies are placed over Music and System services, which are used by the ControlPanel client application.

This section walks through policies that implement limitations for use of music player, depending on temperature. This is an artificial example, but it can be easily demonstrated and trialed within the ControlPanel application.

When the Kanzi Connect Server is running, in the ControlPanel application the Temperature tab allows changing some of the values with sliders. Changing the value of “OUT TEMPERATURE” produces a number of negative verdicts, such as this:

INF [           policycontext] Deny (notify) write(connect.service.system.runtime-data.demo.temperature)/672 us /-2:Default deny, no explicit decision

Similar decisions are recorded for other sliders. The aim is to allow music playing only when the “OUT TEMPERATURE” is higher than 10. To allow changing outside temperature the following policy statement is added over writing to the subject that was recorded in the log:

- name: "Allow writing to temperature."
  subject: connect.service.system.runtime-data.demo.temperature
  operation: write
  conditions:
      - condition: true
  decision: pass
  evaluator: kz_server

After restarting both programs, changing “OUT TEMPERATURE” slider no longer creates denial messages in the log, whereas the other sliders still do that. For limiting the playing use, you can use these policy statements:

- name: "Allow calling Media methods only when temperature is more than 10."
  subject: connect.service.media
  operation: call
  conditions:
      - condition: connect.service.system.runtime-data.demo.temperature > 10
  decision: pass
  evaluator: kz_server

For more fine-grained control, you can target individual methods by adding more refined policy statements below the earlier ones:

- name: "Deny calling Media next if temperature is over 30."
  subject: connect.service.media.method.next
  operation: call
  conditions:
      - condition: connect.service.system.runtime-data.demo.temperature > 30
      - condition: connect.service.connection.runtime-data.peer.type == "connect.bearer.tcp"
  decision: fail
  evaluator: kz_server

The behavior of these is easy to trial within the ControlPanel client application.

Note that when starting the Kanzi Connect Server it lists the subjects for which it has a policy statement as well as the data items that it refers to in the conditions.

List of built-in data values

The data values are typically found directly in the service description XML files along with their types. However, some built-in data values that are not in any service descriptions are going to be changed in later versions of Kanzi Connect.

Connection related, these are unique for each connection, but they are all referenced using peer.

  • connect.coreservice.connection.peer.type string, currently either “ssl” or “tcp”.

  • connect.coreservice.connection.peer.addr string, the IP address of the peer

  • connect.coreservice.connection.peer.role string, either “server” or “client”

  • connect.coreservice.connection.peer.id string, name of the peer (not working at the moment, always “Unknown”)