1**This is the documentation for etcd2 releases. Read [etcd3 doc][v3-docs] for etcd3 releases.**
2
3[v3-docs]: ../docs.md#documentation
4
5
6# v2 Auth and Security
7
8## etcd Resources
9There are three types of resources in etcd
10
111. permission resources: users and roles in the user store
122. key-value resources: key-value pairs in the key-value store
133. settings resources: security settings, auth settings, and dynamic etcd cluster settings (election/heartbeat)
14
15### Permission Resources
16
17#### Users
18A user is an identity to be authenticated. Each user can have multiple roles. The user has a capability (such as reading or writing) on the resource if one of the roles has that capability.
19
20A user named `root` is required before authentication can be enabled, and it always has the ROOT role. The ROOT role can be granted to multiple users, but `root` is required for recovery purposes.
21
22#### Roles
23Each role has exact one associated Permission List. An permission list exists for each permission on key-value resources.
24
25The special static ROOT (named `root`) role has a full permissions on all key-value resources, the permission to manage user resources and settings resources. Only the ROOT role has the permission to manage user resources and modify settings resources. The ROOT role is built-in and does not need to be created.
26
27There is also a special GUEST role, named 'guest'. These are the permissions given to unauthenticated requests to etcd. This role will be created automatically, and by default allows access to the full keyspace due to backward compatibility. (etcd did not previously authenticate any actions.). This role can be modified by a ROOT role holder at any time, to reduce the capabilities of unauthenticated users.
28
29#### Permissions
30
31There are two types of permissions, `read` and `write`. All management and settings require the ROOT role.
32
33A Permission List is a list of allowed patterns for that particular permission (read or write). Only ALLOW prefixes are supported. DENY becomes more complicated and is TBD.
34
35### Key-Value Resources
36A key-value resource is a key-value pairs in the store. Given a list of matching patterns, permission for any given key in a request is granted if any of the patterns in the list match.
37
38Only prefixes or exact keys are supported. A prefix permission string ends in `*`.
39A permission on `/foo` is for that exact key or directory, not its children or recursively. `/foo*` is a prefix that matches `/foo` recursively, and all keys thereunder, and keys with that prefix (eg. `/foobar`. Contrast to the prefix `/foo/*`). `*` alone is permission on the full keyspace.
40
41### Settings Resources
42
43Specific settings for the cluster as a whole. This can include adding and removing cluster members, enabling or disabling authentication, replacing certificates, and any other dynamic configuration by the administrator (holder of the ROOT role).
44
45## v2 Auth
46
47### Basic Auth
48We only support [Basic Auth][basic-auth] for the first version. Client needs to attach the basic auth to the HTTP Authorization Header.
49
50### Authorization field for operations
51Added to requests to /v2/keys, /v2/auth
52Add code 401 Unauthorized to the set of responses from the v2 API
53Authorization: Basic {encoded string}
54
55### Future Work
56Other types of auth can be considered for the future (eg, signed certs, public keys) but the `Authorization:` header allows for other such types
57
58### Things out of Scope for etcd Permissions
59
60* Pluggable AUTH backends like LDAP (other Authorization tokens generated by LDAP et al may be a possibility)
61* Very fine-grained access controls (eg: users modifying keys outside work hours)
62
63
64
65## API endpoints
66
67An Error JSON corresponds to:
68{
69  "name": "ErrErrorName",
70  "description" : "The longer helpful description of the error."
71}
72
73#### Enable and Disable Authentication
74
75**Get auth status**
76
77GET  /v2/auth/enable
78
79    Sent Headers:
80    Possible Status Codes:
81        200 OK
82    200 Body:
83        {
84          "enabled": true
85        }
86
87
88**Enable auth**
89
90PUT  /v2/auth/enable
91
92    Sent Headers:
93    Put Body: (empty)
94    Possible Status Codes:
95        200 OK
96        400 Bad Request (if root user has not been created)
97        409 Conflict (already enabled)
98    200 Body: (empty)
99
100**Disable auth**
101
102DELETE  /v2/auth/enable
103
104    Sent Headers:
105        Authorization: Basic <RootAuthString>
106    Possible Status Codes:
107        200 OK
108        401 Unauthorized (if not a root user)
109        409 Conflict (already disabled)
110    200 Body: (empty)
111
112
113#### Users
114
115The User JSON object is formed as follows:
116
117```
118{
119  "user": "userName",
120  "password": "password",
121  "roles": [
122    "role1",
123    "role2"
124  ],
125  "grant": [],
126  "revoke": []
127}
128```
129
130Password is only passed when necessary.
131
132**Get a List of Users**
133
134GET/HEAD  /v2/auth/users
135
136    Sent Headers:
137        Authorization: Basic <BasicAuthString>
138    Possible Status Codes:
139        200 OK
140        401 Unauthorized
141    200 Headers:
142        Content-type: application/json
143    200 Body:
144        {
145          "users": [
146            {
147              "user": "alice",
148              "roles": [
149                {
150                  "role": "root",
151                  "permissions": {
152                    "kv": {
153                      "read": ["/*"],
154                      "write": ["/*"]
155                    }
156                  }
157                }
158              ]
159            },
160            {
161              "user": "bob",
162              "roles": [
163                {
164                  "role": "guest",
165                  "permissions": {
166                    "kv": {
167                      "read": ["/*"],
168                      "write": ["/*"]
169                    }
170                  }
171                }
172              ]
173            }
174          ]
175        }
176
177**Get User Details**
178
179GET/HEAD  /v2/auth/users/alice
180
181    Sent Headers:
182        Authorization: Basic <BasicAuthString>
183    Possible Status Codes:
184        200 OK
185        401 Unauthorized
186        404 Not Found
187    200 Headers:
188        Content-type: application/json
189    200 Body:
190        {
191          "user" : "alice",
192          "roles" : [
193            {
194              "role": "fleet",
195              "permissions" : {
196                "kv" : {
197                  "read": [ "/fleet/" ],
198                  "write": [ "/fleet/" ]
199                }
200              }
201            },
202            {
203              "role": "etcd",
204              "permissions" : {
205                "kv" : {
206                  "read": [ "/*" ],
207                  "write": [ "/*" ]
208                }
209              }
210            }
211          ]
212        }
213
214**Create Or Update A User**
215
216A user can be created with initial roles, if filled in. However, no roles are required; only the username and password fields
217
218PUT  /v2/auth/users/charlie
219
220    Sent Headers:
221        Authorization: Basic <BasicAuthString>
222    Put Body:
223        JSON struct, above, matching the appropriate name
224          * Starting password and roles when creating.
225          * Grant/Revoke/Password filled in when updating (to grant roles, revoke roles, or change the password).
226    Possible Status Codes:
227        200 OK
228        201 Created
229        400 Bad Request
230        401 Unauthorized
231        404 Not Found (update non-existent users)
232        409 Conflict (when granting duplicated roles or revoking non-existent roles)
233    200 Headers:
234        Content-type: application/json
235    200 Body:
236        JSON state of the user
237
238**Remove A User**
239
240DELETE  /v2/auth/users/charlie
241
242    Sent Headers:
243        Authorization: Basic <BasicAuthString>
244    Possible Status Codes:
245        200 OK
246        401 Unauthorized
247        403 Forbidden (remove root user when auth is enabled)
248        404 Not Found
249    200 Headers:
250    200 Body: (empty)
251
252#### Roles
253
254A full role structure may look like this. A Permission List structure is used for the "permissions", "grant", and "revoke" keys.
255```
256{
257  "role" : "fleet",
258  "permissions" : {
259    "kv" : {
260      "read" : [ "/fleet/" ],
261      "write": [ "/fleet/" ]
262    }
263  },
264  "grant" : {"kv": {...}},
265  "revoke": {"kv": {...}}
266}
267```
268
269**Get Role Details**
270
271GET/HEAD  /v2/auth/roles/fleet
272
273    Sent Headers:
274        Authorization: Basic <BasicAuthString>
275    Possible Status Codes:
276        200 OK
277        401 Unauthorized
278        404 Not Found
279    200 Headers:
280        Content-type: application/json
281    200 Body:
282        {
283          "role" : "fleet",
284          "permissions" : {
285            "kv" : {
286              "read": [ "/fleet/" ],
287              "write": [ "/fleet/" ]
288            }
289          }
290        }
291
292**Get a list of Roles**
293
294GET/HEAD  /v2/auth/roles
295
296    Sent Headers:
297        Authorization: Basic <BasicAuthString>
298    Possible Status Codes:
299        200 OK
300        401 Unauthorized
301    200 Headers:
302        Content-type: application/json
303    200 Body:
304        {
305          "roles": [
306            {
307              "role": "fleet",
308              "permissions": {
309                "kv": {
310                  "read": ["/fleet/"],
311                  "write": ["/fleet/"]
312                }
313              }
314            },
315            {
316              "role": "etcd",
317              "permissions": {
318                "kv": {
319                  "read": ["/*"],
320                  "write": ["/*"]
321                }
322              }
323            },
324            {
325              "role": "quay",
326              "permissions": {
327                "kv": {
328                  "read": ["/*"],
329                  "write": ["/*"]
330                }
331              }
332            }
333          ]
334        }
335
336**Create Or Update A Role**
337
338PUT  /v2/auth/roles/rkt
339
340    Sent Headers:
341        Authorization: Basic <BasicAuthString>
342    Put Body:
343        Initial desired JSON state, including the role name for verification and:
344          * Starting permission set if creating
345          * Granted/Revoked permission set if updating
346    Possible Status Codes:
347        200 OK
348        201 Created
349        400 Bad Request
350        401 Unauthorized
351        404 Not Found (update non-existent roles)
352        409 Conflict (when granting duplicated permission or revoking non-existent permission)
353    200 Body:
354        JSON state of the role
355
356**Remove A Role**
357
358DELETE  /v2/auth/roles/rkt
359
360    Sent Headers:
361        Authorization: Basic <BasicAuthString>
362    Possible Status Codes:
363        200 OK
364        401 Unauthorized
365        403 Forbidden (remove root)
366        404 Not Found
367    200 Headers:
368    200 Body: (empty)
369
370
371## Example Workflow
372
373Let's walk through an example to show two tenants (applications, in our case) using etcd permissions.
374
375### Create root role
376
377```
378PUT  /v2/auth/users/root
379    Put Body:
380        {"user" : "root", "password": "betterRootPW!"}
381```
382
383### Enable auth
384
385```
386PUT  /v2/auth/enable
387```
388
389### Modify guest role (revoke write permission)
390
391```
392PUT  /v2/auth/roles/guest
393    Headers:
394        Authorization: Basic <root:betterRootPW!>
395    Put Body:
396        {
397          "role" : "guest",
398          "revoke" : {
399            "kv" : {
400              "write": [
401                "/*"
402              ]
403            }
404          }
405        }
406```
407
408
409### Create Roles for the Applications
410
411Create the rkt role fully specified:
412
413```
414PUT /v2/auth/roles/rkt
415    Headers:
416        Authorization: Basic <root:betterRootPW!>
417    Body:
418        {
419          "role" : "rkt",
420          "permissions" : {
421            "kv": {
422              "read": [
423                "/rkt/*"
424              ],
425              "write": [
426                "/rkt/*"
427              ]
428            }
429          }
430        }
431```
432
433But let's make fleet just a basic role for now:
434
435```
436PUT /v2/auth/roles/fleet
437    Headers:
438      Authorization: Basic <root:betterRootPW!>
439    Body:
440        {
441          "role" : "fleet"
442        }
443```
444
445### Optional: Grant some permissions to the roles
446
447Well, we finally figured out where we want fleet to live. Let's fix it.
448(Note that we avoided this in the rkt case. So this step is optional.)
449
450
451```
452PUT /v2/auth/roles/fleet
453    Headers:
454        Authorization: Basic <root:betterRootPW!>
455    Put Body:
456        {
457          "role" : "fleet",
458          "grant" : {
459            "kv" : {
460              "read": [
461                "/rkt/fleet",
462                "/fleet/*"
463              ]
464            }
465          }
466        }
467```
468
469### Create Users
470
471Same as before, let's use rocket all at once and fleet separately
472
473```
474PUT /v2/auth/users/rktuser
475    Headers:
476        Authorization: Basic <root:betterRootPW!>
477    Body:
478        {"user" : "rktuser", "password" : "rktpw", "roles" : ["rkt"]}
479```
480
481```
482PUT /v2/auth/users/fleetuser
483    Headers:
484        Authorization: Basic <root:betterRootPW!>
485    Body:
486        {"user" : "fleetuser", "password" : "fleetpw"}
487```
488
489### Optional: Grant Roles to Users
490
491Likewise, let's explicitly grant fleetuser access.
492
493```
494PUT /v2/auth/users/fleetuser
495    Headers:
496        Authorization: Basic <root:betterRootPW!>
497    Body:
498        {"user": "fleetuser", "grant": ["fleet"]}
499```
500
501#### Start to use fleetuser and rktuser
502
503
504For example:
505
506```
507PUT /v2/keys/rkt/RktData
508    Headers:
509        Authorization: Basic <rktuser:rktpw>
510    Body:
511        value=launch
512```
513
514Reads and writes outside the prefixes granted will fail with a 401 Unauthorized.
515
516[basic-auth]: https://en.wikipedia.org/wiki/Basic_access_authentication
517