github.imxd.top/hashicorp/consul@v1.4.5/api/acl.go (about) 1 package api 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "time" 8 ) 9 10 const ( 11 // ACLClientType is the client type token 12 ACLClientType = "client" 13 14 // ACLManagementType is the management type token 15 ACLManagementType = "management" 16 ) 17 18 type ACLTokenPolicyLink struct { 19 ID string 20 Name string 21 } 22 23 // ACLToken represents an ACL Token 24 type ACLToken struct { 25 CreateIndex uint64 26 ModifyIndex uint64 27 AccessorID string 28 SecretID string 29 Description string 30 Policies []*ACLTokenPolicyLink 31 Local bool 32 CreateTime time.Time `json:",omitempty"` 33 Hash []byte `json:",omitempty"` 34 35 // DEPRECATED (ACL-Legacy-Compat) 36 // Rules will only be present for legacy tokens returned via the new APIs 37 Rules string `json:",omitempty"` 38 } 39 40 type ACLTokenListEntry struct { 41 CreateIndex uint64 42 ModifyIndex uint64 43 AccessorID string 44 Description string 45 Policies []*ACLTokenPolicyLink 46 Local bool 47 CreateTime time.Time 48 Hash []byte 49 Legacy bool 50 } 51 52 // ACLEntry is used to represent a legacy ACL token 53 // The legacy tokens are deprecated. 54 type ACLEntry struct { 55 CreateIndex uint64 56 ModifyIndex uint64 57 ID string 58 Name string 59 Type string 60 Rules string 61 } 62 63 // ACLReplicationStatus is used to represent the status of ACL replication. 64 type ACLReplicationStatus struct { 65 Enabled bool 66 Running bool 67 SourceDatacenter string 68 ReplicationType string 69 ReplicatedIndex uint64 70 ReplicatedTokenIndex uint64 71 LastSuccess time.Time 72 LastError time.Time 73 } 74 75 // ACLPolicy represents an ACL Policy. 76 type ACLPolicy struct { 77 ID string 78 Name string 79 Description string 80 Rules string 81 Datacenters []string 82 Hash []byte 83 CreateIndex uint64 84 ModifyIndex uint64 85 } 86 87 type ACLPolicyListEntry struct { 88 ID string 89 Name string 90 Description string 91 Datacenters []string 92 Hash []byte 93 CreateIndex uint64 94 ModifyIndex uint64 95 } 96 97 // ACL can be used to query the ACL endpoints 98 type ACL struct { 99 c *Client 100 } 101 102 // ACL returns a handle to the ACL endpoints 103 func (c *Client) ACL() *ACL { 104 return &ACL{c} 105 } 106 107 // Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster 108 // to get the first management token. 109 func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) { 110 r := a.c.newRequest("PUT", "/v1/acl/bootstrap") 111 rtt, resp, err := requireOK(a.c.doRequest(r)) 112 if err != nil { 113 return nil, nil, err 114 } 115 defer resp.Body.Close() 116 117 wm := &WriteMeta{RequestTime: rtt} 118 var out ACLToken 119 if err := decodeBody(resp, &out); err != nil { 120 return nil, nil, err 121 } 122 return &out, wm, nil 123 } 124 125 // Create is used to generate a new token with the given parameters 126 // 127 // Deprecated: Use TokenCreate instead. 128 func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) { 129 r := a.c.newRequest("PUT", "/v1/acl/create") 130 r.setWriteOptions(q) 131 r.obj = acl 132 rtt, resp, err := requireOK(a.c.doRequest(r)) 133 if err != nil { 134 return "", nil, err 135 } 136 defer resp.Body.Close() 137 138 wm := &WriteMeta{RequestTime: rtt} 139 var out struct{ ID string } 140 if err := decodeBody(resp, &out); err != nil { 141 return "", nil, err 142 } 143 return out.ID, wm, nil 144 } 145 146 // Update is used to update the rules of an existing token 147 // 148 // Deprecated: Use TokenUpdate instead. 149 func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) { 150 r := a.c.newRequest("PUT", "/v1/acl/update") 151 r.setWriteOptions(q) 152 r.obj = acl 153 rtt, resp, err := requireOK(a.c.doRequest(r)) 154 if err != nil { 155 return nil, err 156 } 157 defer resp.Body.Close() 158 159 wm := &WriteMeta{RequestTime: rtt} 160 return wm, nil 161 } 162 163 // Destroy is used to destroy a given ACL token ID 164 // 165 // Deprecated: Use TokenDelete instead. 166 func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) { 167 r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id) 168 r.setWriteOptions(q) 169 rtt, resp, err := requireOK(a.c.doRequest(r)) 170 if err != nil { 171 return nil, err 172 } 173 resp.Body.Close() 174 175 wm := &WriteMeta{RequestTime: rtt} 176 return wm, nil 177 } 178 179 // Clone is used to return a new token cloned from an existing one 180 // 181 // Deprecated: Use TokenClone instead. 182 func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) { 183 r := a.c.newRequest("PUT", "/v1/acl/clone/"+id) 184 r.setWriteOptions(q) 185 rtt, resp, err := requireOK(a.c.doRequest(r)) 186 if err != nil { 187 return "", nil, err 188 } 189 defer resp.Body.Close() 190 191 wm := &WriteMeta{RequestTime: rtt} 192 var out struct{ ID string } 193 if err := decodeBody(resp, &out); err != nil { 194 return "", nil, err 195 } 196 return out.ID, wm, nil 197 } 198 199 // Info is used to query for information about an ACL token 200 // 201 // Deprecated: Use TokenRead instead. 202 func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) { 203 r := a.c.newRequest("GET", "/v1/acl/info/"+id) 204 r.setQueryOptions(q) 205 rtt, resp, err := requireOK(a.c.doRequest(r)) 206 if err != nil { 207 return nil, nil, err 208 } 209 defer resp.Body.Close() 210 211 qm := &QueryMeta{} 212 parseQueryMeta(resp, qm) 213 qm.RequestTime = rtt 214 215 var entries []*ACLEntry 216 if err := decodeBody(resp, &entries); err != nil { 217 return nil, nil, err 218 } 219 if len(entries) > 0 { 220 return entries[0], qm, nil 221 } 222 return nil, qm, nil 223 } 224 225 // List is used to get all the ACL tokens 226 // 227 // Deprecated: Use TokenList instead. 228 func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) { 229 r := a.c.newRequest("GET", "/v1/acl/list") 230 r.setQueryOptions(q) 231 rtt, resp, err := requireOK(a.c.doRequest(r)) 232 if err != nil { 233 return nil, nil, err 234 } 235 defer resp.Body.Close() 236 237 qm := &QueryMeta{} 238 parseQueryMeta(resp, qm) 239 qm.RequestTime = rtt 240 241 var entries []*ACLEntry 242 if err := decodeBody(resp, &entries); err != nil { 243 return nil, nil, err 244 } 245 return entries, qm, nil 246 } 247 248 // Replication returns the status of the ACL replication process in the datacenter 249 func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, error) { 250 r := a.c.newRequest("GET", "/v1/acl/replication") 251 r.setQueryOptions(q) 252 rtt, resp, err := requireOK(a.c.doRequest(r)) 253 if err != nil { 254 return nil, nil, err 255 } 256 defer resp.Body.Close() 257 258 qm := &QueryMeta{} 259 parseQueryMeta(resp, qm) 260 qm.RequestTime = rtt 261 262 var entries *ACLReplicationStatus 263 if err := decodeBody(resp, &entries); err != nil { 264 return nil, nil, err 265 } 266 return entries, qm, nil 267 } 268 269 // TokenCreate creates a new ACL token. It requires that the AccessorID and SecretID fields 270 // of the ACLToken structure to be empty as these will be filled in by Consul. 271 func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 272 if token.AccessorID != "" { 273 return nil, nil, fmt.Errorf("Cannot specify an AccessorID in Token Creation") 274 } 275 276 if token.SecretID != "" { 277 return nil, nil, fmt.Errorf("Cannot specify a SecretID in Token Creation") 278 } 279 280 r := a.c.newRequest("PUT", "/v1/acl/token") 281 r.setWriteOptions(q) 282 r.obj = token 283 rtt, resp, err := requireOK(a.c.doRequest(r)) 284 if err != nil { 285 return nil, nil, err 286 } 287 defer resp.Body.Close() 288 289 wm := &WriteMeta{RequestTime: rtt} 290 var out ACLToken 291 if err := decodeBody(resp, &out); err != nil { 292 return nil, nil, err 293 } 294 295 return &out, wm, nil 296 } 297 298 // TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid 299 // AccessorID must be set in the ACLToken structure passed to this function but the SecretID may 300 // be omitted and will be filled in by Consul with its existing value. 301 func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 302 if token.AccessorID == "" { 303 return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating") 304 } 305 r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID) 306 r.setWriteOptions(q) 307 r.obj = token 308 rtt, resp, err := requireOK(a.c.doRequest(r)) 309 if err != nil { 310 return nil, nil, err 311 } 312 defer resp.Body.Close() 313 314 wm := &WriteMeta{RequestTime: rtt} 315 var out ACLToken 316 if err := decodeBody(resp, &out); err != nil { 317 return nil, nil, err 318 } 319 320 return &out, wm, nil 321 } 322 323 // TokenClone will create a new token with the same policies and locality as the original 324 // token but will have its own auto-generated AccessorID and SecretID as well having the 325 // description passed to this function. The tokenID parameter must be a valid Accessor ID 326 // of an existing token. 327 func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 328 if tokenID == "" { 329 return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning") 330 } 331 332 r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone") 333 r.setWriteOptions(q) 334 r.obj = struct{ Description string }{description} 335 rtt, resp, err := requireOK(a.c.doRequest(r)) 336 if err != nil { 337 return nil, nil, err 338 } 339 defer resp.Body.Close() 340 341 wm := &WriteMeta{RequestTime: rtt} 342 var out ACLToken 343 if err := decodeBody(resp, &out); err != nil { 344 return nil, nil, err 345 } 346 347 return &out, wm, nil 348 } 349 350 // TokenDelete removes a single ACL token. The tokenID parameter must be a valid 351 // Accessor ID of an existing token. 352 func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) { 353 r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID) 354 r.setWriteOptions(q) 355 rtt, resp, err := requireOK(a.c.doRequest(r)) 356 if err != nil { 357 return nil, err 358 } 359 resp.Body.Close() 360 361 wm := &WriteMeta{RequestTime: rtt} 362 return wm, nil 363 } 364 365 // TokenRead retrieves the full token details. The tokenID parameter must be a valid 366 // Accessor ID of an existing token. 367 func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) { 368 r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID) 369 r.setQueryOptions(q) 370 rtt, resp, err := requireOK(a.c.doRequest(r)) 371 if err != nil { 372 return nil, nil, err 373 } 374 defer resp.Body.Close() 375 376 qm := &QueryMeta{} 377 parseQueryMeta(resp, qm) 378 qm.RequestTime = rtt 379 380 var out ACLToken 381 if err := decodeBody(resp, &out); err != nil { 382 return nil, nil, err 383 } 384 385 return &out, qm, nil 386 } 387 388 // TokenReadSelf retrieves the full token details of the token currently 389 // assigned to the API Client. In this manner its possible to read a token 390 // by its Secret ID. 391 func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) { 392 r := a.c.newRequest("GET", "/v1/acl/token/self") 393 r.setQueryOptions(q) 394 rtt, resp, err := requireOK(a.c.doRequest(r)) 395 if err != nil { 396 return nil, nil, err 397 } 398 defer resp.Body.Close() 399 400 qm := &QueryMeta{} 401 parseQueryMeta(resp, qm) 402 qm.RequestTime = rtt 403 404 var out ACLToken 405 if err := decodeBody(resp, &out); err != nil { 406 return nil, nil, err 407 } 408 409 return &out, qm, nil 410 } 411 412 // TokenList lists all tokens. The listing does not contain any SecretIDs as those 413 // may only be retrieved by a call to TokenRead. 414 func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) { 415 r := a.c.newRequest("GET", "/v1/acl/tokens") 416 r.setQueryOptions(q) 417 rtt, resp, err := requireOK(a.c.doRequest(r)) 418 if err != nil { 419 return nil, nil, err 420 } 421 defer resp.Body.Close() 422 423 qm := &QueryMeta{} 424 parseQueryMeta(resp, qm) 425 qm.RequestTime = rtt 426 427 var entries []*ACLTokenListEntry 428 if err := decodeBody(resp, &entries); err != nil { 429 return nil, nil, err 430 } 431 return entries, qm, nil 432 } 433 434 // PolicyCreate will create a new policy. It is not allowed for the policy parameters 435 // ID field to be set as this will be generated by Consul while processing the request. 436 func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 437 if policy.ID != "" { 438 return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation") 439 } 440 441 r := a.c.newRequest("PUT", "/v1/acl/policy") 442 r.setWriteOptions(q) 443 r.obj = policy 444 rtt, resp, err := requireOK(a.c.doRequest(r)) 445 if err != nil { 446 return nil, nil, err 447 } 448 defer resp.Body.Close() 449 450 wm := &WriteMeta{RequestTime: rtt} 451 var out ACLPolicy 452 if err := decodeBody(resp, &out); err != nil { 453 return nil, nil, err 454 } 455 456 return &out, wm, nil 457 } 458 459 // PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an 460 // existing policy ID 461 func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 462 if policy.ID == "" { 463 return nil, nil, fmt.Errorf("Must specify an ID in Policy Creation") 464 } 465 466 r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID) 467 r.setWriteOptions(q) 468 r.obj = policy 469 rtt, resp, err := requireOK(a.c.doRequest(r)) 470 if err != nil { 471 return nil, nil, err 472 } 473 defer resp.Body.Close() 474 475 wm := &WriteMeta{RequestTime: rtt} 476 var out ACLPolicy 477 if err := decodeBody(resp, &out); err != nil { 478 return nil, nil, err 479 } 480 481 return &out, wm, nil 482 } 483 484 // PolicyDelete deletes a policy given its ID. 485 func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) { 486 r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID) 487 r.setWriteOptions(q) 488 rtt, resp, err := requireOK(a.c.doRequest(r)) 489 if err != nil { 490 return nil, err 491 } 492 resp.Body.Close() 493 494 wm := &WriteMeta{RequestTime: rtt} 495 return wm, nil 496 } 497 498 // PolicyRead retrieves the policy details including the rule set. 499 func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { 500 r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID) 501 r.setQueryOptions(q) 502 rtt, resp, err := requireOK(a.c.doRequest(r)) 503 if err != nil { 504 return nil, nil, err 505 } 506 defer resp.Body.Close() 507 508 qm := &QueryMeta{} 509 parseQueryMeta(resp, qm) 510 qm.RequestTime = rtt 511 512 var out ACLPolicy 513 if err := decodeBody(resp, &out); err != nil { 514 return nil, nil, err 515 } 516 517 return &out, qm, nil 518 } 519 520 // PolicyList retrieves a listing of all policies. The listing does not include the 521 // rules for any policy as those should be retrieved by subsequent calls to PolicyRead. 522 func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) { 523 r := a.c.newRequest("GET", "/v1/acl/policies") 524 r.setQueryOptions(q) 525 rtt, resp, err := requireOK(a.c.doRequest(r)) 526 if err != nil { 527 return nil, nil, err 528 } 529 defer resp.Body.Close() 530 531 qm := &QueryMeta{} 532 parseQueryMeta(resp, qm) 533 qm.RequestTime = rtt 534 535 var entries []*ACLPolicyListEntry 536 if err := decodeBody(resp, &entries); err != nil { 537 return nil, nil, err 538 } 539 return entries, qm, nil 540 } 541 542 // RulesTranslate translates the legacy rule syntax into the current syntax. 543 // 544 // Deprecated: Support for the legacy syntax translation will be removed 545 // when legacy ACL support is removed. 546 func (a *ACL) RulesTranslate(rules io.Reader) (string, error) { 547 r := a.c.newRequest("POST", "/v1/acl/rules/translate") 548 r.body = rules 549 rtt, resp, err := requireOK(a.c.doRequest(r)) 550 if err != nil { 551 return "", err 552 } 553 defer resp.Body.Close() 554 qm := &QueryMeta{} 555 parseQueryMeta(resp, qm) 556 qm.RequestTime = rtt 557 558 ruleBytes, err := ioutil.ReadAll(resp.Body) 559 if err != nil { 560 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 561 } 562 563 return string(ruleBytes), nil 564 } 565 566 // RulesTranslateToken translates the rules associated with the legacy syntax 567 // into the current syntax and returns the results. 568 // 569 // Deprecated: Support for the legacy syntax translation will be removed 570 // when legacy ACL support is removed. 571 func (a *ACL) RulesTranslateToken(tokenID string) (string, error) { 572 r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID) 573 rtt, resp, err := requireOK(a.c.doRequest(r)) 574 if err != nil { 575 return "", err 576 } 577 defer resp.Body.Close() 578 qm := &QueryMeta{} 579 parseQueryMeta(resp, qm) 580 qm.RequestTime = rtt 581 582 ruleBytes, err := ioutil.ReadAll(resp.Body) 583 if err != nil { 584 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 585 } 586 587 return string(ruleBytes), nil 588 }