github.com/hashicorp/nomad/api@v0.0.0-20240306165712-3193ac204f65/acl.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package api 5 6 import ( 7 "encoding/json" 8 "errors" 9 "fmt" 10 "time" 11 ) 12 13 // ACLPolicies is used to query the ACL Policy endpoints. 14 type ACLPolicies struct { 15 client *Client 16 } 17 18 // ACLPolicies returns a new handle on the ACL policies. 19 func (c *Client) ACLPolicies() *ACLPolicies { 20 return &ACLPolicies{client: c} 21 } 22 23 // List is used to dump all of the policies. 24 func (a *ACLPolicies) List(q *QueryOptions) ([]*ACLPolicyListStub, *QueryMeta, error) { 25 var resp []*ACLPolicyListStub 26 qm, err := a.client.query("/v1/acl/policies", &resp, q) 27 if err != nil { 28 return nil, nil, err 29 } 30 return resp, qm, nil 31 } 32 33 // Upsert is used to create or update a policy 34 func (a *ACLPolicies) Upsert(policy *ACLPolicy, q *WriteOptions) (*WriteMeta, error) { 35 if policy == nil || policy.Name == "" { 36 return nil, errors.New("missing policy name") 37 } 38 wm, err := a.client.put("/v1/acl/policy/"+policy.Name, policy, nil, q) 39 if err != nil { 40 return nil, err 41 } 42 return wm, nil 43 } 44 45 // Delete is used to delete a policy 46 func (a *ACLPolicies) Delete(policyName string, q *WriteOptions) (*WriteMeta, error) { 47 if policyName == "" { 48 return nil, errors.New("missing policy name") 49 } 50 wm, err := a.client.delete("/v1/acl/policy/"+policyName, nil, nil, q) 51 if err != nil { 52 return nil, err 53 } 54 return wm, nil 55 } 56 57 // Info is used to query a specific policy 58 func (a *ACLPolicies) Info(policyName string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { 59 if policyName == "" { 60 return nil, nil, errors.New("missing policy name") 61 } 62 var resp ACLPolicy 63 wm, err := a.client.query("/v1/acl/policy/"+policyName, &resp, q) 64 if err != nil { 65 return nil, nil, err 66 } 67 return &resp, wm, nil 68 } 69 70 // ACLTokens is used to query the ACL token endpoints. 71 type ACLTokens struct { 72 client *Client 73 } 74 75 // ACLTokens returns a new handle on the ACL tokens. 76 func (c *Client) ACLTokens() *ACLTokens { 77 return &ACLTokens{client: c} 78 } 79 80 // Bootstrap is used to get the initial bootstrap token 81 // 82 // See BootstrapOpts to set ACL bootstrapping options. 83 func (a *ACLTokens) Bootstrap(q *WriteOptions) (*ACLToken, *WriteMeta, error) { 84 var resp ACLToken 85 wm, err := a.client.put("/v1/acl/bootstrap", nil, &resp, q) 86 if err != nil { 87 return nil, nil, err 88 } 89 return &resp, wm, nil 90 } 91 92 // BootstrapOpts is used to get the initial bootstrap token or pass in the one that was provided in the API 93 func (a *ACLTokens) BootstrapOpts(btoken string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 94 if q == nil { 95 q = &WriteOptions{} 96 } 97 req := &BootstrapRequest{ 98 BootstrapSecret: btoken, 99 } 100 101 var resp ACLToken 102 wm, err := a.client.put("/v1/acl/bootstrap", req, &resp, q) 103 if err != nil { 104 return nil, nil, err 105 } 106 return &resp, wm, nil 107 } 108 109 // List is used to dump all of the tokens. 110 func (a *ACLTokens) List(q *QueryOptions) ([]*ACLTokenListStub, *QueryMeta, error) { 111 var resp []*ACLTokenListStub 112 qm, err := a.client.query("/v1/acl/tokens", &resp, q) 113 if err != nil { 114 return nil, nil, err 115 } 116 return resp, qm, nil 117 } 118 119 // Create is used to create a token 120 func (a *ACLTokens) Create(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 121 if token.AccessorID != "" { 122 return nil, nil, errors.New("cannot specify Accessor ID") 123 } 124 var resp ACLToken 125 wm, err := a.client.put("/v1/acl/token", token, &resp, q) 126 if err != nil { 127 return nil, nil, err 128 } 129 return &resp, wm, nil 130 } 131 132 // Update is used to update an existing token 133 func (a *ACLTokens) Update(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 134 if token.AccessorID == "" { 135 return nil, nil, errors.New("missing accessor ID") 136 } 137 var resp ACLToken 138 wm, err := a.client.put("/v1/acl/token/"+token.AccessorID, 139 token, &resp, q) 140 if err != nil { 141 return nil, nil, err 142 } 143 return &resp, wm, nil 144 } 145 146 // Delete is used to delete a token 147 func (a *ACLTokens) Delete(accessorID string, q *WriteOptions) (*WriteMeta, error) { 148 if accessorID == "" { 149 return nil, errors.New("missing accessor ID") 150 } 151 wm, err := a.client.delete("/v1/acl/token/"+accessorID, nil, nil, q) 152 if err != nil { 153 return nil, err 154 } 155 return wm, nil 156 } 157 158 // Info is used to query a token 159 func (a *ACLTokens) Info(accessorID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) { 160 if accessorID == "" { 161 return nil, nil, errors.New("missing accessor ID") 162 } 163 var resp ACLToken 164 wm, err := a.client.query("/v1/acl/token/"+accessorID, &resp, q) 165 if err != nil { 166 return nil, nil, err 167 } 168 return &resp, wm, nil 169 } 170 171 // Self is used to query our own token 172 func (a *ACLTokens) Self(q *QueryOptions) (*ACLToken, *QueryMeta, error) { 173 var resp ACLToken 174 wm, err := a.client.query("/v1/acl/token/self", &resp, q) 175 if err != nil { 176 return nil, nil, err 177 } 178 return &resp, wm, nil 179 } 180 181 // UpsertOneTimeToken is used to create a one-time token 182 func (a *ACLTokens) UpsertOneTimeToken(q *WriteOptions) (*OneTimeToken, *WriteMeta, error) { 183 var resp *OneTimeTokenUpsertResponse 184 wm, err := a.client.put("/v1/acl/token/onetime", nil, &resp, q) 185 if err != nil { 186 return nil, nil, err 187 } 188 if resp == nil { 189 return nil, nil, errors.New("no one-time token returned") 190 } 191 return resp.OneTimeToken, wm, nil 192 } 193 194 // ExchangeOneTimeToken is used to create a one-time token 195 func (a *ACLTokens) ExchangeOneTimeToken(secret string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 196 if secret == "" { 197 return nil, nil, errors.New("missing secret ID") 198 } 199 req := &OneTimeTokenExchangeRequest{OneTimeSecretID: secret} 200 var resp *OneTimeTokenExchangeResponse 201 wm, err := a.client.put("/v1/acl/token/onetime/exchange", req, &resp, q) 202 if err != nil { 203 return nil, nil, err 204 } 205 if resp == nil { 206 return nil, nil, errors.New("no ACL token returned") 207 } 208 return resp.Token, wm, nil 209 } 210 211 var ( 212 // errMissingACLRoleID is the generic errors to use when a call is missing 213 // the required ACL Role ID parameter. 214 errMissingACLRoleID = errors.New("missing ACL role ID") 215 216 // errMissingACLAuthMethodName is the generic error to use when a call is 217 // missing the required ACL auth-method name parameter. 218 errMissingACLAuthMethodName = errors.New("missing ACL auth-method name") 219 220 // errMissingACLBindingRuleID is the generic error to use when a call is 221 // missing the required ACL binding rule ID parameter. 222 errMissingACLBindingRuleID = errors.New("missing ACL binding rule ID") 223 ) 224 225 // ACLRoles is used to query the ACL Role endpoints. 226 type ACLRoles struct { 227 client *Client 228 } 229 230 // ACLRoles returns a new handle on the ACL roles API client. 231 func (c *Client) ACLRoles() *ACLRoles { 232 return &ACLRoles{client: c} 233 } 234 235 // List is used to detail all the ACL roles currently stored within state. 236 func (a *ACLRoles) List(q *QueryOptions) ([]*ACLRoleListStub, *QueryMeta, error) { 237 var resp []*ACLRoleListStub 238 qm, err := a.client.query("/v1/acl/roles", &resp, q) 239 if err != nil { 240 return nil, nil, err 241 } 242 return resp, qm, nil 243 } 244 245 // Create is used to create an ACL role. 246 func (a *ACLRoles) Create(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) { 247 if role.ID != "" { 248 return nil, nil, errors.New("cannot specify ACL role ID") 249 } 250 var resp ACLRole 251 wm, err := a.client.put("/v1/acl/role", role, &resp, w) 252 if err != nil { 253 return nil, nil, err 254 } 255 return &resp, wm, nil 256 } 257 258 // Update is used to update an existing ACL role. 259 func (a *ACLRoles) Update(role *ACLRole, w *WriteOptions) (*ACLRole, *WriteMeta, error) { 260 if role.ID == "" { 261 return nil, nil, errMissingACLRoleID 262 } 263 var resp ACLRole 264 wm, err := a.client.put("/v1/acl/role/"+role.ID, role, &resp, w) 265 if err != nil { 266 return nil, nil, err 267 } 268 return &resp, wm, nil 269 } 270 271 // Delete is used to delete an ACL role. 272 func (a *ACLRoles) Delete(roleID string, w *WriteOptions) (*WriteMeta, error) { 273 if roleID == "" { 274 return nil, errMissingACLRoleID 275 } 276 wm, err := a.client.delete("/v1/acl/role/"+roleID, nil, nil, w) 277 if err != nil { 278 return nil, err 279 } 280 return wm, nil 281 } 282 283 // Get is used to look up an ACL role. 284 func (a *ACLRoles) Get(roleID string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 285 if roleID == "" { 286 return nil, nil, errMissingACLRoleID 287 } 288 var resp ACLRole 289 qm, err := a.client.query("/v1/acl/role/"+roleID, &resp, q) 290 if err != nil { 291 return nil, nil, err 292 } 293 return &resp, qm, nil 294 } 295 296 // GetByName is used to look up an ACL role using its name. 297 func (a *ACLRoles) GetByName(roleName string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 298 if roleName == "" { 299 return nil, nil, errors.New("missing ACL role name") 300 } 301 var resp ACLRole 302 qm, err := a.client.query("/v1/acl/role/name/"+roleName, &resp, q) 303 if err != nil { 304 return nil, nil, err 305 } 306 return &resp, qm, nil 307 } 308 309 // ACLAuthMethods is used to query the ACL auth-methods endpoints. 310 type ACLAuthMethods struct { 311 client *Client 312 } 313 314 // ACLAuthMethods returns a new handle on the ACL auth-methods API client. 315 func (c *Client) ACLAuthMethods() *ACLAuthMethods { 316 return &ACLAuthMethods{client: c} 317 } 318 319 // List is used to detail all the ACL auth-methods currently stored within 320 // state. 321 func (a *ACLAuthMethods) List(q *QueryOptions) ([]*ACLAuthMethodListStub, *QueryMeta, error) { 322 var resp []*ACLAuthMethodListStub 323 qm, err := a.client.query("/v1/acl/auth-methods", &resp, q) 324 if err != nil { 325 return nil, nil, err 326 } 327 return resp, qm, nil 328 } 329 330 // Create is used to create an ACL auth-method. 331 func (a *ACLAuthMethods) Create(authMethod *ACLAuthMethod, w *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 332 if authMethod.Name == "" { 333 return nil, nil, errMissingACLAuthMethodName 334 } 335 var resp ACLAuthMethod 336 wm, err := a.client.put("/v1/acl/auth-method", authMethod, &resp, w) 337 if err != nil { 338 return nil, nil, err 339 } 340 return &resp, wm, nil 341 } 342 343 // Update is used to update an existing ACL auth-method. 344 func (a *ACLAuthMethods) Update(authMethod *ACLAuthMethod, w *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 345 if authMethod.Name == "" { 346 return nil, nil, errMissingACLAuthMethodName 347 } 348 var resp ACLAuthMethod 349 wm, err := a.client.put("/v1/acl/auth-method/"+authMethod.Name, authMethod, &resp, w) 350 if err != nil { 351 return nil, nil, err 352 } 353 return &resp, wm, nil 354 } 355 356 // Delete is used to delete an ACL auth-method. 357 func (a *ACLAuthMethods) Delete(authMethodName string, w *WriteOptions) (*WriteMeta, error) { 358 if authMethodName == "" { 359 return nil, errMissingACLAuthMethodName 360 } 361 wm, err := a.client.delete("/v1/acl/auth-method/"+authMethodName, nil, nil, w) 362 if err != nil { 363 return nil, err 364 } 365 return wm, nil 366 } 367 368 // Get is used to look up an ACL auth-method. 369 func (a *ACLAuthMethods) Get(authMethodName string, q *QueryOptions) (*ACLAuthMethod, *QueryMeta, error) { 370 if authMethodName == "" { 371 return nil, nil, errMissingACLAuthMethodName 372 } 373 var resp ACLAuthMethod 374 qm, err := a.client.query("/v1/acl/auth-method/"+authMethodName, &resp, q) 375 if err != nil { 376 return nil, nil, err 377 } 378 return &resp, qm, nil 379 } 380 381 // ACLBindingRules is used to query the ACL auth-methods endpoints. 382 type ACLBindingRules struct { 383 client *Client 384 } 385 386 // ACLBindingRules returns a new handle on the ACL auth-methods API client. 387 func (c *Client) ACLBindingRules() *ACLBindingRules { 388 return &ACLBindingRules{client: c} 389 } 390 391 // List is used to detail all the ACL binding rules currently stored within 392 // state. 393 func (a *ACLBindingRules) List(q *QueryOptions) ([]*ACLBindingRuleListStub, *QueryMeta, error) { 394 var resp []*ACLBindingRuleListStub 395 qm, err := a.client.query("/v1/acl/binding-rules", &resp, q) 396 if err != nil { 397 return nil, nil, err 398 } 399 return resp, qm, nil 400 } 401 402 // Create is used to create an ACL binding rule. 403 func (a *ACLBindingRules) Create(bindingRule *ACLBindingRule, w *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 404 var resp ACLBindingRule 405 wm, err := a.client.put("/v1/acl/binding-rule", bindingRule, &resp, w) 406 if err != nil { 407 return nil, nil, err 408 } 409 return &resp, wm, nil 410 } 411 412 // Update is used to update an existing ACL binding rule. 413 func (a *ACLBindingRules) Update(bindingRule *ACLBindingRule, w *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 414 if bindingRule.ID == "" { 415 return nil, nil, errMissingACLBindingRuleID 416 } 417 var resp ACLBindingRule 418 wm, err := a.client.put("/v1/acl/binding-rule/"+bindingRule.ID, bindingRule, &resp, w) 419 if err != nil { 420 return nil, nil, err 421 } 422 return &resp, wm, nil 423 } 424 425 // Delete is used to delete an ACL binding rule. 426 func (a *ACLBindingRules) Delete(bindingRuleID string, w *WriteOptions) (*WriteMeta, error) { 427 if bindingRuleID == "" { 428 return nil, errMissingACLBindingRuleID 429 } 430 wm, err := a.client.delete("/v1/acl/binding-rule/"+bindingRuleID, nil, nil, w) 431 if err != nil { 432 return nil, err 433 } 434 return wm, nil 435 } 436 437 // Get is used to look up an ACL binding rule. 438 func (a *ACLBindingRules) Get(bindingRuleID string, q *QueryOptions) (*ACLBindingRule, *QueryMeta, error) { 439 if bindingRuleID == "" { 440 return nil, nil, errMissingACLBindingRuleID 441 } 442 var resp ACLBindingRule 443 qm, err := a.client.query("/v1/acl/binding-rule/"+bindingRuleID, &resp, q) 444 if err != nil { 445 return nil, nil, err 446 } 447 return &resp, qm, nil 448 } 449 450 // ACLOIDC is used to query the ACL OIDC endpoints. 451 // 452 // Deprecated: ACLOIDC is deprecated, use ACLAuth instead. 453 type ACLOIDC struct { 454 client *Client 455 ACLAuth 456 } 457 458 // ACLOIDC returns a new handle on the ACL auth-methods API client. 459 // 460 // Deprecated: c.ACLOIDC() is deprecated, use c.ACLAuth() instead. 461 func (c *Client) ACLOIDC() *ACLOIDC { 462 return &ACLOIDC{client: c} 463 } 464 465 // ACLAuth is used to query the ACL auth endpoints. 466 type ACLAuth struct { 467 client *Client 468 } 469 470 // ACLAuth returns a new handle on the ACL auth-methods API client. 471 func (c *Client) ACLAuth() *ACLAuth { 472 return &ACLAuth{client: c} 473 } 474 475 // GetAuthURL generates the OIDC provider authentication URL. This URL should 476 // be visited in order to sign in to the provider. 477 func (a *ACLAuth) GetAuthURL(req *ACLOIDCAuthURLRequest, q *WriteOptions) (*ACLOIDCAuthURLResponse, *WriteMeta, error) { 478 var resp ACLOIDCAuthURLResponse 479 wm, err := a.client.put("/v1/acl/oidc/auth-url", req, &resp, q) 480 if err != nil { 481 return nil, nil, err 482 } 483 return &resp, wm, nil 484 } 485 486 // CompleteAuth exchanges the OIDC provider token for a Nomad token with the 487 // appropriate claims attached. 488 func (a *ACLAuth) CompleteAuth(req *ACLOIDCCompleteAuthRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 489 var resp ACLToken 490 wm, err := a.client.put("/v1/acl/oidc/complete-auth", req, &resp, q) 491 if err != nil { 492 return nil, nil, err 493 } 494 return &resp, wm, nil 495 } 496 497 // Login exchanges the third party token for a Nomad token with the appropriate 498 // claims attached. 499 func (a *ACLAuth) Login(req *ACLLoginRequest, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 500 var resp ACLToken 501 wm, err := a.client.put("/v1/acl/login", req, &resp, q) 502 if err != nil { 503 return nil, nil, err 504 } 505 return &resp, wm, nil 506 } 507 508 // ACLPolicyListStub is used to for listing ACL policies 509 type ACLPolicyListStub struct { 510 Name string 511 Description string 512 CreateIndex uint64 513 ModifyIndex uint64 514 } 515 516 // ACLPolicy is used to represent an ACL policy 517 type ACLPolicy struct { 518 Name string 519 Description string 520 Rules string 521 JobACL *JobACL 522 523 CreateIndex uint64 524 ModifyIndex uint64 525 } 526 527 // JobACL represents an ACL policy's attachment to a job, group, or task. 528 type JobACL struct { 529 Namespace string 530 JobID string 531 Group string 532 Task string 533 } 534 535 // ACLToken represents a client token which is used to Authenticate 536 type ACLToken struct { 537 AccessorID string 538 SecretID string 539 Name string 540 Type string 541 Policies []string 542 543 // Roles represents the ACL roles that this token is tied to. The token 544 // will inherit the permissions of all policies detailed within the role. 545 Roles []*ACLTokenRoleLink 546 547 Global bool 548 CreateTime time.Time 549 550 // ExpirationTime represents the point after which a token should be 551 // considered revoked and is eligible for destruction. The zero value of 552 // time.Time does not respect json omitempty directives, so we must use a 553 // pointer. 554 ExpirationTime *time.Time `json:",omitempty"` 555 556 // ExpirationTTL is a convenience field for helping set ExpirationTime to a 557 // value of CreateTime+ExpirationTTL. This can only be set during token 558 // creation. This is a string version of a time.Duration like "2m". 559 ExpirationTTL time.Duration `json:",omitempty"` 560 561 CreateIndex uint64 562 ModifyIndex uint64 563 } 564 565 // ACLTokenRoleLink is used to link an ACL token to an ACL role. The ACL token 566 // can therefore inherit all the ACL policy permissions that the ACL role 567 // contains. 568 type ACLTokenRoleLink struct { 569 570 // ID is the ACLRole.ID UUID. This field is immutable and represents the 571 // absolute truth for the link. 572 ID string 573 574 // Name is the human friendly identifier for the ACL role and is a 575 // convenience field for operators. 576 Name string 577 } 578 579 // MarshalJSON implements the json.Marshaler interface and allows 580 // ACLToken.ExpirationTTL to be marshaled correctly. 581 func (a *ACLToken) MarshalJSON() ([]byte, error) { 582 type Alias ACLToken 583 exported := &struct { 584 ExpirationTTL string 585 *Alias 586 }{ 587 ExpirationTTL: a.ExpirationTTL.String(), 588 Alias: (*Alias)(a), 589 } 590 if a.ExpirationTTL == 0 { 591 exported.ExpirationTTL = "" 592 } 593 return json.Marshal(exported) 594 } 595 596 // UnmarshalJSON implements the json.Unmarshaler interface and allows 597 // ACLToken.ExpirationTTL to be unmarshalled correctly. 598 func (a *ACLToken) UnmarshalJSON(data []byte) (err error) { 599 type Alias ACLToken 600 aux := &struct { 601 ExpirationTTL any 602 *Alias 603 }{ 604 Alias: (*Alias)(a), 605 } 606 607 if err = json.Unmarshal(data, &aux); err != nil { 608 return err 609 } 610 if aux.ExpirationTTL != nil { 611 switch v := aux.ExpirationTTL.(type) { 612 case string: 613 if v != "" { 614 if a.ExpirationTTL, err = time.ParseDuration(v); err != nil { 615 return err 616 } 617 } 618 case float64: 619 a.ExpirationTTL = time.Duration(v) 620 } 621 622 } 623 return nil 624 } 625 626 type ACLTokenListStub struct { 627 AccessorID string 628 Name string 629 Type string 630 Policies []string 631 Roles []*ACLTokenRoleLink 632 Global bool 633 CreateTime time.Time 634 635 // ExpirationTime represents the point after which a token should be 636 // considered revoked and is eligible for destruction. A nil value 637 // indicates no expiration has been set on the token. 638 ExpirationTime *time.Time `json:",omitempty"` 639 640 CreateIndex uint64 641 ModifyIndex uint64 642 } 643 644 type OneTimeToken struct { 645 OneTimeSecretID string 646 AccessorID string 647 ExpiresAt time.Time 648 CreateIndex uint64 649 ModifyIndex uint64 650 } 651 652 type OneTimeTokenUpsertResponse struct { 653 OneTimeToken *OneTimeToken 654 } 655 656 type OneTimeTokenExchangeRequest struct { 657 OneTimeSecretID string 658 } 659 660 type OneTimeTokenExchangeResponse struct { 661 Token *ACLToken 662 } 663 664 // BootstrapRequest is used for when operators provide an ACL Bootstrap Token 665 type BootstrapRequest struct { 666 BootstrapSecret string 667 } 668 669 // ACLRole is an abstraction for the ACL system which allows the grouping of 670 // ACL policies into a single object. ACL tokens can be created and linked to 671 // a role; the token then inherits all the permissions granted by the policies. 672 type ACLRole struct { 673 674 // ID is an internally generated UUID for this role and is controlled by 675 // Nomad. It can be used after role creation to update the existing role. 676 ID string 677 678 // Name is unique across the entire set of federated clusters and is 679 // supplied by the operator on role creation. The name can be modified by 680 // updating the role and including the Nomad generated ID. This update will 681 // not affect tokens created and linked to this role. This is a required 682 // field. 683 Name string 684 685 // Description is a human-readable, operator set description that can 686 // provide additional context about the role. This is an optional field. 687 Description string 688 689 // Policies is an array of ACL policy links. Although currently policies 690 // can only be linked using their name, in the future we will want to add 691 // IDs also and thus allow operators to specify either a name, an ID, or 692 // both. At least one entry is required. 693 Policies []*ACLRolePolicyLink 694 695 CreateIndex uint64 696 ModifyIndex uint64 697 } 698 699 // ACLRolePolicyLink is used to link a policy to an ACL role. We use a struct 700 // rather than a list of strings as in the future we will want to add IDs to 701 // policies and then link via these. 702 type ACLRolePolicyLink struct { 703 704 // Name is the ACLPolicy.Name value which will be linked to the ACL role. 705 Name string 706 } 707 708 // ACLRoleListStub is the stub object returned when performing a listing of ACL 709 // roles. While it might not currently be different to the full response 710 // object, it allows us to future-proof the RPC in the event the ACLRole object 711 // grows over time. 712 type ACLRoleListStub struct { 713 714 // ID is an internally generated UUID for this role and is controlled by 715 // Nomad. 716 ID string 717 718 // Name is unique across the entire set of federated clusters and is 719 // supplied by the operator on role creation. The name can be modified by 720 // updating the role and including the Nomad generated ID. This update will 721 // not affect tokens created and linked to this role. This is a required 722 // field. 723 Name string 724 725 // Description is a human-readable, operator set description that can 726 // provide additional context about the role. This is an operational field. 727 Description string 728 729 // Policies is an array of ACL policy links. Although currently policies 730 // can only be linked using their name, in the future we will want to add 731 // IDs also and thus allow operators to specify either a name, an ID, or 732 // both. 733 Policies []*ACLRolePolicyLink 734 735 CreateIndex uint64 736 ModifyIndex uint64 737 } 738 739 // ACLAuthMethod is used to capture the properties of an authentication method 740 // used for single sing-on. 741 type ACLAuthMethod struct { 742 743 // Name is the identifier for this auth-method and is a required parameter. 744 Name string 745 746 // Type is the SSO identifier this auth-method is. Nomad currently only 747 // supports "oidc" and the API contains ACLAuthMethodTypeOIDC for 748 // convenience. 749 Type string 750 751 // Defines whether the auth-method creates a local or global token when 752 // performing SSO login. This should be set to either "local" or "global" 753 // and the API contains ACLAuthMethodTokenLocalityLocal and 754 // ACLAuthMethodTokenLocalityGlobal for convenience. 755 TokenLocality string 756 757 // TokenNameFormat defines the HIL template to use when building the token name 758 TokenNameFormat string 759 760 // MaxTokenTTL is the maximum life of a token created by this method. 761 MaxTokenTTL time.Duration 762 763 // Default identifies whether this is the default auth-method to use when 764 // attempting to login without specifying an auth-method name to use. 765 Default bool 766 767 // Config contains the detailed configuration which is specific to the 768 // auth-method. 769 Config *ACLAuthMethodConfig 770 771 CreateTime time.Time 772 ModifyTime time.Time 773 CreateIndex uint64 774 ModifyIndex uint64 775 } 776 777 // MarshalJSON implements the json.Marshaler interface and allows 778 // ACLAuthMethod.MaxTokenTTL to be marshaled correctly. 779 func (m *ACLAuthMethod) MarshalJSON() ([]byte, error) { 780 type Alias ACLAuthMethod 781 exported := &struct { 782 MaxTokenTTL string 783 *Alias 784 }{ 785 MaxTokenTTL: m.MaxTokenTTL.String(), 786 Alias: (*Alias)(m), 787 } 788 if m.MaxTokenTTL == 0 { 789 exported.MaxTokenTTL = "" 790 } 791 return json.Marshal(exported) 792 } 793 794 // UnmarshalJSON implements the json.Unmarshaler interface and allows 795 // ACLAuthMethod.MaxTokenTTL to be unmarshalled correctly. 796 func (m *ACLAuthMethod) UnmarshalJSON(data []byte) error { 797 type Alias ACLAuthMethod 798 aux := &struct { 799 MaxTokenTTL string 800 *Alias 801 }{ 802 Alias: (*Alias)(m), 803 } 804 if err := json.Unmarshal(data, &aux); err != nil { 805 return err 806 } 807 var err error 808 if aux.MaxTokenTTL != "" { 809 if m.MaxTokenTTL, err = time.ParseDuration(aux.MaxTokenTTL); err != nil { 810 return err 811 } 812 } 813 return nil 814 } 815 816 // ACLAuthMethodConfig is used to store configuration of an auth method. 817 type ACLAuthMethodConfig struct { 818 // A list of PEM-encoded public keys to use to authenticate signatures 819 // locally 820 JWTValidationPubKeys []string 821 // JSON Web Key Sets url for authenticating signatures 822 JWKSURL string 823 // The OIDC Discovery URL, without any .well-known component (base path) 824 OIDCDiscoveryURL string 825 // The OAuth Client ID configured with the OIDC provider 826 OIDCClientID string 827 // The OAuth Client Secret configured with the OIDC provider 828 OIDCClientSecret string 829 // Disable claims from the OIDC UserInfo endpoint 830 OIDCDisableUserInfo bool 831 // List of OIDC scopes 832 OIDCScopes []string 833 // List of auth claims that are valid for login 834 BoundAudiences []string 835 // The value against which to match the iss claim in a JWT 836 BoundIssuer []string 837 // A list of allowed values for redirect_uri 838 AllowedRedirectURIs []string 839 // PEM encoded CA certs for use by the TLS client used to talk with the 840 // OIDC Discovery URL. 841 DiscoveryCaPem []string 842 // PEM encoded CA cert for use by the TLS client used to talk with the JWKS 843 // URL 844 JWKSCACert string 845 // A list of supported signing algorithms 846 SigningAlgs []string 847 // Duration in seconds of leeway when validating expiration of a token to 848 // account for clock skew 849 ExpirationLeeway time.Duration 850 // Duration in seconds of leeway when validating not before values of a 851 // token to account for clock skew. 852 NotBeforeLeeway time.Duration 853 // Duration in seconds of leeway when validating all claims to account for 854 // clock skew. 855 ClockSkewLeeway time.Duration 856 // Mappings of claims (key) that will be copied to a metadata field 857 // (value). 858 ClaimMappings map[string]string 859 ListClaimMappings map[string]string 860 } 861 862 // MarshalJSON implements the json.Marshaler interface and allows 863 // time.Duration fields to be marshaled correctly. 864 func (c *ACLAuthMethodConfig) MarshalJSON() ([]byte, error) { 865 type Alias ACLAuthMethodConfig 866 exported := &struct { 867 ExpirationLeeway string 868 NotBeforeLeeway string 869 ClockSkewLeeway string 870 *Alias 871 }{ 872 ExpirationLeeway: c.ExpirationLeeway.String(), 873 NotBeforeLeeway: c.NotBeforeLeeway.String(), 874 ClockSkewLeeway: c.ClockSkewLeeway.String(), 875 Alias: (*Alias)(c), 876 } 877 if c.ExpirationLeeway == 0 { 878 exported.ExpirationLeeway = "" 879 } 880 if c.NotBeforeLeeway == 0 { 881 exported.NotBeforeLeeway = "" 882 } 883 if c.ClockSkewLeeway == 0 { 884 exported.ClockSkewLeeway = "" 885 } 886 return json.Marshal(exported) 887 } 888 889 // UnmarshalJSON implements the json.Unmarshaler interface and allows 890 // time.Duration fields to be unmarshalled correctly. 891 func (c *ACLAuthMethodConfig) UnmarshalJSON(data []byte) error { 892 type Alias ACLAuthMethodConfig 893 aux := &struct { 894 ExpirationLeeway any 895 NotBeforeLeeway any 896 ClockSkewLeeway any 897 *Alias 898 }{ 899 Alias: (*Alias)(c), 900 } 901 if err := json.Unmarshal(data, &aux); err != nil { 902 return err 903 } 904 var err error 905 if aux.ExpirationLeeway != nil { 906 switch v := aux.ExpirationLeeway.(type) { 907 case string: 908 if v != "" { 909 if c.ExpirationLeeway, err = time.ParseDuration(v); err != nil { 910 return err 911 } 912 } 913 case float64: 914 c.ExpirationLeeway = time.Duration(v) 915 default: 916 return fmt.Errorf("unexpected ExpirationLeeway type: %v", v) 917 } 918 } 919 if aux.NotBeforeLeeway != nil { 920 switch v := aux.NotBeforeLeeway.(type) { 921 case string: 922 if v != "" { 923 if c.NotBeforeLeeway, err = time.ParseDuration(v); err != nil { 924 return err 925 } 926 } 927 case float64: 928 c.NotBeforeLeeway = time.Duration(v) 929 default: 930 return fmt.Errorf("unexpected NotBeforeLeeway type: %v", v) 931 } 932 } 933 if aux.ClockSkewLeeway != nil { 934 switch v := aux.ClockSkewLeeway.(type) { 935 case string: 936 if v != "" { 937 if c.ClockSkewLeeway, err = time.ParseDuration(v); err != nil { 938 return err 939 } 940 } 941 case float64: 942 c.ClockSkewLeeway = time.Duration(v) 943 default: 944 return fmt.Errorf("unexpected ClockSkewLeeway type: %v", v) 945 } 946 } 947 return nil 948 } 949 950 // ACLAuthMethodListStub is the stub object returned when performing a listing 951 // of ACL auth-methods. It is intentionally minimal due to the unauthenticated 952 // nature of the list endpoint. 953 type ACLAuthMethodListStub struct { 954 Name string 955 Type string 956 Default bool 957 958 CreateIndex uint64 959 ModifyIndex uint64 960 } 961 962 const ( 963 // ACLAuthMethodTokenLocalityLocal is the ACLAuthMethod.TokenLocality that 964 // will generate ACL tokens which can only be used on the local cluster the 965 // request was made. 966 ACLAuthMethodTokenLocalityLocal = "local" 967 968 // ACLAuthMethodTokenLocalityGlobal is the ACLAuthMethod.TokenLocality that 969 // will generate ACL tokens which can be used on all federated clusters. 970 ACLAuthMethodTokenLocalityGlobal = "global" 971 972 // ACLAuthMethodTypeOIDC the ACLAuthMethod.Type and represents an 973 // auth-method which uses the OIDC protocol. 974 ACLAuthMethodTypeOIDC = "OIDC" 975 976 // ACLAuthMethodTypeJWT the ACLAuthMethod.Type and represents an auth-method 977 // which uses the JWT type. 978 ACLAuthMethodTypeJWT = "JWT" 979 ) 980 981 // ACLBindingRule contains a direct relation to an ACLAuthMethod and represents 982 // a rule to apply when logging in via the named AuthMethod. This allows the 983 // transformation of OIDC provider claims, to Nomad based ACL concepts such as 984 // ACL Roles and Policies. 985 type ACLBindingRule struct { 986 987 // ID is an internally generated UUID for this rule and is controlled by 988 // Nomad. 989 ID string 990 991 // Description is a human-readable, operator set description that can 992 // provide additional context about the binding rule. This is an 993 // operational field. 994 Description string 995 996 // AuthMethod is the name of the auth method for which this rule applies 997 // to. This is required and the method must exist within state before the 998 // cluster administrator can create the rule. 999 AuthMethod string 1000 1001 // Selector is an expression that matches against verified identity 1002 // attributes returned from the auth method during login. This is optional 1003 // and when not set, provides a catch-all rule. 1004 Selector string 1005 1006 // BindType adjusts how this binding rule is applied at login time. The 1007 // valid values are ACLBindingRuleBindTypeRole, 1008 // ACLBindingRuleBindTypePolicy, and ACLBindingRuleBindTypeManagement. 1009 BindType string 1010 1011 // BindName is the target of the binding. Can be lightly templated using 1012 // HIL ${foo} syntax from available field names. How it is used depends 1013 // upon the BindType. 1014 BindName string 1015 1016 CreateTime time.Time 1017 ModifyTime time.Time 1018 CreateIndex uint64 1019 ModifyIndex uint64 1020 } 1021 1022 const ( 1023 // ACLBindingRuleBindTypeRole is the ACL binding rule bind type that only 1024 // allows the binding rule to function if a role exists at login-time. The 1025 // role will be specified within the ACLBindingRule.BindName parameter, and 1026 // will identify whether this is an ID or Name. 1027 ACLBindingRuleBindTypeRole = "role" 1028 1029 // ACLBindingRuleBindTypePolicy is the ACL binding rule bind type that 1030 // assigns a policy to the generate ACL token. The role will be specified 1031 // within the ACLBindingRule.BindName parameter, and will be the policy 1032 // name. 1033 ACLBindingRuleBindTypePolicy = "policy" 1034 1035 // ACLBindingRuleBindTypeManagement is the ACL binding rule bind type that 1036 // will generate management ACL tokens when matched. 1037 ACLBindingRuleBindTypeManagement = "management" 1038 ) 1039 1040 // ACLBindingRuleListStub is the stub object returned when performing a listing 1041 // of ACL binding rules. 1042 type ACLBindingRuleListStub struct { 1043 1044 // ID is an internally generated UUID for this role and is controlled by 1045 // Nomad. 1046 ID string 1047 1048 // Description is a human-readable, operator set description that can 1049 // provide additional context about the binding role. This is an 1050 // operational field. 1051 Description string 1052 1053 // AuthMethod is the name of the auth method for which this rule applies 1054 // to. This is required and the method must exist within state before the 1055 // cluster administrator can create the rule. 1056 AuthMethod string 1057 1058 CreateIndex uint64 1059 ModifyIndex uint64 1060 } 1061 1062 // ACLOIDCAuthURLRequest is the request to make when starting the OIDC 1063 // authentication login flow. 1064 type ACLOIDCAuthURLRequest struct { 1065 1066 // AuthMethodName is the OIDC auth-method to use. This is a required 1067 // parameter. 1068 AuthMethodName string 1069 1070 // RedirectURI is the URL that authorization should redirect to. This is a 1071 // required parameter. 1072 RedirectURI string 1073 1074 // ClientNonce is a randomly generated string to prevent replay attacks. It 1075 // is up to the client to generate this and Go integrations should use the 1076 // oidc.NewID function within the hashicorp/cap library. 1077 ClientNonce string 1078 } 1079 1080 // ACLOIDCAuthURLResponse is the response when starting the OIDC authentication 1081 // login flow. 1082 type ACLOIDCAuthURLResponse struct { 1083 1084 // AuthURL is URL to begin authorization and is where the user logging in 1085 // should go. 1086 AuthURL string 1087 } 1088 1089 // ACLOIDCCompleteAuthRequest is the request object to begin completing the 1090 // OIDC auth cycle after receiving the callback from the OIDC provider. 1091 type ACLOIDCCompleteAuthRequest struct { 1092 1093 // AuthMethodName is the name of the auth method being used to login via 1094 // OIDC. This will match AuthUrlArgs.AuthMethodName. This is a required 1095 // parameter. 1096 AuthMethodName string 1097 1098 // ClientNonce, State, and Code are provided from the parameters given to 1099 // the redirect URL. These are all required parameters. 1100 ClientNonce string 1101 State string 1102 Code string 1103 1104 // RedirectURI is the URL that authorization should redirect to. This is a 1105 // required parameter. 1106 RedirectURI string 1107 } 1108 1109 // ACLLoginRequest is the request object to begin auth with an external bearer 1110 // token provider. 1111 type ACLLoginRequest struct { 1112 // AuthMethodName is the name of the auth method being used to login. This 1113 // is a required parameter. 1114 AuthMethodName string 1115 // LoginToken is the token used to login. This is a required parameter. 1116 LoginToken string 1117 }