From b3a0b999eb9be13d0f894fa41730817b36a14517 Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Fri, 13 Nov 2020 17:44:10 +0000 Subject: [PATCH] First draft of dynsec documentation. --- www/pages/documentation/dynamic-security.md | 539 ++++++++++++++++++++ 1 file changed, 539 insertions(+) create mode 100644 www/pages/documentation/dynamic-security.md diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md new file mode 100644 index 00000000..d1d2be0b --- /dev/null +++ b/www/pages/documentation/dynamic-security.md @@ -0,0 +1,539 @@ + + +## Introduction + +The Dynamic Security plugin is a Mosquitto plugin which provides role based +authentication and access control features that can updated whilst the broker +is running, using a special topic based API. + +It is supported since Mosquitto 2.0, and should be available in all +installations, but will not be activated by default. + +## Concepts + +This section describes the concepts of how the plugin operates. If you want to +find out how to use the plugin features, look in the [Usage] section below. + +The plugin allows you to create three main objects, `clients`, `groups`, and `roles`. + +This document will use the term `clients` to mean the clients defined in the +plugin, and `devices` or `users` to mean the MQTT clients that connect to the +broker. + +--- + +### Clients + +When you want a device or user to be able to connect and authenticate to the +broker, you create a client. Each client has the following attributes: + +#### Username + +The client username maps to the username provided in the CONNECT packet when a +device connects. The username is unique across the plugin, so attempting to +create a client with a duplicate username will result in an error. The username +acts as the primary key if you want to change anything about the client. + +#### Password + +The client password maps to the password provided in the CONNECT packet when a +device connects. The password may be unset when a client is created, this will +mean that devices will be unable to connect as the corresponding client. + +The password can be updated at any point, but only by a client with the correct +access. Devices typically cannot update their own passwords. + +#### Client ID + +The client id maps to the client id provided in the CONNECT packet when a +device connects. This is an optional attribute. + +If the client id is empty or not provided, then any device can connect with the +username for this client regardless of its client id. This means that multiple +devices could connect with the same credentials at the same time, but sharing +credentials between devices is not recommended. + +If the client id is set, then a device can only connect as this client if the +triple of username, password, and client id all match those in the client. + +#### Groups + +A client can be a member of any number of groups. + +#### Roles + +A client can be assigned to any number of roles. A role gives the client access +to different topics. + +#### Text name + +This is an optional text field to give a human friendly name to this client. + +#### Text description + +This is an optional text field to give a human friendly description to this +client. + +#### Disabled + +A client can be set to be enabled/disabled at any point. Disabling a client +means that any devices currently connected using the credentials for that +client will be disconnected and unable to reconnect. + +--- + +### Groups + +Multiple clients can be placed in a group. Groups can have roles assigned to +them, so using groups is appropriate where you have a number of clients that +need to have the same access. + +Groups have the following attributes: + +#### Group name + +The group name is the primary name for the group. It is used when modifying the +group in any way, such as adding a client or a role. + +#### Roles + +A group can be assigned to any number of roles. A role gives the group access +to different topics. + +#### Text name + +This is an optional text field to give a human friendly name to this group. + +#### Text description + +This is an optional text field to give a human friendly description to this +group. + +--- + +### Roles + +Roles contain multiple access control lists (ACLs), and can be assigned to clients and/or groups. + +Roles have the following attributes: + +#### Role name + +The role name is the primary name for the role. It is used when modifying the +role in any way, such as adding an ACL. + +#### Access Control Lists + +ACLs are the feature which allows access to topics to be controlled. Checks are +made on different events as they happen: `publishClientSend`, +`publishClientReceive`, `subscribe`, and `unsubscribe`. The `publishClientSend` +event occurs when a device sends a PUBLISH message to the broker, i.e. "is the +device allowed to publish to this topic". The `publishClientReceive` event +occurs when a device is due to receive a PUBLISH message from the broker, i.e. +it has a valid subscription and a matching message has been published to the +broker. The `subscribe` event occurs in response to a device sending a +SUBSCRIBE message, and the `unsubscribe` event occurs in response to a device +sending an UNSUBSCRIBE packet. + +The default behaviour of the different events can be set to allow or deny +access. The default behaviour applies if no matching ACL is found. + +The default behaviour for the different events when the plugin has first been +configured is: + +* `publishClientSend`: deny +* `publishClientReceive`: allow +* `subscribe`: deny +* `unsubscribe`: allow + +There is some overlap between `publishClientReceive` and `subscribe`. In most +cases, using a `subscribe` ACL is sufficient to provide the control you need, +however by combining the two types it is possible to e.g. allow subscriptions +to a wildcard topic like `topic/#`, but deny access for device to receive +messages on a specific topic within that hierarchy like 'topic/secret'. + +The different events have ACL types associated with them, and it is these ACLs +that you will add to your roles. Each ACL has a `topic`, a `priority`, and can +be set to `allow` or `deny`. + +The `publishClientSend` and `publishClientReceive` ACL types map directly to +the events of the same name. The topic can contain wildcards, so allowing send +access to `topic/#` will allow devices to publish to all topics in the +`topic/#` hierarchy, including `topic`. + +The `subscribe` and `unsubscribe` events have two ACL types each: +`subscribeLiteral`, `subscribePattern`, `unsubscribeLiteral`, and +`unsubscribePattern`. + +The `*Literal` ACL types make a literal comparison between the topic filter +provided for the ACL and the topic filter provided in the SUBSCRIBE or +UNSUBSCRIBE message. This means that setting a `subscribeLiteral` ACL with +topic filter `#` to deny would prevent matching devices from subscribing the +the `#` topic filter only, but still allow them to subscribe to `topic/#`, for +example. + +The `*Pattern` ACL types allow or deny access based on a wildcard comparison of +the ACL topic filter and the topic provided in the SUBSCRIBE or UNSUBSCRIBE +message. This means that setting a `subscribePattern` ACL with topic filter `#` +to deny would prevent matching devices from subscribing to any topic at all. + +#### Text name + +This is an optional text field to give a human friendly name to this role. + +#### Text description + +This is an optional text field to give a human friendly description to this +role. + +--- + +### Priorities + +**FIXME** example needs completing. + +If you are working with more than one role per client or group, or more than +one group per client, then it is crucial to understand how roles and ACLs are +applied. + +The order in which checks are made is determined in part by the `priority` of +groups, roles and ACLs. Each client group has a priority, each client role and +group role has a priority, and each ACL within a role has a priority. If not +set explicitly, priorities will default to -1. + +For each of the group, role, and ACL objects, checks are made in priority order +from the highest numerical value to the lowest numerical value. If two objects +of the same type have the same priority, then they will be checked in +lexographical order according to the username/groupname/rolename, but it is +advised to use unique priorities per object type. + +When an event occurs that needs an ACL check, the ACLs for that ACL type are +checked in order until there is a matching ACL for the topic in question. + +Within each role that is checked, the ACLs are checked in priority order. + +The roles assigned to a client are checked first, in priority order. +Each client group is checked in priority order, with all of the roles in a +group being checked in priority order before the next group is checked. + +As an example, let us assume we have the following client, groups, and roles: + +Client: `sensor` +Groups: `temperature` (priority 2), `humidity` (priority 1) +Roles: `hallway` + +Group: `temperature` +Roles: `input` (priority 5), `output` (priority 1) + +Group: `humidity` +Roles: `humidity` + +Role: `hallway` + +Role: `input` + +Role: `output` + +Role: `humidity` + + +### Anonymous access + +All of the documentation so far assumes that you do not allow anonymous +unauthenticated access - meaning devices or users that connect without a +username. + +You may wish to allow anonymous access, but still make use of the dynamic +security plugin, and this is supported through the automatic anonymous group. +If allowed, anything connecting without a username will be assigned to a group +that you define. By assigning roles to that group, you can control what +anonymous devices can access. + +## Initial configuration + +To use the Dynamic Security plugin, it must be configured in the broker and an +initial plugin configuration must be generated. + +To configure the broker, add the following to your configuration file. + +Linux/BSD: +``` +plugin path/to/mosquitto_dynamic_security.so +plugin_opt_config_file path/to/dynamic-security.json +``` + +Windows: +``` +plugin path\to\mosquitto_dynamic_security.dll +plugin_opt_config_file path\to\dynamic-security.json +``` + +It is recommended to use `per_listener_settings false` with this plugin, so all +listeners use the same authentication and access control. + +The `dynamic-security.json` file is where the plugin configuration will be +stored. To generate an initial file, use the `mosquitto_ctrl` utility. + +``` +mosquitto_ctrl dynsec init path/to/dynamic-security.json admin-user +``` + +Choose your own `admin-user` username. You will be asked for a password for the +client. This user will be assigned the `admin` role, which has the following +access: + +* publishClientSend: `$CONTROL/dynamic-security/#` - this allows the client to + control the Dynamic security plugin. +* publishClientReceive: `$CONTROL/dynamic-security/#` - this allows the client + to receive information from the plugin. This is not necessary in the default + configuration, but is included in case the default behaviour for + `publishClientReceive` is set to `deny`. +* subscribePattern: `$CONTROL/dynamic-security/#` - this allows the client to + receive information from the plugin. +* publishClientReceive: `$SYS/#` - this allows the client to see the broker + metrics. +* subscribePattern: `$SYS/#` - this allows the client to see the broker + metrics. +* publishClientReceive: `#` - this allows the client to examine the messages + being published by other clients. +* subscribePattern: `#` - this allows the client to examine the messages + being published by other clients. +* unsubscribePattern: `#` - this allows the client to undo previous + subscriptions. This is not necessary in the default configuration, but is + included in case the default behaviour for `unsubscribe` is set to `deny`. + +The admin user does not have access to publish to normal application topics in +the `#` hierarchy by default. You are strongly encouraged to keep the admin +user purely for administering the plugin, and create other clients for your +application. + +## Using mosquitto_ctrl with a running broker + +The initial configuration is the only time that `mosquitto_ctrl` does not +connect to a broker to carry out the configuration. All other commands require +a connection to a broker, and hence a username, password, and whatever else is +required for that particular connection. + +The connection options must be given before the `dynsec` part of the command +line: +``` +mosquitto_ctrl dynsec ... +``` + +For example: + +``` +mosquitto_ctrl -u admin -h localhost dynsec ... +``` + +It is possible to provide the admin password on the command line, but this is +not recommended. + +See **FIXME** for the full list of options available for `mosquitto_ctrl`. + +## Configuring default access + +The initial configuration sets the default ACL type behaviours to: + +* `publishClientSend`: deny +* `publishClientReceive`: allow +* `subscribe`: deny +* `unsubscribe`: allow + +If you wish to change these, use `mosquitto_ctrl`. + +``` +mosquitto_ctrl dynsec setDefaultACLAccess publishClientSend deny +mosquitto_ctrl dynsec setDefaultACLAccess publishClientReceive deny +mosquitto_ctrl dynsec setDefaultACLAccess subscribe deny +mosquitto_ctrl dynsec setDefaultACLAccess unsubscribe deny +``` + +You can examine the current default access with the `getDefaultACLAccess` command: + +``` +mosquitto_ctrl dynsec getDefaultACLAccess unsubscribe +``` + +## Creating and modifying clients + +To create a new client: + +``` +mosquitto_ctrl dynsec createClient +``` + +This creates a client which does not have a client id associated with it. You +will be asked for the password for the new client before you are asked for the +admin user password. Pay attention to the messages on the command line. + +``` +mosquitto_ctrl dynsec createClient -i +``` +This creates a client which has a client id associated with it. + + +To delete a client (clients connected with these credentials will be +disconnected from the broker): + +``` +mosquitto_ctrl dynsec deleteClient +``` + +To disable a client (clients connected with these credentials will be +disconnected from the broker): + +``` +mosquitto_ctrl dynsec disableClient +``` + +To enable a client (clients will be able to use these credentials to log in +again): + +``` +mosquitto_ctrl dynsec enableClient +``` + +To set a client password: + +``` +mosquitto_ctrl dynsec setClientPassword +mosquitto_ctrl dynsec setClientPassword +``` + +To add/remove a role to/from a client: + +``` +mosquitto_ctrl dynsec addClientRole +mosquitto_ctrl dynsec removeClientRole +``` + +To get information on a client: + +``` +mosquitto_ctrl dynsec getClient +``` + +To list all clients: + +``` +mosquitto_ctrl dynsec listClients +``` + +The `modifyClient` command also exists in the topic API, but is not currently available in `mosquitto_ctrl`. + + +## Creating and modifying groups + +To create a new group: + +``` +mosquitto_ctrl dynsec createGroup +``` + +To delete a group: + +``` +mosquitto_ctrl dynsec deleteGroup +``` + +To add/remove a client to/from a group: + +``` +mosquitto_ctrl dynsec addGroupClient +mosquitto_ctrl dynsec removeGroupClient +``` + +In this case the `priority` refers to the priority of the group within the +client's list of groups. + +To add/remove a role to/from a group: + +``` +mosquitto_ctrl dynsec addGroupRole +mosquitto_ctrl dynsec removeGroupRole +``` + +To set/get the group that anonymous devices are assigned to: + +``` +mosquitto_ctrl dynsec setAnonymousGroup +mosquitto_ctrl dynsec getAnonymousGroup +``` + +To get information on a group: + +``` +mosquitto_ctrl dynsec getGroup +``` + +To list all groups: + +``` +mosquitto_ctrl dynsec listGroups +``` + +The `modifyGroup` command also exists in the topic API, but is not currently +available in `mosquitto_ctrl`. + +## Creating and modifying roles + +To create a new role: + +``` +mosquitto_ctrl dynsec createRole +``` + +To delete a role: + +``` +mosquitto_ctrl dynsec deleteRole +``` + +To add an ACL to a role: +``` +mosquitto_ctrl dynsec addRoleACL allow|deny +``` +Where `acltype` is one of `publishClientSend`, `publishClientReceive`, +`subscribeLiteral`, `subscribePattern`, `unsubscribeLiteral`, and +`unsubscribePattern`. + +For example: + +``` +mosquitto_ctrl dynsec addRoleACL clientPublishSend client/topic allow 5 +``` + +To remove an ACL from a role using the topic filter as the key: +``` +mosquitto_ctrl dynsec removeRoleACL +``` +For example: + +``` +mosquitto_ctrl dynsec removeRoleACL clientPublishSend client/topic +``` + +To get information on a role: + +``` +mosquitto_ctrl dynsec getRole +``` + +To list all roles: + +``` +mosquitto_ctrl dynsec listRoles +``` + +The `modifyRole` command also exists in the topic API, but is not currently +available in `mosquitto_ctrl`.