Implement a basic authentication protocol

Registered by Kostja Osipov

What do we need this for?
----------------------------------
- as a pre-requisite for authorization; we need to get rid of the read-only and read-write ports, and track privileges based on the connection identity
- user limits (limit memory consumed by a user)
- managed Tarantool hosting: we want to be able to open up a few machines to the community so that they can try out tarantool without installing it
- We need to be able to establish identity of an event in the binary log (i.e. its author), e.g. to be able to track buggy applications that corrupt the data store.
Implement authentication on connect and keep track of the user id for every event in the binary log.

Backward compatibility
-----------------------------

To be able to gradually phase out current applications, that are not authentication-aware, authentication will be optional. A connection which was not authenticated will belong to "anonymous" user.

Selecting the protocol
----------------------------
Since Tarantool supports multiple protocols, we need to be able to select the protocol for use right after authentication. On the same token, for easier backward compatibility, since we add an exchange between client and server per every connect, we need to add client and server capability information to that exchange, to be able to roll out further changes in the protocol more easily.

The question arises how we pass these capabilities along with the authentication information, in a pluggable manner.

Pluggability
---------------
The server needs to make its authentication protocol pluggable. We need to be able to support some very simple authentication schemes, used in the most cases, a basic secure scheme, which ensures we never transfer unencrypted password over the network or store on server side, single-sign-on capabilities, i.e. use
of the operating system credential information, and advanced schemes, such as SASL and Kerberos.
Support for stateless proxying
---------------------------------------
A common use case with Tarantool/Box is when a user-space TCP/IP proxy is put in the middle,
to multiplex thousands of incoming connections to just a few connections to Tarantool/Box.
The current protocol is state-less: the server can read thousands of requests and reply to them
asynchronously, possibly in an ad-hoc order. The job of the proxy is, therefore, to simply route incoming
request packets according to a strategy (e.g. round-robin), and route back the response according
to its sequence id. As a result, our authentication should not restrict the connection to a given client:
the connection should continue to be stateless, rather, we should extend each packet
with an authentication token. Additionally, it should be possible to re-issue an authentication
request and thus get a new token: this will allow to re-authenticate a now purely logical
session with different credentials once in a while.

References
---------------

Pluggable authentication in MySQL 5.5:
http://forge.mysql.com/worklog/task.php?id=1054 (click on high level architecture/low level design for details)

Open issues
----------------
What's our default authentication plug-in? DES based?
How and whether we need to support multiple authentication schemes per server? Perhaps only with advanced plug-ins.
What are the introspection capabilities we add? How do I know which who I am?

Current Development Status
------------------------------------

1. Authentication

* Basic support for plugable modules has been added. Now server loads all plugins from plugin directory (plug_dir config param).
Plugins can extend any future server functionality, not just authentication.

* Authentication support done with authentication mechanism (AM) abstraction. Plugins or other entities can register own AM's.
Server uses specified (auth config param) AM to handle all authentication. When authentication is done, AM returns client-selected protocol type.

* Main authentication plugin auth_chap (plugins/auth_chap) been added. It adds "chap" AM, that uses 3-way user authentication in following maner:

   [1] client connection to server.
   [2] server sends authentication token (random)
   [3] client gets hash by encrypting server token with client key and sends it back to server
         with selected tarantool protocol type (admin, ro, rw) and user id
   [4] server gets hash by encrypting token with server key, and compares hashes, search for specified user id
   [5] server sends authentication result to client

Auth_chap encription is based on AES-128 Cipher-based Message Authentication (CMAC) from OpenBSD implementation (third_party/rijndael.c, third_party/cmac.c). It uses 16 bytes key length.

Choice of AES been made from analyzing speed/keylen of common ciphers/hash's, and idea that, if necessary, some future hardware encryption speed-ups can be granted from AES-NI cpu (xeon, i5-i7) extension.

* Basic user support added. Users can be declared in configuration file (users param) in id-key maner. Current authenticated user is associated with it's connection (fiber).

* New port added with authentication support (main_port config param).

2. Client library (connector/c)

* tarantool client library (libtnt) added (connector/c). It has
  following features:

    - authentication (chap and none methods supported)
    - tuple sets encoding/decoding
    - bufferized send/recv
    - support of ping, insert, update, delete, select operations
    - one interface receiving operation
    - admin protocol available through tnt_raw interface

3. Stress-suite

* basic tarantool stress-suite client based on libtnt (test-stress). It meassures all common operations
  timing (query-response) for different buffer sizes/flags etc.

4. Open Issues (Authentication)

* Feeder authentication support? Feeder should authenticate server? Or server should authenticate feeder?
Perhaps two-factor authentication is needed.

* Connected state-less Proxy authentication. In this context state-less means proxy doens't know anything about tarantool
protocol. There are some major issue's supporting client authentication by proxy who is always connected to server:

   1. Client connects to proxy and awaits server token response. In that case, proxy should know when to send authentication request
to server (which also should be a part of protocol), so the basic idea of state-less is loosing in this point.

   2. If we can try to avoid first issue by trying to change steps of authentication sequence like:

        1. when client connects, it sends { procol type, and id } (not awaits token from server). Authentication in that case,
should be implemented like new tarantol protocol operation.
        2. server sends token back, etc
        3. client signs token
        4. server sends reply.

   In that case, we would get following situation:

        - we have to send new undesirable message

        - server should know about clients that processes authentication in a moment (by reqid, or other new token field)
lf
        - tarantool server need to know, that it speeks to proxy, to support authentication operation (if it is not proxy, how can we
correctly authenticate user? there should be some internal state, that indicates that current client is authenticated, before sending other operations).

        - how can we track that current user is authenticated - we should attach some token field to all transactions? In that case, if any other clients connects to proxy, and uses then same token, it can send req's like that user. In that case - sending token is the same like sending passwords in plain text. We can avoid it only, if we would sign _every transaction between user-server.

Resuming following issues, state-less proxy would have a great performance lost in the end, with need in unreasonable major code modifications.

Probably proxy server should be a part of tarantool project, maybe it should be implemented as proxy mod (tarantool_proxy), like box, feeder, etc.

Audit log
-------------

Implement audit log to be able to log all authenticated users.

Other issues to consider
---------------------------------
- change the bind address/port specification scheme in the configuration file, to support uris, so that we can bind to different transport using the same configuration file (unix://localhost/var/run/sock, tcp://192.168.1.10:33015, and so on).
- make it possible to bind to multiple URLs, but support only a few protocols on a given uri
- make it possible to switch off authentication completely

Blueprint information

Status:
Not started
Approver:
Kostja Osipov
Priority:
Undefined
Drafter:
None
Direction:
Approved
Assignee:
Dmitry Simonenko
Definition:
Discussion
Series goal:
Accepted for 1.5
Implementation:
Deferred
Milestone target:
None

Related branches

Sprints

Whiteboard

(?)

Work Items

This blueprint contains Public information 
Everyone can see this information.

Subscribers

No subscribers.