1package consul 2 3import ( 4 "fmt" 5 "sort" 6 "sync" 7 "time" 8 9 metrics "github.com/armon/go-metrics" 10 "github.com/hashicorp/consul/acl" 11 "github.com/hashicorp/consul/agent/structs" 12 "github.com/hashicorp/consul/logging" 13 "github.com/hashicorp/go-hclog" 14 "golang.org/x/sync/singleflight" 15 "golang.org/x/time/rate" 16) 17 18// These must be kept in sync with the constants in command/agent/acl.go. 19const ( 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 allowed. 34 aclUpgradeRateLimit rate.Limit = 1.0 35 36 // aclTokenReapingRateLimit is the number of batch token reaping requests per second allowed. 37 aclTokenReapingRateLimit rate.Limit = 1.0 38 39 // aclTokenReapingBurst is the number of batch token reaping requests per second 40 // that can burst after a period of idleness. 41 aclTokenReapingBurst = 5 42 43 // aclBatchDeleteSize is the number of deletions to send in a single batch operation. 4096 should produce a batch that is <150KB 44 // in size but should be sufficiently large to handle 1 replication round in a single batch 45 aclBatchDeleteSize = 4096 46 47 // aclBatchUpsertSize is the target size in bytes we want to submit for a batch upsert request. We estimate the size at runtime 48 // due to the data being more variable in its size. 49 aclBatchUpsertSize = 256 * 1024 50 51 // DEPRECATED (ACL-Legacy-Compat) aclModeCheck* are all only for legacy usage 52 // aclModeCheckMinInterval is the minimum amount of time between checking if the 53 // agent should be using the new or legacy ACL system. All the places it is 54 // currently used will backoff as it detects that it is remaining in legacy mode. 55 // However the initial min value is kept small so that new cluster creation 56 // can enter into new ACL mode quickly. 57 aclModeCheckMinInterval = 50 * time.Millisecond 58 59 // aclModeCheckMaxInterval controls the maximum interval for how often the agent 60 // checks if it should be using the new or legacy ACL system. 61 aclModeCheckMaxInterval = 30 * time.Second 62 63 // Maximum number of re-resolution requests to be made if the token is modified between 64 // resolving the token and resolving its policies that would remove one of its policies. 65 tokenPolicyResolutionMaxRetries = 5 66 67 // Maximum number of re-resolution requests to be made if the token is modified between 68 // resolving the token and resolving its roles that would remove one of its roles. 69 tokenRoleResolutionMaxRetries = 5 70) 71 72// missingIdentity is used to return some identity in the event that the real identity cannot be ascertained 73type missingIdentity struct { 74 reason string 75 token string 76} 77 78func (id *missingIdentity) ID() string { 79 return id.reason 80} 81 82func (id *missingIdentity) SecretToken() string { 83 return id.token 84} 85 86func (id *missingIdentity) PolicyIDs() []string { 87 return nil 88} 89 90func (id *missingIdentity) RoleIDs() []string { 91 return nil 92} 93 94func (id *missingIdentity) EmbeddedPolicy() *structs.ACLPolicy { 95 return nil 96} 97 98func (id *missingIdentity) ServiceIdentityList() []*structs.ACLServiceIdentity { 99 return nil 100} 101 102func (id *missingIdentity) IsExpired(asOf time.Time) bool { 103 return false 104} 105 106func (id *missingIdentity) EnterpriseMetadata() *structs.EnterpriseMeta { 107 return structs.DefaultEnterpriseMeta() 108} 109 110func minTTL(a time.Duration, b time.Duration) time.Duration { 111 if a < b { 112 return a 113 } 114 return b 115} 116 117type ACLRemoteError struct { 118 Err error 119} 120 121func (e ACLRemoteError) Error() string { 122 return fmt.Sprintf("Error communicating with the ACL Datacenter: %v", e.Err) 123} 124 125func IsACLRemoteError(err error) bool { 126 _, ok := err.(ACLRemoteError) 127 return ok 128} 129 130func tokenSecretCacheID(token string) string { 131 return "token-secret:" + token 132} 133 134type ACLResolverDelegate interface { 135 ACLsEnabled() bool 136 ACLDatacenter(legacy bool) string 137 UseLegacyACLs() bool 138 ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error) 139 ResolvePolicyFromID(policyID string) (bool, *structs.ACLPolicy, error) 140 ResolveRoleFromID(roleID string) (bool, *structs.ACLRole, error) 141 RPC(method string, args interface{}, reply interface{}) error 142 EnterpriseACLResolverDelegate 143} 144 145type policyOrRoleTokenError struct { 146 Err error 147 token string 148} 149 150func (e policyOrRoleTokenError) Error() string { 151 return e.Err.Error() 152} 153 154// ACLResolverConfig holds all the configuration necessary to create an ACLResolver 155type ACLResolverConfig struct { 156 Config *Config 157 Logger hclog.Logger 158 159 // CacheConfig is a pass through configuration for ACL cache limits 160 CacheConfig *structs.ACLCachesConfig 161 162 // Delegate that implements some helper functionality that is server/client specific 163 Delegate ACLResolverDelegate 164 165 // AutoDisable indicates that RPC responses should be checked and if they indicate ACLs are disabled 166 // remotely then disable them locally as well. This is particularly useful for the client agent 167 // so that it can detect when the servers have gotten ACLs enabled. 168 AutoDisable bool 169 170 // ACLConfig is the configuration necessary to pass through to the acl package when creating authorizers 171 // and when authorizing access 172 ACLConfig *acl.Config 173} 174 175// ACLResolver is the type to handle all your token and policy resolution needs. 176// 177// Supports: 178// - Resolving tokens locally via the ACLResolverDelegate 179// - Resolving policies locally via the ACLResolverDelegate 180// - Resolving roles locally via the ACLResolverDelegate 181// - Resolving legacy tokens remotely via an ACL.GetPolicy RPC 182// - Resolving tokens remotely via an ACL.TokenRead RPC 183// - Resolving policies remotely via an ACL.PolicyResolve RPC 184// - Resolving roles remotely via an ACL.RoleResolve RPC 185// 186// Remote Resolution: 187// Remote resolution can be done synchronously or asynchronously depending 188// on the ACLDownPolicy in the Config passed to the resolver. 189// 190// When the down policy is set to async-cache and we have already cached values 191// then go routines will be spawned to perform the RPCs in the background 192// and then will update the cache with either the positive or negative result. 193// 194// When the down policy is set to extend-cache or the token/policy/role is not already 195// cached then the same go routines are spawned to do the RPCs in the background. 196// However in this mode channels are created to receive the results of the RPC 197// and are registered with the resolver. Those channels are immediately read/blocked 198// upon. 199// 200type ACLResolver struct { 201 config *Config 202 logger hclog.Logger 203 204 delegate ACLResolverDelegate 205 aclConf *acl.Config 206 207 cache *structs.ACLCaches 208 identityGroup singleflight.Group 209 policyGroup singleflight.Group 210 roleGroup singleflight.Group 211 legacyGroup singleflight.Group 212 213 down acl.Authorizer 214 215 autoDisable bool 216 disabled time.Time 217 disabledLock sync.RWMutex 218} 219 220func NewACLResolver(config *ACLResolverConfig) (*ACLResolver, error) { 221 if config == nil { 222 return nil, fmt.Errorf("ACL Resolver must be initialized with a config") 223 } 224 225 if config.Config == nil { 226 return nil, fmt.Errorf("ACLResolverConfig.Config must not be nil") 227 } 228 229 if config.Delegate == nil { 230 return nil, fmt.Errorf("ACL Resolver must be initialized with a valid delegate") 231 } 232 233 if config.Logger == nil { 234 config.Logger = hclog.New(&hclog.LoggerOptions{}) 235 } 236 237 cache, err := structs.NewACLCaches(config.CacheConfig) 238 if err != nil { 239 return nil, err 240 } 241 242 var down acl.Authorizer 243 switch config.Config.ACLDownPolicy { 244 case "allow": 245 down = acl.AllowAll() 246 case "deny": 247 down = acl.DenyAll() 248 case "async-cache", "extend-cache": 249 // Leave the down policy as nil to signal this. 250 default: 251 return nil, fmt.Errorf("invalid ACL down policy %q", config.Config.ACLDownPolicy) 252 } 253 254 return &ACLResolver{ 255 config: config.Config, 256 logger: config.Logger.Named(logging.ACL), 257 delegate: config.Delegate, 258 aclConf: config.ACLConfig, 259 cache: cache, 260 autoDisable: config.AutoDisable, 261 down: down, 262 }, nil 263} 264 265func (r *ACLResolver) Close() { 266 r.aclConf.Close() 267} 268 269func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.AuthorizerCacheEntry) (acl.Authorizer, error) { 270 req := structs.ACLPolicyResolveLegacyRequest{ 271 Datacenter: r.delegate.ACLDatacenter(true), 272 ACL: token, 273 } 274 275 cacheTTL := r.config.ACLTokenTTL 276 if cached != nil { 277 cacheTTL = cached.TTL 278 } 279 280 var reply structs.ACLPolicyResolveLegacyResponse 281 err := r.delegate.RPC("ACL.GetPolicy", &req, &reply) 282 if err == nil { 283 parent := acl.RootAuthorizer(reply.Parent) 284 if parent == nil { 285 var authorizer acl.Authorizer 286 if cached != nil { 287 authorizer = cached.Authorizer 288 } 289 r.cache.PutAuthorizerWithTTL(token, authorizer, cacheTTL) 290 return authorizer, acl.ErrInvalidParent 291 } 292 293 var policies []*acl.Policy 294 policy := reply.Policy 295 if policy != nil { 296 policies = append(policies, policy.ConvertFromLegacy()) 297 } 298 299 authorizer, err := acl.NewPolicyAuthorizerWithDefaults(parent, policies, r.aclConf) 300 301 r.cache.PutAuthorizerWithTTL(token, authorizer, reply.TTL) 302 return authorizer, err 303 } 304 305 if acl.IsErrNotFound(err) { 306 // Make sure to remove from the cache if it was deleted 307 r.cache.PutAuthorizerWithTTL(token, nil, cacheTTL) 308 return nil, acl.ErrNotFound 309 310 } 311 312 // some other RPC error 313 switch r.config.ACLDownPolicy { 314 case "allow": 315 r.cache.PutAuthorizerWithTTL(token, acl.AllowAll(), cacheTTL) 316 return acl.AllowAll(), nil 317 case "async-cache", "extend-cache": 318 if cached != nil { 319 r.cache.PutAuthorizerWithTTL(token, cached.Authorizer, cacheTTL) 320 return cached.Authorizer, nil 321 } 322 fallthrough 323 default: 324 r.cache.PutAuthorizerWithTTL(token, acl.DenyAll(), cacheTTL) 325 return acl.DenyAll(), nil 326 } 327} 328 329func (r *ACLResolver) resolveTokenLegacy(token string) (structs.ACLIdentity, acl.Authorizer, error) { 330 defer metrics.MeasureSince([]string{"acl", "resolveTokenLegacy"}, time.Now()) 331 332 // Attempt to resolve locally first (local results are not cached) 333 // This is only useful for servers where either legacy replication is being 334 // done or the server is within the primary datacenter. 335 if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done { 336 if err == nil && identity != nil { 337 policies, err := r.resolvePoliciesForIdentity(identity) 338 if err != nil { 339 return identity, nil, err 340 } 341 342 authz, err := policies.Compile(r.cache, r.aclConf) 343 if err != nil { 344 return identity, nil, err 345 } 346 347 return identity, acl.NewChainedAuthorizer([]acl.Authorizer{authz, acl.RootAuthorizer(r.config.ACLDefaultPolicy)}), nil 348 } 349 350 return nil, nil, err 351 } 352 353 identity := &missingIdentity{ 354 reason: "legacy-token", 355 token: token, 356 } 357 358 // Look in the cache prior to making a RPC request 359 entry := r.cache.GetAuthorizer(token) 360 361 if entry != nil && entry.Age() <= minTTL(entry.TTL, r.config.ACLTokenTTL) { 362 metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) 363 if entry.Authorizer != nil { 364 return identity, entry.Authorizer, nil 365 } 366 return identity, nil, acl.ErrNotFound 367 } 368 369 metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1) 370 371 // Resolve the token in the background and wait on the result if we must 372 waitChan := r.legacyGroup.DoChan(token, func() (interface{}, error) { 373 authorizer, err := r.fetchAndCacheTokenLegacy(token, entry) 374 return authorizer, err 375 }) 376 377 waitForResult := entry == nil || r.config.ACLDownPolicy != "async-cache" 378 if !waitForResult { 379 // waitForResult being false requires the cacheEntry to not be nil 380 if entry.Authorizer != nil { 381 return identity, entry.Authorizer, nil 382 } 383 return identity, nil, acl.ErrNotFound 384 } 385 386 // block waiting for the async RPC to finish. 387 res := <-waitChan 388 389 var authorizer acl.Authorizer 390 if res.Val != nil { // avoid a nil-not-nil bug 391 authorizer = res.Val.(acl.Authorizer) 392 } 393 394 return identity, authorizer, res.Err 395} 396 397func (r *ACLResolver) fetchAndCacheIdentityFromToken(token string, cached *structs.IdentityCacheEntry) (structs.ACLIdentity, error) { 398 cacheID := tokenSecretCacheID(token) 399 400 req := structs.ACLTokenGetRequest{ 401 Datacenter: r.delegate.ACLDatacenter(false), 402 TokenID: token, 403 TokenIDType: structs.ACLTokenSecret, 404 QueryOptions: structs.QueryOptions{ 405 Token: token, 406 AllowStale: true, 407 }, 408 } 409 410 var resp structs.ACLTokenResponse 411 err := r.delegate.RPC("ACL.TokenRead", &req, &resp) 412 if err == nil { 413 if resp.Token == nil { 414 r.cache.PutIdentity(cacheID, nil) 415 return nil, acl.ErrNotFound 416 } else { 417 r.cache.PutIdentity(cacheID, resp.Token) 418 return resp.Token, nil 419 } 420 } 421 422 if acl.IsErrNotFound(err) { 423 // Make sure to remove from the cache if it was deleted 424 r.cache.PutIdentity(cacheID, nil) 425 return nil, acl.ErrNotFound 426 427 } 428 429 // some other RPC error 430 if cached != nil && (r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache") { 431 // extend the cache 432 r.cache.PutIdentity(cacheID, cached.Identity) 433 return cached.Identity, nil 434 } 435 436 r.cache.PutIdentity(cacheID, nil) 437 return nil, err 438} 439 440// resolveIdentityFromToken takes a token secret as a string and returns an ACLIdentity. 441// We read the value from ACLResolver's cache if available, and if the read misses 442// we initiate an RPC for the value. 443func (r *ACLResolver) resolveIdentityFromToken(token string) (structs.ACLIdentity, error) { 444 // Attempt to resolve locally first (local results are not cached) 445 if done, identity, err := r.delegate.ResolveIdentityFromToken(token); done { 446 return identity, err 447 } 448 449 // Check the cache before making any RPC requests 450 cacheEntry := r.cache.GetIdentity(tokenSecretCacheID(token)) 451 if cacheEntry != nil && cacheEntry.Age() <= r.config.ACLTokenTTL { 452 metrics.IncrCounter([]string{"acl", "token", "cache_hit"}, 1) 453 return cacheEntry.Identity, nil 454 } 455 456 metrics.IncrCounter([]string{"acl", "token", "cache_miss"}, 1) 457 458 // Background a RPC request and wait on it if we must 459 waitChan := r.identityGroup.DoChan(token, func() (interface{}, error) { 460 identity, err := r.fetchAndCacheIdentityFromToken(token, cacheEntry) 461 return identity, err 462 }) 463 464 waitForResult := cacheEntry == nil || r.config.ACLDownPolicy != "async-cache" 465 if !waitForResult { 466 // waitForResult being false requires the cacheEntry to not be nil 467 return cacheEntry.Identity, nil 468 } 469 470 // block on the read here, this is why we don't need chan buffering 471 res := <-waitChan 472 473 var identity structs.ACLIdentity 474 if res.Val != nil { // avoid a nil-not-nil bug 475 identity = res.Val.(structs.ACLIdentity) 476 } 477 478 if res.Err != nil && !acl.IsErrNotFound(res.Err) { 479 return identity, ACLRemoteError{Err: res.Err} 480 } 481 return identity, res.Err 482} 483 484func (r *ACLResolver) fetchAndCachePoliciesForIdentity(identity structs.ACLIdentity, policyIDs []string, cached map[string]*structs.PolicyCacheEntry) (map[string]*structs.ACLPolicy, error) { 485 req := structs.ACLPolicyBatchGetRequest{ 486 Datacenter: r.delegate.ACLDatacenter(false), 487 PolicyIDs: policyIDs, 488 QueryOptions: structs.QueryOptions{ 489 Token: identity.SecretToken(), 490 AllowStale: true, 491 }, 492 } 493 494 var resp structs.ACLPolicyBatchResponse 495 err := r.delegate.RPC("ACL.PolicyResolve", &req, &resp) 496 if err == nil { 497 out := make(map[string]*structs.ACLPolicy) 498 for _, policy := range resp.Policies { 499 out[policy.ID] = policy 500 } 501 502 for _, policyID := range policyIDs { 503 if policy, ok := out[policyID]; ok { 504 r.cache.PutPolicy(policyID, policy) 505 } else { 506 r.cache.PutPolicy(policyID, nil) 507 } 508 } 509 return out, nil 510 } 511 512 if handledErr := r.maybeHandleIdentityErrorDuringFetch(identity, err); handledErr != nil { 513 return nil, handledErr 514 } 515 516 // other RPC error - use cache if available 517 518 extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache" 519 520 out := make(map[string]*structs.ACLPolicy) 521 insufficientCache := false 522 for _, policyID := range policyIDs { 523 if entry, ok := cached[policyID]; extendCache && ok { 524 r.cache.PutPolicy(policyID, entry.Policy) 525 if entry.Policy != nil { 526 out[policyID] = entry.Policy 527 } 528 } else { 529 r.cache.PutPolicy(policyID, nil) 530 insufficientCache = true 531 } 532 } 533 if insufficientCache { 534 return nil, ACLRemoteError{Err: err} 535 } 536 return out, nil 537} 538 539func (r *ACLResolver) fetchAndCacheRolesForIdentity(identity structs.ACLIdentity, roleIDs []string, cached map[string]*structs.RoleCacheEntry) (map[string]*structs.ACLRole, error) { 540 req := structs.ACLRoleBatchGetRequest{ 541 Datacenter: r.delegate.ACLDatacenter(false), 542 RoleIDs: roleIDs, 543 QueryOptions: structs.QueryOptions{ 544 Token: identity.SecretToken(), 545 AllowStale: true, 546 }, 547 } 548 549 var resp structs.ACLRoleBatchResponse 550 err := r.delegate.RPC("ACL.RoleResolve", &req, &resp) 551 if err == nil { 552 out := make(map[string]*structs.ACLRole) 553 for _, role := range resp.Roles { 554 out[role.ID] = role 555 } 556 557 for _, roleID := range roleIDs { 558 if role, ok := out[roleID]; ok { 559 r.cache.PutRole(roleID, role) 560 } else { 561 r.cache.PutRole(roleID, nil) 562 } 563 } 564 return out, nil 565 } 566 567 if handledErr := r.maybeHandleIdentityErrorDuringFetch(identity, err); handledErr != nil { 568 return nil, handledErr 569 } 570 571 // other RPC error - use cache if available 572 573 extendCache := r.config.ACLDownPolicy == "extend-cache" || r.config.ACLDownPolicy == "async-cache" 574 575 out := make(map[string]*structs.ACLRole) 576 insufficientCache := false 577 for _, roleID := range roleIDs { 578 if entry, ok := cached[roleID]; extendCache && ok { 579 r.cache.PutRole(roleID, entry.Role) 580 if entry.Role != nil { 581 out[roleID] = entry.Role 582 } 583 } else { 584 r.cache.PutRole(roleID, nil) 585 insufficientCache = true 586 } 587 } 588 589 if insufficientCache { 590 return nil, ACLRemoteError{Err: err} 591 } 592 593 return out, nil 594} 595 596func (r *ACLResolver) maybeHandleIdentityErrorDuringFetch(identity structs.ACLIdentity, err error) error { 597 if acl.IsErrNotFound(err) { 598 // make sure to indicate that this identity is no longer valid within 599 // the cache 600 r.cache.PutIdentity(tokenSecretCacheID(identity.SecretToken()), nil) 601 602 // Do not touch the cache. Getting a top level ACL not found error 603 // only indicates that the secret token used in the request 604 // no longer exists 605 return &policyOrRoleTokenError{acl.ErrNotFound, identity.SecretToken()} 606 } 607 608 if acl.IsErrPermissionDenied(err) { 609 // invalidate our ID cache so that identity resolution will take place 610 // again in the future 611 r.cache.RemoveIdentity(tokenSecretCacheID(identity.SecretToken())) 612 613 // Do not remove from the cache for permission denied 614 // what this does indicate is that our view of the token is out of date 615 return &policyOrRoleTokenError{acl.ErrPermissionDenied, identity.SecretToken()} 616 } 617 618 return nil 619} 620 621func (r *ACLResolver) filterPoliciesByScope(policies structs.ACLPolicies) structs.ACLPolicies { 622 var out structs.ACLPolicies 623 for _, policy := range policies { 624 if len(policy.Datacenters) == 0 { 625 out = append(out, policy) 626 continue 627 } 628 629 for _, dc := range policy.Datacenters { 630 if dc == r.config.Datacenter { 631 out = append(out, policy) 632 continue 633 } 634 } 635 } 636 637 return out 638} 639 640func (r *ACLResolver) resolvePoliciesForIdentity(identity structs.ACLIdentity) (structs.ACLPolicies, error) { 641 policyIDs := identity.PolicyIDs() 642 roleIDs := identity.RoleIDs() 643 serviceIdentities := identity.ServiceIdentityList() 644 645 if len(policyIDs) == 0 && len(serviceIdentities) == 0 && len(roleIDs) == 0 { 646 policy := identity.EmbeddedPolicy() 647 if policy != nil { 648 return []*structs.ACLPolicy{policy}, nil 649 } 650 651 // In this case the default policy will be all that is in effect. 652 return nil, nil 653 } 654 655 // Collect all of the roles tied to this token. 656 roles, err := r.collectRolesForIdentity(identity, roleIDs) 657 if err != nil { 658 return nil, err 659 } 660 661 // Merge the policies and service identities across Token and Role fields. 662 for _, role := range roles { 663 for _, link := range role.Policies { 664 policyIDs = append(policyIDs, link.ID) 665 } 666 serviceIdentities = append(serviceIdentities, role.ServiceIdentities...) 667 } 668 669 // Now deduplicate any policies or service identities that occur more than once. 670 policyIDs = dedupeStringSlice(policyIDs) 671 serviceIdentities = dedupeServiceIdentities(serviceIdentities) 672 673 // Generate synthetic policies for all service identities in effect. 674 syntheticPolicies := r.synthesizePoliciesForServiceIdentities(serviceIdentities, identity.EnterpriseMetadata()) 675 676 // For the new ACLs policy replication is mandatory for correct operation on servers. Therefore 677 // we only attempt to resolve policies locally 678 policies, err := r.collectPoliciesForIdentity(identity, policyIDs, len(syntheticPolicies)) 679 if err != nil { 680 return nil, err 681 } 682 683 policies = append(policies, syntheticPolicies...) 684 filtered := r.filterPoliciesByScope(policies) 685 return filtered, nil 686} 687 688func (r *ACLResolver) synthesizePoliciesForServiceIdentities(serviceIdentities []*structs.ACLServiceIdentity, entMeta *structs.EnterpriseMeta) []*structs.ACLPolicy { 689 if len(serviceIdentities) == 0 { 690 return nil 691 } 692 693 syntheticPolicies := make([]*structs.ACLPolicy, 0, len(serviceIdentities)) 694 for _, s := range serviceIdentities { 695 syntheticPolicies = append(syntheticPolicies, s.SyntheticPolicy(entMeta)) 696 } 697 698 return syntheticPolicies 699} 700 701func dedupeServiceIdentities(in []*structs.ACLServiceIdentity) []*structs.ACLServiceIdentity { 702 // From: https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable 703 704 if len(in) <= 1 { 705 return in 706 } 707 708 sort.Slice(in, func(i, j int) bool { 709 return in[i].ServiceName < in[j].ServiceName 710 }) 711 712 j := 0 713 for i := 1; i < len(in); i++ { 714 if in[j].ServiceName == in[i].ServiceName { 715 // Prefer increasing scope. 716 if len(in[j].Datacenters) == 0 || len(in[i].Datacenters) == 0 { 717 in[j].Datacenters = nil 718 } else { 719 in[j].Datacenters = mergeStringSlice(in[j].Datacenters, in[i].Datacenters) 720 } 721 continue 722 } 723 j++ 724 in[j] = in[i] 725 } 726 727 // Discard the skipped items. 728 for i := j + 1; i < len(in); i++ { 729 in[i] = nil 730 } 731 732 return in[:j+1] 733} 734 735func mergeStringSlice(a, b []string) []string { 736 out := make([]string, 0, len(a)+len(b)) 737 out = append(out, a...) 738 out = append(out, b...) 739 return dedupeStringSlice(out) 740} 741 742func dedupeStringSlice(in []string) []string { 743 // From: https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable 744 745 if len(in) <= 1 { 746 return in 747 } 748 749 sort.Strings(in) 750 751 j := 0 752 for i := 1; i < len(in); i++ { 753 if in[j] == in[i] { 754 continue 755 } 756 j++ 757 in[j] = in[i] 758 } 759 760 return in[:j+1] 761} 762 763func (r *ACLResolver) collectPoliciesForIdentity(identity structs.ACLIdentity, policyIDs []string, extraCap int) ([]*structs.ACLPolicy, error) { 764 policies := make([]*structs.ACLPolicy, 0, len(policyIDs)+extraCap) 765 766 // Get all associated policies 767 var missing []string 768 var expired []*structs.ACLPolicy 769 expCacheMap := make(map[string]*structs.PolicyCacheEntry) 770 771 var accessorID string 772 if identity != nil { 773 accessorID = identity.ID() 774 } 775 776 for _, policyID := range policyIDs { 777 if done, policy, err := r.delegate.ResolvePolicyFromID(policyID); done { 778 if err != nil && !acl.IsErrNotFound(err) { 779 return nil, err 780 } 781 782 if policy != nil { 783 policies = append(policies, policy) 784 } else { 785 r.logger.Warn("policy not found for identity", 786 "policy", policyID, 787 "accessorID", accessorID, 788 ) 789 } 790 791 continue 792 } 793 794 // create the missing list which we can execute an RPC to get all the missing policies at once 795 entry := r.cache.GetPolicy(policyID) 796 if entry == nil { 797 missing = append(missing, policyID) 798 continue 799 } 800 801 if entry.Policy == nil { 802 // this happens when we cache a negative response for the policy's existence 803 continue 804 } 805 806 if entry.Age() >= r.config.ACLPolicyTTL { 807 expired = append(expired, entry.Policy) 808 expCacheMap[policyID] = entry 809 } else { 810 policies = append(policies, entry.Policy) 811 } 812 } 813 814 // Hot-path if we have no missing or expired policies 815 if len(missing)+len(expired) == 0 { 816 return policies, nil 817 } 818 819 hasMissing := len(missing) > 0 820 821 fetchIDs := missing 822 for _, policy := range expired { 823 fetchIDs = append(fetchIDs, policy.ID) 824 } 825 826 // Background a RPC request and wait on it if we must 827 waitChan := r.policyGroup.DoChan(identity.SecretToken(), func() (interface{}, error) { 828 policies, err := r.fetchAndCachePoliciesForIdentity(identity, fetchIDs, expCacheMap) 829 return policies, err 830 }) 831 832 waitForResult := hasMissing || r.config.ACLDownPolicy != "async-cache" 833 if !waitForResult { 834 // waitForResult being false requires that all the policies were cached already 835 policies = append(policies, expired...) 836 return policies, nil 837 } 838 839 res := <-waitChan 840 841 if res.Err != nil { 842 return nil, res.Err 843 } 844 845 if res.Val != nil { 846 foundPolicies := res.Val.(map[string]*structs.ACLPolicy) 847 848 for _, policy := range foundPolicies { 849 policies = append(policies, policy) 850 } 851 } 852 853 return policies, nil 854} 855 856func (r *ACLResolver) resolveRolesForIdentity(identity structs.ACLIdentity) (structs.ACLRoles, error) { 857 return r.collectRolesForIdentity(identity, identity.RoleIDs()) 858} 859 860func (r *ACLResolver) collectRolesForIdentity(identity structs.ACLIdentity, roleIDs []string) (structs.ACLRoles, error) { 861 if len(roleIDs) == 0 { 862 return nil, nil 863 } 864 865 // For the new ACLs policy & role replication is mandatory for correct operation 866 // on servers. Therefore we only attempt to resolve roles locally 867 roles := make([]*structs.ACLRole, 0, len(roleIDs)) 868 869 var missing []string 870 var expired []*structs.ACLRole 871 expCacheMap := make(map[string]*structs.RoleCacheEntry) 872 873 for _, roleID := range roleIDs { 874 if done, role, err := r.delegate.ResolveRoleFromID(roleID); done { 875 if err != nil && !acl.IsErrNotFound(err) { 876 return nil, err 877 } 878 879 if role != nil { 880 roles = append(roles, role) 881 } else { 882 var accessorID string 883 if identity != nil { 884 accessorID = identity.ID() 885 } 886 r.logger.Warn("role not found for identity", 887 "role", roleID, 888 "accessorID", accessorID, 889 ) 890 } 891 892 continue 893 } 894 895 // create the missing list which we can execute an RPC to get all the missing roles at once 896 entry := r.cache.GetRole(roleID) 897 if entry == nil { 898 missing = append(missing, roleID) 899 continue 900 } 901 902 if entry.Role == nil { 903 // this happens when we cache a negative response for the role's existence 904 continue 905 } 906 907 if entry.Age() >= r.config.ACLRoleTTL { 908 expired = append(expired, entry.Role) 909 expCacheMap[roleID] = entry 910 } else { 911 roles = append(roles, entry.Role) 912 } 913 } 914 915 // Hot-path if we have no missing or expired roles 916 if len(missing)+len(expired) == 0 { 917 return roles, nil 918 } 919 920 hasMissing := len(missing) > 0 921 922 fetchIDs := missing 923 for _, role := range expired { 924 fetchIDs = append(fetchIDs, role.ID) 925 } 926 927 waitChan := r.roleGroup.DoChan(identity.SecretToken(), func() (interface{}, error) { 928 roles, err := r.fetchAndCacheRolesForIdentity(identity, fetchIDs, expCacheMap) 929 return roles, err 930 }) 931 932 waitForResult := hasMissing || r.config.ACLDownPolicy != "async-cache" 933 if !waitForResult { 934 // waitForResult being false requires that all the roles were cached already 935 roles = append(roles, expired...) 936 return roles, nil 937 } 938 939 res := <-waitChan 940 941 if res.Err != nil { 942 return nil, res.Err 943 } 944 945 if res.Val != nil { 946 foundRoles := res.Val.(map[string]*structs.ACLRole) 947 948 for _, role := range foundRoles { 949 roles = append(roles, role) 950 } 951 } 952 953 return roles, nil 954} 955 956func (r *ACLResolver) resolveTokenToPolicies(token string) (structs.ACLPolicies, error) { 957 _, policies, err := r.resolveTokenToIdentityAndPolicies(token) 958 return policies, err 959} 960 961func (r *ACLResolver) resolveTokenToIdentityAndPolicies(token string) (structs.ACLIdentity, structs.ACLPolicies, error) { 962 var lastErr error 963 var lastIdentity structs.ACLIdentity 964 965 for i := 0; i < tokenPolicyResolutionMaxRetries; i++ { 966 // Resolve the token to an ACLIdentity 967 identity, err := r.resolveIdentityFromToken(token) 968 if err != nil { 969 return nil, nil, err 970 } else if identity == nil { 971 return nil, nil, acl.ErrNotFound 972 } else if identity.IsExpired(time.Now()) { 973 return nil, nil, acl.ErrNotFound 974 } 975 976 lastIdentity = identity 977 978 policies, err := r.resolvePoliciesForIdentity(identity) 979 if err == nil { 980 return identity, policies, nil 981 } 982 lastErr = err 983 984 if tokenErr, ok := err.(*policyOrRoleTokenError); ok { 985 if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() { 986 // token was deleted while resolving policies 987 return nil, nil, acl.ErrNotFound 988 } 989 990 // other types of policyOrRoleTokenErrors should cause retrying the whole token 991 // resolution process 992 } else { 993 return identity, nil, err 994 } 995 } 996 997 return lastIdentity, nil, lastErr 998} 999 1000func (r *ACLResolver) resolveTokenToIdentityAndRoles(token string) (structs.ACLIdentity, structs.ACLRoles, error) { 1001 var lastErr error 1002 var lastIdentity structs.ACLIdentity 1003 1004 for i := 0; i < tokenRoleResolutionMaxRetries; i++ { 1005 // Resolve the token to an ACLIdentity 1006 identity, err := r.resolveIdentityFromToken(token) 1007 if err != nil { 1008 return nil, nil, err 1009 } else if identity == nil { 1010 return nil, nil, acl.ErrNotFound 1011 } else if identity.IsExpired(time.Now()) { 1012 return nil, nil, acl.ErrNotFound 1013 } 1014 1015 lastIdentity = identity 1016 1017 roles, err := r.resolveRolesForIdentity(identity) 1018 if err == nil { 1019 return identity, roles, nil 1020 } 1021 lastErr = err 1022 1023 if tokenErr, ok := err.(*policyOrRoleTokenError); ok { 1024 if acl.IsErrNotFound(err) && tokenErr.token == identity.SecretToken() { 1025 // token was deleted while resolving roles 1026 return nil, nil, acl.ErrNotFound 1027 } 1028 1029 // other types of policyOrRoleTokenErrors should cause retrying the whole token 1030 // resolution process 1031 } else { 1032 return identity, nil, err 1033 } 1034 } 1035 1036 return lastIdentity, nil, lastErr 1037} 1038 1039func (r *ACLResolver) disableACLsWhenUpstreamDisabled(err error) error { 1040 if !r.autoDisable || err == nil || !acl.IsErrDisabled(err) { 1041 return err 1042 } 1043 1044 r.logger.Debug("ACLs disabled on upstream servers, will retry", "retry_interval", r.config.ACLDisabledTTL) 1045 r.disabledLock.Lock() 1046 r.disabled = time.Now().Add(r.config.ACLDisabledTTL) 1047 r.disabledLock.Unlock() 1048 1049 return err 1050} 1051 1052func (r *ACLResolver) ResolveTokenToIdentityAndAuthorizer(token string) (structs.ACLIdentity, acl.Authorizer, error) { 1053 if !r.ACLsEnabled() { 1054 return nil, nil, nil 1055 } 1056 1057 if acl.RootAuthorizer(token) != nil { 1058 return nil, nil, acl.ErrRootDenied 1059 } 1060 1061 // handle the anonymous token 1062 if token == "" { 1063 token = anonymousToken 1064 } 1065 1066 if r.delegate.UseLegacyACLs() { 1067 identity, authorizer, err := r.resolveTokenLegacy(token) 1068 return identity, authorizer, r.disableACLsWhenUpstreamDisabled(err) 1069 } 1070 1071 defer metrics.MeasureSince([]string{"acl", "ResolveToken"}, time.Now()) 1072 1073 identity, policies, err := r.resolveTokenToIdentityAndPolicies(token) 1074 if err != nil { 1075 r.disableACLsWhenUpstreamDisabled(err) 1076 if IsACLRemoteError(err) { 1077 r.logger.Error("Error resolving token", "error", err) 1078 return &missingIdentity{reason: "primary-dc-down", token: token}, r.down, nil 1079 } 1080 1081 return nil, nil, err 1082 } 1083 1084 // Build the Authorizer 1085 var chain []acl.Authorizer 1086 1087 authz, err := policies.Compile(r.cache, r.aclConf) 1088 if err != nil { 1089 return nil, nil, err 1090 } 1091 chain = append(chain, authz) 1092 1093 authz, err = r.resolveEnterpriseDefaultsForIdentity(identity) 1094 if err != nil { 1095 if IsACLRemoteError(err) { 1096 r.logger.Error("Error resolving identity defaults", "error", err) 1097 return identity, r.down, nil 1098 } 1099 return nil, nil, err 1100 } else if authz != nil { 1101 chain = append(chain, authz) 1102 } 1103 1104 chain = append(chain, acl.RootAuthorizer(r.config.ACLDefaultPolicy)) 1105 return identity, acl.NewChainedAuthorizer(chain), nil 1106} 1107 1108func (r *ACLResolver) ResolveToken(token string) (acl.Authorizer, error) { 1109 _, authz, err := r.ResolveTokenToIdentityAndAuthorizer(token) 1110 return authz, err 1111} 1112 1113func (r *ACLResolver) ACLsEnabled() bool { 1114 // Whether we desire ACLs to be enabled according to configuration 1115 if !r.delegate.ACLsEnabled() { 1116 return false 1117 } 1118 1119 if r.autoDisable { 1120 // Whether ACLs are disabled according to RPCs failing with a ACLs Disabled error 1121 r.disabledLock.RLock() 1122 defer r.disabledLock.RUnlock() 1123 return !time.Now().Before(r.disabled) 1124 } 1125 1126 return true 1127} 1128 1129func (r *ACLResolver) GetMergedPolicyForToken(token string) (*acl.Policy, error) { 1130 policies, err := r.resolveTokenToPolicies(token) 1131 if err != nil { 1132 return nil, err 1133 } 1134 if len(policies) == 0 { 1135 return nil, acl.ErrNotFound 1136 } 1137 1138 return policies.Merge(r.cache, r.aclConf) 1139} 1140 1141// aclFilter is used to filter results from our state store based on ACL rules 1142// configured for the provided token. 1143type aclFilter struct { 1144 authorizer acl.Authorizer 1145 logger hclog.Logger 1146 enforceVersion8 bool 1147} 1148 1149// newACLFilter constructs a new aclFilter. 1150func newACLFilter(authorizer acl.Authorizer, logger hclog.Logger, enforceVersion8 bool) *aclFilter { 1151 if logger == nil { 1152 logger = hclog.New(&hclog.LoggerOptions{}) 1153 } 1154 return &aclFilter{ 1155 authorizer: authorizer, 1156 logger: logger, 1157 enforceVersion8: enforceVersion8, 1158 } 1159} 1160 1161// allowNode is used to determine if a node is accessible for an ACL. 1162func (f *aclFilter) allowNode(node string, ent *acl.AuthorizerContext) bool { 1163 if !f.enforceVersion8 { 1164 return true 1165 } 1166 1167 return f.authorizer.NodeRead(node, ent) == acl.Allow 1168} 1169 1170// allowService is used to determine if a service is accessible for an ACL. 1171func (f *aclFilter) allowService(service string, ent *acl.AuthorizerContext) bool { 1172 if service == "" { 1173 return true 1174 } 1175 1176 if !f.enforceVersion8 && service == structs.ConsulServiceID { 1177 return true 1178 } 1179 return f.authorizer.ServiceRead(service, ent) == acl.Allow 1180} 1181 1182// allowSession is used to determine if a session for a node is accessible for 1183// an ACL. 1184func (f *aclFilter) allowSession(node string, ent *acl.AuthorizerContext) bool { 1185 if !f.enforceVersion8 { 1186 return true 1187 } 1188 return f.authorizer.SessionRead(node, ent) == acl.Allow 1189} 1190 1191// filterHealthChecks is used to filter a set of health checks down based on 1192// the configured ACL rules for a token. 1193func (f *aclFilter) filterHealthChecks(checks *structs.HealthChecks) { 1194 hc := *checks 1195 var authzContext acl.AuthorizerContext 1196 1197 for i := 0; i < len(hc); i++ { 1198 check := hc[i] 1199 check.FillAuthzContext(&authzContext) 1200 if f.allowNode(check.Node, &authzContext) && f.allowService(check.ServiceName, &authzContext) { 1201 continue 1202 } 1203 1204 f.logger.Debug("dropping check from result due to ACLs", "check", check.CheckID) 1205 hc = append(hc[:i], hc[i+1:]...) 1206 i-- 1207 } 1208 *checks = hc 1209} 1210 1211// filterServices is used to filter a set of services based on ACLs. 1212func (f *aclFilter) filterServices(services structs.Services, entMeta *structs.EnterpriseMeta) { 1213 var authzContext acl.AuthorizerContext 1214 entMeta.FillAuthzContext(&authzContext) 1215 1216 for svc := range services { 1217 if f.allowService(svc, &authzContext) { 1218 continue 1219 } 1220 f.logger.Debug("dropping service from result due to ACLs", "service", svc) 1221 delete(services, svc) 1222 } 1223} 1224 1225// filterServiceNodes is used to filter a set of nodes for a given service 1226// based on the configured ACL rules. 1227func (f *aclFilter) filterServiceNodes(nodes *structs.ServiceNodes) { 1228 sn := *nodes 1229 var authzContext acl.AuthorizerContext 1230 1231 for i := 0; i < len(sn); i++ { 1232 node := sn[i] 1233 1234 node.FillAuthzContext(&authzContext) 1235 if f.allowNode(node.Node, &authzContext) && f.allowService(node.ServiceName, &authzContext) { 1236 continue 1237 } 1238 f.logger.Debug("dropping node from result due to ACLs", "node", node.Node) 1239 sn = append(sn[:i], sn[i+1:]...) 1240 i-- 1241 } 1242 *nodes = sn 1243} 1244 1245// filterNodeServices is used to filter services on a given node base on ACLs. 1246func (f *aclFilter) filterNodeServices(services **structs.NodeServices) { 1247 if *services == nil { 1248 return 1249 } 1250 1251 var authzContext acl.AuthorizerContext 1252 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 1253 if !f.allowNode((*services).Node.Node, &authzContext) { 1254 *services = nil 1255 return 1256 } 1257 1258 for svcName, svc := range (*services).Services { 1259 svc.FillAuthzContext(&authzContext) 1260 1261 if f.allowNode((*services).Node.Node, &authzContext) && f.allowService(svcName, &authzContext) { 1262 continue 1263 } 1264 f.logger.Debug("dropping service from result due to ACLs", "service", svc.CompoundServiceID()) 1265 delete((*services).Services, svcName) 1266 } 1267} 1268 1269// filterNodeServices is used to filter services on a given node base on ACLs. 1270func (f *aclFilter) filterNodeServiceList(services **structs.NodeServiceList) { 1271 if services == nil || *services == nil { 1272 return 1273 } 1274 1275 var authzContext acl.AuthorizerContext 1276 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 1277 if !f.allowNode((*services).Node.Node, &authzContext) { 1278 *services = nil 1279 return 1280 } 1281 1282 svcs := (*services).Services 1283 modified := false 1284 for i := 0; i < len(svcs); i++ { 1285 svc := svcs[i] 1286 svc.FillAuthzContext(&authzContext) 1287 1288 if f.allowNode((*services).Node.Node, &authzContext) && f.allowService(svc.Service, &authzContext) { 1289 continue 1290 } 1291 f.logger.Debug("dropping service from result due to ACLs", "service", svc.CompoundServiceID()) 1292 svcs = append(svcs[:i], svcs[i+1:]...) 1293 i-- 1294 modified = true 1295 } 1296 1297 if modified { 1298 *services = &structs.NodeServiceList{ 1299 Node: (*services).Node, 1300 Services: svcs, 1301 } 1302 } 1303} 1304 1305// filterCheckServiceNodes is used to filter nodes based on ACL rules. 1306func (f *aclFilter) filterCheckServiceNodes(nodes *structs.CheckServiceNodes) { 1307 csn := *nodes 1308 var authzContext acl.AuthorizerContext 1309 1310 for i := 0; i < len(csn); i++ { 1311 node := csn[i] 1312 node.Service.FillAuthzContext(&authzContext) 1313 if f.allowNode(node.Node.Node, &authzContext) && f.allowService(node.Service.Service, &authzContext) { 1314 continue 1315 } 1316 f.logger.Debug("dropping node from result due to ACLs", "node", node.Node.Node) 1317 csn = append(csn[:i], csn[i+1:]...) 1318 i-- 1319 } 1320 *nodes = csn 1321} 1322 1323// filterSessions is used to filter a set of sessions based on ACLs. 1324func (f *aclFilter) filterSessions(sessions *structs.Sessions) { 1325 s := *sessions 1326 for i := 0; i < len(s); i++ { 1327 session := s[i] 1328 1329 var entCtx acl.AuthorizerContext 1330 session.FillAuthzContext(&entCtx) 1331 1332 if f.allowSession(session.Node, &entCtx) { 1333 continue 1334 } 1335 f.logger.Debug("dropping session from result due to ACLs", "session", session.ID) 1336 s = append(s[:i], s[i+1:]...) 1337 i-- 1338 } 1339 *sessions = s 1340} 1341 1342// filterCoordinates is used to filter nodes in a coordinate dump based on ACL 1343// rules. 1344func (f *aclFilter) filterCoordinates(coords *structs.Coordinates) { 1345 c := *coords 1346 var authzContext acl.AuthorizerContext 1347 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 1348 1349 for i := 0; i < len(c); i++ { 1350 node := c[i].Node 1351 if f.allowNode(node, &authzContext) { 1352 continue 1353 } 1354 f.logger.Debug("dropping node from result due to ACLs", "node", node) 1355 c = append(c[:i], c[i+1:]...) 1356 i-- 1357 } 1358 *coords = c 1359} 1360 1361// filterIntentions is used to filter intentions based on ACL rules. 1362// We prune entries the user doesn't have access to, and we redact any tokens 1363// if the user doesn't have a management token. 1364func (f *aclFilter) filterIntentions(ixns *structs.Intentions) { 1365 ret := make(structs.Intentions, 0, len(*ixns)) 1366 for _, ixn := range *ixns { 1367 if !ixn.CanRead(f.authorizer) { 1368 f.logger.Debug("dropping intention from result due to ACLs", "intention", ixn.ID) 1369 continue 1370 } 1371 1372 ret = append(ret, ixn) 1373 } 1374 1375 *ixns = ret 1376} 1377 1378// filterNodeDump is used to filter through all parts of a node dump and 1379// remove elements the provided ACL token cannot access. 1380func (f *aclFilter) filterNodeDump(dump *structs.NodeDump) { 1381 nd := *dump 1382 1383 var authzContext acl.AuthorizerContext 1384 for i := 0; i < len(nd); i++ { 1385 info := nd[i] 1386 1387 // Filter nodes 1388 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 1389 if node := info.Node; !f.allowNode(node, &authzContext) { 1390 f.logger.Debug("dropping node from result due to ACLs", "node", node) 1391 nd = append(nd[:i], nd[i+1:]...) 1392 i-- 1393 continue 1394 } 1395 1396 // Filter services 1397 for j := 0; j < len(info.Services); j++ { 1398 svc := info.Services[j].Service 1399 info.Services[j].FillAuthzContext(&authzContext) 1400 if f.allowNode(info.Node, &authzContext) && f.allowService(svc, &authzContext) { 1401 continue 1402 } 1403 f.logger.Debug("dropping service from result due to ACLs", "service", svc) 1404 info.Services = append(info.Services[:j], info.Services[j+1:]...) 1405 j-- 1406 } 1407 1408 // Filter checks 1409 for j := 0; j < len(info.Checks); j++ { 1410 chk := info.Checks[j] 1411 chk.FillAuthzContext(&authzContext) 1412 if f.allowNode(info.Node, &authzContext) && f.allowService(chk.ServiceName, &authzContext) { 1413 continue 1414 } 1415 f.logger.Debug("dropping check from result due to ACLs", "check", chk.CheckID) 1416 info.Checks = append(info.Checks[:j], info.Checks[j+1:]...) 1417 j-- 1418 } 1419 } 1420 *dump = nd 1421} 1422 1423// filterNodes is used to filter through all parts of a node list and remove 1424// elements the provided ACL token cannot access. 1425func (f *aclFilter) filterNodes(nodes *structs.Nodes) { 1426 n := *nodes 1427 1428 var authzContext acl.AuthorizerContext 1429 structs.WildcardEnterpriseMeta().FillAuthzContext(&authzContext) 1430 1431 for i := 0; i < len(n); i++ { 1432 node := n[i].Node 1433 if f.allowNode(node, &authzContext) { 1434 continue 1435 } 1436 f.logger.Debug("dropping node from result due to ACLs", "node", node) 1437 n = append(n[:i], n[i+1:]...) 1438 i-- 1439 } 1440 *nodes = n 1441} 1442 1443// redactPreparedQueryTokens will redact any tokens unless the client has a 1444// management token. This eases the transition to delegated authority over 1445// prepared queries, since it was easy to capture management tokens in Consul 1446// 0.6.3 and earlier, and we don't want to willy-nilly show those. This does 1447// have the limitation of preventing delegated non-management users from seeing 1448// captured tokens, but they can at least see whether or not a token is set. 1449func (f *aclFilter) redactPreparedQueryTokens(query **structs.PreparedQuery) { 1450 // Management tokens can see everything with no filtering. 1451 var authzContext acl.AuthorizerContext 1452 structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext) 1453 if f.authorizer.ACLWrite(&authzContext) == acl.Allow { 1454 return 1455 } 1456 1457 // Let the user see if there's a blank token, otherwise we need 1458 // to redact it, since we know they don't have a management 1459 // token. 1460 if (*query).Token != "" { 1461 // Redact the token, using a copy of the query structure 1462 // since we could be pointed at a live instance from the 1463 // state store so it's not safe to modify it. Note that 1464 // this clone will still point to things like underlying 1465 // arrays in the original, but for modifying just the 1466 // token it will be safe to use. 1467 clone := *(*query) 1468 clone.Token = redactedToken 1469 *query = &clone 1470 } 1471} 1472 1473// filterPreparedQueries is used to filter prepared queries based on ACL rules. 1474// We prune entries the user doesn't have access to, and we redact any tokens 1475// if the user doesn't have a management token. 1476func (f *aclFilter) filterPreparedQueries(queries *structs.PreparedQueries) { 1477 var authzContext acl.AuthorizerContext 1478 structs.DefaultEnterpriseMeta().FillAuthzContext(&authzContext) 1479 // Management tokens can see everything with no filtering. 1480 // TODO is this check even necessary - this looks like a search replace from 1481 // the 1.4 ACL rewrite. The global-management token will provide unrestricted query privileges 1482 // so asking for ACLWrite should be unnecessary. 1483 if f.authorizer.ACLWrite(&authzContext) == acl.Allow { 1484 return 1485 } 1486 1487 // Otherwise, we need to see what the token has access to. 1488 ret := make(structs.PreparedQueries, 0, len(*queries)) 1489 for _, query := range *queries { 1490 // If no prefix ACL applies to this query then filter it, since 1491 // we know at this point the user doesn't have a management 1492 // token, otherwise see what the policy says. 1493 prefix, ok := query.GetACLPrefix() 1494 if !ok || f.authorizer.PreparedQueryRead(prefix, &authzContext) != acl.Allow { 1495 f.logger.Debug("dropping prepared query from result due to ACLs", "query", query.ID) 1496 continue 1497 } 1498 1499 // Redact any tokens if necessary. We make a copy of just the 1500 // pointer so we don't mess with the caller's slice. 1501 final := query 1502 f.redactPreparedQueryTokens(&final) 1503 ret = append(ret, final) 1504 } 1505 *queries = ret 1506} 1507 1508func (f *aclFilter) filterToken(token **structs.ACLToken) { 1509 var entCtx acl.AuthorizerContext 1510 if token == nil || *token == nil || f == nil { 1511 return 1512 } 1513 1514 (*token).FillAuthzContext(&entCtx) 1515 1516 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1517 // no permissions to read 1518 *token = nil 1519 } else if f.authorizer.ACLWrite(&entCtx) != acl.Allow { 1520 // no write permissions - redact secret 1521 clone := *(*token) 1522 clone.SecretID = redactedToken 1523 *token = &clone 1524 } 1525} 1526 1527func (f *aclFilter) filterTokens(tokens *structs.ACLTokens) { 1528 ret := make(structs.ACLTokens, 0, len(*tokens)) 1529 for _, token := range *tokens { 1530 final := token 1531 f.filterToken(&final) 1532 if final != nil { 1533 ret = append(ret, final) 1534 } 1535 } 1536 *tokens = ret 1537} 1538 1539func (f *aclFilter) filterTokenStub(token **structs.ACLTokenListStub) { 1540 var entCtx acl.AuthorizerContext 1541 if token == nil || *token == nil || f == nil { 1542 return 1543 } 1544 1545 (*token).FillAuthzContext(&entCtx) 1546 1547 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1548 *token = nil 1549 } 1550} 1551 1552func (f *aclFilter) filterTokenStubs(tokens *[]*structs.ACLTokenListStub) { 1553 ret := make(structs.ACLTokenListStubs, 0, len(*tokens)) 1554 for _, token := range *tokens { 1555 final := token 1556 f.filterTokenStub(&final) 1557 if final != nil { 1558 ret = append(ret, final) 1559 } 1560 } 1561 *tokens = ret 1562} 1563 1564func (f *aclFilter) filterPolicy(policy **structs.ACLPolicy) { 1565 var entCtx acl.AuthorizerContext 1566 if policy == nil || *policy == nil || f == nil { 1567 return 1568 } 1569 1570 (*policy).FillAuthzContext(&entCtx) 1571 1572 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1573 // no permissions to read 1574 *policy = nil 1575 } 1576} 1577 1578func (f *aclFilter) filterPolicies(policies *structs.ACLPolicies) { 1579 ret := make(structs.ACLPolicies, 0, len(*policies)) 1580 for _, policy := range *policies { 1581 final := policy 1582 f.filterPolicy(&final) 1583 if final != nil { 1584 ret = append(ret, final) 1585 } 1586 } 1587 *policies = ret 1588} 1589 1590func (f *aclFilter) filterRole(role **structs.ACLRole) { 1591 var entCtx acl.AuthorizerContext 1592 if role == nil || *role == nil || f == nil { 1593 return 1594 } 1595 1596 (*role).FillAuthzContext(&entCtx) 1597 1598 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1599 // no permissions to read 1600 *role = nil 1601 } 1602} 1603 1604func (f *aclFilter) filterRoles(roles *structs.ACLRoles) { 1605 ret := make(structs.ACLRoles, 0, len(*roles)) 1606 for _, role := range *roles { 1607 final := role 1608 f.filterRole(&final) 1609 if final != nil { 1610 ret = append(ret, final) 1611 } 1612 } 1613 *roles = ret 1614} 1615 1616func (f *aclFilter) filterBindingRule(rule **structs.ACLBindingRule) { 1617 var entCtx acl.AuthorizerContext 1618 if rule == nil || *rule == nil || f == nil { 1619 return 1620 } 1621 1622 (*rule).FillAuthzContext(&entCtx) 1623 1624 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1625 // no permissions to read 1626 *rule = nil 1627 } 1628} 1629 1630func (f *aclFilter) filterBindingRules(rules *structs.ACLBindingRules) { 1631 ret := make(structs.ACLBindingRules, 0, len(*rules)) 1632 for _, rule := range *rules { 1633 final := rule 1634 f.filterBindingRule(&final) 1635 if final != nil { 1636 ret = append(ret, final) 1637 } 1638 } 1639 *rules = ret 1640} 1641 1642func (f *aclFilter) filterAuthMethod(method **structs.ACLAuthMethod) { 1643 var entCtx acl.AuthorizerContext 1644 if method == nil || *method == nil || f == nil { 1645 return 1646 } 1647 1648 (*method).FillAuthzContext(&entCtx) 1649 1650 if f.authorizer.ACLRead(&entCtx) != acl.Allow { 1651 // no permissions to read 1652 *method = nil 1653 } 1654} 1655 1656func (f *aclFilter) filterAuthMethods(methods *structs.ACLAuthMethods) { 1657 ret := make(structs.ACLAuthMethods, 0, len(*methods)) 1658 for _, method := range *methods { 1659 final := method 1660 f.filterAuthMethod(&final) 1661 if final != nil { 1662 ret = append(ret, final) 1663 } 1664 } 1665 *methods = ret 1666} 1667 1668func (f *aclFilter) filterServiceList(services *structs.ServiceList) { 1669 ret := make(structs.ServiceList, 0, len(*services)) 1670 for _, svc := range *services { 1671 var authzContext acl.AuthorizerContext 1672 1673 svc.FillAuthzContext(&authzContext) 1674 1675 if f.authorizer.ServiceRead(svc.Name, &authzContext) != acl.Allow { 1676 sid := structs.NewServiceID(svc.Name, &svc.EnterpriseMeta) 1677 f.logger.Debug("dropping service from result due to ACLs", "service", sid.String()) 1678 continue 1679 } 1680 1681 ret = append(ret, svc) 1682 } 1683 1684 *services = ret 1685} 1686 1687func (r *ACLResolver) filterACLWithAuthorizer(authorizer acl.Authorizer, subj interface{}) error { 1688 if authorizer == nil { 1689 return nil 1690 } 1691 // Create the filter 1692 filt := newACLFilter(authorizer, r.logger, r.config.ACLEnforceVersion8) 1693 1694 switch v := subj.(type) { 1695 case *structs.CheckServiceNodes: 1696 filt.filterCheckServiceNodes(v) 1697 1698 case *structs.IndexedCheckServiceNodes: 1699 filt.filterCheckServiceNodes(&v.Nodes) 1700 1701 case *structs.IndexedCoordinates: 1702 filt.filterCoordinates(&v.Coordinates) 1703 1704 case *structs.IndexedHealthChecks: 1705 filt.filterHealthChecks(&v.HealthChecks) 1706 1707 case *structs.IndexedIntentions: 1708 filt.filterIntentions(&v.Intentions) 1709 1710 case *structs.IndexedNodeDump: 1711 filt.filterNodeDump(&v.Dump) 1712 1713 case *structs.IndexedNodes: 1714 filt.filterNodes(&v.Nodes) 1715 1716 case *structs.IndexedNodeServices: 1717 filt.filterNodeServices(&v.NodeServices) 1718 1719 case **structs.NodeServiceList: 1720 filt.filterNodeServiceList(v) 1721 1722 case *structs.IndexedServiceNodes: 1723 filt.filterServiceNodes(&v.ServiceNodes) 1724 1725 case *structs.IndexedServices: 1726 filt.filterServices(v.Services, &v.EnterpriseMeta) 1727 1728 case *structs.IndexedSessions: 1729 filt.filterSessions(&v.Sessions) 1730 1731 case *structs.IndexedPreparedQueries: 1732 filt.filterPreparedQueries(&v.Queries) 1733 1734 case **structs.PreparedQuery: 1735 filt.redactPreparedQueryTokens(v) 1736 1737 case *structs.ACLTokens: 1738 filt.filterTokens(v) 1739 case **structs.ACLToken: 1740 filt.filterToken(v) 1741 case *[]*structs.ACLTokenListStub: 1742 filt.filterTokenStubs(v) 1743 case **structs.ACLTokenListStub: 1744 filt.filterTokenStub(v) 1745 1746 case *structs.ACLPolicies: 1747 filt.filterPolicies(v) 1748 case **structs.ACLPolicy: 1749 filt.filterPolicy(v) 1750 1751 case *structs.ACLRoles: 1752 filt.filterRoles(v) 1753 case **structs.ACLRole: 1754 filt.filterRole(v) 1755 1756 case *structs.ACLBindingRules: 1757 filt.filterBindingRules(v) 1758 case **structs.ACLBindingRule: 1759 filt.filterBindingRule(v) 1760 1761 case *structs.ACLAuthMethods: 1762 filt.filterAuthMethods(v) 1763 case **structs.ACLAuthMethod: 1764 filt.filterAuthMethod(v) 1765 1766 case *structs.IndexedServiceList: 1767 filt.filterServiceList(&v.Services) 1768 default: 1769 panic(fmt.Errorf("Unhandled type passed to ACL filter: %T %#v", subj, subj)) 1770 } 1771 1772 return nil 1773} 1774 1775// filterACL is used to filter results from our service catalog based on the 1776// rules configured for the provided token. 1777func (r *ACLResolver) filterACL(token string, subj interface{}) error { 1778 // Get the ACL from the token 1779 authorizer, err := r.ResolveToken(token) 1780 if err != nil { 1781 return err 1782 } 1783 1784 // Fast path if ACLs are not enabled 1785 if authorizer == nil { 1786 return nil 1787 } 1788 1789 return r.filterACLWithAuthorizer(authorizer, subj) 1790} 1791 1792// vetRegisterWithACL applies the given ACL's policy to the catalog update and 1793// determines if it is allowed. Since the catalog register request is so 1794// dynamic, this is a pretty complex algorithm and was worth breaking out of the 1795// endpoint. The NodeServices record for the node must be supplied, and can be 1796// nil. 1797// 1798// This is a bit racy because we have to check the state store outside of a 1799// transaction. It's the best we can do because we don't want to flow ACL 1800// checking down there. The node information doesn't change in practice, so this 1801// will be fine. If we expose ways to change node addresses in a later version, 1802// then we should split the catalog API at the node and service level so we can 1803// address this race better (even then it would be super rare, and would at 1804// worst let a service update revert a recent node update, so it doesn't open up 1805// too much abuse). 1806func vetRegisterWithACL(rule acl.Authorizer, subj *structs.RegisterRequest, 1807 ns *structs.NodeServices) error { 1808 // Fast path if ACLs are not enabled. 1809 if rule == nil { 1810 return nil 1811 } 1812 1813 var authzContext acl.AuthorizerContext 1814 subj.FillAuthzContext(&authzContext) 1815 1816 // Vet the node info. This allows service updates to re-post the required 1817 // node info for each request without having to have node "write" 1818 // privileges. 1819 needsNode := ns == nil || subj.ChangesNode(ns.Node) 1820 1821 if needsNode && rule.NodeWrite(subj.Node, &authzContext) != acl.Allow { 1822 return acl.ErrPermissionDenied 1823 } 1824 1825 // Vet the service change. This includes making sure they can register 1826 // the given service, and that we can write to any existing service that 1827 // is being modified by id (if any). 1828 if subj.Service != nil { 1829 if rule.ServiceWrite(subj.Service.Service, &authzContext) != acl.Allow { 1830 return acl.ErrPermissionDenied 1831 } 1832 1833 if ns != nil { 1834 other, ok := ns.Services[subj.Service.ID] 1835 1836 if ok { 1837 // This is effectively a delete, so we DO NOT apply the 1838 // sentinel scope to the service we are overwriting, just 1839 // the regular ACL policy. 1840 var secondaryCtx acl.AuthorizerContext 1841 other.FillAuthzContext(&secondaryCtx) 1842 1843 if rule.ServiceWrite(other.Service, &secondaryCtx) != acl.Allow { 1844 return acl.ErrPermissionDenied 1845 } 1846 } 1847 } 1848 } 1849 1850 // Make sure that the member was flattened before we got there. This 1851 // keeps us from having to verify this check as well. 1852 if subj.Check != nil { 1853 return fmt.Errorf("check member must be nil") 1854 } 1855 1856 // Vet the checks. Node-level checks require node write, and 1857 // service-level checks require service write. 1858 for _, check := range subj.Checks { 1859 // Make sure that the node matches - we don't allow you to mix 1860 // checks from other nodes because we'd have to pull a bunch 1861 // more state store data to check this. If ACLs are enabled then 1862 // we simply require them to match in a given request. There's a 1863 // note in state_store.go to ban this down there in Consul 0.8, 1864 // but it's good to leave this here because it's required for 1865 // correctness wrt. ACLs. 1866 if check.Node != subj.Node { 1867 return fmt.Errorf("Node '%s' for check '%s' doesn't match register request node '%s'", 1868 check.Node, check.CheckID, subj.Node) 1869 } 1870 1871 // Node-level check. 1872 if check.ServiceID == "" { 1873 if rule.NodeWrite(subj.Node, &authzContext) != acl.Allow { 1874 return acl.ErrPermissionDenied 1875 } 1876 continue 1877 } 1878 1879 // Service-level check, check the common case where it 1880 // matches the service part of this request, which has 1881 // already been vetted above, and might be being registered 1882 // along with its checks. 1883 if subj.Service != nil && subj.Service.ID == check.ServiceID { 1884 continue 1885 } 1886 1887 // Service-level check for some other service. Make sure they've 1888 // got write permissions for that service. 1889 if ns == nil { 1890 return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID) 1891 } 1892 1893 other, ok := ns.Services[check.ServiceID] 1894 if !ok { 1895 return fmt.Errorf("Unknown service '%s' for check '%s'", check.ServiceID, check.CheckID) 1896 } 1897 1898 // We are only adding a check here, so we don't add the scope, 1899 // since the sentinel policy doesn't apply to adding checks at 1900 // this time. 1901 var secondaryCtx acl.AuthorizerContext 1902 other.FillAuthzContext(&secondaryCtx) 1903 1904 if rule.ServiceWrite(other.Service, &secondaryCtx) != acl.Allow { 1905 return acl.ErrPermissionDenied 1906 } 1907 } 1908 1909 return nil 1910} 1911 1912// vetDeregisterWithACL applies the given ACL's policy to the catalog update and 1913// determines if it is allowed. Since the catalog deregister request is so 1914// dynamic, this is a pretty complex algorithm and was worth breaking out of the 1915// endpoint. The NodeService for the referenced service must be supplied, and can 1916// be nil; similar for the HealthCheck for the referenced health check. 1917func vetDeregisterWithACL(rule acl.Authorizer, subj *structs.DeregisterRequest, 1918 ns *structs.NodeService, nc *structs.HealthCheck) error { 1919 1920 // Fast path if ACLs are not enabled. 1921 if rule == nil { 1922 return nil 1923 } 1924 1925 // We don't apply sentinel in this path, since at this time sentinel 1926 // only applies to create and update operations. 1927 1928 var authzContext acl.AuthorizerContext 1929 // fill with the defaults for use with the NodeWrite check 1930 subj.FillAuthzContext(&authzContext) 1931 1932 // Allow service deregistration if the token has write permission for the node. 1933 // This accounts for cases where the agent no longer has a token with write permission 1934 // on the service to deregister it. 1935 if rule.NodeWrite(subj.Node, &authzContext) == acl.Allow { 1936 return nil 1937 } 1938 1939 // This order must match the code in applyDeregister() in 1940 // fsm/commands_oss.go since it also evaluates things in this order, 1941 // and will ignore fields based on this precedence. This lets us also 1942 // ignore them from an ACL perspective. 1943 if subj.ServiceID != "" { 1944 if ns == nil { 1945 return fmt.Errorf("Unknown service '%s'", subj.ServiceID) 1946 } 1947 1948 ns.FillAuthzContext(&authzContext) 1949 1950 if rule.ServiceWrite(ns.Service, &authzContext) != acl.Allow { 1951 return acl.ErrPermissionDenied 1952 } 1953 } else if subj.CheckID != "" { 1954 if nc == nil { 1955 return fmt.Errorf("Unknown check '%s'", subj.CheckID) 1956 } 1957 1958 nc.FillAuthzContext(&authzContext) 1959 1960 if nc.ServiceID != "" { 1961 if rule.ServiceWrite(nc.ServiceName, &authzContext) != acl.Allow { 1962 return acl.ErrPermissionDenied 1963 } 1964 } else { 1965 if rule.NodeWrite(subj.Node, &authzContext) != acl.Allow { 1966 return acl.ErrPermissionDenied 1967 } 1968 } 1969 } else { 1970 // Since NodeWrite is not given - otherwise the earlier check 1971 // would've returned already - we can deny here. 1972 return acl.ErrPermissionDenied 1973 } 1974 1975 return nil 1976} 1977 1978// vetNodeTxnOp applies the given ACL policy to a node transaction operation. 1979func vetNodeTxnOp(op *structs.TxnNodeOp, rule acl.Authorizer) error { 1980 // Fast path if ACLs are not enabled. 1981 if rule == nil { 1982 return nil 1983 } 1984 1985 var authzContext acl.AuthorizerContext 1986 op.FillAuthzContext(&authzContext) 1987 1988 if rule != nil && rule.NodeWrite(op.Node.Node, &authzContext) != acl.Allow { 1989 return acl.ErrPermissionDenied 1990 } 1991 1992 return nil 1993} 1994 1995// vetServiceTxnOp applies the given ACL policy to a service transaction operation. 1996func vetServiceTxnOp(op *structs.TxnServiceOp, rule acl.Authorizer) error { 1997 // Fast path if ACLs are not enabled. 1998 if rule == nil { 1999 return nil 2000 } 2001 2002 var authzContext acl.AuthorizerContext 2003 op.FillAuthzContext(&authzContext) 2004 2005 if rule.ServiceWrite(op.Service.Service, &authzContext) != acl.Allow { 2006 return acl.ErrPermissionDenied 2007 } 2008 2009 return nil 2010} 2011 2012// vetCheckTxnOp applies the given ACL policy to a check transaction operation. 2013func vetCheckTxnOp(op *structs.TxnCheckOp, rule acl.Authorizer) error { 2014 // Fast path if ACLs are not enabled. 2015 if rule == nil { 2016 return nil 2017 } 2018 2019 var authzContext acl.AuthorizerContext 2020 op.FillAuthzContext(&authzContext) 2021 2022 if op.Check.ServiceID == "" { 2023 // Node-level check. 2024 if rule.NodeWrite(op.Check.Node, &authzContext) != acl.Allow { 2025 return acl.ErrPermissionDenied 2026 } 2027 } else { 2028 // Service-level check. 2029 if rule.ServiceWrite(op.Check.ServiceName, &authzContext) != acl.Allow { 2030 return acl.ErrPermissionDenied 2031 } 2032 } 2033 2034 return nil 2035} 2036