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