1package vault 2 3import ( 4 "context" 5 "fmt" 6 "path" 7 "strings" 8 "sync" 9 "time" 10 11 metrics "github.com/armon/go-metrics" 12 "github.com/hashicorp/errwrap" 13 log "github.com/hashicorp/go-hclog" 14 lru "github.com/hashicorp/golang-lru" 15 "github.com/hashicorp/vault/helper/identity" 16 "github.com/hashicorp/vault/helper/namespace" 17 "github.com/hashicorp/vault/sdk/helper/consts" 18 "github.com/hashicorp/vault/sdk/helper/strutil" 19 "github.com/hashicorp/vault/sdk/logical" 20) 21 22const ( 23 // policySubPath is the sub-path used for the policy store view. This is 24 // nested under the system view. policyRGPSubPath/policyEGPSubPath are 25 // similar but for RGPs/EGPs. 26 policyACLSubPath = "policy/" 27 policyRGPSubPath = "policy-rgp/" 28 policyEGPSubPath = "policy-egp/" 29 30 // policyCacheSize is the number of policies that are kept cached 31 policyCacheSize = 1024 32 33 // defaultPolicyName is the name of the default policy 34 defaultPolicyName = "default" 35 36 // responseWrappingPolicyName is the name of the fixed policy 37 responseWrappingPolicyName = "response-wrapping" 38 39 // controlGroupPolicyName is the name of the fixed policy for control group 40 // tokens 41 controlGroupPolicyName = "control-group" 42 43 // responseWrappingPolicy is the policy that ensures cubbyhole response 44 // wrapping can always succeed. 45 responseWrappingPolicy = ` 46path "cubbyhole/response" { 47 capabilities = ["create", "read"] 48} 49 50path "sys/wrapping/unwrap" { 51 capabilities = ["update"] 52} 53` 54 // controlGroupPolicy is the policy that ensures control group requests can 55 // commit themselves 56 controlGroupPolicy = ` 57path "cubbyhole/control-group" { 58 capabilities = ["update", "create", "read"] 59} 60 61path "sys/wrapping/unwrap" { 62 capabilities = ["update"] 63} 64` 65 // defaultPolicy is the "default" policy 66 defaultPolicy = ` 67# Allow tokens to look up their own properties 68path "auth/token/lookup-self" { 69 capabilities = ["read"] 70} 71 72# Allow tokens to renew themselves 73path "auth/token/renew-self" { 74 capabilities = ["update"] 75} 76 77# Allow tokens to revoke themselves 78path "auth/token/revoke-self" { 79 capabilities = ["update"] 80} 81 82# Allow a token to look up its own capabilities on a path 83path "sys/capabilities-self" { 84 capabilities = ["update"] 85} 86 87# Allow a token to look up its own entity by id or name 88path "identity/entity/id/{{identity.entity.id}}" { 89 capabilities = ["read"] 90} 91path "identity/entity/name/{{identity.entity.name}}" { 92 capabilities = ["read"] 93} 94 95 96# Allow a token to look up its resultant ACL from all policies. This is useful 97# for UIs. It is an internal path because the format may change at any time 98# based on how the internal ACL features and capabilities change. 99path "sys/internal/ui/resultant-acl" { 100 capabilities = ["read"] 101} 102 103# Allow a token to renew a lease via lease_id in the request body; old path for 104# old clients, new path for newer 105path "sys/renew" { 106 capabilities = ["update"] 107} 108path "sys/leases/renew" { 109 capabilities = ["update"] 110} 111 112# Allow looking up lease properties. This requires knowing the lease ID ahead 113# of time and does not divulge any sensitive information. 114path "sys/leases/lookup" { 115 capabilities = ["update"] 116} 117 118# Allow a token to manage its own cubbyhole 119path "cubbyhole/*" { 120 capabilities = ["create", "read", "update", "delete", "list"] 121} 122 123# Allow a token to wrap arbitrary values in a response-wrapping token 124path "sys/wrapping/wrap" { 125 capabilities = ["update"] 126} 127 128# Allow a token to look up the creation time and TTL of a given 129# response-wrapping token 130path "sys/wrapping/lookup" { 131 capabilities = ["update"] 132} 133 134# Allow a token to unwrap a response-wrapping token. This is a convenience to 135# avoid client token swapping since this is also part of the response wrapping 136# policy. 137path "sys/wrapping/unwrap" { 138 capabilities = ["update"] 139} 140 141# Allow general purpose tools 142path "sys/tools/hash" { 143 capabilities = ["update"] 144} 145path "sys/tools/hash/*" { 146 capabilities = ["update"] 147} 148 149# Allow checking the status of a Control Group request if the user has the 150# accessor 151path "sys/control-group/request" { 152 capabilities = ["update"] 153} 154` 155) 156 157var ( 158 immutablePolicies = []string{ 159 "root", 160 responseWrappingPolicyName, 161 controlGroupPolicyName, 162 } 163 nonAssignablePolicies = []string{ 164 responseWrappingPolicyName, 165 controlGroupPolicyName, 166 } 167) 168 169// PolicyStore is used to provide durable storage of policy, and to 170// manage ACLs associated with them. 171type PolicyStore struct { 172 entPolicyStore 173 174 core *Core 175 aclView *BarrierView 176 rgpView *BarrierView 177 egpView *BarrierView 178 179 tokenPoliciesLRU *lru.TwoQueueCache 180 egpLRU *lru.TwoQueueCache 181 182 // This is used to ensure that writes to the store (acl/rgp) or to the egp 183 // path tree don't happen concurrently. We are okay reading stale data so 184 // long as there aren't concurrent writes. 185 modifyLock *sync.RWMutex 186 187 // Stores whether a token policy is ACL or RGP 188 policyTypeMap sync.Map 189 190 // logger is the server logger copied over from core 191 logger log.Logger 192} 193 194// PolicyEntry is used to store a policy by name 195type PolicyEntry struct { 196 sentinelPolicy 197 198 Version int 199 Raw string 200 Templated bool 201 Type PolicyType 202} 203 204// NewPolicyStore creates a new PolicyStore that is backed 205// using a given view. It used used to durable store and manage named policy. 206func NewPolicyStore(ctx context.Context, core *Core, baseView *BarrierView, system logical.SystemView, logger log.Logger) (*PolicyStore, error) { 207 ps := &PolicyStore{ 208 aclView: baseView.SubView(policyACLSubPath), 209 rgpView: baseView.SubView(policyRGPSubPath), 210 egpView: baseView.SubView(policyEGPSubPath), 211 modifyLock: new(sync.RWMutex), 212 logger: logger, 213 core: core, 214 } 215 216 ps.extraInit() 217 218 if !system.CachingDisabled() { 219 cache, _ := lru.New2Q(policyCacheSize) 220 ps.tokenPoliciesLRU = cache 221 cache, _ = lru.New2Q(policyCacheSize) 222 ps.egpLRU = cache 223 } 224 225 aclView := ps.getACLView(namespace.RootNamespace) 226 keys, err := logical.CollectKeys(namespace.RootContext(ctx), aclView) 227 if err != nil { 228 ps.logger.Error("error collecting acl policy keys", "error", err) 229 return nil, err 230 } 231 for _, key := range keys { 232 index := ps.cacheKey(namespace.RootNamespace, ps.sanitizeName(key)) 233 ps.policyTypeMap.Store(index, PolicyTypeACL) 234 } 235 236 if err := ps.loadNamespacePolicies(ctx, core); err != nil { 237 return nil, err 238 } 239 240 // Special-case root; doesn't exist on disk but does need to be found 241 ps.policyTypeMap.Store(ps.cacheKey(namespace.RootNamespace, "root"), PolicyTypeACL) 242 return ps, nil 243} 244 245// setupPolicyStore is used to initialize the policy store 246// when the vault is being unsealed. 247func (c *Core) setupPolicyStore(ctx context.Context) error { 248 // Create the policy store 249 var err error 250 sysView := &dynamicSystemView{core: c} 251 psLogger := c.baseLogger.Named("policy") 252 c.AddLogger(psLogger) 253 c.policyStore, err = NewPolicyStore(ctx, c, c.systemBarrierView, sysView, psLogger) 254 if err != nil { 255 return err 256 } 257 258 if c.ReplicationState().HasState(consts.ReplicationPerformanceSecondary | consts.ReplicationDRSecondary) { 259 // Policies will sync from the primary 260 return nil 261 } 262 263 // Ensure that the default policy exists, and if not, create it 264 if err := c.policyStore.loadACLPolicy(ctx, defaultPolicyName, defaultPolicy); err != nil { 265 return err 266 } 267 // Ensure that the response wrapping policy exists 268 if err := c.policyStore.loadACLPolicy(ctx, responseWrappingPolicyName, responseWrappingPolicy); err != nil { 269 return err 270 } 271 // Ensure that the control group policy exists 272 if err := c.policyStore.loadACLPolicy(ctx, controlGroupPolicyName, controlGroupPolicy); err != nil { 273 return err 274 } 275 276 return nil 277} 278 279// teardownPolicyStore is used to reverse setupPolicyStore 280// when the vault is being sealed. 281func (c *Core) teardownPolicyStore() error { 282 c.policyStore = nil 283 return nil 284} 285 286func (ps *PolicyStore) invalidate(ctx context.Context, name string, policyType PolicyType) { 287 ns, err := namespace.FromContext(ctx) 288 if err != nil { 289 ps.logger.Error("unable to invalidate key, no namespace info passed", "key", name) 290 return 291 } 292 293 // This may come with a prefixed "/" due to joining the file path 294 saneName := strings.TrimPrefix(name, "/") 295 index := ps.cacheKey(ns, saneName) 296 297 ps.modifyLock.Lock() 298 defer ps.modifyLock.Unlock() 299 300 // We don't lock before removing from the LRU here because the worst that 301 // can happen is we load again if something since added it 302 switch policyType { 303 case PolicyTypeACL, PolicyTypeRGP: 304 if ps.tokenPoliciesLRU != nil { 305 ps.tokenPoliciesLRU.Remove(index) 306 } 307 308 case PolicyTypeEGP: 309 if ps.egpLRU != nil { 310 ps.egpLRU.Remove(index) 311 } 312 313 default: 314 // Can't do anything 315 return 316 } 317 318 // Force a reload 319 out, err := ps.switchedGetPolicy(ctx, name, policyType, false) 320 if err != nil { 321 ps.logger.Error("error fetching policy after invalidation", "name", saneName) 322 } 323 324 // If true, the invalidation was actually a delete, so we may need to 325 // perform further deletion tasks. We skip the physical deletion just in 326 // case another process has re-written the policy; instead next time Get is 327 // called the values will be loaded back in. 328 if out == nil { 329 ps.switchedDeletePolicy(ctx, name, policyType, false, true) 330 } 331 332 return 333} 334 335// SetPolicy is used to create or update the given policy 336func (ps *PolicyStore) SetPolicy(ctx context.Context, p *Policy) error { 337 defer metrics.MeasureSince([]string{"policy", "set_policy"}, time.Now()) 338 if p == nil { 339 return fmt.Errorf("nil policy passed in for storage") 340 } 341 if p.Name == "" { 342 return fmt.Errorf("policy name missing") 343 } 344 // Policies are normalized to lower-case 345 p.Name = ps.sanitizeName(p.Name) 346 if strutil.StrListContains(immutablePolicies, p.Name) { 347 return fmt.Errorf("cannot update %q policy", p.Name) 348 } 349 350 return ps.setPolicyInternal(ctx, p) 351} 352 353func (ps *PolicyStore) setPolicyInternal(ctx context.Context, p *Policy) error { 354 ps.modifyLock.Lock() 355 defer ps.modifyLock.Unlock() 356 357 // Get the appropriate view based on policy type and namespace 358 view := ps.getBarrierView(p.namespace, p.Type) 359 if view == nil { 360 return fmt.Errorf("unable to get the barrier subview for policy type %q", p.Type) 361 } 362 363 if err := ps.parseEGPPaths(p); err != nil { 364 return err 365 } 366 367 // Create the entry 368 entry, err := logical.StorageEntryJSON(p.Name, &PolicyEntry{ 369 Version: 2, 370 Raw: p.Raw, 371 Type: p.Type, 372 Templated: p.Templated, 373 sentinelPolicy: p.sentinelPolicy, 374 }) 375 if err != nil { 376 return errwrap.Wrapf("failed to create entry: {{err}}", err) 377 } 378 379 // Construct the cache key 380 index := ps.cacheKey(p.namespace, p.Name) 381 382 switch p.Type { 383 case PolicyTypeACL: 384 rgpView := ps.getRGPView(p.namespace) 385 rgp, err := rgpView.Get(ctx, entry.Key) 386 if err != nil { 387 return errwrap.Wrapf("failed looking up conflicting policy: {{err}}", err) 388 } 389 if rgp != nil { 390 return fmt.Errorf("cannot reuse policy names between ACLs and RGPs") 391 } 392 393 if err := view.Put(ctx, entry); err != nil { 394 return errwrap.Wrapf("failed to persist policy: {{err}}", err) 395 } 396 397 ps.policyTypeMap.Store(index, PolicyTypeACL) 398 399 if ps.tokenPoliciesLRU != nil { 400 ps.tokenPoliciesLRU.Add(index, p) 401 } 402 403 case PolicyTypeRGP: 404 aclView := ps.getACLView(p.namespace) 405 acl, err := aclView.Get(ctx, entry.Key) 406 if err != nil { 407 return errwrap.Wrapf("failed looking up conflicting policy: {{err}}", err) 408 } 409 if acl != nil { 410 return fmt.Errorf("cannot reuse policy names between ACLs and RGPs") 411 } 412 413 if err := ps.handleSentinelPolicy(ctx, p, view, entry); err != nil { 414 return err 415 } 416 417 ps.policyTypeMap.Store(index, PolicyTypeRGP) 418 419 // We load here after successfully loading into Sentinel so that on 420 // error we will try loading again on the next get 421 if ps.tokenPoliciesLRU != nil { 422 ps.tokenPoliciesLRU.Add(index, p) 423 } 424 425 case PolicyTypeEGP: 426 if err := ps.handleSentinelPolicy(ctx, p, view, entry); err != nil { 427 return err 428 } 429 430 // We load here after successfully loading into Sentinel so that on 431 // error we will try loading again on the next get 432 if ps.egpLRU != nil { 433 ps.egpLRU.Add(index, p) 434 } 435 436 default: 437 return fmt.Errorf("unknown policy type, cannot set") 438 } 439 440 return nil 441} 442 443// GetPolicy is used to fetch the named policy 444func (ps *PolicyStore) GetPolicy(ctx context.Context, name string, policyType PolicyType) (*Policy, error) { 445 return ps.switchedGetPolicy(ctx, name, policyType, true) 446} 447 448func (ps *PolicyStore) switchedGetPolicy(ctx context.Context, name string, policyType PolicyType, grabLock bool) (*Policy, error) { 449 defer metrics.MeasureSince([]string{"policy", "get_policy"}, time.Now()) 450 451 ns, err := namespace.FromContext(ctx) 452 if err != nil { 453 return nil, err 454 } 455 // Policies are normalized to lower-case 456 name = ps.sanitizeName(name) 457 index := ps.cacheKey(ns, name) 458 459 var cache *lru.TwoQueueCache 460 var view *BarrierView 461 462 switch policyType { 463 case PolicyTypeACL: 464 cache = ps.tokenPoliciesLRU 465 view = ps.getACLView(ns) 466 case PolicyTypeRGP: 467 cache = ps.tokenPoliciesLRU 468 view = ps.getRGPView(ns) 469 case PolicyTypeEGP: 470 cache = ps.egpLRU 471 view = ps.getEGPView(ns) 472 case PolicyTypeToken: 473 cache = ps.tokenPoliciesLRU 474 val, ok := ps.policyTypeMap.Load(index) 475 if !ok { 476 // Doesn't exist 477 return nil, nil 478 } 479 policyType = val.(PolicyType) 480 switch policyType { 481 case PolicyTypeACL: 482 view = ps.getACLView(ns) 483 case PolicyTypeRGP: 484 view = ps.getRGPView(ns) 485 default: 486 return nil, fmt.Errorf("invalid type of policy in type map: %q", policyType) 487 } 488 } 489 490 if cache != nil { 491 // Check for cached policy 492 if raw, ok := cache.Get(index); ok { 493 return raw.(*Policy), nil 494 } 495 } 496 497 // Special case the root policy 498 if policyType == PolicyTypeACL && name == "root" && ns.ID == namespace.RootNamespaceID { 499 p := &Policy{ 500 Name: "root", 501 namespace: namespace.RootNamespace, 502 } 503 if cache != nil { 504 cache.Add(index, p) 505 } 506 return p, nil 507 } 508 509 if grabLock { 510 ps.modifyLock.Lock() 511 defer ps.modifyLock.Unlock() 512 } 513 514 // See if anything has added it since we got the lock 515 if cache != nil { 516 if raw, ok := cache.Get(index); ok { 517 return raw.(*Policy), nil 518 } 519 } 520 521 // Nil-check on the view before proceeding to retrieve from storage 522 if view == nil { 523 return nil, fmt.Errorf("unable to get the barrier subview for policy type %q", policyType) 524 } 525 526 out, err := view.Get(ctx, name) 527 if err != nil { 528 return nil, errwrap.Wrapf("failed to read policy: {{err}}", err) 529 } 530 531 if out == nil { 532 return nil, nil 533 } 534 535 policyEntry := new(PolicyEntry) 536 policy := new(Policy) 537 err = out.DecodeJSON(policyEntry) 538 if err != nil { 539 return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) 540 } 541 542 // Set these up here so that they're available for loading into 543 // Sentinel 544 policy.Name = name 545 policy.Raw = policyEntry.Raw 546 policy.Type = policyEntry.Type 547 policy.Templated = policyEntry.Templated 548 policy.sentinelPolicy = policyEntry.sentinelPolicy 549 policy.namespace = ns 550 switch policyEntry.Type { 551 case PolicyTypeACL: 552 // Parse normally 553 p, err := ParseACLPolicy(ns, policyEntry.Raw) 554 if err != nil { 555 return nil, errwrap.Wrapf("failed to parse policy: {{err}}", err) 556 } 557 policy.Paths = p.Paths 558 559 // Reset this in case they set the name in the policy itself 560 policy.Name = name 561 562 ps.policyTypeMap.Store(index, PolicyTypeACL) 563 564 case PolicyTypeRGP: 565 if err := ps.handleSentinelPolicy(ctx, policy, nil, nil); err != nil { 566 return nil, err 567 } 568 569 ps.policyTypeMap.Store(index, PolicyTypeRGP) 570 571 case PolicyTypeEGP: 572 if err := ps.handleSentinelPolicy(ctx, policy, nil, nil); err != nil { 573 return nil, err 574 } 575 576 default: 577 return nil, fmt.Errorf("unknown policy type %q", policyEntry.Type.String()) 578 } 579 580 if cache != nil { 581 // Update the LRU cache 582 cache.Add(index, policy) 583 } 584 585 return policy, nil 586} 587 588// ListPolicies is used to list the available policies 589func (ps *PolicyStore) ListPolicies(ctx context.Context, policyType PolicyType) ([]string, error) { 590 defer metrics.MeasureSince([]string{"policy", "list_policies"}, time.Now()) 591 592 ns, err := namespace.FromContext(ctx) 593 if err != nil { 594 return nil, err 595 } 596 if ns == nil { 597 return nil, namespace.ErrNoNamespace 598 } 599 600 // Get the appropriate view based on policy type and namespace 601 view := ps.getBarrierView(ns, policyType) 602 if view == nil { 603 return []string{}, fmt.Errorf("unable to get the barrier subview for policy type %q", policyType) 604 } 605 606 // Scan the view, since the policy names are the same as the 607 // key names. 608 var keys []string 609 switch policyType { 610 case PolicyTypeACL: 611 keys, err = logical.CollectKeys(ctx, view) 612 case PolicyTypeRGP: 613 return logical.CollectKeys(ctx, view) 614 case PolicyTypeEGP: 615 return logical.CollectKeys(ctx, view) 616 default: 617 return nil, fmt.Errorf("unknown policy type %q", policyType) 618 } 619 620 // We only have non-assignable ACL policies at the moment 621 for _, nonAssignable := range nonAssignablePolicies { 622 deleteIndex := -1 623 // Find indices of non-assignable policies in keys 624 for index, key := range keys { 625 if key == nonAssignable { 626 // Delete collection outside the loop 627 deleteIndex = index 628 break 629 } 630 } 631 // Remove non-assignable policies when found 632 if deleteIndex != -1 { 633 keys = append(keys[:deleteIndex], keys[deleteIndex+1:]...) 634 } 635 } 636 637 return keys, err 638} 639 640// DeletePolicy is used to delete the named policy 641func (ps *PolicyStore) DeletePolicy(ctx context.Context, name string, policyType PolicyType) error { 642 return ps.switchedDeletePolicy(ctx, name, policyType, true, false) 643} 644 645// deletePolicyForce is used to delete the named policy and force it even if 646// default or a singleton. It's used for invalidations or namespace deletion 647// where we internally need to actually remove a policy that the user normally 648// isn't allowed to remove. 649func (ps *PolicyStore) deletePolicyForce(ctx context.Context, name string, policyType PolicyType) error { 650 return ps.switchedDeletePolicy(ctx, name, policyType, true, true) 651} 652 653func (ps *PolicyStore) switchedDeletePolicy(ctx context.Context, name string, policyType PolicyType, physicalDeletion, force bool) error { 654 defer metrics.MeasureSince([]string{"policy", "delete_policy"}, time.Now()) 655 656 ns, err := namespace.FromContext(ctx) 657 if err != nil { 658 return err 659 } 660 // If not set, the call comes from invalidation, where we'll already have 661 // grabbed the lock 662 if physicalDeletion { 663 ps.modifyLock.Lock() 664 defer ps.modifyLock.Unlock() 665 } 666 667 // Policies are normalized to lower-case 668 name = ps.sanitizeName(name) 669 index := ps.cacheKey(ns, name) 670 671 view := ps.getBarrierView(ns, policyType) 672 if view == nil { 673 return fmt.Errorf("unable to get the barrier subview for policy type %q", policyType) 674 } 675 676 switch policyType { 677 case PolicyTypeACL: 678 if !force { 679 if strutil.StrListContains(immutablePolicies, name) { 680 return fmt.Errorf("cannot delete %q policy", name) 681 } 682 if name == "default" { 683 return fmt.Errorf("cannot delete default policy") 684 } 685 } 686 687 if physicalDeletion { 688 err := view.Delete(ctx, name) 689 if err != nil { 690 return errwrap.Wrapf("failed to delete policy: {{err}}", err) 691 } 692 } 693 694 if ps.tokenPoliciesLRU != nil { 695 // Clear the cache 696 ps.tokenPoliciesLRU.Remove(index) 697 } 698 699 ps.policyTypeMap.Delete(index) 700 701 case PolicyTypeRGP: 702 if physicalDeletion { 703 err := view.Delete(ctx, name) 704 if err != nil { 705 return errwrap.Wrapf("failed to delete policy: {{err}}", err) 706 } 707 } 708 709 if ps.tokenPoliciesLRU != nil { 710 // Clear the cache 711 ps.tokenPoliciesLRU.Remove(index) 712 } 713 714 ps.policyTypeMap.Delete(index) 715 716 defer ps.core.invalidateSentinelPolicy(policyType, index) 717 718 case PolicyTypeEGP: 719 if physicalDeletion { 720 err := view.Delete(ctx, name) 721 if err != nil { 722 return errwrap.Wrapf("failed to delete policy: {{err}}", err) 723 } 724 } 725 726 if ps.egpLRU != nil { 727 // Clear the cache 728 ps.egpLRU.Remove(index) 729 } 730 731 defer ps.core.invalidateSentinelPolicy(policyType, index) 732 733 ps.invalidateEGPTreePath(index) 734 } 735 736 return nil 737} 738 739type TemplateError struct { 740 Err error 741} 742 743func (t *TemplateError) WrappedErrors() []error { 744 return []error{t.Err} 745} 746 747func (t *TemplateError) Error() string { 748 return t.Err.Error() 749} 750 751// ACL is used to return an ACL which is built using the 752// named policies. 753func (ps *PolicyStore) ACL(ctx context.Context, entity *identity.Entity, policyNames map[string][]string) (*ACL, error) { 754 var policies []*Policy 755 // Fetch the policies 756 for nsID, nsPolicyNames := range policyNames { 757 policyNS, err := NamespaceByID(ctx, nsID, ps.core) 758 if err != nil { 759 return nil, err 760 } 761 if policyNS == nil { 762 return nil, namespace.ErrNoNamespace 763 } 764 policyCtx := namespace.ContextWithNamespace(ctx, policyNS) 765 for _, nsPolicyName := range nsPolicyNames { 766 p, err := ps.GetPolicy(policyCtx, nsPolicyName, PolicyTypeToken) 767 if err != nil { 768 return nil, errwrap.Wrapf("failed to get policy: {{err}}", err) 769 } 770 if p != nil { 771 policies = append(policies, p) 772 } 773 } 774 } 775 776 var fetchedGroups bool 777 var groups []*identity.Group 778 for i, policy := range policies { 779 if policy.Type == PolicyTypeACL && policy.Templated { 780 if !fetchedGroups { 781 fetchedGroups = true 782 if entity != nil { 783 directGroups, inheritedGroups, err := ps.core.identityStore.groupsByEntityID(entity.ID) 784 if err != nil { 785 return nil, errwrap.Wrapf("failed to fetch group memberships: {{err}}", err) 786 } 787 groups = append(directGroups, inheritedGroups...) 788 } 789 } 790 p, err := parseACLPolicyWithTemplating(policy.namespace, policy.Raw, true, entity, groups) 791 if err != nil { 792 return nil, errwrap.Wrapf(fmt.Sprintf("error parsing templated policy %q: {{err}}", policy.Name), err) 793 } 794 p.Name = policy.Name 795 policies[i] = p 796 } 797 } 798 799 // Construct the ACL 800 acl, err := NewACL(ctx, policies) 801 if err != nil { 802 return nil, errwrap.Wrapf("failed to construct ACL: {{err}}", err) 803 } 804 805 return acl, nil 806} 807 808// loadACLPolicy is used to load default ACL policies. The default policies will 809// be loaded to all namespaces. 810func (ps *PolicyStore) loadACLPolicy(ctx context.Context, policyName, policyText string) error { 811 return ps.loadACLPolicyNamespaces(ctx, policyName, policyText) 812} 813 814// loadACLPolicyInternal is used to load default ACL policies in a specific 815// namespace. 816func (ps *PolicyStore) loadACLPolicyInternal(ctx context.Context, policyName, policyText string) error { 817 ns, err := namespace.FromContext(ctx) 818 if err != nil { 819 return err 820 } 821 822 // Check if the policy already exists 823 policy, err := ps.GetPolicy(ctx, policyName, PolicyTypeACL) 824 if err != nil { 825 return errwrap.Wrapf(fmt.Sprintf("error fetching %s policy from store: {{err}}", policyName), err) 826 } 827 if policy != nil { 828 if !strutil.StrListContains(immutablePolicies, policyName) || policyText == policy.Raw { 829 return nil 830 } 831 } 832 833 policy, err = ParseACLPolicy(ns, policyText) 834 if err != nil { 835 return errwrap.Wrapf(fmt.Sprintf("error parsing %s policy: {{err}}", policyName), err) 836 } 837 838 if policy == nil { 839 return fmt.Errorf("parsing %q policy resulted in nil policy", policyName) 840 } 841 842 policy.Name = policyName 843 policy.Type = PolicyTypeACL 844 return ps.setPolicyInternal(ctx, policy) 845} 846 847func (ps *PolicyStore) sanitizeName(name string) string { 848 return strings.ToLower(strings.TrimSpace(name)) 849} 850 851func (ps *PolicyStore) cacheKey(ns *namespace.Namespace, name string) string { 852 return path.Join(ns.ID, name) 853} 854