Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12931 from zmstone/0425-fix-acl.conf-topic-templa…
…te-render-fialure-handling 0425 fix acl.conf topic template render fialure handling
- Loading branch information
Showing
4 changed files
with
179 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,123 @@ | ||
%%-------------------------------------------------------------------- | ||
%% -type(ipaddr() :: {ipaddr, string()}). | ||
%% | ||
%% -type(ipaddrs() :: {ipaddrs, [string()]}). | ||
%% | ||
%% -type(username() :: {user | username, string()} | {user | username, {re, regex()}}). | ||
%%-------------- Default ACL rules ------------------------------------------------------- | ||
|
||
{allow, {username, {re, "^dashboard$"}}, subscribe, ["$SYS/#"]}. | ||
|
||
{allow, {ipaddr, "127.0.0.1"}, all, ["$SYS/#", "#"]}. | ||
|
||
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. | ||
|
||
{allow, all}. | ||
%% NOTE! when deploy in production: | ||
%% - Change the last rule to `{deny, all}.` | ||
%% - Set config `authorization.no_match = deny` | ||
|
||
%% See docs below | ||
%% | ||
%% -type(clientid() :: {client | clientid, string()} | {client | clientid, {re, regex()}}). | ||
%% ------------ The formal spec ---------------------------------------------------------- | ||
%% | ||
%% -type(who() :: ipaddr() | ipaddrs() | username() | clientid() | | ||
%% -type ipaddr() :: {ipaddr, string()}. | ||
%% -type ipaddrs() :: {ipaddrs, [string()]}. | ||
%% -type username() :: {user | username, string()} | {user | username, {re, regex()}}. | ||
%% -type clientid() :: {client | clientid, string()} | {client | clientid, {re, regex()}}. | ||
%% -type who() :: ipaddr() | ipaddrs() | username() | clientid() | | ||
%% {'and', [ipaddr() | ipaddrs() | username() | clientid()]} | | ||
%% {'or', [ipaddr() | ipaddrs() | username() | clientid()]} | | ||
%% all). | ||
%% all. | ||
%% -type simple_action() :: subscribe | publish | all. | ||
%% -type complex_action() :: {simple_action(), [{qos, 0..2}, {retain, true|false|all}]}. | ||
%% -type action() :: simple_action() | complex_action(). | ||
%% -type topic() :: string(). | ||
%% -type topic_filter() :: string(). | ||
%% -type topic_match() :: topic() | topic_filter() | {eq, topic() | topic_filter()}. | ||
%% -type perm() :: allow | deny. | ||
%% -type rule() :: {perm(), who(), action(), [topic_match()]} | {perm(), all}. | ||
|
||
%%-------------- Viusal aid for the spec ------------------------------------------------- | ||
%% | ||
%% -type(action() :: subscribe | publish | all). | ||
%% rule() | ||
%% ├── {perm(), who(), action(), [topic_match()]} | ||
%% │ │ │ │ ├── topic() :: string() | ||
%% │ │ │ │ ├── topic_filter() :: string() | ||
%% │ │ │ │ └── {eq, topic() | topic_filter()} | ||
%% │ │ │ │ | ||
%% │ │ │ ├── simple_action() | ||
%% │ │ │ │ ├── publish | ||
%% │ │ │ │ ├── subscribe | ||
%% │ │ │ │ └── all | ||
%% │ │ │ └── {simple_action(), [{qos,0..2},{retain,true|false|all}]} | ||
%% │ │ │ | ||
%% │ │ ├── ipaddr() | ||
%% │ │ │ └── {ipaddr, string()} | ||
%% │ │ ├── ipaddrs() | ||
%% │ │ │ └── {ipaddrs, [string()]} | ||
%% │ │ ├── username() | ||
%% │ │ │ ├── {user | username, string()} | ||
%% │ │ │ └── {user | username, {re, regex()}} | ||
%% │ │ ├── clientid() | ||
%% │ │ │ ├── {client | clientid, string()} | ||
%% │ │ │ └── {client | clientid, {re, regex()}} | ||
%% │ │ ├── {'and', [ipaddr() | ipaddrs() | username() | clientid()]} | ||
%% │ │ ├── {'or', [ipaddr() | ipaddrs() | username() | clientid()]} | ||
%% │ │ └── all | ||
%% │ │ | ||
%% │ ├── allow | ||
%% │ └── deny | ||
%% │ | ||
%% └── {perm(), all} | ||
%% | ||
%% -type(topic_filters() :: string()). | ||
|
||
%% This file defines a set of ACL rules for MQTT client pub/sub authorization. | ||
%% The content is of Erlang-term format. | ||
%% Each Erlang-term is a tuple `{...}` terminated by dot `.` | ||
%% | ||
%% -type(topics() :: [topic_filters() | {eq, topic_filters()}]). | ||
%% NOTE: When deploy to production, the last rule should be changed to {deny, all}. | ||
%% | ||
%% -type(permission() :: allow | deny). | ||
%% NOTE: It's a good practice to keep the nubmer of rules small, because in worst case | ||
%% scenarios, all rules have to be traversed for each message publish. | ||
%% | ||
%% -type(rule() :: {permission(), who(), action(), topics()} | {permission(), all}). | ||
%%-------------------------------------------------------------------- | ||
|
||
{allow, {username, {re, "^dashboard$"}}, subscribe, ["$SYS/#"]}. | ||
|
||
{allow, {ipaddr, "127.0.0.1"}, all, ["$SYS/#", "#"]}. | ||
|
||
{deny, all, subscribe, ["$SYS/#", {eq, "#"}]}. | ||
|
||
{allow, all}. | ||
%% A rule is a 4-element tuple. | ||
%% For example, `{allow, {username, "Jon"}, subscribe, ["#"]}` allows Jon to subscribe to | ||
%% any topic they want. | ||
%% | ||
%% Below is an explanation: | ||
%% | ||
%% - `perm()`: The permission. | ||
%% Defines whether this is an `allow` or `deny` rule. | ||
%% | ||
%% - `who()`: The MQTT client matching condition. | ||
%% - `all`: A rule which applies to all clients. | ||
%% - `{ipaddr, IpAddress}`: Matches a client by source IP address. CIDR notation is allowed. | ||
%% - `{ipaddrs, [IpAddress]}`: Matches clients by a set of IP addresses. CIDR notation is allowed. | ||
%% - `{clientid, ClientID}`: Matches a client by ID. | ||
%% - `{username, Username}`: Matches a client by username. | ||
%% - `{..., {re, ..}}`: Regular expression to match either clientid or username. | ||
%% - `{'and', [...]}`: Combines a list of matching conditions. | ||
%% - `{'or', [...]}`: Combines a list of matching conditions. | ||
%% | ||
%% - `action()`: Matches publish or subscribe actions (or both). | ||
%% Applies the rule to `publish` or `subscribe` actions. | ||
%% The special value `all` denotes allowing or denying both `publish` and `subscribe`. | ||
%% It can also be associated with `qos` and `retain` flags to match the action with | ||
%% more specifics. For example, `{publish, [{qos,0},{retain,false}]}` should only | ||
%% match the `publish` action when the message has QoS 0, and without retained flag set. | ||
%% | ||
%% - `[topic_match()]`: | ||
%% A list of topics, topic-filters, or template rendering to match the topic being | ||
%% subscribed to or published. | ||
%% For example, `{allow, {username, "Jan"}, publish, ["jan/#"]}` permits Jan to publish | ||
%% to any topic matching the wildcard pattern "jan/#". | ||
%% A special tuple `{eq, topic_match()}` is useful to allow or deny the specific wildcard | ||
%% subscription instead of performing a topic match. | ||
%% A `topic_match()` can also contain a placeholder rendered with actual value at runtime, | ||
%% for example, `{allow, all, publish, "${clientid}/#"}` allows all clients to publish to | ||
%% topics prefixed by their own client ID. | ||
%% | ||
%% Supported placeholders are: | ||
%% - `${cn}`: TLS certificate common name. | ||
%% - `${clientid}`: The client ID. | ||
%% - `${username}`: The username. | ||
%% - `${client_attrs.NAME}`: A client attribute named `NAME`, which can be initialized by | ||
%% `mqtt.client_attrs_init` config or extended by certain authentication backends. | ||
%% NOTE: Placeholder is not rendered as empty string if the referencing value is not | ||
%% foud. For example, `${client_attrs.group}/#` is not rendered as `/#` if the | ||
%% client does not have a `group` attribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters