README.md 7.26 KB
Newer Older
ale's avatar
ale committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

auth-server
===========

A low-level authentication server with pluggable backends and some
advanced features:

* two-factor authentication support (TOTP, U2F)
* application-specific passwords
* rate limiting and brute force protection
* new device detection

Its purpose is to be the single point of authentication for all
authentication flows in a service.

# Deployment

The auth-server is fully stateless: it delegates state to other
backends such as Memcached for short-term storage, and
[usermetadb](https://git.autistici.org/id/usermetadb) for long-term
anonymized user activity data. For this reason, it is recommended to
install an auth-server on every host.

It listens for authorization requests over a UNIX socket. UNIX
permissions should be used to control access to the socket if
necessary. Clients speak a custom simple line-based attribute/value
protocol, and can send multiple requests over the same connection.

## Services

A *service* in auth-server is a specific scope for an authentication
workflow, normally associated with a specific user-facing
service. Multiple services can be defined, each with its own
functionality and user backends.

## User backends

The authentication server data model is based on the concept of a
*user account*. The server knows how to retrieve user accounts stored
in LDAP, but it has to be told the specific details of how to find
them and how to map the information there to what it needs.


# Configuration


The behavior of auth-server can be configured with a YAML file.
The YAML file should contain a dictionary with the following attributes:

* `services` is a dictionary describing all known services and their
  authentication parameters. See the *Service definition* section below
* `rate_limits` defines the global rate limiters and blacklists. See
  the *Rate limiting* section below.
* `enabled_backends` is the list of user backends that should be
  enabled (the available backends are *file* and *ldap*)
* `ldap_config` specifies the configuration for the LDAP backend --
  see the *LDAP Backend* section below
* `user_meta_server` holds the configuration for the user-meta-server
  backend:
  * `backend_url` is the URL of the service
  * `tls_config` configures TLS for the client:
    * `cert` is the path to the client certificate
    * `key` is the path to the client private key
    * `ca` is the path to the CA store to verify the server certificate

## Rate limiting

Rate limits and blacklists are global (available to all services), to
allow brute force protection to work across multiple services. The
top-level configuration attribute `rate_limits` is a dictionary of
named rate limiting configurations, that can be later referenced in
the service-specific `rate_limits` list. Each rate limiter definition
should specify the following attributes:

* `limit` counts the number of events to allow over a period of time
* `period` defines the period of time
* `blacklist_for` adds the client to a blacklist if their request rate
  goes above the specified threshold
* `on_failure` is a boolean value, when true the rate limiter will
  only be applied to failed authentication requests
* `keys` is a list of strings specifying the request identifiers that
  will make up the rate limiter key. The list can include one or both
  of *ip* (referring to the remote client's IP) and *user* (username)

## Service definition

Each service definition is a dictionary with the following attributes:

* `backends` is a list of user backend specifications, each one should
  include a backend-specific configuration under an attribute named
  after the backend itself:
  * `file` is simply a path to a user list file, see the *File
    backend* section below
  * `ldap` configues the LDAP backend for this service
* `challenge_response` is a boolean parameter that, when true, enables
  two-factor authentication for this service (it should be enabled
  only for interactive services)
* `enforce_2fa` is a boolean flag that, when true, will disable
  non-2FA logins for this service
* `enable_device_tracking` is a boolean flag that enables device
  tracking for this service (assuming the client provides device
  information)
* `rate_limits` is a list of names of global rate limiters to be
  applied to this service.

## File backend

The *file* backend reads users and their credentials from a
YAML-encoded file. This file should contain a list of dictionaries,
each representing a user, with the following attributes:

* `name` is the username
* `email` is the email associated with the user (optional)
* `password` stores the encrypted password
* `totp_secret` stores the *unencrypted* TOTP secret seed
* `groups` is a list of group names that the user belongs to

The file backend only supports TOTP as a two-factor authentication
method, U2F support is currently missing.

## LDAP Backend

The *ldap* backend will look up user information in a LDAP database.

### Query definition

LDAP queries are meant to return a single user account object from the
database using a *search* operation. There's two parts to it: first
the right object needs to be located, then we need to map the object's
attributes to someting that the auth-server understands.

The LDAP query for a service is defined by the following standard LDAP
parameters:

* `search_base` specifies a base DN for the search
* `search_filter` specifies a filter to apply to the search
* `scope` specifies the scope of the LDAP search, must be one of
  *base*, *one* or *sub*
* `attrs` is a dictionary mapping LDAP attributes to their auth-server
  metadata counterparts, see *Schema definition* below.

The `search_filter` should contain somewhere the literal string `%s`,
which will be replaced with the username in the final LDAP query.

### Schema definition

In order to retrieve authentication information from the LDAP object,
the authentication server needs to know which attributes to use. To do
so, we use a so-called *schema definition* (a map of symbolic names to
LDAP attributes). The following attribute names are defined:

* `password` contains the encrypted password. Since this attribute is
  often also used for authentication of the LDAP protocol itself, an
  eventual `{crypt}` prefix is ignored. Passwords should be encrypted.
* `otp_secret` should contain the hex-encoded TOTP secret
* `app_specific_password` (possibly repeated) contains an encrypted
  app-specific password

The default attribute mapping looks like this:

    password: userPassword
    totp_secret: totpSecret
    app_specific_password: appSpecificPassword

Except for *userPassword*, the others are custom LDAP attributes and
are not part of any standard schema definition. You should create your
own.

App-specific passwords should be encoded as colon-separated strings:

    service:encrypted_password:comment

The password should be encrypted. The comment is a free-form string
set by the user to tell the various credentials apart.

## OTP implementation

The authentication server uses a very simple implementation of
time-based OTP (TOTP), supporting a single secret per user and without
any fancy features such as emergency tokens etc. The reason for this
is that TOTP authentication requires just plain read-only access to
the user database, while counter-based authentication with proper
token revocation is a read-write, locked operation which is more
difficult to perform on a LDAP backend.