github.com/Aestek/consul@v1.2.4-0.20190309222502-b2c31e33971a/agent/consul/acl.go (about) 1 package consul 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "sync" 8 "time" 9 10 "github.com/armon/go-metrics" 11 "github.com/hashicorp/consul/acl" 12 "github.com/hashicorp/consul/agent/structs" 13 "github.com/hashicorp/consul/api" 14 "github.com/hashicorp/consul/sentinel" 15 "golang.org/x/time/rate" 16 ) 17 18 // These must be kept in sync with the constants in command/agent/acl.go. 19 const ( 20 // anonymousToken is the token ID we re-write to if there is no token ID 21 // provided. 22 anonymousToken = "anonymous" 23 24 // redactedToken is shown in structures with embedded tokens when they 25 // are not allowed to be displayed. 26 redactedToken = "<hidden>" 27 28 // aclUpgradeBatchSize controls how many tokens we look at during each round of upgrading. Individual raft logs 29 // will be further capped using the aclBatchUpsertSize. This limit just prevents us from creating a single slice 30 // with all tokens in it. 31 aclUpgradeBatchSize = 128 32 33 // aclUpgradeRateLimit is the number of batch upgrade requests per second. 34 aclUpgradeRateLimit rate.Limit = 1.0 35 36 // aclBatchDeleteSize is the number of deletions to send in a single batch operation. 4096 should produce a batch that is <150KB 37 // in size but should be sufficiently large to handle 1 replication round in a single batch 38 aclBatchDeleteSize = 4096 39 40 // aclBatchUpsertSize is the target size in bytes we want to submit for a batch upsert request. We estimate the size at runtime 41 // due to the data being more variable in its size. 42 aclBatchUpsertSize = 256 * 1024 43 44 // DEPRECATED (ACL-Legacy-Compat) aclModeCheck* are all only for legacy usage 45 // aclModeCheckMinInterval is the minimum amount of time between checking if the 46 // agent should be using the new or legacy ACL system. All the places it is 47 // currently used will backoff as it detects that it is remaining in legacy mode. 48 // However the initial min value is kept small so that new cluster creation 49 // can enter into new ACL mode quickly. 50 aclModeCheckMinInterval = 50 * time.Millisecond 51 52 // aclModeCheckMaxInterval controls the maximum interval for how often the agent 53 // checks if it should be using the new or legacy ACL system. 54 aclModeCheckMaxInterval = 30 * time.Second 55 56 // Maximum number of re-resolution requests to be made if the token is modified between 57 // resolving the token and resolving its policies that would remove one of its policies. 58 tokenPolicyResolutionMaxRetries = 5 59 ) 60 61 func minTTL(a time.Duration, b time.Duration) time.Duration { 62 if a < b { 63 return a 64 } 65 return b 66 } 67 68 type ACLRemoteError struct { 69 Err error 70 } 71 72 func (e ACLRemoteError) Error() string { 73 return fmt.Sprintf("Error communicating with the ACL Datacenter: %v", e.Err) 74 } 75 76 func IsACLRemoteError(err error) bool { 77 _, ok := err.(ACLRemoteError) 78 return ok 79 } 80 81 type ACLResolverDelegate interface { 82 ACLsEnabled() bool 83 ACLDatacenter(legacy bool) string 84 // UseLegacyACLs 85 UseLegacyACLs() bool 86 ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error) 87 ResolvePolicyFromID(policyID string) (bool, *structs.ACLPolicy, error) 88 RPC(method string, args interface{}, reply interface{}) error 89 } 90 91 type remoteACLLegacyResult struct { 92 authorizer acl.Authorizer 93 err error 94 } 95 96 type remoteACLIdentityResult struct { 97 identity structs.ACLIdentity 98 err error 99 } 100 101 type remoteACLPolicyResult struct { 102 policy *structs.ACLPolicy 103 err error 104 } 105 106 type policyTokenError struct { 107 Err error 108 token string 109 } 110 111 func (e policyTokenError) Error() string { 112 return e.Err.Error() 113 } 114 115 // ACLResolverConfig holds all the configuration necessary to create an ACLResolver 116 type ACLResolverConfig struct { 117 Config *Config 118 Logger *log.Logger 119 120 // CacheConfig is a pass through configuration for ACL cache limits 121 CacheConfig *structs.ACLCachesConfig 122 123 // Delegate that implements some helper functionality that is server/client specific 124 Delegate ACLResolverDelegate 125 126 // AutoDisable indicates that RPC responses should be checked and if they indicate ACLs are disabled 127 // remotely then disable them locally as well. This is particularly useful for the client agent 128 // so that it can detect when the servers have gotten ACLs enabled. 129 AutoDisable bool 130 131 Sentinel sentinel.Evaluator 132 } 133 134 // ACLResolver is the type to handle all your token and policy resolution needs. 135 // 136 // Supports: 137 // - Resolving tokens locally via the ACLResolverDelegate 138 // - Resolving policies locally via the ACLResolverDelegate 139 // - Resolving legacy tokens remotely via a ACL.GetPolicy RPC 140 // - Resolving tokens remotely via an ACL.TokenRead RPC 141 // - Resolving policies remotely via an ACL.PolicyResolve RPC 142 // 143 // Remote Resolution: 144 // Remote resolution can be done syncrhonously or asynchronously depending 145 // on the ACLDownPolicy in the Config passed to the resolver. 146 // 147 // When the down policy is set to async-cache and we have already cached values 148 // then go routines will be spawned to perform the RPCs in the background 149 // and then will udpate the cache with either the positive or negative result. 150 // 151 // When the down policy is set to extend-cache or the token/policy is not already 152 // cached then the same go routines are spawned to do the RPCs in the background. 153 // However in this mode channels are created to receive the results of the RPC 154 // and are registered with the resolver. Those channels are immediately read/blocked 155 // upon. 156 // 157 type ACLResolver struct { 158 config *Config 159 logger *log.Logger 160 161 delegate ACLResolverDelegate 162 sentinel sentinel.Evaluator 163 164 cache *structs.ACLCaches 165 asyncIdentityResults map[string][]chan (*remoteACLIdentityResult) 166 asyncIdentityResultsMutex sync.RWMutex 167 asyncPolicyResults map[string][]chan (*remoteACLPolicyResult) 168 asyncPolicyResultsMutex sync.RWMutex 169 asyncLegacyResults map[string][]chan (*remoteACLLegacyResult) 170 asyncLegacyMutex sync.RWMutex 171 172 down acl.Authorizer 173 174 autoDisable bool 175 disabled time.Time 176 disabledLock sync.RWMutex 177 } 178 179 func NewACLResolver(config *ACLResolverConfig) (*ACLResolver, error) { 180 if config == nil { 181 return nil, fmt.Errorf("ACL Resolver must be initialized with a config") 182 } 183 184 if config.Config == nil { 185 return nil, fmt.Errorf("ACLResolverConfig.Config must not be nil") 186 } 187 188 if config.Delegate == nil { 189 return nil, fmt.Errorf("ACL Resolver must be initialized with a valid delegate") 190 } 191 192 if config.Logger == nil { 193 config.Logger = log.New(os.Stderr, "", log.LstdFlags) 194 } 195 196 cache, err := structs.NewACLCaches(config.CacheConfig) 197 if err != nil { 198 return nil, err 199 } 200 201 var down acl.Authorizer 202 switch config.Config.ACLDownPolicy { 203 case "allow": 204 down = acl.AllowAll() 205 case "deny": 206 down = acl.DenyAll() 207 case "async-cache", "extend-cache": 208 // Leave the down policy as nil to signal this. 209 default: 210 return nil, fmt.Errorf("invalid ACL down policy %q", config.Config.ACLDownPolicy) 211 } 212 213 return &ACLResolver{ 214 config: config.Config, 215 logger: config.Logger, 216 delegate: config.Delegate, 217 sentinel: config.Sentinel, 218 cache: cache, 219 asyncIdentityResults: make(map[string][]chan (*remoteACLIdentityResult)), 220 asyncPolicyResults: make(map[string][]chan (*remoteACLPolicyResult)), 221 asyncLegacyResults: make(map[string][]chan (*remoteACLLegacyResult)), 222 autoDisable: config.AutoDisable, 223 down: down, 224 }, nil 225 } 226 227 // fireAsyncLegacyResult is used to notify any watchers that legacy resolution of a token is complete 228 func (r *ACLResolver) fireAsyncLegacyResult(token string, authorizer acl.Authorizer, ttl time.Duration, err error) { 229 // cache the result: positive or negative 230 r.cache.PutAuthorizerWithTTL(token, authorizer, ttl) 231 232 // get the list of channels to send the result to 233 r.asyncLegacyMutex.Lock() 234 channels := r.asyncLegacyResults[token] 235 delete(r.asyncLegacyResults, token) 236 r.asyncLegacyMutex.Unlock() 237 238 // notify all watchers of the RPC results 239 result := &remoteACLLegacyResult{authorizer, err} 240 for _, cx := range channels { 241 // only chans that are being blocked on will be in the list of channels so this cannot block 242 cx <- result 243 close(cx) 244 } 245 } 246 247 func (r *ACLResolver) resolveTokenLegacyAsync(token string, cached *structs.AuthorizerCacheEntry) { 248 req := structs.ACLPolicyResolveLegacyRequest{ 249 Datacenter: r.delegate.ACLDatacenter(true), 250 ACL: token, 251 } 252 253 cacheTTL := r.config.ACLTokenTTL 254 if cached != nil { 255 cacheTTL = cached.TTL 256 } 257 258 var reply structs.ACLPolicyResolveLegacyResponse 259 err := r.delegate.RPC("ACL.GetPolicy", &req, &reply) 260 if err == nil { 261 parent := acl.RootAuthorizer(reply.Parent) 262 if parent == nil { 263 r.fireAsyncLegacyResult(token, cached.Authorizer, cacheTTL, acl.ErrInvalidParent) 264 return 265 } 266 267 var policies []*acl.Policy 268 policy := reply.Policy 269 if policy != nil { 270 policies = append(policies, policy.ConvertFromLegacy()) 271 } 272 273 authorizer, err := acl.NewPolicyAuthorizer(parent, policies, r.sentinel) 274 r.fireAsyncLegacyResult(token, authorizer, reply.TTL, err) 275 return 276 } 277 278 if acl.IsErrNotFound(err) { 279 // Make sure to remove from the cache if it was deleted 280 r.fireAsyncLegacyResult(token, nil, cacheTTL, acl.ErrNotFound) 281 return 282 } 283 284 // some other RPC error 285 switch r.config.ACLDownPolicy { 286 case "allow": 287 r.fireAsyncLegacyResult(token, acl.AllowAll(), cacheTTL, nil) 288 return 289 case "async-cache", "extend-cache": 290 if cached != nil { 291 r.fireAsyncLegacyResult(token, cached.Authorizer, cacheTTL, nil) 292 return 293 } 294 fallthrough 295 default: 296 r.fireAsyncLegacyResult(token, acl.DenyAll(), cacheTTL, nil) 297 return 298 } 299 } 300 301 func (r *ACLResolver) resolveTokenLegacy(token string) (acl.Authorizer, error) { 302 defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now()) 303 304 // Attempt to resolve locally first (local results are not cached) 305 // This is only useful for servers where either legacy replication is being 306 // done or the server is within the primary datacenter. 307 if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done { 308 if err == nil && identity != nil { 309 policies, err := r.resolvePoliciesForIdentity(identity) 310 if err != nil { 311 return nil, err 312 } 313 314 return policies.Compile(acl.RootAuthorizer(r.config.ACLDefaultPolicy), r.cache, r.sentinel) 315 } 316 317 return nil, err 318 } 319 320 // Look in the cache prior to making a RPC request 321 entry := r.cache.GetAuthorizer(token) 322 323 if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) { 324 metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) 325 if entry.Authorizer != nil { 326 return entry.Authorizer, nil 327 } 328 return nil, acl.ErrNotFound 329 } 330 331 metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1) 332 333 // Resolve the token in the background and wait on the result if we must 334 var waitChan chan *remoteACLLegacyResult 335 waitForResult := entry == nil || r.config.ACLDownPolicy != "async-cache" 336 337 r.asyncLegacyMutex.Lock() 338 339 // check if resolution for this token is already happening 340 waiters, ok := r.asyncLegacyResults[token] 341 if !ok || waiters == nil { 342 // initialize the slice of waiters if not already done 343 waiters = make([]chan *remoteACLLegacyResult, 0) 344 } 345 if waitForResult { 346 // create the waitChan only if we are going to block waiting 347 // for the response and then append it to the list of waiters 348 // Because we will block (not select or discard this chan) we 349 // do not need to create it as buffered 350 waitChan = make(chan *remoteACLLegacyResult) 351 r.asyncLegacyResults[token] = append(waiters, waitChan) 352 } 353 r.asyncLegacyMutex.Unlock() 354 355 if !ok { 356 // start the async RPC if it wasn't already ongoing 357 go r.resolveTokenLegacyAsync(token, entry) 358 } 359 360 if !waitForResult { 361 // waitForResult being false requires the cacheEntry to not be nil 362 if entry.Authorizer != nil { 363 return entry.Authorizer, nil 364 } 365 return nil, acl.ErrNotFound 366 } 367 368 // block waiting for the async RPC to finish. 369 res := <-waitChan 370 return res.authorizer, res.err 371 } 372 373 // fireAsyncTokenResult is used to notify all waiters that the results of a token resolution is complete 374 func (r *ACLResolver) fireAsyncTokenResult(token string, identity structs.ACLIdentity, err error) { 375 // cache the result: positive or negative 376 r.cache.PutIdentity(token, identity) 377 378 // get the list of channels to send the result to 379 r.asyncIdentityResultsMutex.Lock() 380 channels := r.asyncIdentityResults[token] 381 delete(r.asyncIdentityResults, token) 382 r.asyncIdentityResultsMutex.Unlock() 383 384 // notify all watchers of the RPC results 385 result := &remoteACLIdentityResult{identity, err} 386 for _, cx := range channels { 387 // cannot block because all wait chans will have another goroutine blocked on the read 388 cx <- result 389 close(cx) 390 } 391 } 392 393 func (r *ACLResolver) resolveIdentityFromTokenAsync(token string, cached *structs.IdentityCacheEntry) { 394 req := structs.ACLTokenGetRequest{ 395 Datacenter: r.delegate.ACLDatacenter(false), 396 TokenID: token, 397 TokenIDType: structs.ACLTokenSecret, 398 QueryOptions: structs.QueryOptions{ 399 Token: token, 400 AllowStale: true, 401 }, 402 } 403 404 var resp structs.ACLTokenResponse 405 err := r.delegate.RPC("ACL.TokenRead", &req, &resp) 406 if err == nil { 407 if resp.Token == nil { 408 r.fireAsyncTokenResult(token, nil, acl.ErrNotFound) 409 } else { 410 r.fireAsyncTokenResult(token, resp.Token, nil) 411 } 412 return 413 } 414 415 if acl.IsErrNotFound(err) { 416 // Make sure to remove from the cache if it was deleted 417 r.fireAsyncTokenResult(token, nil, acl.ErrNotFound) 418 return 419 } 420 421 // some other RPC error 422 if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") { 423 // extend the cache 424 r.fireAsyncTokenResult(token, cached.Identity, nil) 425 } 426 427 r.fireAsyncTokenResult(token, nil, err) 428 return 429 } 430 431 func (r *ACLResolver) resolveIdentityFromToken(token string) (structs.ACLIdentity, error) { 432 // Attempt to resolve locally first (local results are not cached) 433 if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done { 434 return identity, err 435 } 436 437 // Check the cache before making any RPC requests 438 cacheEntry := r.cache.GetIdentity(token) 439 if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL { 440 metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) 441 return cacheEntry.Identity, nil 442 } 443 444 metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1) 445 446 // Background a RPC request and wait on it if we must 447 var waitChan chan *remoteACLIdentityResult 448 449 waitForResult := cacheEntry == nil || r.config.ACLDownPolicy != "async-cache" 450 451 r.asyncIdentityResultsMutex.Lock() 452 // check if resolution of this token is already ongoing 453 waiters, ok := r.asyncIdentityResults[token] 454 if !ok || waiters == nil { 455 // only initialize the slice of waiters if need be (when this token resolution isn't ongoing) 456 waiters = make([]chan *remoteACLIdentityResult, 0) 457 } 458 if waitForResult { 459 // create the waitChan only if we are going to block waiting 460 // for the response and then append it to the list of waiters 461 // Because we will block (not select or discard this chan) we 462 // do not need to create it as buffered 463 waitChan = make(chan *remoteACLIdentityResult) 464 r.asyncIdentityResults[token] = append(waiters, waitChan) 465 } 466 r.asyncIdentityResultsMutex.Unlock() 467 468 if !ok { 469 // only start the RPC if one isn't in flight 470 go r.resolveIdentityFromTokenAsync(token, cacheEntry) 471 } 472 473 if !waitForResult { 474 // waitForResult being false requires the cacheEntry to not be nil 475 return cacheEntry.Identity, nil 476 } 477 478 // block on the read here, this is why we don't need chan buffering 479 res := <-waitChan 480 481 if res.err != nil && !acl.IsErrNotFound(res.err) { 482 return res.identity, ACLRemoteError{Err: res.err} 483 } 484 return res.identity, res.err 485 } 486 487 // fireAsyncPolicyResult is used to notify all waiters that policy resolution is complete. 488 func (r *ACLResolver) fireAsyncPolicyResult(policyID string, policy *structs.ACLPolicy, err error, updateCache bool) { 489 if updateCache { 490 // cache the result: positive or negative 491 r.cache.PutPolicy(policyID, policy) 492 } 493 494 // get the list of channels to send the result to 495 r.asyncPolicyResultsMutex.Lock() 496 channels := r.asyncPolicyResults[policyID] 497 delete(r.asyncPolicyResults, policyID) 498 r.asyncPolicyResultsMutex.Unlock() 499 500 // notify all watchers of the RPC results 501 result := &remoteACLPolicyResult{policy, err} 502 for _, cx := range channels { 503 // not closing the channel as there could be more events to be fired. 504 cx <- result 505 } 506 } 507 508 func (r *ACLResolver) resolvePoliciesAsyncForIdentity(identity structs.ACLIdentity, policyIDs []string, cached map[string]*structs.PolicyCacheEntry) { 509 req := structs.ACLPolicyBatchGetRequest{ 510 Datacenter: r.delegate.ACLDatacenter(false), 511 PolicyIDs: policyIDs, 512 QueryOptions: structs.QueryOptions{ 513 Token: identity.SecretToken(), 514 AllowStale: true, 515 }, 516 } 517 518 found := make(map[string]struct{}) 519 var resp structs.ACLPolicyBatchResponse 520 err := r.delegate.RPC("ACL.PolicyResolve", &req, &resp) 521 if err == nil { 522 for _, policy := range resp.Policies { 523 r.fireAsyncPolicyResult(policy.ID, policy, nil, true) 524 found[policy.ID] = struct{}{} 525 } 526 527 for _, policyID := range policyIDs { 528 if _, ok := found[policyID]; !ok { 529 r.fireAsyncPolicyResult(policyID, nil, acl.ErrNotFound, true) 530 } 531 } 532 return 533 } 534 535 if acl.IsErrNotFound(err) { 536 // make sure to indicate that this identity is no longer valid within 537 // the cache 538 // 539 // Note - This must be done before firing the results or else it would 540 // be possible for waiters to get woken up an get the cached identity 541 // again 542 r.cache.PutIdentity(identity.SecretToken(), nil) 543 for _, policyID := range policyIDs { 544 // Do not touch the cache. Getting a top level ACL not found error 545 // only indicates that the secret token used in the request 546 // no longer exists 547 r.fireAsyncPolicyResult(policyID, nil, &policyTokenError{acl.ErrNotFound, identity.SecretToken()}, false) 548 } 549 return 550 } 551 552 if acl.IsErrPermissionDenied(err) { 553 // invalidate our ID cache so that identity resolution will take place 554 // again in the future 555 // 556 // Note - This must be done before firing the results or else it would 557 // be possible for waiters to get woken up and get the cached identity 558 // again 559 r.cache.RemoveIdentity(identity.SecretToken()) 560 561 for _, policyID := range policyIDs { 562 // Do not remove from the cache for permission denied 563 // what this does indicate is that our view of the token is out of date 564 r.fireAsyncPolicyResult(policyID, nil, &policyTokenError{acl.ErrPermissionDenied, identity.SecretToken()}, false) 565 } 566 return 567 } 568 569 // other RPC error - use cache if available 570 571 extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache" 572 for _, policyID := range policyIDs { 573 if entry, ok := cached[policyID]; extendCache && ok { 574 r.fireAsyncPolicyResult(policyID, entry.Policy, nil, true) 575 } else { 576 r.fireAsyncPolicyResult(policyID, nil, ACLRemoteError{Err: err}, true) 577 } 578 } 579 return 580 } 581 582 func (r *ACLResolver) filterPoliciesByScope(policies structs.ACLPolicies) structs.ACLPolicies { 583 var out structs.ACLPolicies 584 for _, policy := range policies { 585 if len(policy.Datacenters) == 0 { 586 out = append(out, policy) 587 continue 588 } 589 590 for _, dc := range policy.Datacenters { 591 if dc == r.config.Datacenter { 592 out = append(out, policy) 593 continue 594 } 595 } 596 } 597 598 return out 599 } 600 601 func (r *ACLResolver) resolvePoliciesForIdentity(identity structs.ACLIdentity) (structs.ACLPolicies, error) { 602 policyIDs := identity.PolicyIDs() 603 if len(policyIDs) == 0 { 604 policy := identity.EmbeddedPolicy() 605 if policy != nil { 606 return []*structs.ACLPolicy{policy}, nil 607 } 608 609 // In this case the default policy will be all that is in effect. 610 return nil, nil 611 } 612 613 // For the new ACLs policy replication is mandatory for correct operation on servers. Therefore 614 // we only attempt to resolve policies locally 615 policies := make([]*structs.ACLPolicy, 0, len(policyIDs)) 616 617 // Get all associated policies 618 var missing []string 619 var expired []*structs.ACLPolicy 620 expCacheMap := make(map[string]*structs.PolicyCacheEntry) 621 622 for _, policyID := range policyIDs { 623 if done, policy, err := r.delegate.ResolvePolicyFromID(policyID); done { 624 if err != nil && !acl.IsErrNotFound(err) { 625 return nil, err 626 } 627 628 if policy != nil { 629 policies = append(policies, policy) 630 } else { 631 r.logger.Printf("[WARN] acl: policy %q not found for identity %q", policyID, identity.ID()) 632 } 633 634 continue 635 } 636 637 // create the missing list which we can execute an RPC to get all the missing policies at once 638 entry := r.cache.GetPolicy(policyID) 639 if entry == nil { 640 missing = append(missing, policyID) 641 continue 642 } 643 644 if entry.Policy == nil { 645 // this happens when we cache a negative response for the policies existence 646 continue 647 } 648 649 if entry.Age() >= r.config.ACLPolicyTTL { 650 expired = append(expired, entry.Policy) 651 expCacheMap[policyID] = entry 652 } else { 653 policies = append(policies, entry.Policy) 654 } 655 } 656 657 // Hot-path if we have no missing or expired policies 658 if len(missing)+len(expired) == 0 { 659 return r.filterPoliciesByScope(policies), nil 660 } 661 662 fetchIDs := missing 663 for _, policy := range expired { 664 fetchIDs = append(fetchIDs, policy.ID) 665 } 666 667 // Background a RPC request and wait on it if we must 668 var waitChan chan *remoteACLPolicyResult 669 waitForResult := len(missing) > 0 || r.config.ACLDownPolicy != "async-cache" 670 if waitForResult { 671 // buffered because there are going to be multiple go routines that send data to this chan 672 waitChan = make(chan *remoteACLPolicyResult, len(fetchIDs)) 673 } 674 675 var newAsyncFetchIds []string 676 r.asyncPolicyResultsMutex.Lock() 677 for _, policyID := range fetchIDs { 678 clients, ok := r.asyncPolicyResults[policyID] 679 if !ok || clients == nil { 680 clients = make([]chan *remoteACLPolicyResult, 0) 681 } 682 if waitForResult { 683 r.asyncPolicyResults[policyID] = append(clients, waitChan) 684 } 685 686 if !ok { 687 newAsyncFetchIds = append(newAsyncFetchIds, policyID) 688 } 689 } 690 r.asyncPolicyResultsMutex.Unlock() 691 692 if len(newAsyncFetchIds) > 0 { 693 // only start the RPC if one isn't in flight 694 go r.resolvePoliciesAsyncForIdentity(identity, newAsyncFetchIds, expCacheMap) 695 } 696 697 if !waitForResult { 698 // waitForResult being false requires that all the policies were cached already 699 policies = append(policies, expired...) 700 return r.filterPoliciesByScope(policies), nil 701 } 702 703 for i := 0; i < len(fetchIDs); i++ { 704 res := <-waitChan 705 706 if res.err != nil { 707 if _, ok := res.err.(*policyTokenError); ok { 708 // always return token errors 709 return nil, res.err 710 } else if !acl.IsErrNotFound(res.err) { 711 // ignore regular not found errors for policies 712 return nil, res.err 713 } 714 } 715 716 // we probably could handle a special case where we 717 // get a permission denied error due to another requests 718 // issues and spawn the go routine to resolve it ourselves. 719 // however this should be exceedingly rare and in this case 720 // we can just kick the can down the road and retry the whole 721 // token/policy resolution. All the remaining good bits that 722 // we need will already be cached anyways. 723 724 if res.policy != nil { 725 policies = append(policies, res.policy) 726 } 727 } 728 729 return r.filterPoliciesByScope(policies), nil 730 } 731 732 func (r *ACLResolver) resolveTokenToPolicies(token string) (structs.ACLPolicies, error) { 733 _, policies, err := r.resolveTokenToIdentityAndPolicies(token) 734 return policies, err 735 } 736 737 func (r *ACLResolver) resolveTokenToIdentityAndPolicies(token string) (structs.ACLIdentity, structs.ACLPolicies, error) { 738 var lastErr error 739 var lastIdentity structs.ACLIdentity 740 741 for i := 0; i < tokenPolicyResolutionMaxRetries; i++ { 742 // Resolve the token to an ACLIdentity 743 identity, err := r.resolveIdentityFromToken(token) 744 if err != nil { 745 return nil, nil, err 746 } else if identity == nil { 747 return nil, nil, acl.ErrNotFound 748 } 749 750 lastIdentity = identity 751 752 policies, err := r.resolvePoliciesForIdentity(identity) 753 if err == nil { 754 return identity, policies, nil 755 } 756 lastErr = err 757 758 if tokenErr, ok := err.(*policyTokenError); ok { 759 if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() { 760 // token was deleted while resolving policies 761 return nil, nil, acl.ErrNotFound 762 } 763 764 // other types of policyTokenErrors should cause retrying the whole token 765 // resolution process 766 } else { 767 return identity, nil, err 768 } 769 } 770 771 return lastIdentity, nil, lastErr 772 } 773 774 func (r *ACLResolver) disableACLsWhenUpstreamDisabled(err error) error { 775 if !r.autoDisable || err == nil || !acl.IsErrDisabled(err) { 776 return err 777 } 778 779 r.logger.Printf("[DEBUG] acl: ACLs disabled on upstream servers, will check again after %s", r.config.ACLDisabledTTL) 780 r.disabledLock.Lock() 781 r.disabled = time.Now().Add(r.config.ACLDisabledTTL) 782 r.disabledLock.Unlock() 783 784 return err 785 } 786 787 func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) { 788 if !r.ACLsEnabled() { 789 return nil, nil 790 } 791 792 if acl.RootAuthorizer(token) != nil { 793 return nil, acl.ErrRootDenied 794 } 795 796 // handle the anonymous token 797 if token == "" { 798 token = anonymousToken 799 } 800 801 if r.delegate.UseLegacyACLs() { 802 authorizer, err := r.resolveTokenLegacy(token) 803 return authorizer, r.disableACLsWhenUpstreamDisabled(err) 804 } 805 806 defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now()) 807 808 policies, err := r.resolveTokenToPolicies(token) 809 if err != nil { 810 r.disableACLsWhenUpstreamDisabled(err) 811 if IsACLRemoteError(err) { 812 r.logger.Printf("[ERR] consul.acl: %v", err) 813 return r.down, nil 814 } 815 816 return nil, err 817 } 818 819 // Build the Authorizer 820 authorizer, err := policies.Compile(acl.RootAuthorizer(r.config.ACLDefaultPolicy), r.cache, r.sentinel) 821 return authorizer, err 822 823 } 824 825 func (r *ACLResolver) ACLsEnabled() bool { 826 // Whether we desire ACLs to be enabled according to configuration 827 if !r.delegate.ACLsEnabled() { 828 return false 829 } 830 831 if r.autoDisable { 832 // Whether ACLs are disabled according to RPCs failing with a ACLs Disabled error 833 r.disabledLock.RLock() 834 defer r.disabledLock.RUnlock() 835 return !time.Now().Before(r.disabled) 836 } 837 838 return true 839 } 840 841 func (r *ACLResolver) GetMergedPolicyForToken(token string) (*acl.Policy, error) { 842 policies, err := r.resolveTokenToPolicies(token) 843 if err != nil { 844 return nil, err 845 } 846 if len(policies) == 0 { 847 return nil, acl.ErrNotFound 848 } 849 850 return policies.Merge(r.cache, r.sentinel) 851 } 852 853 // aclFilter is used to filter results from our state store based on ACL rules 854 // configured for the provided token. 855 type aclFilter struct { 856 authorizer acl.Authorizer 857 logger *log.Logger 858 enforceVersion8 bool 859 } 860 861 // newACLFilter constructs a new aclFilter. 862 func newACLFilter(authorizer acl.Authorizer, logger *log.Logger, enforceVersion8 bool) *aclFilter { 863 if logger == nil { 864 logger = log.New(os.Stderr, "", log.LstdFlags) 865 } 866 return &aclFilter{ 867 authorizer: authorizer, 868 logger: logger, 869 enforceVersion8: enforceVersion8, 870 } 871 } 872 873 // allowNode is used to determine if a node is accessible for an ACL. 874 func (f *aclFilter) allowNode(node string) bool { 875 if !f.enforceVersion8 { 876 return true 877 } 878 return f.authorizer.NodeRead(node) 879 } 880 881 // allowService is used to determine if a service is accessible for an ACL. 882 func (f *aclFilter) allowService(service string) bool { 883 if service == "" { 884 return true 885 } 886 887 if !f.enforceVersion8 && service == structs.ConsulServiceID { 888 return true 889 } 890 return f.authorizer.ServiceRead(service) 891 } 892 893 // allowSession is used to determine if a session for a node is accessible for 894 // an ACL. 895 func (f *aclFilter) allowSession(node string) bool { 896 if !f.enforceVersion8 { 897 return true 898 } 899 return f.authorizer.SessionRead(node) 900 } 901 902 // filterHealthChecks is used to filter a set of health checks down based on 903 // the configured ACL rules for a token. 904 func (f *aclFilter) filterHealthChecks(checks *structs.HealthChecks) { 905 hc := *checks 906 for i := 0; i < len(hc); i++ { 907 check := hc[i] 908 if f.allowNode(check.Node) && f.allowService(check.ServiceName) { 909 continue 910 } 911 f.logger.Printf("[DEBUG] consul: dropping check %q from result due to ACLs", check.CheckID) 912 hc = append(hc[:i], hc[i+1:]...) 913 i-- 914 } 915 *checks = hc 916 } 917 918 // filterServices is used to filter a set of services based on ACLs. 919 func (f *aclFilter) filterServices(services structs.Services) { 920 for svc := range services { 921 if f.allowService(svc) { 922 continue 923 } 924 f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc) 925 delete(services, svc) 926 } 927 } 928 929 // filterServiceNodes is used to filter a set of nodes for a given service 930 // based on the configured ACL rules. 931 func (f *aclFilter) filterServiceNodes(nodes *structs.ServiceNodes) { 932 sn := *nodes 933 for i := 0; i < len(sn); i++ { 934 node := sn[i] 935 if f.allowNode(node.Node) && f.allowService(node.ServiceName) { 936 continue 937 } 938 f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node.Node) 939 sn = append(sn[:i], sn[i+1:]...) 940 i-- 941 } 942 *nodes = sn 943 } 944 945 // filterNodeServices is used to filter services on a given node base on ACLs. 946 func (f *aclFilter) filterNodeServices(services **structs.NodeServices) { 947 if *services == nil { 948 return 949 } 950 951 if !f.allowNode((*services).Node.Node) { 952 *services = nil 953 return 954 } 955 956 for svc := range (*services).Services { 957 if f.allowService(svc) { 958 continue 959 } 960 f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc) 961 delete((*services).Services, svc) 962 } 963 } 964 965 // filterCheckServiceNodes is used to filter nodes based on ACL rules. 966 func (f *aclFilter) filterCheckServiceNodes(nodes *structs.CheckServiceNodes) { 967 csn := *nodes 968 for i := 0; i < len(csn); i++ { 969 node := csn[i] 970 if f.allowNode(node.Node.Node) && f.allowService(node.Service.Service) { 971 continue 972 } 973 f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node.Node.Node) 974 csn = append(csn[:i], csn[i+1:]...) 975 i-- 976 } 977 *nodes = csn 978 } 979 980 // filterSessions is used to filter a set of sessions based on ACLs. 981 func (f *aclFilter) filterSessions(sessions *structs.Sessions) { 982 s := *sessions 983 for i := 0; i < len(s); i++ { 984 session := s[i] 985 if f.allowSession(session.Node) { 986 continue 987 } 988 f.logger.Printf("[DEBUG] consul: dropping session %q from result due to ACLs", session.ID) 989 s = append(s[:i], s[i+1:]...) 990 i-- 991 } 992 *sessions = s 993 } 994 995 // filterCoordinates is used to filter nodes in a coordinate dump based on ACL 996 // rules. 997 func (f *aclFilter) filterCoordinates(coords *structs.Coordinates) { 998 c := *coords 999 for i := 0; i < len(c); i++ { 1000 node := c[i].Node 1001 if f.allowNode(node) { 1002 continue 1003 } 1004 f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node) 1005 c = append(c[:i], c[i+1:]...) 1006 i-- 1007 } 1008 *coords = c 1009 } 1010 1011 // filterIntentions is used to filter intentions based on ACL rules. 1012 // We prune entries the user doesn't have access to, and we redact any tokens 1013 // if the user doesn't have a management token. 1014 func (f *aclFilter) filterIntentions(ixns *structs.Intentions) { 1015 // Management tokens can see everything with no filtering. 1016 if f.authorizer.ACLRead() { 1017 return 1018 } 1019 1020 // Otherwise, we need to see what the token has access to. 1021 ret := make(structs.Intentions, 0, len(*ixns)) 1022 for _, ixn := range *ixns { 1023 // If no prefix ACL applies to this then filter it, since 1024 // we know at this point the user doesn't have a management 1025 // token, otherwise see what the policy says. 1026 prefix, ok := ixn.GetACLPrefix() 1027 if !ok || !f.authorizer.IntentionRead(prefix) { 1028 f.logger.Printf("[DEBUG] consul: dropping intention %q from result due to ACLs", ixn.ID) 1029 continue 1030 } 1031 1032 ret = append(ret, ixn) 1033 } 1034 1035 *ixns = ret 1036 } 1037 1038 // filterNodeDump is used to filter through all parts of a node dump and 1039 // remove elements the provided ACL token cannot access. 1040 func (f *aclFilter) filterNodeDump(dump *structs.NodeDump) { 1041 nd := *dump 1042 for i := 0; i < len(nd); i++ { 1043 info := nd[i] 1044 1045 // Filter nodes 1046 if node := info.Node; !f.allowNode(node) { 1047 f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node) 1048 nd = append(nd[:i], nd[i+1:]...) 1049 i-- 1050 continue 1051 } 1052 1053 // Filter services 1054 for j := 0; j < len(info.Services); j++ { 1055 svc := info.Services[j].Service 1056 if f.allowService(svc) { 1057 continue 1058 } 1059 f.logger.Printf("[DEBUG] consul: dropping service %q from result due to ACLs", svc) 1060 info.Services = append(info.Services[:j], info.Services[j+1:]...) 1061 j-- 1062 } 1063 1064 // Filter checks 1065 for j := 0; j < len(info.Checks); j++ { 1066 chk := info.Checks[j] 1067 if f.allowService(chk.ServiceName) { 1068 continue 1069 } 1070 f.logger.Printf("[DEBUG] consul: dropping check %q from result due to ACLs", chk.CheckID) 1071 info.Checks = append(info.Checks[:j], info.Checks[j+1:]...) 1072 j-- 1073 } 1074 } 1075 *dump = nd 1076 } 1077 1078 // filterNodes is used to filter through all parts of a node list and remove 1079 // elements the provided ACL token cannot access. 1080 func (f *aclFilter) filterNodes(nodes *structs.Nodes) { 1081 n := *nodes 1082 for i := 0; i < len(n); i++ { 1083 node := n[i].Node 1084 if f.allowNode(node) { 1085 continue 1086 } 1087 f.logger.Printf("[DEBUG] consul: dropping node %q from result due to ACLs", node) 1088 n = append(n[:i], n[i+1:]...) 1089 i-- 1090 } 1091 *nodes = n 1092 } 1093 1094 // redactPreparedQueryTokens will redact any tokens unless the client has a 1095 // management token. This eases the transition to delegated authority over 1096 // prepared queries, since it was easy to capture management tokens in Consul 1097 // 0.6.3 and earlier, and we don't want to willy-nilly show those. This does 1098 // have the limitation of preventing delegated non-management users from seeing 1099 // captured tokens, but they can at least see whether or not a token is set. 1100 func (f *aclFilter) redactPreparedQueryTokens(query **structs.PreparedQuery) { 1101 // Management tokens can see everything with no filtering. 1102 if f.authorizer.ACLWrite() { 1103 return 1104 } 1105 1106 // Let the user see if there's a blank token, otherwise we need 1107 // to redact it, since we know they don't have a management 1108 // token. 1109 if (*query).Token != "" { 1110 // Redact the token, using a copy of the query structure 1111 // since we could be pointed at a live instance from the 1112 // state store so it's not safe to modify it. Note that 1113 // this clone will still point to things like underlying 1114 // arrays in the original, but for modifying just the 1115 // token it will be safe to use. 1116 clone := *(*query) 1117 clone.Token = redactedToken 1118 *query = &clone 1119 } 1120 } 1121 1122 // filterPreparedQueries is used to filter prepared queries based on ACL rules. 1123 // We prune entries the user doesn't have access to, and we redact any tokens 1124 // if the user doesn't have a management token. 1125 func (f *aclFilter) filterPreparedQueries(queries *structs.PreparedQueries) { 1126 // Management tokens can see everything with no filtering. 1127 if f.authorizer.ACLWrite() { 1128 return 1129 } 1130 1131 // Otherwise, we need to see what the token has access to. 1132 ret := make(structs.PreparedQueries, 0, len(*queries)) 1133 for _, query := range *queries { 1134 // If no prefix ACL applies to this query then filter it, since 1135 // we know at this point the user doesn't have a management 1136 // token, otherwise see what the policy says. 1137 prefix, ok := query.GetACLPrefix() 1138 if !ok || !f.authorizer.PreparedQueryRead(prefix) { 1139 f.logger.Printf("[DEBUG] consul: dropping prepared query %q from result due to ACLs", query.ID) 1140 continue 1141 } 1142 1143 // Redact any tokens if necessary. We make a copy of just the 1144 // pointer so we don't mess with the caller's slice. 1145 final := query 1146 f.redactPreparedQueryTokens(&final) 1147 ret = append(ret, final) 1148 } 1149 *queries = ret 1150 } 1151 1152 func (f *aclFilter) redactTokenSecret(token **structs.ACLToken) { 1153 if token == nil || *token == nil || f == nil || f.authorizer.ACLWrite() { 1154 return 1155 } 1156 clone := *(*token) 1157 clone.SecretID = redactedToken 1158 *token = &clone 1159 } 1160 1161 func (f *aclFilter) redactTokenSecrets(tokens *structs.ACLTokens) { 1162 ret := make(structs.ACLTokens, 0, len(*tokens)) 1163 for _, token := range *tokens { 1164 final := token 1165 f.redactTokenSecret(&final) 1166 ret = append(ret, final) 1167 } 1168 *tokens = ret 1169 } 1170 1171 func (r *ACLResolver) filterACLWithAuthorizer(authorizer acl.Authorizer, subj interface{}) error { 1172 if authorizer == nil { 1173 return nil 1174 } 1175 // Create the filter 1176 filt := newACLFilter(authorizer, r.logger, r.config.ACLEnforceVersion8) 1177 1178 switch v := subj.(type) { 1179 case *structs.CheckServiceNodes: 1180 filt.filterCheckServiceNodes(v) 1181 1182 case *structs.IndexedCheckServiceNodes: 1183 filt.filterCheckServiceNodes(&v.Nodes) 1184 1185 case *structs.IndexedCoordinates: 1186 filt.filterCoordinates(&v.Coordinates) 1187 1188 case *structs.IndexedHealthChecks: 1189 filt.filterHealthChecks(&v.HealthChecks) 1190 1191 case *structs.IndexedIntentions: 1192 filt.filterIntentions(&v.Intentions) 1193 1194 case *structs.IndexedNodeDump: 1195 filt.filterNodeDump(&v.Dump) 1196 1197 case *structs.IndexedNodes: 1198 filt.filterNodes(&v.Nodes) 1199 1200 case *structs.IndexedNodeServices: 1201 filt.filterNodeServices(&v.NodeServices) 1202 1203 case *structs.IndexedServiceNodes: 1204 filt.filterServiceNodes(&v.ServiceNodes) 1205 1206 case *structs.IndexedServices: 1207 filt.filterServices(v.Services) 1208 1209 case *structs.IndexedSessions: 1210 filt.filterSessions(&v.Sessions) 1211 1212 case *structs.IndexedPreparedQueries: 1213 filt.filterPreparedQueries(&v.Queries) 1214 1215 case **structs.PreparedQuery: 1216 filt.redactPreparedQueryTokens(v) 1217 1218 case *structs.ACLTokens: 1219 filt.redactTokenSecrets(v) 1220 1221 case **structs.ACLToken: 1222 filt.redactTokenSecret(v) 1223 1224 default: 1225 panic(fmt.Errorf("Unhandled type passed to ACL filter: %#v", subj)) 1226 } 1227 1228 return nil 1229 } 1230 1231 // filterACL is used to filter results from our service catalog based on the 1232 // rules configured for the provided token. 1233 func (r *ACLResolver) filterACL(token string, subj interface{}) error { 1234 // Get the ACL from the token 1235 authorizer, err := r.ResolveToken(token) 1236 if err != nil { 1237 return err 1238 } 1239 1240 // Fast path if ACLs are not enabled 1241 if authorizer == nil { 1242 return nil 1243 } 1244 1245 return r.filterACLWithAuthorizer(authorizer, subj) 1246 } 1247 1248 // vetRegisterWithACL applies the given ACL's policy to the catalog update and 1249 // determines if it is allowed. Since the catalog register request is so 1250 // dynamic, this is a pretty complex algorithm and was worth breaking out of the 1251 // endpoint. The NodeServices record for the node must be supplied, and can be 1252 // nil. 1253 // 1254 // This is a bit racy because we have to check the state store outside of a 1255 // transaction. It's the best we can do because we don't want to flow ACL 1256 // checking down there. The node information doesn't change in practice, so this 1257 // will be fine. If we expose ways to change node addresses in a later version, 1258 // then we should split the catalog API at the node and service level so we can 1259 // address this race better (even then it would be super rare, and would at 1260 // worst let a service update revert a recent node update, so it doesn't open up 1261 // too much abuse). 1262 func vetRegisterWithACL(rule acl.Authorizer, subj *structs.RegisterRequest, 1263 ns *structs.NodeServices) error { 1264 // Fast path if ACLs are not enabled. 1265 if rule == nil { 1266 return nil 1267 } 1268 1269 // This gets called potentially from a few spots so we save it and 1270 // return the structure we made if we have it. 1271 var memo map[string]interface{} 1272 scope := func() map[string]interface{} { 1273 if memo != nil { 1274 return memo 1275 } 1276 1277 node := &api.Node{ 1278 ID: string(subj.ID), 1279 Node: subj.Node, 1280 Address: subj.Address, 1281 Datacenter: subj.Datacenter, 1282 TaggedAddresses: subj.TaggedAddresses, 1283 Meta: subj.NodeMeta, 1284 } 1285 1286 var service *api.AgentService 1287 if subj.Service != nil { 1288 service = &api.AgentService{ 1289 ID: subj.Service.ID, 1290 Service: subj.Service.Service, 1291 Tags: subj.Service.Tags, 1292 Meta: subj.Service.Meta, 1293 Address: subj.Service.Address, 1294 Port: subj.Service.Port, 1295 EnableTagOverride: subj.Service.EnableTagOverride, 1296 } 1297 } 1298 1299 memo = sentinel.ScopeCatalogUpsert(node, service) 1300 return memo 1301 } 1302 1303 // Vet the node info. This allows service updates to re-post the required 1304 // node info for each request without having to have node "write" 1305 // privileges. 1306 needsNode := ns == nil || subj.ChangesNode(ns.Node) 1307 1308 if needsNode && !rule.NodeWrite(subj.Node, scope) { 1309 return acl.ErrPermissionDenied 1310 } 1311 1312 // Vet the service change. This includes making sure they can register 1313 // the given service, and that we can write to any existing service that 1314 // is being modified by id (if any). 1315 if subj.Service != nil { 1316 if !rule.ServiceWrite(subj.Service.Service, scope) { 1317 return acl.ErrPermissionDenied 1318 } 1319 1320 if ns != nil { 1321 other, ok := ns.Services[subj.Service.ID] 1322 1323 // This is effectively a delete, so we DO NOT apply the 1324 // sentinel scope to the service we are overwriting, just 1325 // the regular ACL policy. 1326 if ok && !rule.ServiceWrite(other.Service, nil) { 1327 return acl.ErrPermissionDenied 1328 } 1329 } 1330 } 1331 1332 // Make sure that the member was flattened before we got there. This 1333 // keeps us from having to verify this check as well. 1334 if subj.Check != nil { 1335 return fmt.Errorf("check member must be nil") 1336 } 1337 1338 // Vet the checks. Node-level checks require node write, and 1339 // service-level checks require service write. 1340 for _, check := range subj.Checks { 1341 // Make sure that the node matches - we don't allow you to mix 1342 // checks from other nodes because we'd have to pull a bunch 1343 // more state store data to check this. If ACLs are enabled then 1344 // we simply require them to match in a given request. There's a 1345 // note in state_store.go to ban this down there in Consul 0.8, 1346 // but it's good to leave this here because it's required for 1347 // correctness wrt. ACLs. 1348 if check.Node != subj.Node { 1349 return fmt.Errorf("Node '%s' for check '%s' doesn't match register request node '%s'", 1350 check.Node, check.CheckID, subj.Node) 1351 } 1352 1353 // Node-level check. 1354 if check.ServiceID == "" { 1355 if !rule.NodeWrite(subj.Node, scope) { 1356 return acl.ErrPermissionDenied 1357 } 1358 continue 1359 } 1360 1361 // Service-level check, check the common case where it 1362 // matches the service part of this request, which has 1363 // already been vetted above, and might be being registered 1364 // along with its checks. 1365 if subj.Service != nil && subj.Service.ID == check.ServiceID { 1366 continue 1367 } 1368 1369 // Service-level check for some other service. Make sure they've 1370 // got write permissions for that service. 1371 if ns == nil { 1372 return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID) 1373 } 1374 1375 other, ok := ns.Services[check.ServiceID] 1376 if !ok { 1377 return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID) 1378 } 1379 1380 // We are only adding a check here, so we don't add the scope, 1381 // since the sentinel policy doesn't apply to adding checks at 1382 // this time. 1383 if !rule.ServiceWrite(other.Service, nil) { 1384 return acl.ErrPermissionDenied 1385 } 1386 } 1387 1388 return nil 1389 } 1390 1391 // vetDeregisterWithACL applies the given ACL's policy to the catalog update and 1392 // determines if it is allowed. Since the catalog deregister request is so 1393 // dynamic, this is a pretty complex algorithm and was worth breaking out of the 1394 // endpoint. The NodeService for the referenced service must be supplied, and can 1395 // be nil; similar for the HealthCheck for the referenced health check. 1396 func vetDeregisterWithACL(rule acl.Authorizer, subj *structs.DeregisterRequest, 1397 ns *structs.NodeService, nc *structs.HealthCheck) error { 1398 1399 // Fast path if ACLs are not enabled. 1400 if rule == nil { 1401 return nil 1402 } 1403 1404 // We don't apply sentinel in this path, since at this time sentinel 1405 // only applies to create and update operations. 1406 1407 // This order must match the code in applyRegister() in fsm.go since it 1408 // also evaluates things in this order, and will ignore fields based on 1409 // this precedence. This lets us also ignore them from an ACL perspective. 1410 if subj.ServiceID != "" { 1411 if ns == nil { 1412 return fmt.Errorf("Unknown service '%s'", subj.ServiceID) 1413 } 1414 if !rule.ServiceWrite(ns.Service, nil) { 1415 return acl.ErrPermissionDenied 1416 } 1417 } else if subj.CheckID != "" { 1418 if nc == nil { 1419 return fmt.Errorf("Unknown check '%s'", subj.CheckID) 1420 } 1421 if nc.ServiceID != "" { 1422 if !rule.ServiceWrite(nc.ServiceName, nil) { 1423 return acl.ErrPermissionDenied 1424 } 1425 } else { 1426 if !rule.NodeWrite(subj.Node, nil) { 1427 return acl.ErrPermissionDenied 1428 } 1429 } 1430 } else { 1431 if !rule.NodeWrite(subj.Node, nil) { 1432 return acl.ErrPermissionDenied 1433 } 1434 } 1435 1436 return nil 1437 } 1438 1439 // vetNodeTxnOp applies the given ACL policy to a node transaction operation. 1440 func vetNodeTxnOp(op *structs.TxnNodeOp, rule acl.Authorizer) error { 1441 // Fast path if ACLs are not enabled. 1442 if rule == nil { 1443 return nil 1444 } 1445 1446 node := op.Node 1447 1448 n := &api.Node{ 1449 Node: node.Node, 1450 ID: string(node.ID), 1451 Address: node.Address, 1452 Datacenter: node.Datacenter, 1453 TaggedAddresses: node.TaggedAddresses, 1454 Meta: node.Meta, 1455 } 1456 1457 // Sentinel doesn't apply to deletes, only creates/updates, so we don't need the scopeFn. 1458 var scope func() map[string]interface{} 1459 if op.Verb != api.NodeDelete && op.Verb != api.NodeDeleteCAS { 1460 scope = func() map[string]interface{} { 1461 return sentinel.ScopeCatalogUpsert(n, nil) 1462 } 1463 } 1464 1465 if rule != nil && !rule.NodeWrite(node.Node, scope) { 1466 return acl.ErrPermissionDenied 1467 } 1468 1469 return nil 1470 } 1471 1472 // vetServiceTxnOp applies the given ACL policy to a service transaction operation. 1473 func vetServiceTxnOp(op *structs.TxnServiceOp, rule acl.Authorizer) error { 1474 // Fast path if ACLs are not enabled. 1475 if rule == nil { 1476 return nil 1477 } 1478 1479 service := op.Service 1480 1481 n := &api.Node{Node: op.Node} 1482 svc := &api.AgentService{ 1483 ID: service.ID, 1484 Service: service.Service, 1485 Tags: service.Tags, 1486 Meta: service.Meta, 1487 Address: service.Address, 1488 Port: service.Port, 1489 EnableTagOverride: service.EnableTagOverride, 1490 } 1491 var scope func() map[string]interface{} 1492 if op.Verb != api.ServiceDelete && op.Verb != api.ServiceDeleteCAS { 1493 scope = func() map[string]interface{} { 1494 return sentinel.ScopeCatalogUpsert(n, svc) 1495 } 1496 } 1497 if !rule.ServiceWrite(service.Service, scope) { 1498 return acl.ErrPermissionDenied 1499 } 1500 1501 return nil 1502 } 1503 1504 // vetCheckTxnOp applies the given ACL policy to a check transaction operation. 1505 func vetCheckTxnOp(op *structs.TxnCheckOp, rule acl.Authorizer) error { 1506 // Fast path if ACLs are not enabled. 1507 if rule == nil { 1508 return nil 1509 } 1510 1511 n := &api.Node{Node: op.Check.Node} 1512 svc := &api.AgentService{ 1513 ID: op.Check.ServiceID, 1514 Service: op.Check.ServiceID, 1515 Tags: op.Check.ServiceTags, 1516 } 1517 var scope func() map[string]interface{} 1518 if op.Check.ServiceID == "" { 1519 // Node-level check. 1520 if op.Verb == api.CheckDelete || op.Verb == api.CheckDeleteCAS { 1521 scope = func() map[string]interface{} { 1522 return sentinel.ScopeCatalogUpsert(n, svc) 1523 } 1524 } 1525 if !rule.NodeWrite(op.Check.Node, scope) { 1526 return acl.ErrPermissionDenied 1527 } 1528 } else { 1529 // Service-level check. 1530 if op.Verb == api.CheckDelete || op.Verb == api.CheckDeleteCAS { 1531 scope = func() map[string]interface{} { 1532 return sentinel.ScopeCatalogUpsert(n, svc) 1533 } 1534 } 1535 if !rule.ServiceWrite(op.Check.ServiceName, scope) { 1536 return acl.ErrPermissionDenied 1537 } 1538 } 1539 1540 return nil 1541 }