RAPI authentication and authorization using PAM

This design document describes a way of Ganeti remote API authentication and authorization refactoring by using the pluggable authentication modules (PAM).

Current State

Currently Ganeti remote API supports authentication using basic auth over https protocol. The users are stored in a file (usually /var/lib/ganeti/rapi/users) and have either read or write rights. Please read Users and passwords for more details.

Motivation

During GanetiCon 2015 the following features were requested by the community:

  • Support for different authentication methods;
  • Granular access to different RAPI command subsets;
  • Granular access to different target instances.

The last two statements may be desired when an administrator wants to provide some restricted cluster or instance management rights for users.

Proposed Implementation

Ganeti RAPI will use PAM for authentication and account (authorization) purposes. ganeti-basic PAM module performing authentication and account based on the contents of ganeti/rapi/users file will be distributed with Ganeti. Ganeti rapi will interact with PAM using ganeti-rapi service name. The default configuration for ganeti-rapi PAM service will just use ganeti-basic module.

A good documentation on client-server PAM model is available at http://www.linux-pam.org/pre/doc/current-draft.txt.

Authentication Specific Details

In case of basic auth over http, the username and password will be extracted as they are presented in the standard form. Note, that independent from authentication method, all interactions will be performed via https protocol.

In case of another authentication method, additional user’s credintials (e.g. request signature) should be provided in Ganeti-RAPI-Credential field. The field should be encoded using base64 algorithm as for the basic auth over http.

Ganeti will copy the username to PAM_USER field of a pam_handler and the contents of Ganeti-RAPI-Credential http header fielf to PAM_AUTHTOK field of a pam_handler.

User’s password will be send as a reply to each request made by conversation function with PAM_PROMPT_ECHO_OFF message constant. Other requests will be just ignored.

Authorization Specific Details

Ganeti will pass several parameters that might be useful for the authorization phase to the modules via the private PAM environmental variables (using pam_setenv)

GANETI_RAPI_URI
The requested URI.
GANETI_REQUEST_BODY
The body of a request if any or an empty string otherwise.
GANETI_REQUEST_METHOD
The method of an http request (GET, PUT, POST or DELETE).
GANETI_RESOURCE_ACCESS
The comma-separated access handlers of a resource if provided in rlib2 or empty string otherwise.

One More Time About the Goals

Support for Different Authentication Methods

The proposed solution allows to use signatures of any kind instead of user password or in addition to it. It allows an administrator to support more complex and secure authentication schemes than just a basic authentication over http.

Granular Access to Different Command Subsets

This functionality can be implemented just by writing more complex authorization module that will permit or deny execution of some command based on the environment variables passed and some additional config file.

Granular Access to Different Target Instances

For such kind of authorization, a PAM module may be implemented as well. The main difference is that for complex access rights maintaining the module will have to store users rights and lists of owned objects on some kind of dynamic database instead of simple static config file.

Switching Between the Old and the New Implementations

As the changes introduced should be backwards compatible, a new ganeti-rapi daemon run-time option --enable_pam_rapi will be introduced.

Other Changes

As writing PAM module is an universal solution for the authorization problem, sometimes such flexibility is not necessary or not available because of disabled PAM. In that case it is still possible to provide granular access to the RAPI.

For that purpose RAPI-Auth:username will be added to the reason trail just before sending a job for a further processing. That will allow to configure a filter that will reject job subsets initiated by some specific user i.e. add a user to a blacklist. See Filtering of jobs for the Ganeti job queue for more information about job filters.

Additionally, we propose to introduce a new filter predicate, username that will contain the authenticated user’s login and thus will make it possible to define an allowed user set for each operation.