%%-------------- 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 %% %% ------------ The formal spec ---------------------------------------------------------- %% %% -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. %% -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 ------------------------------------------------- %% %% 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} %% %% 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 `.` %% %% NOTE: When deploy to production, the last rule should be changed to {deny, all}. %% %% 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. %% %% 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.