This document describes authentication and authorization machinery that implements access control.
Authentication backends should not be confused with authentication mechanisms, which are defined in some protocols supported by RabbitMQ. For AMQP 0-9-1 authentication mechanisms, see documentation.
Authentication and authorization are often confused or used interchangeably. That's wrong and RabbitMQ separates the two. For the sake of simplicity, we'll define authentication as "identifying who the user is" and authorization as "determining what the user is and isn't allowed to do."
Authentication and authorization are pluggable. Modules that provide implementations must implement the following behaviours:
rabbit_authn_backend
for authentication ("authn") backendsrabbit_authz_backend
for authorization ("authz") backends
It is possible to implement both in a single module.
For example internal
, ldap
and http
backends do so.
It is possible to use multiple backends for authn or authz. Then the first positive result returned by a backend in the chain is considered to be final.
The rabbit_authn_backend
behaviour defines authentication process with single function:
user_login_authentication(UserName, AuthProps) -> {ok, #auth_user{}} | {refused, Format, Args} | {error, Reason}
Where UserName
is the name of the user which is trying to authorize,
AuthProps
is an authorization context (proplist) (e.g. it can be []
for x509 certificate-based
authentication or [{password, Password}]
for password-based one).
This function returns
{ok, #auth_user{}}
in case of successfull authentication. The#auth_user{}
record is then passed on to other modules, associated with the connection, etc.{refused, Format, Args}
when user authentication fails.Format
andArgs
are meant to be used withio:format/2
and similar functions.{error, Reason}
when an unexpected error occurs.
The rabbit_authz_backend
behaviour defines functions that authorize access
to RabbitMQ resources, such as vhost
, exchange
, queue
or topic
.
It contains following functions:
% if user is allowed to access broker.
user_login_authorization(UserName) -> {ok, Impl} | {ok, Impl, Tags} | {refused, Format, Args} | {error, Reason}.
% if user have access to specific vhost.
check_vhost_access(#auth_user{}, Vhost, Socket) -> boolean() | {error, Reason}.
% if user have access to specific resource
check_resource_access(#auth_user{}, #resource{}, Permission) -> boolean() | {error, Reason}.
Where
UserName
,Format
,Args
: see above.Impl
is internal state of authorization backend. It will vary between backends and can be thought of as backend'sState
.Tags
is user tags. Those are used by features such as policies, plugins such as management, and so on. Tags can be an empty list.Vhost
is self-explanatoryPermission
currently one ofconfigure
,read
, orwrite
The #auth_user{}
record represents a user whenever we need to
check access to vhosts and resources.
This record has the following structure:
#auth_user{ username :: binary(), impl :: any(), tags :: [any()] }
,
where impl
is internal backend state, tags
is user tags (see above).
impl
can be used to check resource access by querying an external data source or performing
a check solely on the provided state (local data).
#resource{ virtual_host :: binary(), kind :: query|exchange|topic, name :: binary() }
represents a resource (a queue, exchange, or topic) access to which is restricted.
Backends are configured the usual way and can have multiple "syntaxes" (recognised forms):
% To enable single backend:
{rabbit, [{auth_backends, [my_auth_backend]}]}.
% To check several backends. If one is refused - check next.
{rabbit, [{auth_backends, [my_auth_backend, my_other_auth_backend]}]}.
% To use different modules as AuthN and AuthZ backends
{rabbit, [{auth_backends, [{my_authn_backend, my_authz_backend}]}]}.
% You can still fallback if using different modules
{rabbit, [{auth_backends, [{my_authn_backend, my_authz_backend}, my_other_auth_backend]}]}.
If backend is defined by a tuple,
the first element will be used as an AuthN
module and the second as the AuthZ
one.
If it is defined by an atom, it willbe used for both AuthN
and AuthZ
.
When a backend is defined by a list, the server will use modules in the chain in order until one of them returns a positive result or the list is exhausted (the Chain of Responsibility pattern in object-oriented parlance).
If authentication is successfull then the AuthZ
backend from the same tuple ("chain element")
will be used for authorization checks later.
rabbit_auth_backend_dummy
: a dummy no-op backend, only used as the most trivial examplerabbit_auth_backend_internal
: internal data store backend. See https://www.rabbitmq.com/access-control.html for more inforabbit_auth_backend_ldap
: providesAuthN
andAuthZ
backends in a single module, backed by LDAPrabbit_auth_backend_http
: providesAuthN
andAuthZ
backends in a single module, backed by an HTTP servicerabbit_auth_backend_amqp
: providesAuthN
andAuthZ
backends in a single module, backed by an AMQP 0-9-1 service that uses request/response ("RPC")rabbit_quth_backend_uaa
: providesAuthN
andAuthZ
backends in a single module, backed by Cloud Foundry UAA.