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