github.com/DerekStrickland/consul@v1.4.5/agent/consul/acl_test.go (about) 1 package consul 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "reflect" 8 "strings" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/consul/acl" 14 "github.com/hashicorp/consul/agent/structs" 15 "github.com/hashicorp/consul/testutil/retry" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 var testACLPolicy = ` 21 key "" { 22 policy = "deny" 23 } 24 key "foo/" { 25 policy = "write" 26 } 27 ` 28 29 var testACLPolicyNew = ` 30 key_prefix "" { 31 policy = "deny" 32 } 33 key_prefix "foo/" { 34 policy = "write" 35 } 36 ` 37 38 type asyncResolutionResult struct { 39 authz acl.Authorizer 40 err error 41 } 42 43 func resolveTokenAsync(r *ACLResolver, token string, ch chan *asyncResolutionResult) { 44 authz, err := r.ResolveToken(token) 45 ch <- &asyncResolutionResult{authz: authz, err: err} 46 } 47 48 func testIdentityForToken(token string) (bool, structs.ACLIdentity, error) { 49 switch token { 50 case "missing-policy": 51 return true, &structs.ACLToken{ 52 AccessorID: "435a75af-1763-4980-89f4-f0951dda53b4", 53 SecretID: "b1b6be70-ed2e-4c80-8495-bdb3db110b1e", 54 Policies: []structs.ACLTokenPolicyLink{ 55 structs.ACLTokenPolicyLink{ 56 ID: "not-found", 57 }, 58 structs.ACLTokenPolicyLink{ 59 ID: "acl-ro", 60 }, 61 }, 62 }, nil 63 case "legacy-management": 64 return true, &structs.ACLToken{ 65 AccessorID: "d109a033-99d1-47e2-a711-d6593373a973", 66 SecretID: "415cd1e1-1493-4fb4-827d-d762ed9cfe7c", 67 Type: structs.ACLTokenTypeManagement, 68 }, nil 69 case "legacy-client": 70 return true, &structs.ACLToken{ 71 AccessorID: "b7375838-b104-4a25-b457-329d939bf257", 72 SecretID: "03f49328-c23c-4b26-92a2-3b898332400d", 73 Type: structs.ACLTokenTypeClient, 74 Rules: `service "" { policy = "read" }`, 75 }, nil 76 case "found": 77 return true, &structs.ACLToken{ 78 AccessorID: "5f57c1f6-6a89-4186-9445-531b316e01df", 79 SecretID: "a1a54629-5050-4d17-8a4e-560d2423f835", 80 Policies: []structs.ACLTokenPolicyLink{ 81 structs.ACLTokenPolicyLink{ 82 ID: "node-wr", 83 }, 84 structs.ACLTokenPolicyLink{ 85 ID: "dc2-key-wr", 86 }, 87 }, 88 }, nil 89 case "acl-ro": 90 return true, &structs.ACLToken{ 91 AccessorID: "435a75af-1763-4980-89f4-f0951dda53b4", 92 SecretID: "b1b6be70-ed2e-4c80-8495-bdb3db110b1e", 93 Policies: []structs.ACLTokenPolicyLink{ 94 structs.ACLTokenPolicyLink{ 95 ID: "acl-ro", 96 }, 97 }, 98 }, nil 99 case "acl-wr": 100 return true, &structs.ACLToken{ 101 AccessorID: "435a75af-1763-4980-89f4-f0951dda53b4", 102 SecretID: "b1b6be70-ed2e-4c80-8495-bdb3db110b1e", 103 Policies: []structs.ACLTokenPolicyLink{ 104 structs.ACLTokenPolicyLink{ 105 ID: "acl-wr", 106 }, 107 }, 108 }, nil 109 case "racey-unmodified": 110 return true, &structs.ACLToken{ 111 AccessorID: "5f57c1f6-6a89-4186-9445-531b316e01df", 112 SecretID: "a1a54629-5050-4d17-8a4e-560d2423f835", 113 Policies: []structs.ACLTokenPolicyLink{ 114 structs.ACLTokenPolicyLink{ 115 ID: "node-wr", 116 }, 117 structs.ACLTokenPolicyLink{ 118 ID: "acl-wr", 119 }, 120 }, 121 }, nil 122 case "racey-modified": 123 return true, &structs.ACLToken{ 124 AccessorID: "5f57c1f6-6a89-4186-9445-531b316e01df", 125 SecretID: "a1a54629-5050-4d17-8a4e-560d2423f835", 126 Policies: []structs.ACLTokenPolicyLink{ 127 structs.ACLTokenPolicyLink{ 128 ID: "node-wr", 129 }, 130 }, 131 }, nil 132 case "concurrent-resolve": 133 return true, &structs.ACLToken{ 134 AccessorID: "5f57c1f6-6a89-4186-9445-531b316e01df", 135 SecretID: "a1a54629-5050-4d17-8a4e-560d2423f835", 136 Policies: []structs.ACLTokenPolicyLink{ 137 structs.ACLTokenPolicyLink{ 138 ID: "node-wr", 139 }, 140 structs.ACLTokenPolicyLink{ 141 ID: "acl-wr", 142 }, 143 }, 144 }, nil 145 case anonymousToken: 146 return true, &structs.ACLToken{ 147 AccessorID: "00000000-0000-0000-0000-000000000002", 148 SecretID: anonymousToken, 149 Policies: []structs.ACLTokenPolicyLink{ 150 structs.ACLTokenPolicyLink{ 151 ID: "node-wr", 152 }, 153 }, 154 }, nil 155 default: 156 return true, nil, acl.ErrNotFound 157 } 158 } 159 160 func testPolicyForID(policyID string) (bool, *structs.ACLPolicy, error) { 161 switch policyID { 162 case "acl-ro": 163 return true, &structs.ACLPolicy{ 164 ID: "acl-ro", 165 Name: "acl-ro", 166 Description: "acl-ro", 167 Rules: `acl = "read"`, 168 Syntax: acl.SyntaxCurrent, 169 RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, 170 }, nil 171 case "acl-wr": 172 return true, &structs.ACLPolicy{ 173 ID: "acl-wr", 174 Name: "acl-wr", 175 Description: "acl-wr", 176 Rules: `acl = "write"`, 177 Syntax: acl.SyntaxCurrent, 178 RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, 179 }, nil 180 case "node-wr": 181 return true, &structs.ACLPolicy{ 182 ID: "node-wr", 183 Name: "node-wr", 184 Description: "node-wr", 185 Rules: `node_prefix "" { policy = "write"}`, 186 Syntax: acl.SyntaxCurrent, 187 Datacenters: []string{"dc1"}, 188 RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, 189 }, nil 190 case "dc2-key-wr": 191 return true, &structs.ACLPolicy{ 192 ID: "dc2-key-wr", 193 Name: "dc2-key-wr", 194 Description: "dc2-key-wr", 195 Rules: `key_prefix "" { policy = "write"}`, 196 Syntax: acl.SyntaxCurrent, 197 Datacenters: []string{"dc2"}, 198 RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, 199 }, nil 200 default: 201 return true, nil, acl.ErrNotFound 202 } 203 } 204 205 // ACLResolverTestDelegate is used to test 206 // the ACLResolver without running Agents 207 type ACLResolverTestDelegate struct { 208 enabled bool 209 datacenter string 210 legacy bool 211 localTokens bool 212 localPolicies bool 213 getPolicyFn func(*structs.ACLPolicyResolveLegacyRequest, *structs.ACLPolicyResolveLegacyResponse) error 214 tokenReadFn func(*structs.ACLTokenGetRequest, *structs.ACLTokenResponse) error 215 policyResolveFn func(*structs.ACLPolicyBatchGetRequest, *structs.ACLPolicyBatchResponse) error 216 } 217 218 func (d *ACLResolverTestDelegate) ACLsEnabled() bool { 219 return d.enabled 220 } 221 222 func (d *ACLResolverTestDelegate) ACLDatacenter(legacy bool) string { 223 return d.datacenter 224 } 225 226 func (d *ACLResolverTestDelegate) UseLegacyACLs() bool { 227 return d.legacy 228 } 229 230 func (d *ACLResolverTestDelegate) ResolveIdentityFromToken(token string) (bool, structs.ACLIdentity, error) { 231 if !d.localTokens { 232 return false, nil, nil 233 } 234 235 return testIdentityForToken(token) 236 } 237 238 func (d *ACLResolverTestDelegate) ResolvePolicyFromID(policyID string) (bool, *structs.ACLPolicy, error) { 239 if !d.localPolicies { 240 return false, nil, nil 241 } 242 243 return testPolicyForID(policyID) 244 } 245 246 func (d *ACLResolverTestDelegate) RPC(method string, args interface{}, reply interface{}) error { 247 switch method { 248 case "ACL.GetPolicy": 249 if d.getPolicyFn != nil { 250 return d.getPolicyFn(args.(*structs.ACLPolicyResolveLegacyRequest), reply.(*structs.ACLPolicyResolveLegacyResponse)) 251 } 252 panic("Bad Test Implmentation: should provide a getPolicyFn to the ACLResolverTestDelegate") 253 case "ACL.TokenRead": 254 if d.tokenReadFn != nil { 255 return d.tokenReadFn(args.(*structs.ACLTokenGetRequest), reply.(*structs.ACLTokenResponse)) 256 } 257 panic("Bad Test Implmentation: should provide a tokenReadFn to the ACLResolverTestDelegate") 258 case "ACL.PolicyResolve": 259 if d.policyResolveFn != nil { 260 return d.policyResolveFn(args.(*structs.ACLPolicyBatchGetRequest), reply.(*structs.ACLPolicyBatchResponse)) 261 } 262 panic("Bad Test Implmentation: should provide a policyResolveFn to the ACLResolverTestDelegate") 263 } 264 panic("Bad Test Implementation: Was the ACLResolver updated to use new RPC methods") 265 } 266 267 func newTestACLResolver(t *testing.T, delegate ACLResolverDelegate, cb func(*ACLResolverConfig)) *ACLResolver { 268 config := DefaultConfig() 269 config.ACLDefaultPolicy = "deny" 270 config.ACLDownPolicy = "extend-cache" 271 rconf := &ACLResolverConfig{ 272 Config: config, 273 Logger: log.New(os.Stdout, t.Name()+" - ", log.LstdFlags|log.Lmicroseconds), 274 CacheConfig: &structs.ACLCachesConfig{ 275 Identities: 4, 276 Policies: 4, 277 ParsedPolicies: 4, 278 Authorizers: 4, 279 }, 280 AutoDisable: true, 281 Delegate: delegate, 282 } 283 284 if cb != nil { 285 cb(rconf) 286 } 287 288 resolver, err := NewACLResolver(rconf) 289 require.NoError(t, err) 290 return resolver 291 } 292 293 func TestACLResolver_Disabled(t *testing.T) { 294 t.Parallel() 295 296 delegate := &ACLResolverTestDelegate{ 297 enabled: false, 298 datacenter: "dc1", 299 legacy: false, 300 } 301 302 r := newTestACLResolver(t, delegate, nil) 303 304 authz, err := r.ResolveToken("does not exist") 305 require.Nil(t, authz) 306 require.Nil(t, err) 307 } 308 309 func TestACLResolver_ResolveRootACL(t *testing.T) { 310 t.Parallel() 311 delegate := &ACLResolverTestDelegate{ 312 enabled: true, 313 datacenter: "dc1", 314 legacy: false, 315 } 316 r := newTestACLResolver(t, delegate, nil) 317 318 t.Run("Allow", func(t *testing.T) { 319 authz, err := r.ResolveToken("allow") 320 require.Nil(t, authz) 321 require.Error(t, err) 322 require.True(t, acl.IsErrRootDenied(err)) 323 }) 324 325 t.Run("Deny", func(t *testing.T) { 326 authz, err := r.ResolveToken("deny") 327 require.Nil(t, authz) 328 require.Error(t, err) 329 require.True(t, acl.IsErrRootDenied(err)) 330 }) 331 332 t.Run("Manage", func(t *testing.T) { 333 authz, err := r.ResolveToken("manage") 334 require.Nil(t, authz) 335 require.Error(t, err) 336 require.True(t, acl.IsErrRootDenied(err)) 337 }) 338 } 339 340 func TestACLResolver_DownPolicy(t *testing.T) { 341 t.Parallel() 342 343 requireIdentityCached := func(t *testing.T, r *ACLResolver, token string, present bool, msg string) { 344 t.Helper() 345 346 cacheVal := r.cache.GetIdentity(token) 347 require.NotNil(t, cacheVal) 348 if present { 349 require.NotNil(t, cacheVal.Identity, msg) 350 } else { 351 require.Nil(t, cacheVal.Identity, msg) 352 } 353 } 354 requirePolicyCached := func(t *testing.T, r *ACLResolver, policyID string, present bool, msg string) { 355 t.Helper() 356 357 cacheVal := r.cache.GetPolicy(policyID) 358 require.NotNil(t, cacheVal) 359 if present { 360 require.NotNil(t, cacheVal.Policy, msg) 361 } else { 362 require.Nil(t, cacheVal.Policy, msg) 363 } 364 } 365 366 t.Run("Deny", func(t *testing.T) { 367 t.Parallel() 368 delegate := &ACLResolverTestDelegate{ 369 enabled: true, 370 datacenter: "dc1", 371 legacy: false, 372 localTokens: false, 373 localPolicies: true, 374 tokenReadFn: func(*structs.ACLTokenGetRequest, *structs.ACLTokenResponse) error { 375 return fmt.Errorf("Induced RPC Error") 376 }, 377 } 378 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 379 config.Config.ACLDownPolicy = "deny" 380 }) 381 382 authz, err := r.ResolveToken("foo") 383 require.NoError(t, err) 384 require.NotNil(t, authz) 385 require.Equal(t, authz, acl.DenyAll()) 386 387 requireIdentityCached(t, r, "foo", false, "not present") 388 }) 389 390 t.Run("Allow", func(t *testing.T) { 391 t.Parallel() 392 delegate := &ACLResolverTestDelegate{ 393 enabled: true, 394 datacenter: "dc1", 395 legacy: false, 396 localTokens: false, 397 localPolicies: true, 398 tokenReadFn: func(*structs.ACLTokenGetRequest, *structs.ACLTokenResponse) error { 399 return fmt.Errorf("Induced RPC Error") 400 }, 401 } 402 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 403 config.Config.ACLDownPolicy = "allow" 404 }) 405 406 authz, err := r.ResolveToken("foo") 407 require.NoError(t, err) 408 require.NotNil(t, authz) 409 require.Equal(t, authz, acl.AllowAll()) 410 411 requireIdentityCached(t, r, "foo", false, "not present") 412 }) 413 414 t.Run("Expired-Policy", func(t *testing.T) { 415 t.Parallel() 416 policyCached := false 417 delegate := &ACLResolverTestDelegate{ 418 enabled: true, 419 datacenter: "dc1", 420 legacy: false, 421 localTokens: true, 422 localPolicies: false, 423 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 424 if !policyCached { 425 for _, policyID := range args.PolicyIDs { 426 _, policy, _ := testPolicyForID(policyID) 427 if policy != nil { 428 reply.Policies = append(reply.Policies, policy) 429 } 430 } 431 432 policyCached = true 433 return nil 434 } 435 436 return fmt.Errorf("Induced RPC Error") 437 }, 438 } 439 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 440 config.Config.ACLDownPolicy = "deny" 441 config.Config.ACLPolicyTTL = 0 442 }) 443 444 authz, err := r.ResolveToken("found") 445 require.NoError(t, err) 446 require.NotNil(t, authz) 447 require.True(t, authz.NodeWrite("foo", nil)) 448 449 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 450 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 451 452 // policy cache expired - so we will fail to resolve that policy and use the default policy only 453 authz2, err := r.ResolveToken("found") 454 require.NoError(t, err) 455 require.NotNil(t, authz2) 456 require.False(t, authz == authz2) 457 require.False(t, authz2.NodeWrite("foo", nil)) 458 459 requirePolicyCached(t, r, "node-wr", false, "expired") // from "found" token 460 requirePolicyCached(t, r, "dc2-key-wr", false, "expired") // from "found" token 461 }) 462 463 t.Run("Extend-Cache", func(t *testing.T) { 464 t.Parallel() 465 cached := false 466 delegate := &ACLResolverTestDelegate{ 467 enabled: true, 468 datacenter: "dc1", 469 legacy: false, 470 localTokens: false, 471 localPolicies: true, 472 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 473 if !cached { 474 _, token, _ := testIdentityForToken("found") 475 reply.Token = token.(*structs.ACLToken) 476 cached = true 477 return nil 478 } 479 return fmt.Errorf("Induced RPC Error") 480 }, 481 } 482 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 483 config.Config.ACLDownPolicy = "extend-cache" 484 config.Config.ACLTokenTTL = 0 485 }) 486 487 authz, err := r.ResolveToken("foo") 488 require.NoError(t, err) 489 require.NotNil(t, authz) 490 require.True(t, authz.NodeWrite("foo", nil)) 491 492 requireIdentityCached(t, r, "foo", true, "cached") 493 494 authz2, err := r.ResolveToken("foo") 495 require.NoError(t, err) 496 require.NotNil(t, authz2) 497 // testing pointer equality - these will be the same object because it is cached. 498 require.True(t, authz == authz2) 499 require.True(t, authz.NodeWrite("foo", nil)) 500 501 requireIdentityCached(t, r, "foo", true, "still cached") 502 }) 503 504 t.Run("Extend-Cache-Expired-Policy", func(t *testing.T) { 505 t.Parallel() 506 policyCached := false 507 delegate := &ACLResolverTestDelegate{ 508 enabled: true, 509 datacenter: "dc1", 510 legacy: false, 511 localTokens: true, 512 localPolicies: false, 513 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 514 if !policyCached { 515 for _, policyID := range args.PolicyIDs { 516 _, policy, _ := testPolicyForID(policyID) 517 if policy != nil { 518 reply.Policies = append(reply.Policies, policy) 519 } 520 } 521 522 policyCached = true 523 return nil 524 } 525 526 return fmt.Errorf("Induced RPC Error") 527 }, 528 } 529 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 530 config.Config.ACLDownPolicy = "extend-cache" 531 config.Config.ACLPolicyTTL = 0 532 }) 533 534 authz, err := r.ResolveToken("found") 535 require.NoError(t, err) 536 require.NotNil(t, authz) 537 require.True(t, authz.NodeWrite("foo", nil)) 538 539 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 540 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 541 542 // Will just use the policy cache 543 authz2, err := r.ResolveToken("found") 544 require.NoError(t, err) 545 require.NotNil(t, authz2) 546 require.True(t, authz == authz2) 547 require.True(t, authz.NodeWrite("foo", nil)) 548 549 requirePolicyCached(t, r, "node-wr", true, "still cached") // from "found" token 550 requirePolicyCached(t, r, "dc2-key-wr", true, "still cached") // from "found" token 551 }) 552 553 t.Run("Async-Cache-Expired-Policy", func(t *testing.T) { 554 t.Parallel() 555 policyCached := false 556 delegate := &ACLResolverTestDelegate{ 557 enabled: true, 558 datacenter: "dc1", 559 legacy: false, 560 localTokens: true, 561 localPolicies: false, 562 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 563 if !policyCached { 564 for _, policyID := range args.PolicyIDs { 565 _, policy, _ := testPolicyForID(policyID) 566 if policy != nil { 567 reply.Policies = append(reply.Policies, policy) 568 } 569 } 570 571 policyCached = true 572 return nil 573 } 574 575 // We don't need to return acl.ErrNotFound here but we could. The ACLResolver will search for any 576 // policies not in the response and emit an ACL not found for any not-found within the result set. 577 return nil 578 }, 579 } 580 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 581 config.Config.ACLDownPolicy = "async-cache" 582 config.Config.ACLPolicyTTL = 0 583 }) 584 585 authz, err := r.ResolveToken("found") 586 require.NoError(t, err) 587 require.NotNil(t, authz) 588 require.True(t, authz.NodeWrite("foo", nil)) 589 590 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 591 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 592 593 // The identity should have been cached so this should still be valid 594 authz2, err := r.ResolveToken("found") 595 require.NoError(t, err) 596 require.NotNil(t, authz2) 597 // testing pointer equality - these will be the same object because it is cached. 598 require.True(t, authz == authz2) 599 require.True(t, authz.NodeWrite("foo", nil)) 600 601 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 602 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 603 604 // the go routine spawned will eventually return with a authz that doesn't have the policy 605 retry.Run(t, func(t *retry.R) { 606 authz3, err := r.ResolveToken("found") 607 assert.NoError(t, err) 608 assert.NotNil(t, authz3) 609 assert.False(t, authz3.NodeWrite("foo", nil)) 610 }) 611 612 requirePolicyCached(t, r, "node-wr", false, "no longer cached") // from "found" token 613 requirePolicyCached(t, r, "dc2-key-wr", false, "no longer cached") // from "found" token 614 }) 615 616 t.Run("Extend-Cache-Client", func(t *testing.T) { 617 t.Parallel() 618 tokenCached := false 619 policyCached := false 620 delegate := &ACLResolverTestDelegate{ 621 enabled: true, 622 datacenter: "dc1", 623 legacy: false, 624 localTokens: false, 625 localPolicies: false, 626 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 627 if !tokenCached { 628 _, token, _ := testIdentityForToken("found") 629 reply.Token = token.(*structs.ACLToken) 630 tokenCached = true 631 return nil 632 } 633 return fmt.Errorf("Induced RPC Error") 634 }, 635 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 636 if !policyCached { 637 for _, policyID := range args.PolicyIDs { 638 _, policy, _ := testPolicyForID(policyID) 639 if policy != nil { 640 reply.Policies = append(reply.Policies, policy) 641 } 642 } 643 644 policyCached = true 645 return nil 646 } 647 648 return fmt.Errorf("Induced RPC Error") 649 }, 650 } 651 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 652 config.Config.ACLDownPolicy = "extend-cache" 653 config.Config.ACLTokenTTL = 0 654 config.Config.ACLPolicyTTL = 0 655 }) 656 657 authz, err := r.ResolveToken("found") 658 require.NoError(t, err) 659 require.NotNil(t, authz) 660 require.True(t, authz.NodeWrite("foo", nil)) 661 662 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 663 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 664 665 authz2, err := r.ResolveToken("found") 666 require.NoError(t, err) 667 require.NotNil(t, authz2) 668 // testing pointer equality - these will be the same object because it is cached. 669 require.True(t, authz == authz2) 670 require.True(t, authz.NodeWrite("foo", nil)) 671 672 requirePolicyCached(t, r, "node-wr", true, "still cached") // from "found" token 673 requirePolicyCached(t, r, "dc2-key-wr", true, "still cached") // from "found" token 674 }) 675 676 t.Run("Async-Cache", func(t *testing.T) { 677 t.Parallel() 678 cached := false 679 delegate := &ACLResolverTestDelegate{ 680 enabled: true, 681 datacenter: "dc1", 682 legacy: false, 683 localTokens: false, 684 localPolicies: true, 685 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 686 if !cached { 687 _, token, _ := testIdentityForToken("found") 688 reply.Token = token.(*structs.ACLToken) 689 cached = true 690 return nil 691 } 692 return acl.ErrNotFound 693 }, 694 } 695 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 696 config.Config.ACLDownPolicy = "async-cache" 697 config.Config.ACLTokenTTL = 0 698 }) 699 700 authz, err := r.ResolveToken("foo") 701 require.NoError(t, err) 702 require.NotNil(t, authz) 703 require.True(t, authz.NodeWrite("foo", nil)) 704 705 requireIdentityCached(t, r, "foo", true, "cached") 706 707 // The identity should have been cached so this should still be valid 708 authz2, err := r.ResolveToken("foo") 709 require.NoError(t, err) 710 require.NotNil(t, authz2) 711 // testing pointer equality - these will be the same object because it is cached. 712 require.True(t, authz == authz2) 713 require.True(t, authz.NodeWrite("foo", nil)) 714 715 requireIdentityCached(t, r, "foo", true, "cached") 716 717 // the go routine spawned will eventually return and this will be a not found error 718 retry.Run(t, func(t *retry.R) { 719 authz3, err := r.ResolveToken("foo") 720 assert.Error(t, err) 721 assert.True(t, acl.IsErrNotFound(err)) 722 assert.Nil(t, authz3) 723 }) 724 725 requireIdentityCached(t, r, "foo", false, "no longer cached") 726 }) 727 728 t.Run("PolicyResolve-TokenNotFound", func(t *testing.T) { 729 t.Parallel() 730 731 _, rawToken, _ := testIdentityForToken("found") 732 foundToken := rawToken.(*structs.ACLToken) 733 secretID := foundToken.SecretID 734 735 tokenResolved := false 736 policyResolved := false 737 delegate := &ACLResolverTestDelegate{ 738 enabled: true, 739 datacenter: "dc1", 740 legacy: false, 741 localTokens: false, 742 localPolicies: false, 743 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 744 if !tokenResolved { 745 reply.Token = foundToken 746 tokenResolved = true 747 return nil 748 } 749 750 return fmt.Errorf("Not Supposed to be Invoked again") 751 }, 752 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 753 if !policyResolved { 754 for _, policyID := range args.PolicyIDs { 755 _, policy, _ := testPolicyForID(policyID) 756 if policy != nil { 757 reply.Policies = append(reply.Policies, policy) 758 } 759 } 760 policyResolved = true 761 return nil 762 } 763 return acl.ErrNotFound // test condition 764 }, 765 } 766 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 767 config.Config.ACLDownPolicy = "extend-cache" 768 config.Config.ACLTokenTTL = 0 769 config.Config.ACLPolicyTTL = 0 770 }) 771 772 // Prime the standard caches. 773 authz, err := r.ResolveToken(secretID) 774 require.NoError(t, err) 775 require.NotNil(t, authz) 776 require.True(t, authz.NodeWrite("foo", nil)) 777 778 // Verify that the caches are setup properly. 779 requireIdentityCached(t, r, secretID, true, "cached") 780 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 781 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 782 783 // Nuke 1 policy from the cache so that we force a policy resolve 784 // during token resolve. 785 r.cache.RemovePolicy("dc2-key-wr") 786 787 _, err = r.ResolveToken(secretID) 788 require.True(t, acl.IsErrNotFound(err)) 789 790 requireIdentityCached(t, r, secretID, false, "identity not found cached") 791 requirePolicyCached(t, r, "node-wr", true, "still cached") 792 require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all") 793 }) 794 795 t.Run("PolicyResolve-PermissionDenied", func(t *testing.T) { 796 t.Parallel() 797 798 _, rawToken, _ := testIdentityForToken("found") 799 foundToken := rawToken.(*structs.ACLToken) 800 secretID := foundToken.SecretID 801 802 policyResolved := false 803 delegate := &ACLResolverTestDelegate{ 804 enabled: true, 805 datacenter: "dc1", 806 legacy: false, 807 localTokens: false, 808 localPolicies: false, 809 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 810 // no limit 811 reply.Token = foundToken 812 return nil 813 }, 814 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 815 if !policyResolved { 816 for _, policyID := range args.PolicyIDs { 817 _, policy, _ := testPolicyForID(policyID) 818 if policy != nil { 819 reply.Policies = append(reply.Policies, policy) 820 } 821 } 822 policyResolved = true 823 return nil 824 } 825 return acl.ErrPermissionDenied // test condition 826 }, 827 } 828 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 829 config.Config.ACLDownPolicy = "extend-cache" 830 config.Config.ACLTokenTTL = 0 831 config.Config.ACLPolicyTTL = 0 832 }) 833 834 // Prime the standard caches. 835 authz, err := r.ResolveToken(secretID) 836 require.NoError(t, err) 837 require.NotNil(t, authz) 838 require.True(t, authz.NodeWrite("foo", nil)) 839 840 // Verify that the caches are setup properly. 841 requireIdentityCached(t, r, secretID, true, "cached") 842 requirePolicyCached(t, r, "node-wr", true, "cached") // from "found" token 843 requirePolicyCached(t, r, "dc2-key-wr", true, "cached") // from "found" token 844 845 // Nuke 1 policy from the cache so that we force a policy resolve 846 // during token resolve. 847 r.cache.RemovePolicy("dc2-key-wr") 848 849 _, err = r.ResolveToken(secretID) 850 require.True(t, acl.IsErrPermissionDenied(err)) 851 852 require.Nil(t, r.cache.GetIdentity(secretID), "identity not stored at all") 853 requirePolicyCached(t, r, "node-wr", true, "still cached") 854 require.Nil(t, r.cache.GetPolicy("dc2-key-wr"), "not stored at all") 855 }) 856 } 857 858 func TestACLResolver_DatacenterScoping(t *testing.T) { 859 t.Parallel() 860 t.Run("dc1", func(t *testing.T) { 861 delegate := &ACLResolverTestDelegate{ 862 enabled: true, 863 datacenter: "dc1", 864 legacy: false, 865 localTokens: true, 866 localPolicies: true, 867 // No need to provide any of the RPC callbacks 868 } 869 r := newTestACLResolver(t, delegate, nil) 870 871 authz, err := r.ResolveToken("found") 872 require.NotNil(t, authz) 873 require.NoError(t, err) 874 require.False(t, authz.ACLRead()) 875 require.True(t, authz.NodeWrite("foo", nil)) 876 require.False(t, authz.KeyWrite("foo", nil)) 877 }) 878 879 t.Run("dc2", func(t *testing.T) { 880 delegate := &ACLResolverTestDelegate{ 881 enabled: true, 882 datacenter: "dc2", 883 legacy: false, 884 localTokens: true, 885 localPolicies: true, 886 // No need to provide any of the RPC callbacks 887 } 888 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 889 config.Config.Datacenter = "dc2" 890 }) 891 892 authz, err := r.ResolveToken("found") 893 require.NotNil(t, authz) 894 require.NoError(t, err) 895 require.False(t, authz.ACLRead()) 896 require.False(t, authz.NodeWrite("foo", nil)) 897 require.True(t, authz.KeyWrite("foo", nil)) 898 }) 899 } 900 901 func TestACLResolver_Client(t *testing.T) { 902 t.Parallel() 903 904 t.Run("Racey-Token-Mod-Policy-Resolve", func(t *testing.T) { 905 t.Parallel() 906 var tokenReads int32 907 var policyResolves int32 908 modified := false 909 deleted := false 910 delegate := &ACLResolverTestDelegate{ 911 enabled: true, 912 datacenter: "dc1", 913 legacy: false, 914 localTokens: false, 915 localPolicies: false, 916 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 917 atomic.AddInt32(&tokenReads, 1) 918 if deleted { 919 return acl.ErrNotFound 920 } else if modified { 921 _, token, _ := testIdentityForToken("racey-modified") 922 reply.Token = token.(*structs.ACLToken) 923 } else { 924 _, token, _ := testIdentityForToken("racey-unmodified") 925 reply.Token = token.(*structs.ACLToken) 926 } 927 return nil 928 }, 929 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 930 atomic.AddInt32(&policyResolves, 1) 931 if deleted { 932 return acl.ErrNotFound 933 } else if !modified { 934 modified = true 935 return acl.ErrPermissionDenied 936 } else { 937 deleted = true 938 for _, policyID := range args.PolicyIDs { 939 _, policy, _ := testPolicyForID(policyID) 940 if policy != nil { 941 reply.Policies = append(reply.Policies, policy) 942 } 943 } 944 945 modified = true 946 return nil 947 } 948 }, 949 } 950 951 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 952 config.Config.ACLTokenTTL = 600 * time.Second 953 config.Config.ACLPolicyTTL = 30 * time.Millisecond 954 config.Config.ACLDownPolicy = "extend-cache" 955 }) 956 957 // resolves the token 958 // gets a permission denied resolving the policies - token updated 959 // invalidates the token 960 // refetches the token 961 // fetches the policies from the modified token 962 // creates the authorizers 963 // 964 // Must use the token secret here in order for the cached identity 965 // to be removed properly. Many other tests just resolve some other 966 // random name and it wont matter but this one cannot. 967 authz, err := r.ResolveToken("a1a54629-5050-4d17-8a4e-560d2423f835") 968 require.NoError(t, err) 969 require.NotNil(t, authz) 970 require.True(t, authz.NodeWrite("foo", nil)) 971 require.False(t, authz.ACLRead()) 972 require.True(t, modified) 973 require.True(t, deleted) 974 require.Equal(t, int32(2), tokenReads) 975 require.Equal(t, int32(2), policyResolves) 976 977 // sleep long enough for the policy cache to expire 978 time.Sleep(50 * time.Millisecond) 979 980 // this round the identity will be resolved from the cache 981 // then the policy will be resolved but resolution will return ACL not found 982 // resolution will stop with the not found error (even though we still have the 983 // policies within the cache) 984 authz, err = r.ResolveToken("a1a54629-5050-4d17-8a4e-560d2423f835") 985 require.EqualError(t, err, acl.ErrNotFound.Error()) 986 require.Nil(t, authz) 987 988 require.True(t, modified) 989 require.True(t, deleted) 990 require.Equal(t, tokenReads, int32(2)) 991 require.Equal(t, policyResolves, int32(3)) 992 }) 993 994 t.Run("Concurrent-Token-Resolve", func(t *testing.T) { 995 t.Parallel() 996 997 var tokenReads int32 998 var policyResolves int32 999 readyCh := make(chan struct{}) 1000 1001 delegate := &ACLResolverTestDelegate{ 1002 enabled: true, 1003 datacenter: "dc1", 1004 legacy: false, 1005 localTokens: false, 1006 localPolicies: false, 1007 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 1008 atomic.AddInt32(&tokenReads, 1) 1009 1010 switch args.TokenID { 1011 case "a1a54629-5050-4d17-8a4e-560d2423f835": 1012 _, token, _ := testIdentityForToken("concurrent-resolve") 1013 reply.Token = token.(*structs.ACLToken) 1014 default: 1015 return acl.ErrNotFound 1016 } 1017 1018 select { 1019 case <-readyCh: 1020 } 1021 time.Sleep(100 * time.Millisecond) 1022 return nil 1023 }, 1024 policyResolveFn: func(args *structs.ACLPolicyBatchGetRequest, reply *structs.ACLPolicyBatchResponse) error { 1025 atomic.AddInt32(&policyResolves, 1) 1026 1027 for _, policyID := range args.PolicyIDs { 1028 _, policy, _ := testPolicyForID(policyID) 1029 if policy != nil { 1030 reply.Policies = append(reply.Policies, policy) 1031 } 1032 } 1033 return nil 1034 }, 1035 } 1036 1037 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 1038 // effectively disable caching - so the only way we end up with 1 token read is if they were 1039 // being resolved concurrently 1040 config.Config.ACLTokenTTL = 0 * time.Second 1041 config.Config.ACLPolicyTTL = 30 * time.Millisecond 1042 config.Config.ACLDownPolicy = "extend-cache" 1043 }) 1044 1045 ch1 := make(chan *asyncResolutionResult) 1046 ch2 := make(chan *asyncResolutionResult) 1047 go resolveTokenAsync(r, "a1a54629-5050-4d17-8a4e-560d2423f835", ch1) 1048 go resolveTokenAsync(r, "a1a54629-5050-4d17-8a4e-560d2423f835", ch2) 1049 close(readyCh) 1050 1051 res1 := <-ch1 1052 res2 := <-ch2 1053 require.NoError(t, res1.err) 1054 require.NoError(t, res2.err) 1055 require.Equal(t, res1.authz, res2.authz) 1056 require.Equal(t, int32(1), tokenReads) 1057 require.Equal(t, int32(1), policyResolves) 1058 }) 1059 } 1060 1061 func TestACLResolver_LocalTokensAndPolicies(t *testing.T) { 1062 t.Parallel() 1063 delegate := &ACLResolverTestDelegate{ 1064 enabled: true, 1065 datacenter: "dc1", 1066 legacy: false, 1067 localTokens: true, 1068 localPolicies: true, 1069 // No need to provide any of the RPC callbacks 1070 } 1071 r := newTestACLResolver(t, delegate, nil) 1072 1073 t.Run("Missing Identity", func(t *testing.T) { 1074 authz, err := r.ResolveToken("doesn't exist") 1075 require.Nil(t, authz) 1076 require.Error(t, err) 1077 require.True(t, acl.IsErrNotFound(err)) 1078 }) 1079 1080 t.Run("Missing Policy", func(t *testing.T) { 1081 authz, err := r.ResolveToken("missing-policy") 1082 require.NoError(t, err) 1083 require.NotNil(t, authz) 1084 require.True(t, authz.ACLRead()) 1085 require.False(t, authz.NodeWrite("foo", nil)) 1086 }) 1087 1088 t.Run("Normal", func(t *testing.T) { 1089 authz, err := r.ResolveToken("found") 1090 require.NotNil(t, authz) 1091 require.NoError(t, err) 1092 require.False(t, authz.ACLRead()) 1093 require.True(t, authz.NodeWrite("foo", nil)) 1094 }) 1095 1096 t.Run("Anonymous", func(t *testing.T) { 1097 authz, err := r.ResolveToken("") 1098 require.NotNil(t, authz) 1099 require.NoError(t, err) 1100 require.False(t, authz.ACLRead()) 1101 require.True(t, authz.NodeWrite("foo", nil)) 1102 }) 1103 1104 t.Run("legacy-management", func(t *testing.T) { 1105 authz, err := r.ResolveToken("legacy-management") 1106 require.NotNil(t, authz) 1107 require.NoError(t, err) 1108 require.True(t, authz.ACLWrite()) 1109 require.True(t, authz.KeyRead("foo")) 1110 }) 1111 1112 t.Run("legacy-client", func(t *testing.T) { 1113 authz, err := r.ResolveToken("legacy-client") 1114 require.NoError(t, err) 1115 require.NotNil(t, authz) 1116 require.False(t, authz.OperatorRead()) 1117 require.True(t, authz.ServiceRead("foo")) 1118 }) 1119 } 1120 1121 func TestACLResolver_LocalPolicies(t *testing.T) { 1122 t.Parallel() 1123 delegate := &ACLResolverTestDelegate{ 1124 enabled: true, 1125 datacenter: "dc1", 1126 legacy: false, 1127 localTokens: false, 1128 localPolicies: true, 1129 tokenReadFn: func(args *structs.ACLTokenGetRequest, reply *structs.ACLTokenResponse) error { 1130 _, token, err := testIdentityForToken(args.TokenID) 1131 1132 if token != nil { 1133 reply.Token = token.(*structs.ACLToken) 1134 } 1135 return err 1136 }, 1137 } 1138 r := newTestACLResolver(t, delegate, nil) 1139 1140 t.Run("Missing Identity", func(t *testing.T) { 1141 authz, err := r.ResolveToken("doesn't exist") 1142 require.Nil(t, authz) 1143 require.Error(t, err) 1144 require.True(t, acl.IsErrNotFound(err)) 1145 }) 1146 1147 t.Run("Missing Policy", func(t *testing.T) { 1148 authz, err := r.ResolveToken("missing-policy") 1149 require.NoError(t, err) 1150 require.NotNil(t, authz) 1151 require.True(t, authz.ACLRead()) 1152 require.False(t, authz.NodeWrite("foo", nil)) 1153 }) 1154 1155 t.Run("Normal", func(t *testing.T) { 1156 authz, err := r.ResolveToken("found") 1157 require.NotNil(t, authz) 1158 require.NoError(t, err) 1159 require.False(t, authz.ACLRead()) 1160 require.True(t, authz.NodeWrite("foo", nil)) 1161 }) 1162 1163 t.Run("Anonymous", func(t *testing.T) { 1164 authz, err := r.ResolveToken("") 1165 require.NotNil(t, authz) 1166 require.NoError(t, err) 1167 require.False(t, authz.ACLRead()) 1168 require.True(t, authz.NodeWrite("foo", nil)) 1169 }) 1170 1171 t.Run("legacy-management", func(t *testing.T) { 1172 authz, err := r.ResolveToken("legacy-management") 1173 require.NotNil(t, authz) 1174 require.NoError(t, err) 1175 require.True(t, authz.ACLWrite()) 1176 require.True(t, authz.KeyRead("foo")) 1177 }) 1178 1179 t.Run("legacy-client", func(t *testing.T) { 1180 authz, err := r.ResolveToken("legacy-client") 1181 require.NoError(t, err) 1182 require.NotNil(t, authz) 1183 require.False(t, authz.OperatorRead()) 1184 require.True(t, authz.ServiceRead("foo")) 1185 }) 1186 } 1187 1188 func TestACLResolver_Legacy(t *testing.T) { 1189 t.Parallel() 1190 1191 t.Run("Cached", func(t *testing.T) { 1192 t.Parallel() 1193 cached := false 1194 delegate := &ACLResolverTestDelegate{ 1195 enabled: true, 1196 datacenter: "dc1", 1197 legacy: true, 1198 localTokens: false, 1199 localPolicies: false, 1200 getPolicyFn: func(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error { 1201 if !cached { 1202 reply.Parent = "deny" 1203 reply.TTL = 30 1204 reply.ETag = "nothing" 1205 reply.Policy = &acl.Policy{ 1206 ID: "not-needed", 1207 Nodes: []*acl.NodePolicy{ 1208 &acl.NodePolicy{ 1209 Name: "foo", 1210 Policy: acl.PolicyWrite, 1211 }, 1212 }, 1213 } 1214 cached = true 1215 return nil 1216 } 1217 return fmt.Errorf("Induced RPC Error") 1218 }, 1219 } 1220 r := newTestACLResolver(t, delegate, nil) 1221 1222 authz, err := r.ResolveToken("foo") 1223 require.NoError(t, err) 1224 require.NotNil(t, authz) 1225 // there is a bit of translation that happens 1226 require.True(t, authz.NodeWrite("foo", nil)) 1227 require.True(t, authz.NodeWrite("foo/bar", nil)) 1228 require.False(t, authz.NodeWrite("fo", nil)) 1229 1230 // this should be from the cache 1231 authz, err = r.ResolveToken("foo") 1232 require.NoError(t, err) 1233 require.NotNil(t, authz) 1234 // there is a bit of translation that happens 1235 require.True(t, authz.NodeWrite("foo", nil)) 1236 require.True(t, authz.NodeWrite("foo/bar", nil)) 1237 require.False(t, authz.NodeWrite("fo", nil)) 1238 }) 1239 1240 t.Run("Cache-Expiry-Extend", func(t *testing.T) { 1241 t.Parallel() 1242 cached := false 1243 delegate := &ACLResolverTestDelegate{ 1244 enabled: true, 1245 datacenter: "dc1", 1246 legacy: true, 1247 localTokens: false, 1248 localPolicies: false, 1249 getPolicyFn: func(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error { 1250 if !cached { 1251 reply.Parent = "deny" 1252 reply.TTL = 0 1253 reply.ETag = "nothing" 1254 reply.Policy = &acl.Policy{ 1255 ID: "not-needed", 1256 Nodes: []*acl.NodePolicy{ 1257 &acl.NodePolicy{ 1258 Name: "foo", 1259 Policy: acl.PolicyWrite, 1260 }, 1261 }, 1262 } 1263 cached = true 1264 return nil 1265 } 1266 return fmt.Errorf("Induced RPC Error") 1267 }, 1268 } 1269 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 1270 config.Config.ACLTokenTTL = 0 1271 }) 1272 1273 authz, err := r.ResolveToken("foo") 1274 require.NoError(t, err) 1275 require.NotNil(t, authz) 1276 // there is a bit of translation that happens 1277 require.True(t, authz.NodeWrite("foo", nil)) 1278 require.True(t, authz.NodeWrite("foo/bar", nil)) 1279 require.False(t, authz.NodeWrite("fo", nil)) 1280 1281 // this should be from the cache 1282 authz, err = r.ResolveToken("foo") 1283 require.NoError(t, err) 1284 require.NotNil(t, authz) 1285 // there is a bit of translation that happens 1286 require.True(t, authz.NodeWrite("foo", nil)) 1287 require.True(t, authz.NodeWrite("foo/bar", nil)) 1288 require.False(t, authz.NodeWrite("fo", nil)) 1289 }) 1290 1291 t.Run("Cache-Expiry-Allow", func(t *testing.T) { 1292 t.Parallel() 1293 cached := false 1294 delegate := &ACLResolverTestDelegate{ 1295 enabled: true, 1296 datacenter: "dc1", 1297 legacy: true, 1298 localTokens: false, 1299 localPolicies: false, 1300 getPolicyFn: func(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error { 1301 if !cached { 1302 reply.Parent = "deny" 1303 reply.TTL = 0 1304 reply.ETag = "nothing" 1305 reply.Policy = &acl.Policy{ 1306 ID: "not-needed", 1307 Nodes: []*acl.NodePolicy{ 1308 &acl.NodePolicy{ 1309 Name: "foo", 1310 Policy: acl.PolicyWrite, 1311 }, 1312 }, 1313 } 1314 cached = true 1315 return nil 1316 } 1317 return fmt.Errorf("Induced RPC Error") 1318 }, 1319 } 1320 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 1321 config.Config.ACLDownPolicy = "allow" 1322 config.Config.ACLTokenTTL = 0 1323 }) 1324 1325 authz, err := r.ResolveToken("foo") 1326 require.NoError(t, err) 1327 require.NotNil(t, authz) 1328 // there is a bit of translation that happens 1329 require.True(t, authz.NodeWrite("foo", nil)) 1330 require.True(t, authz.NodeWrite("foo/bar", nil)) 1331 require.False(t, authz.NodeWrite("fo", nil)) 1332 1333 // this should be from the cache 1334 authz, err = r.ResolveToken("foo") 1335 require.NoError(t, err) 1336 require.NotNil(t, authz) 1337 // there is a bit of translation that happens 1338 require.True(t, authz.NodeWrite("foo", nil)) 1339 require.True(t, authz.NodeWrite("foo/bar", nil)) 1340 require.True(t, authz.NodeWrite("fo", nil)) 1341 }) 1342 1343 t.Run("Cache-Expiry-Deny", func(t *testing.T) { 1344 t.Parallel() 1345 cached := false 1346 delegate := &ACLResolverTestDelegate{ 1347 enabled: true, 1348 datacenter: "dc1", 1349 legacy: true, 1350 localTokens: false, 1351 localPolicies: false, 1352 getPolicyFn: func(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error { 1353 if !cached { 1354 reply.Parent = "deny" 1355 reply.TTL = 0 1356 reply.ETag = "nothing" 1357 reply.Policy = &acl.Policy{ 1358 ID: "not-needed", 1359 Nodes: []*acl.NodePolicy{ 1360 &acl.NodePolicy{ 1361 Name: "foo", 1362 Policy: acl.PolicyWrite, 1363 }, 1364 }, 1365 } 1366 cached = true 1367 return nil 1368 } 1369 return fmt.Errorf("Induced RPC Error") 1370 }, 1371 } 1372 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 1373 config.Config.ACLDownPolicy = "deny" 1374 config.Config.ACLTokenTTL = 0 1375 }) 1376 1377 authz, err := r.ResolveToken("foo") 1378 require.NoError(t, err) 1379 require.NotNil(t, authz) 1380 // there is a bit of translation that happens 1381 require.True(t, authz.NodeWrite("foo", nil)) 1382 require.True(t, authz.NodeWrite("foo/bar", nil)) 1383 require.False(t, authz.NodeWrite("fo", nil)) 1384 1385 // this should be from the cache 1386 authz, err = r.ResolveToken("foo") 1387 require.NoError(t, err) 1388 require.NotNil(t, authz) 1389 // there is a bit of translation that happens 1390 require.False(t, authz.NodeWrite("foo", nil)) 1391 require.False(t, authz.NodeWrite("foo/bar", nil)) 1392 require.False(t, authz.NodeWrite("fo", nil)) 1393 }) 1394 1395 t.Run("Cache-Expiry-Async-Cache", func(t *testing.T) { 1396 t.Parallel() 1397 cached := false 1398 delegate := &ACLResolverTestDelegate{ 1399 enabled: true, 1400 datacenter: "dc1", 1401 legacy: true, 1402 localTokens: false, 1403 localPolicies: false, 1404 getPolicyFn: func(args *structs.ACLPolicyResolveLegacyRequest, reply *structs.ACLPolicyResolveLegacyResponse) error { 1405 if !cached { 1406 reply.Parent = "deny" 1407 reply.TTL = 0 1408 reply.ETag = "nothing" 1409 reply.Policy = &acl.Policy{ 1410 ID: "not-needed", 1411 Nodes: []*acl.NodePolicy{ 1412 &acl.NodePolicy{ 1413 Name: "foo", 1414 Policy: acl.PolicyWrite, 1415 }, 1416 }, 1417 } 1418 cached = true 1419 return nil 1420 } 1421 return acl.ErrNotFound 1422 }, 1423 } 1424 r := newTestACLResolver(t, delegate, func(config *ACLResolverConfig) { 1425 config.Config.ACLDownPolicy = "async-cache" 1426 config.Config.ACLTokenTTL = 0 1427 }) 1428 1429 authz, err := r.ResolveToken("foo") 1430 require.NoError(t, err) 1431 require.NotNil(t, authz) 1432 // there is a bit of translation that happens 1433 require.True(t, authz.NodeWrite("foo", nil)) 1434 require.True(t, authz.NodeWrite("foo/bar", nil)) 1435 require.False(t, authz.NodeWrite("fo", nil)) 1436 1437 // delivered from the cache 1438 authz2, err := r.ResolveToken("foo") 1439 require.NoError(t, err) 1440 require.NotNil(t, authz) 1441 require.True(t, authz == authz2) 1442 1443 // the go routine spawned will eventually return and this will be a not found error 1444 retry.Run(t, func(t *retry.R) { 1445 authz3, err := r.ResolveToken("foo") 1446 assert.Error(t, err) 1447 assert.True(t, acl.IsErrNotFound(err)) 1448 assert.Nil(t, authz3) 1449 }) 1450 }) 1451 } 1452 1453 /* 1454 1455 func TestACL_Replication(t *testing.T) { 1456 t.Parallel() 1457 aclExtendPolicies := []string{"extend-cache", "async-cache"} //"async-cache" 1458 1459 for _, aclDownPolicy := range aclExtendPolicies { 1460 dir1, s1 := testServerWithConfig(t, func(c *Config) { 1461 c.ACLDatacenter = "dc1" 1462 c.ACLMasterToken = "root" 1463 }) 1464 defer os.RemoveAll(dir1) 1465 defer s1.Shutdown() 1466 client := rpcClient(t, s1) 1467 defer client.Close() 1468 1469 dir2, s2 := testServerWithConfig(t, func(c *Config) { 1470 c.Datacenter = "dc2" 1471 c.ACLDatacenter = "dc1" 1472 c.ACLDefaultPolicy = "deny" 1473 c.ACLDownPolicy = aclDownPolicy 1474 c.ACLTokenReplication = true 1475 c.ACLReplicationRate = 100 1476 c.ACLReplicationBurst = 100 1477 c.ACLReplicationApplyLimit = 1000000 1478 }) 1479 s2.tokens.UpdateReplicationToken("root") 1480 defer os.RemoveAll(dir2) 1481 defer s2.Shutdown() 1482 1483 dir3, s3 := testServerWithConfig(t, func(c *Config) { 1484 c.Datacenter = "dc3" 1485 c.ACLDatacenter = "dc1" 1486 c.ACLDownPolicy = "deny" 1487 c.ACLTokenReplication = true 1488 c.ACLReplicationRate = 100 1489 c.ACLReplicationBurst = 100 1490 c.ACLReplicationApplyLimit = 1000000 1491 }) 1492 s3.tokens.UpdateReplicationToken("root") 1493 defer os.RemoveAll(dir3) 1494 defer s3.Shutdown() 1495 1496 // Try to join. 1497 joinWAN(t, s2, s1) 1498 joinWAN(t, s3, s1) 1499 testrpc.WaitForLeader(t, s1.RPC, "dc1") 1500 testrpc.WaitForLeader(t, s1.RPC, "dc2") 1501 testrpc.WaitForLeader(t, s1.RPC, "dc3") 1502 1503 // Create a new token. 1504 arg := structs.ACLRequest{ 1505 Datacenter: "dc1", 1506 Op: structs.ACLSet, 1507 ACL: structs.ACL{ 1508 Name: "User token", 1509 Type: structs.ACLTokenTypeClient, 1510 Rules: testACLPolicy, 1511 }, 1512 WriteRequest: structs.WriteRequest{Token: "root"}, 1513 } 1514 var id string 1515 if err := s1.RPC("ACL.Apply", &arg, &id); err != nil { 1516 t.Fatalf("err: %v", err) 1517 } 1518 // Wait for replication to occur. 1519 retry.Run(t, func(r *retry.R) { 1520 _, acl, err := s2.fsm.State().ACLTokenGetBySecret(nil, id) 1521 if err != nil { 1522 r.Fatal(err) 1523 } 1524 if acl == nil { 1525 r.Fatal(nil) 1526 } 1527 _, acl, err = s3.fsm.State().ACLTokenGetBySecret(nil, id) 1528 if err != nil { 1529 r.Fatal(err) 1530 } 1531 if acl == nil { 1532 r.Fatal(nil) 1533 } 1534 }) 1535 1536 // Kill the ACL datacenter. 1537 s1.Shutdown() 1538 1539 // Token should resolve on s2, which has replication + extend-cache. 1540 acl, err := s2.ResolveToken(id) 1541 if err != nil { 1542 t.Fatalf("err: %v", err) 1543 } 1544 if acl == nil { 1545 t.Fatalf("missing acl") 1546 } 1547 1548 // Check the policy 1549 if acl.KeyRead("bar") { 1550 t.Fatalf("unexpected read") 1551 } 1552 if !acl.KeyRead("foo/test") { 1553 t.Fatalf("unexpected failed read") 1554 } 1555 1556 // Although s3 has replication, and we verified that the ACL is there, 1557 // it can not be used because of the down policy. 1558 acl, err = s3.ResolveToken(id) 1559 if err != nil { 1560 t.Fatalf("err: %v", err) 1561 } 1562 if acl == nil { 1563 t.Fatalf("missing acl") 1564 } 1565 1566 // Check the policy. 1567 if acl.KeyRead("bar") { 1568 t.Fatalf("unexpected read") 1569 } 1570 if acl.KeyRead("foo/test") { 1571 t.Fatalf("unexpected read") 1572 } 1573 } 1574 } 1575 1576 func TestACL_MultiDC_Found(t *testing.T) { 1577 t.Parallel() 1578 dir1, s1 := testServerWithConfig(t, func(c *Config) { 1579 c.ACLDatacenter = "dc1" 1580 c.ACLMasterToken = "root" 1581 }) 1582 defer os.RemoveAll(dir1) 1583 defer s1.Shutdown() 1584 client := rpcClient(t, s1) 1585 defer client.Close() 1586 1587 dir2, s2 := testServerWithConfig(t, func(c *Config) { 1588 c.Datacenter = "dc2" 1589 c.ACLDatacenter = "dc1" // Enable ACLs! 1590 }) 1591 defer os.RemoveAll(dir2) 1592 defer s2.Shutdown() 1593 1594 // Try to join 1595 joinWAN(t, s2, s1) 1596 1597 testrpc.WaitForLeader(t, s1.RPC, "dc1") 1598 testrpc.WaitForLeader(t, s1.RPC, "dc2") 1599 1600 // Create a new token 1601 arg := structs.ACLRequest{ 1602 Datacenter: "dc1", 1603 Op: structs.ACLSet, 1604 ACL: structs.ACL{ 1605 Name: "User token", 1606 Type: structs.ACLTokenTypeClient, 1607 Rules: testACLPolicy, 1608 }, 1609 WriteRequest: structs.WriteRequest{Token: "root"}, 1610 } 1611 var id string 1612 if err := s1.RPC("ACL.Apply", &arg, &id); err != nil { 1613 t.Fatalf("err: %v", err) 1614 } 1615 1616 // Token should resolve 1617 acl, err := s2.ResolveToken(id) 1618 if err != nil { 1619 t.Fatalf("err: %v", err) 1620 } 1621 if acl == nil { 1622 t.Fatalf("missing acl") 1623 } 1624 1625 // Check the policy 1626 if acl.KeyRead("bar") { 1627 t.Fatalf("unexpected read") 1628 } 1629 if !acl.KeyRead("foo/test") { 1630 t.Fatalf("unexpected failed read") 1631 } 1632 } 1633 */ 1634 1635 func TestACL_filterHealthChecks(t *testing.T) { 1636 t.Parallel() 1637 // Create some health checks. 1638 fill := func() structs.HealthChecks { 1639 return structs.HealthChecks{ 1640 &structs.HealthCheck{ 1641 Node: "node1", 1642 CheckID: "check1", 1643 ServiceName: "foo", 1644 }, 1645 } 1646 } 1647 1648 // Try permissive filtering. 1649 { 1650 hc := fill() 1651 filt := newACLFilter(acl.AllowAll(), nil, false) 1652 filt.filterHealthChecks(&hc) 1653 if len(hc) != 1 { 1654 t.Fatalf("bad: %#v", hc) 1655 } 1656 } 1657 1658 // Try restrictive filtering. 1659 { 1660 hc := fill() 1661 filt := newACLFilter(acl.DenyAll(), nil, false) 1662 filt.filterHealthChecks(&hc) 1663 if len(hc) != 0 { 1664 t.Fatalf("bad: %#v", hc) 1665 } 1666 } 1667 1668 // Allowed to see the service but not the node. 1669 policy, err := acl.NewPolicyFromSource("", 0, ` 1670 service "foo" { 1671 policy = "read" 1672 } 1673 `, acl.SyntaxLegacy, nil) 1674 if err != nil { 1675 t.Fatalf("err %v", err) 1676 } 1677 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 1678 if err != nil { 1679 t.Fatalf("err: %v", err) 1680 } 1681 1682 // This will work because version 8 ACLs aren't being enforced. 1683 { 1684 hc := fill() 1685 filt := newACLFilter(perms, nil, false) 1686 filt.filterHealthChecks(&hc) 1687 if len(hc) != 1 { 1688 t.Fatalf("bad: %#v", hc) 1689 } 1690 } 1691 1692 // But with version 8 the node will block it. 1693 { 1694 hc := fill() 1695 filt := newACLFilter(perms, nil, true) 1696 filt.filterHealthChecks(&hc) 1697 if len(hc) != 0 { 1698 t.Fatalf("bad: %#v", hc) 1699 } 1700 } 1701 1702 // Chain on access to the node. 1703 policy, err = acl.NewPolicyFromSource("", 0, ` 1704 node "node1" { 1705 policy = "read" 1706 } 1707 `, acl.SyntaxLegacy, nil) 1708 if err != nil { 1709 t.Fatalf("err %v", err) 1710 } 1711 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 1712 if err != nil { 1713 t.Fatalf("err: %v", err) 1714 } 1715 1716 // Now it should go through. 1717 { 1718 hc := fill() 1719 filt := newACLFilter(perms, nil, true) 1720 filt.filterHealthChecks(&hc) 1721 if len(hc) != 1 { 1722 t.Fatalf("bad: %#v", hc) 1723 } 1724 } 1725 } 1726 1727 func TestACL_filterIntentions(t *testing.T) { 1728 t.Parallel() 1729 assert := assert.New(t) 1730 1731 fill := func() structs.Intentions { 1732 return structs.Intentions{ 1733 &structs.Intention{ 1734 ID: "f004177f-2c28-83b7-4229-eacc25fe55d1", 1735 DestinationName: "bar", 1736 }, 1737 &structs.Intention{ 1738 ID: "f004177f-2c28-83b7-4229-eacc25fe55d2", 1739 DestinationName: "foo", 1740 }, 1741 } 1742 } 1743 1744 // Try permissive filtering. 1745 { 1746 ixns := fill() 1747 filt := newACLFilter(acl.AllowAll(), nil, false) 1748 filt.filterIntentions(&ixns) 1749 assert.Len(ixns, 2) 1750 } 1751 1752 // Try restrictive filtering. 1753 { 1754 ixns := fill() 1755 filt := newACLFilter(acl.DenyAll(), nil, false) 1756 filt.filterIntentions(&ixns) 1757 assert.Len(ixns, 0) 1758 } 1759 1760 // Policy to see one 1761 policy, err := acl.NewPolicyFromSource("", 0, ` 1762 service "foo" { 1763 policy = "read" 1764 } 1765 `, acl.SyntaxLegacy, nil) 1766 assert.Nil(err) 1767 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 1768 assert.Nil(err) 1769 1770 // Filter 1771 { 1772 ixns := fill() 1773 filt := newACLFilter(perms, nil, false) 1774 filt.filterIntentions(&ixns) 1775 assert.Len(ixns, 1) 1776 } 1777 } 1778 1779 func TestACL_filterServices(t *testing.T) { 1780 t.Parallel() 1781 // Create some services 1782 services := structs.Services{ 1783 "service1": []string{}, 1784 "service2": []string{}, 1785 "consul": []string{}, 1786 } 1787 1788 // Try permissive filtering. 1789 filt := newACLFilter(acl.AllowAll(), nil, false) 1790 filt.filterServices(services) 1791 if len(services) != 3 { 1792 t.Fatalf("bad: %#v", services) 1793 } 1794 1795 // Try restrictive filtering. 1796 filt = newACLFilter(acl.DenyAll(), nil, false) 1797 filt.filterServices(services) 1798 if len(services) != 1 { 1799 t.Fatalf("bad: %#v", services) 1800 } 1801 if _, ok := services["consul"]; !ok { 1802 t.Fatalf("bad: %#v", services) 1803 } 1804 1805 // Try restrictive filtering with version 8 enforcement. 1806 filt = newACLFilter(acl.DenyAll(), nil, true) 1807 filt.filterServices(services) 1808 if len(services) != 0 { 1809 t.Fatalf("bad: %#v", services) 1810 } 1811 } 1812 1813 func TestACL_filterServiceNodes(t *testing.T) { 1814 t.Parallel() 1815 // Create some service nodes. 1816 fill := func() structs.ServiceNodes { 1817 return structs.ServiceNodes{ 1818 &structs.ServiceNode{ 1819 Node: "node1", 1820 ServiceName: "foo", 1821 }, 1822 } 1823 } 1824 1825 // Try permissive filtering. 1826 { 1827 nodes := fill() 1828 filt := newACLFilter(acl.AllowAll(), nil, false) 1829 filt.filterServiceNodes(&nodes) 1830 if len(nodes) != 1 { 1831 t.Fatalf("bad: %#v", nodes) 1832 } 1833 } 1834 1835 // Try restrictive filtering. 1836 { 1837 nodes := fill() 1838 filt := newACLFilter(acl.DenyAll(), nil, false) 1839 filt.filterServiceNodes(&nodes) 1840 if len(nodes) != 0 { 1841 t.Fatalf("bad: %#v", nodes) 1842 } 1843 } 1844 1845 // Allowed to see the service but not the node. 1846 policy, err := acl.NewPolicyFromSource("", 0, ` 1847 service "foo" { 1848 policy = "read" 1849 } 1850 `, acl.SyntaxLegacy, nil) 1851 if err != nil { 1852 t.Fatalf("err %v", err) 1853 } 1854 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 1855 if err != nil { 1856 t.Fatalf("err: %v", err) 1857 } 1858 1859 // This will work because version 8 ACLs aren't being enforced. 1860 { 1861 nodes := fill() 1862 filt := newACLFilter(perms, nil, false) 1863 filt.filterServiceNodes(&nodes) 1864 if len(nodes) != 1 { 1865 t.Fatalf("bad: %#v", nodes) 1866 } 1867 } 1868 1869 // But with version 8 the node will block it. 1870 { 1871 nodes := fill() 1872 filt := newACLFilter(perms, nil, true) 1873 filt.filterServiceNodes(&nodes) 1874 if len(nodes) != 0 { 1875 t.Fatalf("bad: %#v", nodes) 1876 } 1877 } 1878 1879 // Chain on access to the node. 1880 policy, err = acl.NewPolicyFromSource("", 0, ` 1881 node "node1" { 1882 policy = "read" 1883 } 1884 `, acl.SyntaxLegacy, nil) 1885 if err != nil { 1886 t.Fatalf("err %v", err) 1887 } 1888 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 1889 if err != nil { 1890 t.Fatalf("err: %v", err) 1891 } 1892 1893 // Now it should go through. 1894 { 1895 nodes := fill() 1896 filt := newACLFilter(perms, nil, true) 1897 filt.filterServiceNodes(&nodes) 1898 if len(nodes) != 1 { 1899 t.Fatalf("bad: %#v", nodes) 1900 } 1901 } 1902 } 1903 1904 func TestACL_filterNodeServices(t *testing.T) { 1905 t.Parallel() 1906 // Create some node services. 1907 fill := func() *structs.NodeServices { 1908 return &structs.NodeServices{ 1909 Node: &structs.Node{ 1910 Node: "node1", 1911 }, 1912 Services: map[string]*structs.NodeService{ 1913 "foo": &structs.NodeService{ 1914 ID: "foo", 1915 Service: "foo", 1916 }, 1917 }, 1918 } 1919 } 1920 1921 // Try nil, which is a possible input. 1922 { 1923 var services *structs.NodeServices 1924 filt := newACLFilter(acl.AllowAll(), nil, false) 1925 filt.filterNodeServices(&services) 1926 if services != nil { 1927 t.Fatalf("bad: %#v", services) 1928 } 1929 } 1930 1931 // Try permissive filtering. 1932 { 1933 services := fill() 1934 filt := newACLFilter(acl.AllowAll(), nil, false) 1935 filt.filterNodeServices(&services) 1936 if len(services.Services) != 1 { 1937 t.Fatalf("bad: %#v", services.Services) 1938 } 1939 } 1940 1941 // Try restrictive filtering. 1942 { 1943 services := fill() 1944 filt := newACLFilter(acl.DenyAll(), nil, false) 1945 filt.filterNodeServices(&services) 1946 if len((*services).Services) != 0 { 1947 t.Fatalf("bad: %#v", (*services).Services) 1948 } 1949 } 1950 1951 // Allowed to see the service but not the node. 1952 policy, err := acl.NewPolicyFromSource("", 0, ` 1953 service "foo" { 1954 policy = "read" 1955 } 1956 `, acl.SyntaxLegacy, nil) 1957 if err != nil { 1958 t.Fatalf("err %v", err) 1959 } 1960 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 1961 if err != nil { 1962 t.Fatalf("err: %v", err) 1963 } 1964 1965 // This will work because version 8 ACLs aren't being enforced. 1966 { 1967 services := fill() 1968 filt := newACLFilter(perms, nil, false) 1969 filt.filterNodeServices(&services) 1970 if len((*services).Services) != 1 { 1971 t.Fatalf("bad: %#v", (*services).Services) 1972 } 1973 } 1974 1975 // But with version 8 the node will block it. 1976 { 1977 services := fill() 1978 filt := newACLFilter(perms, nil, true) 1979 filt.filterNodeServices(&services) 1980 if services != nil { 1981 t.Fatalf("bad: %#v", services) 1982 } 1983 } 1984 1985 // Chain on access to the node. 1986 policy, err = acl.NewPolicyFromSource("", 0, ` 1987 node "node1" { 1988 policy = "read" 1989 } 1990 `, acl.SyntaxLegacy, nil) 1991 if err != nil { 1992 t.Fatalf("err %v", err) 1993 } 1994 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 1995 if err != nil { 1996 t.Fatalf("err: %v", err) 1997 } 1998 1999 // Now it should go through. 2000 { 2001 services := fill() 2002 filt := newACLFilter(perms, nil, true) 2003 filt.filterNodeServices(&services) 2004 if len((*services).Services) != 1 { 2005 t.Fatalf("bad: %#v", (*services).Services) 2006 } 2007 } 2008 } 2009 2010 func TestACL_filterCheckServiceNodes(t *testing.T) { 2011 t.Parallel() 2012 // Create some nodes. 2013 fill := func() structs.CheckServiceNodes { 2014 return structs.CheckServiceNodes{ 2015 structs.CheckServiceNode{ 2016 Node: &structs.Node{ 2017 Node: "node1", 2018 }, 2019 Service: &structs.NodeService{ 2020 ID: "foo", 2021 Service: "foo", 2022 }, 2023 Checks: structs.HealthChecks{ 2024 &structs.HealthCheck{ 2025 Node: "node1", 2026 CheckID: "check1", 2027 ServiceName: "foo", 2028 }, 2029 }, 2030 }, 2031 } 2032 } 2033 2034 // Try permissive filtering. 2035 { 2036 nodes := fill() 2037 filt := newACLFilter(acl.AllowAll(), nil, false) 2038 filt.filterCheckServiceNodes(&nodes) 2039 if len(nodes) != 1 { 2040 t.Fatalf("bad: %#v", nodes) 2041 } 2042 if len(nodes[0].Checks) != 1 { 2043 t.Fatalf("bad: %#v", nodes[0].Checks) 2044 } 2045 } 2046 2047 // Try restrictive filtering. 2048 { 2049 nodes := fill() 2050 filt := newACLFilter(acl.DenyAll(), nil, false) 2051 filt.filterCheckServiceNodes(&nodes) 2052 if len(nodes) != 0 { 2053 t.Fatalf("bad: %#v", nodes) 2054 } 2055 } 2056 2057 // Allowed to see the service but not the node. 2058 policy, err := acl.NewPolicyFromSource("", 0, ` 2059 service "foo" { 2060 policy = "read" 2061 } 2062 `, acl.SyntaxLegacy, nil) 2063 if err != nil { 2064 t.Fatalf("err %v", err) 2065 } 2066 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 2067 if err != nil { 2068 t.Fatalf("err: %v", err) 2069 } 2070 2071 // This will work because version 8 ACLs aren't being enforced. 2072 { 2073 nodes := fill() 2074 filt := newACLFilter(perms, nil, false) 2075 filt.filterCheckServiceNodes(&nodes) 2076 if len(nodes) != 1 { 2077 t.Fatalf("bad: %#v", nodes) 2078 } 2079 if len(nodes[0].Checks) != 1 { 2080 t.Fatalf("bad: %#v", nodes[0].Checks) 2081 } 2082 } 2083 2084 // But with version 8 the node will block it. 2085 { 2086 nodes := fill() 2087 filt := newACLFilter(perms, nil, true) 2088 filt.filterCheckServiceNodes(&nodes) 2089 if len(nodes) != 0 { 2090 t.Fatalf("bad: %#v", nodes) 2091 } 2092 } 2093 2094 // Chain on access to the node. 2095 policy, err = acl.NewPolicyFromSource("", 0, ` 2096 node "node1" { 2097 policy = "read" 2098 } 2099 `, acl.SyntaxLegacy, nil) 2100 if err != nil { 2101 t.Fatalf("err %v", err) 2102 } 2103 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2104 if err != nil { 2105 t.Fatalf("err: %v", err) 2106 } 2107 2108 // Now it should go through. 2109 { 2110 nodes := fill() 2111 filt := newACLFilter(perms, nil, true) 2112 filt.filterCheckServiceNodes(&nodes) 2113 if len(nodes) != 1 { 2114 t.Fatalf("bad: %#v", nodes) 2115 } 2116 if len(nodes[0].Checks) != 1 { 2117 t.Fatalf("bad: %#v", nodes[0].Checks) 2118 } 2119 } 2120 } 2121 2122 func TestACL_filterCoordinates(t *testing.T) { 2123 t.Parallel() 2124 // Create some coordinates. 2125 coords := structs.Coordinates{ 2126 &structs.Coordinate{ 2127 Node: "node1", 2128 Coord: generateRandomCoordinate(), 2129 }, 2130 &structs.Coordinate{ 2131 Node: "node2", 2132 Coord: generateRandomCoordinate(), 2133 }, 2134 } 2135 2136 // Try permissive filtering. 2137 filt := newACLFilter(acl.AllowAll(), nil, false) 2138 filt.filterCoordinates(&coords) 2139 if len(coords) != 2 { 2140 t.Fatalf("bad: %#v", coords) 2141 } 2142 2143 // Try restrictive filtering without version 8 ACL enforcement. 2144 filt = newACLFilter(acl.DenyAll(), nil, false) 2145 filt.filterCoordinates(&coords) 2146 if len(coords) != 2 { 2147 t.Fatalf("bad: %#v", coords) 2148 } 2149 2150 // Try restrictive filtering with version 8 ACL enforcement. 2151 filt = newACLFilter(acl.DenyAll(), nil, true) 2152 filt.filterCoordinates(&coords) 2153 if len(coords) != 0 { 2154 t.Fatalf("bad: %#v", coords) 2155 } 2156 } 2157 2158 func TestACL_filterSessions(t *testing.T) { 2159 t.Parallel() 2160 // Create a session list. 2161 sessions := structs.Sessions{ 2162 &structs.Session{ 2163 Node: "foo", 2164 }, 2165 &structs.Session{ 2166 Node: "bar", 2167 }, 2168 } 2169 2170 // Try permissive filtering. 2171 filt := newACLFilter(acl.AllowAll(), nil, true) 2172 filt.filterSessions(&sessions) 2173 if len(sessions) != 2 { 2174 t.Fatalf("bad: %#v", sessions) 2175 } 2176 2177 // Try restrictive filtering but with version 8 enforcement turned off. 2178 filt = newACLFilter(acl.DenyAll(), nil, false) 2179 filt.filterSessions(&sessions) 2180 if len(sessions) != 2 { 2181 t.Fatalf("bad: %#v", sessions) 2182 } 2183 2184 // Try restrictive filtering with version 8 enforcement turned on. 2185 filt = newACLFilter(acl.DenyAll(), nil, true) 2186 filt.filterSessions(&sessions) 2187 if len(sessions) != 0 { 2188 t.Fatalf("bad: %#v", sessions) 2189 } 2190 } 2191 2192 func TestACL_filterNodeDump(t *testing.T) { 2193 t.Parallel() 2194 // Create a node dump. 2195 fill := func() structs.NodeDump { 2196 return structs.NodeDump{ 2197 &structs.NodeInfo{ 2198 Node: "node1", 2199 Services: []*structs.NodeService{ 2200 &structs.NodeService{ 2201 ID: "foo", 2202 Service: "foo", 2203 }, 2204 }, 2205 Checks: []*structs.HealthCheck{ 2206 &structs.HealthCheck{ 2207 Node: "node1", 2208 CheckID: "check1", 2209 ServiceName: "foo", 2210 }, 2211 }, 2212 }, 2213 } 2214 } 2215 2216 // Try permissive filtering. 2217 { 2218 dump := fill() 2219 filt := newACLFilter(acl.AllowAll(), nil, false) 2220 filt.filterNodeDump(&dump) 2221 if len(dump) != 1 { 2222 t.Fatalf("bad: %#v", dump) 2223 } 2224 if len(dump[0].Services) != 1 { 2225 t.Fatalf("bad: %#v", dump[0].Services) 2226 } 2227 if len(dump[0].Checks) != 1 { 2228 t.Fatalf("bad: %#v", dump[0].Checks) 2229 } 2230 } 2231 2232 // Try restrictive filtering. 2233 { 2234 dump := fill() 2235 filt := newACLFilter(acl.DenyAll(), nil, false) 2236 filt.filterNodeDump(&dump) 2237 if len(dump) != 1 { 2238 t.Fatalf("bad: %#v", dump) 2239 } 2240 if len(dump[0].Services) != 0 { 2241 t.Fatalf("bad: %#v", dump[0].Services) 2242 } 2243 if len(dump[0].Checks) != 0 { 2244 t.Fatalf("bad: %#v", dump[0].Checks) 2245 } 2246 } 2247 2248 // Allowed to see the service but not the node. 2249 policy, err := acl.NewPolicyFromSource("", 0, ` 2250 service "foo" { 2251 policy = "read" 2252 } 2253 `, acl.SyntaxLegacy, nil) 2254 if err != nil { 2255 t.Fatalf("err %v", err) 2256 } 2257 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 2258 if err != nil { 2259 t.Fatalf("err: %v", err) 2260 } 2261 2262 // This will work because version 8 ACLs aren't being enforced. 2263 { 2264 dump := fill() 2265 filt := newACLFilter(perms, nil, false) 2266 filt.filterNodeDump(&dump) 2267 if len(dump) != 1 { 2268 t.Fatalf("bad: %#v", dump) 2269 } 2270 if len(dump[0].Services) != 1 { 2271 t.Fatalf("bad: %#v", dump[0].Services) 2272 } 2273 if len(dump[0].Checks) != 1 { 2274 t.Fatalf("bad: %#v", dump[0].Checks) 2275 } 2276 } 2277 2278 // But with version 8 the node will block it. 2279 { 2280 dump := fill() 2281 filt := newACLFilter(perms, nil, true) 2282 filt.filterNodeDump(&dump) 2283 if len(dump) != 0 { 2284 t.Fatalf("bad: %#v", dump) 2285 } 2286 } 2287 2288 // Chain on access to the node. 2289 policy, err = acl.NewPolicyFromSource("", 0, ` 2290 node "node1" { 2291 policy = "read" 2292 } 2293 `, acl.SyntaxLegacy, nil) 2294 if err != nil { 2295 t.Fatalf("err %v", err) 2296 } 2297 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2298 if err != nil { 2299 t.Fatalf("err: %v", err) 2300 } 2301 2302 // Now it should go through. 2303 { 2304 dump := fill() 2305 filt := newACLFilter(perms, nil, true) 2306 filt.filterNodeDump(&dump) 2307 if len(dump) != 1 { 2308 t.Fatalf("bad: %#v", dump) 2309 } 2310 if len(dump[0].Services) != 1 { 2311 t.Fatalf("bad: %#v", dump[0].Services) 2312 } 2313 if len(dump[0].Checks) != 1 { 2314 t.Fatalf("bad: %#v", dump[0].Checks) 2315 } 2316 } 2317 } 2318 2319 func TestACL_filterNodes(t *testing.T) { 2320 t.Parallel() 2321 // Create a nodes list. 2322 nodes := structs.Nodes{ 2323 &structs.Node{ 2324 Node: "foo", 2325 }, 2326 &structs.Node{ 2327 Node: "bar", 2328 }, 2329 } 2330 2331 // Try permissive filtering. 2332 filt := newACLFilter(acl.AllowAll(), nil, true) 2333 filt.filterNodes(&nodes) 2334 if len(nodes) != 2 { 2335 t.Fatalf("bad: %#v", nodes) 2336 } 2337 2338 // Try restrictive filtering but with version 8 enforcement turned off. 2339 filt = newACLFilter(acl.DenyAll(), nil, false) 2340 filt.filterNodes(&nodes) 2341 if len(nodes) != 2 { 2342 t.Fatalf("bad: %#v", nodes) 2343 } 2344 2345 // Try restrictive filtering with version 8 enforcement turned on. 2346 filt = newACLFilter(acl.DenyAll(), nil, true) 2347 filt.filterNodes(&nodes) 2348 if len(nodes) != 0 { 2349 t.Fatalf("bad: %#v", nodes) 2350 } 2351 } 2352 2353 func TestACL_redactPreparedQueryTokens(t *testing.T) { 2354 t.Parallel() 2355 query := &structs.PreparedQuery{ 2356 ID: "f004177f-2c28-83b7-4229-eacc25fe55d1", 2357 Token: "root", 2358 } 2359 2360 expected := &structs.PreparedQuery{ 2361 ID: "f004177f-2c28-83b7-4229-eacc25fe55d1", 2362 Token: "root", 2363 } 2364 2365 // Try permissive filtering with a management token. This will allow the 2366 // embedded token to be seen. 2367 filt := newACLFilter(acl.ManageAll(), nil, false) 2368 filt.redactPreparedQueryTokens(&query) 2369 if !reflect.DeepEqual(query, expected) { 2370 t.Fatalf("bad: %#v", &query) 2371 } 2372 2373 // Hang on to the entry with a token, which needs to survive the next 2374 // operation. 2375 original := query 2376 2377 // Now try permissive filtering with a client token, which should cause 2378 // the embedded token to get redacted. 2379 filt = newACLFilter(acl.AllowAll(), nil, false) 2380 filt.redactPreparedQueryTokens(&query) 2381 expected.Token = redactedToken 2382 if !reflect.DeepEqual(query, expected) { 2383 t.Fatalf("bad: %#v", *query) 2384 } 2385 2386 // Make sure that the original object didn't lose its token. 2387 if original.Token != "root" { 2388 t.Fatalf("bad token: %s", original.Token) 2389 } 2390 } 2391 2392 func TestACL_redactTokenSecret(t *testing.T) { 2393 t.Parallel() 2394 delegate := &ACLResolverTestDelegate{ 2395 enabled: true, 2396 datacenter: "dc1", 2397 legacy: false, 2398 localTokens: true, 2399 localPolicies: true, 2400 // No need to provide any of the RPC callbacks 2401 } 2402 r := newTestACLResolver(t, delegate, nil) 2403 2404 token := &structs.ACLToken{ 2405 AccessorID: "6a5e25b3-28f2-4085-9012-c3fb754314d1", 2406 SecretID: "6a5e25b3-28f2-4085-9012-c3fb754314d1", 2407 } 2408 2409 err := r.filterACL("acl-wr", &token) 2410 require.NoError(t, err) 2411 require.Equal(t, "6a5e25b3-28f2-4085-9012-c3fb754314d1", token.SecretID) 2412 2413 err = r.filterACL("acl-ro", &token) 2414 require.NoError(t, err) 2415 require.Equal(t, redactedToken, token.SecretID) 2416 } 2417 2418 func TestACL_redactTokenSecrets(t *testing.T) { 2419 t.Parallel() 2420 delegate := &ACLResolverTestDelegate{ 2421 enabled: true, 2422 datacenter: "dc1", 2423 legacy: false, 2424 localTokens: true, 2425 localPolicies: true, 2426 // No need to provide any of the RPC callbacks 2427 } 2428 r := newTestACLResolver(t, delegate, nil) 2429 2430 tokens := structs.ACLTokens{ 2431 &structs.ACLToken{ 2432 AccessorID: "6a5e25b3-28f2-4085-9012-c3fb754314d1", 2433 SecretID: "6a5e25b3-28f2-4085-9012-c3fb754314d1", 2434 }, 2435 } 2436 2437 err := r.filterACL("acl-wr", &tokens) 2438 require.NoError(t, err) 2439 require.Equal(t, "6a5e25b3-28f2-4085-9012-c3fb754314d1", tokens[0].SecretID) 2440 2441 err = r.filterACL("acl-ro", &tokens) 2442 require.NoError(t, err) 2443 require.Equal(t, redactedToken, tokens[0].SecretID) 2444 } 2445 2446 func TestACL_filterPreparedQueries(t *testing.T) { 2447 t.Parallel() 2448 queries := structs.PreparedQueries{ 2449 &structs.PreparedQuery{ 2450 ID: "f004177f-2c28-83b7-4229-eacc25fe55d1", 2451 }, 2452 &structs.PreparedQuery{ 2453 ID: "f004177f-2c28-83b7-4229-eacc25fe55d2", 2454 Name: "query-with-no-token", 2455 }, 2456 &structs.PreparedQuery{ 2457 ID: "f004177f-2c28-83b7-4229-eacc25fe55d3", 2458 Name: "query-with-a-token", 2459 Token: "root", 2460 }, 2461 } 2462 2463 expected := structs.PreparedQueries{ 2464 &structs.PreparedQuery{ 2465 ID: "f004177f-2c28-83b7-4229-eacc25fe55d1", 2466 }, 2467 &structs.PreparedQuery{ 2468 ID: "f004177f-2c28-83b7-4229-eacc25fe55d2", 2469 Name: "query-with-no-token", 2470 }, 2471 &structs.PreparedQuery{ 2472 ID: "f004177f-2c28-83b7-4229-eacc25fe55d3", 2473 Name: "query-with-a-token", 2474 Token: "root", 2475 }, 2476 } 2477 2478 // Try permissive filtering with a management token. This will allow the 2479 // embedded token to be seen. 2480 filt := newACLFilter(acl.ManageAll(), nil, false) 2481 filt.filterPreparedQueries(&queries) 2482 if !reflect.DeepEqual(queries, expected) { 2483 t.Fatalf("bad: %#v", queries) 2484 } 2485 2486 // Hang on to the entry with a token, which needs to survive the next 2487 // operation. 2488 original := queries[2] 2489 2490 // Now try permissive filtering with a client token, which should cause 2491 // the embedded token to get redacted, and the query with no name to get 2492 // filtered out. 2493 filt = newACLFilter(acl.AllowAll(), nil, false) 2494 filt.filterPreparedQueries(&queries) 2495 expected[2].Token = redactedToken 2496 expected = append(structs.PreparedQueries{}, expected[1], expected[2]) 2497 if !reflect.DeepEqual(queries, expected) { 2498 t.Fatalf("bad: %#v", queries) 2499 } 2500 2501 // Make sure that the original object didn't lose its token. 2502 if original.Token != "root" { 2503 t.Fatalf("bad token: %s", original.Token) 2504 } 2505 2506 // Now try restrictive filtering. 2507 filt = newACLFilter(acl.DenyAll(), nil, false) 2508 filt.filterPreparedQueries(&queries) 2509 if len(queries) != 0 { 2510 t.Fatalf("bad: %#v", queries) 2511 } 2512 } 2513 2514 func TestACL_unhandledFilterType(t *testing.T) { 2515 t.Parallel() 2516 defer func(t *testing.T) { 2517 if recover() == nil { 2518 t.Fatalf("should panic") 2519 } 2520 }(t) 2521 2522 // Create the server 2523 dir, token, srv, client := testACLFilterServer(t) 2524 defer os.RemoveAll(dir) 2525 defer srv.Shutdown() 2526 defer client.Close() 2527 2528 // Pass an unhandled type into the ACL filter. 2529 srv.filterACL(token, &structs.HealthCheck{}) 2530 } 2531 2532 func TestACL_vetRegisterWithACL(t *testing.T) { 2533 t.Parallel() 2534 args := &structs.RegisterRequest{ 2535 Node: "nope", 2536 Address: "127.0.0.1", 2537 } 2538 2539 // With a nil ACL, the update should be allowed. 2540 if err := vetRegisterWithACL(nil, args, nil); err != nil { 2541 t.Fatalf("err: %v", err) 2542 } 2543 2544 // Create a basic node policy. 2545 policy, err := acl.NewPolicyFromSource("", 0, ` 2546 node "node" { 2547 policy = "write" 2548 } 2549 `, acl.SyntaxLegacy, nil) 2550 if err != nil { 2551 t.Fatalf("err %v", err) 2552 } 2553 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 2554 if err != nil { 2555 t.Fatalf("err: %v", err) 2556 } 2557 2558 // With that policy, the update should now be blocked for node reasons. 2559 err = vetRegisterWithACL(perms, args, nil) 2560 if !acl.IsErrPermissionDenied(err) { 2561 t.Fatalf("bad: %v", err) 2562 } 2563 2564 // Now use a permitted node name. 2565 args.Node = "node" 2566 if err := vetRegisterWithACL(perms, args, nil); err != nil { 2567 t.Fatalf("err: %v", err) 2568 } 2569 2570 // Build some node info that matches what we have now. 2571 ns := &structs.NodeServices{ 2572 Node: &structs.Node{ 2573 Node: "node", 2574 Address: "127.0.0.1", 2575 }, 2576 Services: make(map[string]*structs.NodeService), 2577 } 2578 2579 // Try to register a service, which should be blocked. 2580 args.Service = &structs.NodeService{ 2581 Service: "service", 2582 ID: "my-id", 2583 } 2584 err = vetRegisterWithACL(perms, args, ns) 2585 if !acl.IsErrPermissionDenied(err) { 2586 t.Fatalf("bad: %v", err) 2587 } 2588 2589 // Chain on a basic service policy. 2590 policy, err = acl.NewPolicyFromSource("", 0, ` 2591 service "service" { 2592 policy = "write" 2593 } 2594 `, acl.SyntaxLegacy, nil) 2595 if err != nil { 2596 t.Fatalf("err %v", err) 2597 } 2598 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2599 if err != nil { 2600 t.Fatalf("err: %v", err) 2601 } 2602 2603 // With the service ACL, the update should go through. 2604 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2605 t.Fatalf("err: %v", err) 2606 } 2607 2608 // Add an existing service that they are clobbering and aren't allowed 2609 // to write to. 2610 ns.Services["my-id"] = &structs.NodeService{ 2611 Service: "other", 2612 ID: "my-id", 2613 } 2614 err = vetRegisterWithACL(perms, args, ns) 2615 if !acl.IsErrPermissionDenied(err) { 2616 t.Fatalf("bad: %v", err) 2617 } 2618 2619 // Chain on a policy that allows them to write to the other service. 2620 policy, err = acl.NewPolicyFromSource("", 0, ` 2621 service "other" { 2622 policy = "write" 2623 } 2624 `, acl.SyntaxLegacy, nil) 2625 if err != nil { 2626 t.Fatalf("err %v", err) 2627 } 2628 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2629 if err != nil { 2630 t.Fatalf("err: %v", err) 2631 } 2632 2633 // Now it should go through. 2634 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2635 t.Fatalf("err: %v", err) 2636 } 2637 2638 // Try creating the node and the service at once by having no existing 2639 // node record. This should be ok since we have node and service 2640 // permissions. 2641 if err := vetRegisterWithACL(perms, args, nil); err != nil { 2642 t.Fatalf("err: %v", err) 2643 } 2644 2645 // Add a node-level check to the member, which should be rejected. 2646 args.Check = &structs.HealthCheck{ 2647 Node: "node", 2648 } 2649 err = vetRegisterWithACL(perms, args, ns) 2650 if err == nil || !strings.Contains(err.Error(), "check member must be nil") { 2651 t.Fatalf("bad: %v", err) 2652 } 2653 2654 // Move the check into the slice, but give a bad node name. 2655 args.Check.Node = "nope" 2656 args.Checks = append(args.Checks, args.Check) 2657 args.Check = nil 2658 err = vetRegisterWithACL(perms, args, ns) 2659 if err == nil || !strings.Contains(err.Error(), "doesn't match register request node") { 2660 t.Fatalf("bad: %v", err) 2661 } 2662 2663 // Fix the node name, which should now go through. 2664 args.Checks[0].Node = "node" 2665 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2666 t.Fatalf("err: %v", err) 2667 } 2668 2669 // Add a service-level check. 2670 args.Checks = append(args.Checks, &structs.HealthCheck{ 2671 Node: "node", 2672 ServiceID: "my-id", 2673 }) 2674 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2675 t.Fatalf("err: %v", err) 2676 } 2677 2678 // Try creating everything at once. This should be ok since we have all 2679 // the permissions we need. It also makes sure that we can register a 2680 // new node, service, and associated checks. 2681 if err := vetRegisterWithACL(perms, args, nil); err != nil { 2682 t.Fatalf("err: %v", err) 2683 } 2684 2685 // Nil out the service registration, which'll skip the special case 2686 // and force us to look at the ns data (it will look like we are 2687 // writing to the "other" service which also has "my-id"). 2688 args.Service = nil 2689 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2690 t.Fatalf("err: %v", err) 2691 } 2692 2693 // Chain on a policy that forbids them to write to the other service. 2694 policy, err = acl.NewPolicyFromSource("", 0, ` 2695 service "other" { 2696 policy = "deny" 2697 } 2698 `, acl.SyntaxLegacy, nil) 2699 if err != nil { 2700 t.Fatalf("err %v", err) 2701 } 2702 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2703 if err != nil { 2704 t.Fatalf("err: %v", err) 2705 } 2706 2707 // This should get rejected. 2708 err = vetRegisterWithACL(perms, args, ns) 2709 if !acl.IsErrPermissionDenied(err) { 2710 t.Fatalf("bad: %v", err) 2711 } 2712 2713 // Change the existing service data to point to a service name they 2714 // car write to. This should go through. 2715 ns.Services["my-id"] = &structs.NodeService{ 2716 Service: "service", 2717 ID: "my-id", 2718 } 2719 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2720 t.Fatalf("err: %v", err) 2721 } 2722 2723 // Chain on a policy that forbids them to write to the node. 2724 policy, err = acl.NewPolicyFromSource("", 0, ` 2725 node "node" { 2726 policy = "deny" 2727 } 2728 `, acl.SyntaxLegacy, nil) 2729 if err != nil { 2730 t.Fatalf("err %v", err) 2731 } 2732 perms, err = acl.NewPolicyAuthorizer(perms, []*acl.Policy{policy}, nil) 2733 if err != nil { 2734 t.Fatalf("err: %v", err) 2735 } 2736 2737 // This should get rejected because there's a node-level check in here. 2738 err = vetRegisterWithACL(perms, args, ns) 2739 if !acl.IsErrPermissionDenied(err) { 2740 t.Fatalf("bad: %v", err) 2741 } 2742 2743 // Change the node-level check into a service check, and then it should 2744 // go through. 2745 args.Checks[0].ServiceID = "my-id" 2746 if err := vetRegisterWithACL(perms, args, ns); err != nil { 2747 t.Fatalf("err: %v", err) 2748 } 2749 2750 // Finally, attempt to update the node part of the data and make sure 2751 // that gets rejected since they no longer have permissions. 2752 args.Address = "127.0.0.2" 2753 err = vetRegisterWithACL(perms, args, ns) 2754 if !acl.IsErrPermissionDenied(err) { 2755 t.Fatalf("bad: %v", err) 2756 } 2757 } 2758 2759 func TestACL_vetDeregisterWithACL(t *testing.T) { 2760 t.Parallel() 2761 args := &structs.DeregisterRequest{ 2762 Node: "nope", 2763 } 2764 2765 // With a nil ACL, the update should be allowed. 2766 if err := vetDeregisterWithACL(nil, args, nil, nil); err != nil { 2767 t.Fatalf("err: %v", err) 2768 } 2769 2770 // Create a basic node policy. 2771 policy, err := acl.NewPolicyFromSource("", 0, ` 2772 node "node" { 2773 policy = "write" 2774 } 2775 service "service" { 2776 policy = "write" 2777 } 2778 `, acl.SyntaxLegacy, nil) 2779 if err != nil { 2780 t.Fatalf("err %v", err) 2781 } 2782 perms, err := acl.NewPolicyAuthorizer(acl.DenyAll(), []*acl.Policy{policy}, nil) 2783 if err != nil { 2784 t.Fatalf("err: %v", err) 2785 } 2786 2787 // With that policy, the update should now be blocked for node reasons. 2788 err = vetDeregisterWithACL(perms, args, nil, nil) 2789 if !acl.IsErrPermissionDenied(err) { 2790 t.Fatalf("bad: %v", err) 2791 } 2792 2793 // Now use a permitted node name. 2794 args.Node = "node" 2795 if err := vetDeregisterWithACL(perms, args, nil, nil); err != nil { 2796 t.Fatalf("err: %v", err) 2797 } 2798 2799 // Try an unknown check. 2800 args.CheckID = "check-id" 2801 err = vetDeregisterWithACL(perms, args, nil, nil) 2802 if err == nil || !strings.Contains(err.Error(), "Unknown check") { 2803 t.Fatalf("bad: %v", err) 2804 } 2805 2806 // Now pass in a check that should be blocked. 2807 nc := &structs.HealthCheck{ 2808 Node: "node", 2809 CheckID: "check-id", 2810 ServiceID: "service-id", 2811 ServiceName: "nope", 2812 } 2813 err = vetDeregisterWithACL(perms, args, nil, nc) 2814 if !acl.IsErrPermissionDenied(err) { 2815 t.Fatalf("bad: %v", err) 2816 } 2817 2818 // Change it to an allowed service, which should go through. 2819 nc.ServiceName = "service" 2820 if err := vetDeregisterWithACL(perms, args, nil, nc); err != nil { 2821 t.Fatalf("err: %v", err) 2822 } 2823 2824 // Switch to a node check that should be blocked. 2825 args.Node = "nope" 2826 nc.Node = "nope" 2827 nc.ServiceID = "" 2828 nc.ServiceName = "" 2829 err = vetDeregisterWithACL(perms, args, nil, nc) 2830 if !acl.IsErrPermissionDenied(err) { 2831 t.Fatalf("bad: %v", err) 2832 } 2833 2834 // Switch to an allowed node check, which should go through. 2835 args.Node = "node" 2836 nc.Node = "node" 2837 if err := vetDeregisterWithACL(perms, args, nil, nc); err != nil { 2838 t.Fatalf("err: %v", err) 2839 } 2840 2841 // Try an unknown service. 2842 args.ServiceID = "service-id" 2843 err = vetDeregisterWithACL(perms, args, nil, nil) 2844 if err == nil || !strings.Contains(err.Error(), "Unknown service") { 2845 t.Fatalf("bad: %v", err) 2846 } 2847 2848 // Now pass in a service that should be blocked. 2849 ns := &structs.NodeService{ 2850 ID: "service-id", 2851 Service: "nope", 2852 } 2853 err = vetDeregisterWithACL(perms, args, ns, nil) 2854 if !acl.IsErrPermissionDenied(err) { 2855 t.Fatalf("bad: %v", err) 2856 } 2857 2858 // Change it to an allowed service, which should go through. 2859 ns.Service = "service" 2860 if err := vetDeregisterWithACL(perms, args, ns, nil); err != nil { 2861 t.Fatalf("err: %v", err) 2862 } 2863 }