128 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# PAM Authenticator
 | 
						|
 | 
						|
Pluggable authentication module (PAM) is a general purpose authentication API.
 | 
						|
An application using PAM can authenticate a user without knowledge about the
 | 
						|
underlying authentication implementation. The actual authentication scheme is
 | 
						|
defined in the operating system PAM config (e.g. `/etc/pam.d/`), and can be
 | 
						|
quite elaborate. MaxScale supports a very limited form of the PAM protocol,
 | 
						|
which this document details.
 | 
						|
 | 
						|
## Configuration
 | 
						|
 | 
						|
The MaxScale PAM modules themselves have no configuration. All that is required
 | 
						|
is to change the listener and backend authenticator modules to `PAMAuth` and
 | 
						|
`PAMBackendAuth`, respectively.
 | 
						|
 | 
						|
```
 | 
						|
[Read-Write-Listener]
 | 
						|
type=listener
 | 
						|
address=::
 | 
						|
service=Read-Write-Service
 | 
						|
protocol=MariaDBClient
 | 
						|
authenticator=PAMAuth
 | 
						|
 | 
						|
[Master-Server]
 | 
						|
type=server
 | 
						|
address=123.456.789.10
 | 
						|
port=12345
 | 
						|
protocol=MariaDBBackend
 | 
						|
authenticator=PAMBackendAuth
 | 
						|
```
 | 
						|
 | 
						|
The PAM authenticator fetches user entries with `plugin='pam'` from the
 | 
						|
`mysql.user` table of a backend. The user accounts also need to have either the
 | 
						|
global SELECT-privilege or a database or a table-level privilege. Privileges
 | 
						|
through a default role are also detected. The PAM service name of a user is read
 | 
						|
from the `authetication_string`-column. The matching PAM service in the
 | 
						|
operating system PAM config is used for authenticating the user. If the
 | 
						|
`authetication_string` for a user is empty, the fallback service `mysql` is
 | 
						|
used.
 | 
						|
 | 
						|
PAM service configuration is out of the scope of this document, see
 | 
						|
[The Linux-PAM System Administrators' Guide
 | 
						|
](http://www.linux-pam.org/Linux-PAM-html/Linux-PAM_SAG.html) for more
 | 
						|
information. A simple service definition used for testing this module is below.
 | 
						|
 | 
						|
```
 | 
						|
auth            required        pam_unix.so
 | 
						|
account         required        pam_unix.so
 | 
						|
```
 | 
						|
 | 
						|
## Anonymous user mapping
 | 
						|
 | 
						|
The MaxScale PAM authenticator supports a limited version of
 | 
						|
[user mapping](https://mariadb.com/kb/en/library/user-and-group-mapping-with-pam/).
 | 
						|
It requires less configuration but is also less accurate than the server
 | 
						|
authentication. Anonymous mapping is enabled in MaxScale if the following user
 | 
						|
exists:
 | 
						|
- Empty username (e.g. `''@'%'` or `''@'myhost.com'`)
 | 
						|
- `plugin = 'pam'`
 | 
						|
- Proxy grant is on (The query `SHOW GRANTS FOR user@host;` returns at least one
 | 
						|
row with `GRANT PROXY ON ...`)
 | 
						|
 | 
						|
When the authenticator detects such users, anonymous account mapping is enabled
 | 
						|
for the hosts of the anonymous users. To verify this, enable the info log
 | 
						|
(`log_info=1` in MaxScale config file) and look for messages such as "Found 2
 | 
						|
anonymous PAM user(s) ..." and "Added anonymous PAM user ..." during MaxScale
 | 
						|
startup.
 | 
						|
 | 
						|
When mapping is on, the MaxScale PAM authenticator does not require client
 | 
						|
accounts to exist in the `mysql.user`-table received from the backend. MaxScale
 | 
						|
only requires that the hostname of the incoming client matches the host field of
 | 
						|
one of the anonymous users (comparison performed using `LIKE`). If a match is
 | 
						|
found, MaxScale attempts to authenticate the client to the local machine with
 | 
						|
the username and password supplied. The PAM service used for authentication is
 | 
						|
read from the `authentication_string`-field of the anonymous user. If
 | 
						|
authentication was successful, MaxScale then uses the username and password to
 | 
						|
log to the backends.
 | 
						|
 | 
						|
Anonymous mapping is only attempted if the client username is not found in the
 | 
						|
`mysql.user`-table as explained in [Configuration](#configuration). This means,
 | 
						|
that if a user is found and the authentication fails, anonymous authentication
 | 
						|
is not attempted even when it could use a different PAM service with a different
 | 
						|
outcome.
 | 
						|
 | 
						|
Setting up PAM group mapping for the MariaDB server is a more involved process
 | 
						|
as the server requires details on which Unix user or group is mapped to which
 | 
						|
MariaDB user. See
 | 
						|
[this guide](https://mariadb.com/kb/en/library/configuring-pam-authentication-and-user-mapping-with-unix-authentication/)
 | 
						|
for more details. Performing all the steps in the guide also on the MaxScale
 | 
						|
machine is not required, as the MaxScale PAM plugin only checks that the client
 | 
						|
host matches an anonymous user and that the client (with the username and
 | 
						|
password it provided) can log into the local PAM configuration. If using normal
 | 
						|
password authentication, simply generating the Unix user and password should be
 | 
						|
enough.
 | 
						|
 | 
						|
## Implementation details and limitations
 | 
						|
 | 
						|
The general PAM authentication scheme is difficult for a proxy such as MaxScale.
 | 
						|
An application using the PAM interface needs to define a *conversation function*
 | 
						|
to allow the OS PAM modules to communicate with the client, possibly exchanging
 | 
						|
multiple messages. This works when a client logs in to a normal server, but not
 | 
						|
with MaxScale since it needs to autonomously log into multiple backends. For
 | 
						|
MaxScale to successfully log into the servers, the messages and answers need to
 | 
						|
be predefined. This requirement denies the use of more exotic schemes such as
 | 
						|
one-time passwords or two-factor authentication.
 | 
						|
 | 
						|
The MaxScale PAM authentication module only supports a simple password exchange.
 | 
						|
On the client side, the authentication begins with MaxScale sending an
 | 
						|
AuthSwitchRequest packet. In addition to the command, the packet contains the
 | 
						|
client plugin name `dialog`, a message type byte `4` and the message
 | 
						|
`Password: `. In the next packet, the client should send the password, which
 | 
						|
MaxScale will forward to the PAM API running on the local machine. If the
 | 
						|
password is correct, an OK packet is sent to the client. If the local PAM API
 | 
						|
asks for  additional credentials as is typical in two-factor authentication
 | 
						|
schemes, authentication fails. Informational messages such as password
 | 
						|
expiration notifications are allowed. These are simply printed to the log.
 | 
						|
 | 
						|
On the backend side, MaxScale expects the servers to act as MaxScale did towards
 | 
						|
the client. The servers should send an AuthSwitchRequest packet as defined
 | 
						|
above, MaxScale responds with the password received by the client authenticator
 | 
						|
and finally backend replies with OK. Informational messages from backends are
 | 
						|
only printed to the info-log.
 | 
						|
 | 
						|
## Building the module
 | 
						|
 | 
						|
The PAM authenticator modules require the PAM and SQLite3 development
 | 
						|
libraries (libpam0g-dev and sqlite3-dev on Ubuntu).
 |