github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/agent/consul/acl_testing.go (about) 1 package consul 2 3 import ( 4 "errors" 5 "sync" 6 "time" 7 8 "github.com/hashicorp/consul/api" 9 "github.com/hashicorp/go-hclog" 10 "github.com/hashicorp/nomad/helper/uuid" 11 ) 12 13 var _ ACLsAPI = (*MockACLsAPI)(nil) 14 15 // MockACLsAPI is a mock of consul.ACLsAPI 16 type MockACLsAPI struct { 17 logger hclog.Logger 18 19 lock sync.Mutex 20 state struct { 21 index uint64 22 error error 23 tokens map[string]*api.ACLToken 24 } 25 } 26 27 func NewMockACLsAPI(l hclog.Logger) *MockACLsAPI { 28 return &MockACLsAPI{ 29 logger: l.Named("mock_consul"), 30 state: struct { 31 index uint64 32 error error 33 tokens map[string]*api.ACLToken 34 }{tokens: make(map[string]*api.ACLToken)}, 35 } 36 } 37 38 // Example Consul policies for use in tests. 39 const ( 40 ExamplePolicyID1 = "a7c86856-0af5-4ab5-8834-03f4517e5564" 41 ExamplePolicyID2 = "ffa1b66c-967d-4468-8775-c687b5cfc16e" 42 ExamplePolicyID3 = "f68f0c36-51f8-4343-97dd-f0d4816c915f" 43 ExamplePolicyID4 = "1087ff34-b8a0-9bb3-9430-d2f758f52bd3" 44 ) 45 46 func (m *MockACLsAPI) PolicyRead(policyID string, _ *api.QueryOptions) (*api.ACLPolicy, *api.QueryMeta, error) { 47 switch policyID { 48 49 case ExamplePolicyID1: 50 return &api.ACLPolicy{ 51 ID: ExamplePolicyID1, 52 Name: "example-policy-1", 53 Rules: `service "service1" { policy = "write" }`, 54 }, nil, nil 55 56 case ExamplePolicyID2: 57 return &api.ACLPolicy{ 58 ID: ExamplePolicyID2, 59 Rules: `service_prefix "foo-" { policy = "write" }`, 60 }, nil, nil 61 62 case ExamplePolicyID3: 63 return &api.ACLPolicy{ 64 ID: ExamplePolicyID3, 65 Rules: ` 66 service "service1" { policy = "read" } 67 service "service2" { policy = "write" }`, 68 }, nil, nil 69 70 case ExamplePolicyID4: 71 return &api.ACLPolicy{ 72 ID: ExamplePolicyID4, 73 Rules: `key_prefix "" { policy = "read" }`, 74 }, nil, nil 75 76 default: 77 return nil, nil, errors.New("no such policy") 78 } 79 } 80 81 // Example Consul roles for use in tests. 82 const ( 83 ExampleRoleID1 = "e569a3a8-7dfb-b024-e492-e790fe3c4183" 84 ExampleRoleID2 = "88c825f4-d0da-1c2b-0c1c-cc9fe84c4468" 85 ExampleRoleID3 = "b19b2058-6205-6dff-d2b0-470f29b8e627" 86 ) 87 88 func (m *MockACLsAPI) RoleRead(roleID string, _ *api.QueryOptions) (*api.ACLRole, *api.QueryMeta, error) { 89 switch roleID { 90 case ExampleRoleID1: 91 return &api.ACLRole{ 92 ID: ExampleRoleID1, 93 Name: "example-role-1", 94 Policies: []*api.ACLRolePolicyLink{{ 95 ID: ExamplePolicyID1, 96 Name: "example-policy-1", 97 }}, 98 ServiceIdentities: nil, 99 }, nil, nil 100 case ExampleRoleID2: 101 return &api.ACLRole{ 102 ID: ExampleRoleID2, 103 Name: "example-role-2", 104 Policies: []*api.ACLRolePolicyLink{{ 105 ID: ExamplePolicyID2, 106 Name: "example-policy-2", 107 }}, 108 ServiceIdentities: nil, 109 }, nil, nil 110 case ExampleRoleID3: 111 return &api.ACLRole{ 112 ID: ExampleRoleID3, 113 Name: "example-role-3", 114 Policies: nil, // todo add more if needed 115 ServiceIdentities: nil, // todo add more if needed 116 }, nil, nil 117 default: 118 return nil, nil, nil 119 } 120 } 121 122 // Example Consul ACL tokens for use in tests. These tokens belong to the 123 // default Consul namespace. 124 const ( 125 ExampleOperatorTokenID0 = "de591604-86eb-1e6f-8b44-d4db752921ae" 126 ExampleOperatorTokenID1 = "59c219c2-47e4-43f3-bb45-258fd13f59d5" 127 ExampleOperatorTokenID2 = "868cc216-e123-4c2b-b362-f4d4c087de8e" 128 ExampleOperatorTokenID3 = "6177d1b9-c0f6-4118-b891-d818a3cb80b1" 129 ExampleOperatorTokenID4 = "754ae26c-f3cc-e088-d486-9c0d20f5eaea" 130 ExampleOperatorTokenID5 = "097cbb45-506b-c79c-ec38-82eb0dc0794a" 131 ) 132 133 // Example Consul ACL tokens for use in tests that match the policies as the 134 // tokens above, but these belong to the "banana" Consul namespace. 135 const ( 136 ExampleOperatorTokenID10 = "ddfe688f-655f-e8dd-1db5-5650eed00aeb" 137 ExampleOperatorTokenID11 = "46d09394-598c-1e55-b7fd-64cd2f409707" 138 ExampleOperatorTokenID12 = "a041cb88-0f4b-0314-89f6-10e1e093d2e5" 139 ExampleOperatorTokenID13 = "cc22a583-243f-3258-14ad-db0e56749657" 140 ExampleOperatorTokenID14 = "5b6d0508-13a6-4bc3-33a1-ba1941e1175b" 141 ExampleOperatorTokenID15 = "e9db1754-c075-d0fc-0a7e-de1e9e7bff98" 142 ) 143 144 // Example Consul ACL tokens for use in tests that match the policies as the 145 // tokens above, but these belong to the "default" Consul namespace. 146 const ( 147 ExampleOperatorTokenID20 = "937b3287-557c-5af8-beb0-d62191988719" 148 ExampleOperatorTokenID21 = "067fd927-abfb-d98f-b693-bb05dccea565" 149 ExampleOperatorTokenID22 = "71f8030f-f6bd-6157-6614-ba6a0bbfba9f" 150 ExampleOperatorTokenID23 = "1dfd2982-b7a1-89ec-09b4-74712983d13c" 151 ExampleOperatorTokenID24 = "d26dbc2a-d5d8-e3d9-8a38-e05dec499124" 152 ExampleOperatorTokenID25 = "dd5a8eef-554c-a1f9-fdb8-f25eb77258bc" 153 ) 154 155 var ( 156 // In no Consul namespace (OSS, ENT w/o Namespaces) 157 158 ExampleOperatorToken0 = &api.ACLToken{ 159 SecretID: ExampleOperatorTokenID0, 160 AccessorID: "228865c6-3bf6-6683-df03-06dea2779088 ", 161 Description: "Operator Token 0", 162 Namespace: "", 163 } 164 165 ExampleOperatorToken1 = &api.ACLToken{ 166 SecretID: ExampleOperatorTokenID1, 167 AccessorID: "e341bacd-535e-417c-8f45-f88d7faffcaf", 168 Description: "Operator Token 1", 169 Policies: []*api.ACLTokenPolicyLink{{ 170 ID: ExamplePolicyID1, 171 }}, 172 Namespace: "", 173 } 174 175 ExampleOperatorToken2 = &api.ACLToken{ 176 SecretID: ExampleOperatorTokenID2, 177 AccessorID: "615b4d77-5164-4ec6-b616-24c0b24ac9cb", 178 Description: "Operator Token 2", 179 Policies: []*api.ACLTokenPolicyLink{{ 180 ID: ExamplePolicyID2, 181 }}, 182 Namespace: "", 183 } 184 185 ExampleOperatorToken3 = &api.ACLToken{ 186 SecretID: ExampleOperatorTokenID3, 187 AccessorID: "6b7de0d7-15f7-45b4-95eb-fb775bfe3fdc", 188 Description: "Operator Token 3", 189 Policies: []*api.ACLTokenPolicyLink{{ 190 ID: ExamplePolicyID3, 191 }}, 192 Namespace: "", 193 } 194 195 ExampleOperatorToken4 = &api.ACLToken{ 196 SecretID: ExampleOperatorTokenID4, 197 AccessorID: "7b5fdb1a-71e5-f3d8-2cfe-448d973f327d", 198 Description: "Operator Token 4", 199 Policies: nil, // no direct policy, only roles 200 Roles: []*api.ACLTokenRoleLink{{ 201 ID: ExampleRoleID1, 202 Name: "example-role-1", 203 }}, 204 Namespace: "", 205 } 206 207 ExampleOperatorToken5 = &api.ACLToken{ 208 SecretID: ExampleOperatorTokenID5, 209 AccessorID: "cf39aad5-00c3-af23-cf0b-75d41e12f28d", 210 Description: "Operator Token 5", 211 Policies: []*api.ACLTokenPolicyLink{{ 212 ID: ExamplePolicyID4, 213 }}, 214 Namespace: "", 215 } 216 217 // In Consul namespace "banana" 218 219 ExampleOperatorToken10 = &api.ACLToken{ 220 SecretID: ExampleOperatorTokenID10, 221 AccessorID: "76a2c3b5-5d64-9089-f701-660eec2d3554", 222 Description: "Operator Token 0", 223 Namespace: "banana", 224 } 225 226 ExampleOperatorToken11 = &api.ACLToken{ 227 SecretID: ExampleOperatorTokenID11, 228 AccessorID: "40f2a36a-0a65-1972-106c-b2e5dd46d6e8", 229 Description: "Operator Token 1", 230 Policies: []*api.ACLTokenPolicyLink{{ 231 ID: ExamplePolicyID1, 232 }}, 233 Namespace: "banana", 234 } 235 236 ExampleOperatorToken12 = &api.ACLToken{ 237 SecretID: ExampleOperatorTokenID12, 238 AccessorID: "894f2c5c-b285-71bf-4acb-6344cecf71f3", 239 Description: "Operator Token 2", 240 Policies: []*api.ACLTokenPolicyLink{{ 241 ID: ExamplePolicyID2, 242 }}, 243 Namespace: "banana", 244 } 245 246 ExampleOperatorToken13 = &api.ACLToken{ 247 SecretID: ExampleOperatorTokenID13, 248 AccessorID: "2a81ec0b-692e-845e-f5b8-c33c05e5af22", 249 Description: "Operator Token 3", 250 Policies: []*api.ACLTokenPolicyLink{{ 251 ID: ExamplePolicyID3, 252 }}, 253 Namespace: "banana", 254 } 255 256 ExampleOperatorToken14 = &api.ACLToken{ 257 SecretID: ExampleOperatorTokenID14, 258 AccessorID: "4273f1cc-5626-7a77-dc65-1f24af035ed5d", 259 Description: "Operator Token 4", 260 Policies: nil, // no direct policy, only roles 261 Roles: []*api.ACLTokenRoleLink{{ 262 ID: ExampleRoleID1, 263 Name: "example-role-1", 264 }}, 265 Namespace: "banana", 266 } 267 268 ExampleOperatorToken15 = &api.ACLToken{ 269 SecretID: ExampleOperatorTokenID15, 270 AccessorID: "5b78e186-87d8-c1ad-966f-f5fa87b05c9a", 271 Description: "Operator Token 5", 272 Policies: []*api.ACLTokenPolicyLink{{ 273 ID: ExamplePolicyID4, 274 }}, 275 Namespace: "banana", 276 } 277 278 // In Consul namespace "default" 279 280 ExampleOperatorToken20 = &api.ACLToken{ 281 SecretID: ExampleOperatorTokenID20, 282 AccessorID: "228865c6-3bf6-6683-df03-06dea2779088", 283 Description: "Operator Token 0", 284 // Should still be able to register jobs where no namespace was set 285 Namespace: "default", 286 } 287 288 ExampleOperatorToken21 = &api.ACLToken{ 289 SecretID: ExampleOperatorTokenID21, 290 AccessorID: "54d01af9-5036-31d3-296b-b15b941d7aa2", 291 Description: "Operator Token 1", 292 Policies: []*api.ACLTokenPolicyLink{{ 293 ID: ExamplePolicyID1, 294 }}, 295 // Should still be able to register jobs where no namespace was set 296 Namespace: "default", 297 } 298 299 ExampleOperatorToken22 = &api.ACLToken{ 300 SecretID: ExampleOperatorTokenID22, 301 AccessorID: "894f2c5c-b285-71bf-4acb-6344cecf71f3", 302 Description: "Operator Token 2", 303 Policies: []*api.ACLTokenPolicyLink{{ 304 ID: ExamplePolicyID2, 305 }}, 306 Namespace: "default", 307 } 308 309 ExampleOperatorToken23 = &api.ACLToken{ 310 SecretID: ExampleOperatorTokenID23, 311 AccessorID: "2a81ec0b-692e-845e-f5b8-c33c05e5af22", 312 Description: "Operator Token 3", 313 Policies: []*api.ACLTokenPolicyLink{{ 314 ID: ExamplePolicyID3, 315 }}, 316 Namespace: "default", 317 } 318 319 ExampleOperatorToken24 = &api.ACLToken{ 320 SecretID: ExampleOperatorTokenID24, 321 AccessorID: "4273f1cc-5626-7a77-dc65-1f24af035ed5d", 322 Description: "Operator Token 4", 323 Policies: nil, // no direct policy, only roles 324 Roles: []*api.ACLTokenRoleLink{{ 325 ID: ExampleRoleID1, 326 Name: "example-role-1", 327 }}, 328 Namespace: "default", 329 } 330 331 ExampleOperatorToken25 = &api.ACLToken{ 332 SecretID: ExampleOperatorTokenID25, 333 AccessorID: "5b78e186-87d8-c1ad-966f-f5fa87b05c9a", 334 Description: "Operator Token 5", 335 Policies: []*api.ACLTokenPolicyLink{{ 336 ID: ExamplePolicyID4, 337 }}, 338 Namespace: "default", 339 } 340 ) 341 342 func (m *MockACLsAPI) TokenReadSelf(q *api.QueryOptions) (*api.ACLToken, *api.QueryMeta, error) { 343 switch q.Token { 344 345 case ExampleOperatorTokenID1: 346 return ExampleOperatorToken1, nil, nil 347 348 case ExampleOperatorTokenID2: 349 return ExampleOperatorToken2, nil, nil 350 351 case ExampleOperatorTokenID3: 352 return ExampleOperatorToken3, nil, nil 353 354 case ExampleOperatorTokenID4: 355 return ExampleOperatorToken4, nil, nil 356 357 case ExampleOperatorTokenID5: 358 return ExampleOperatorToken5, nil, nil 359 360 case ExampleOperatorTokenID10: 361 return ExampleOperatorToken10, nil, nil 362 363 case ExampleOperatorTokenID11: 364 return ExampleOperatorToken11, nil, nil 365 366 case ExampleOperatorTokenID12: 367 return ExampleOperatorToken12, nil, nil 368 369 case ExampleOperatorTokenID13: 370 return ExampleOperatorToken13, nil, nil 371 372 case ExampleOperatorTokenID14: 373 return ExampleOperatorToken14, nil, nil 374 375 case ExampleOperatorTokenID15: 376 return ExampleOperatorToken15, nil, nil 377 378 case ExampleOperatorTokenID20: 379 return ExampleOperatorToken20, nil, nil 380 381 case ExampleOperatorTokenID21: 382 return ExampleOperatorToken21, nil, nil 383 384 case ExampleOperatorTokenID22: 385 return ExampleOperatorToken22, nil, nil 386 387 case ExampleOperatorTokenID23: 388 return ExampleOperatorToken23, nil, nil 389 390 case ExampleOperatorTokenID24: 391 return ExampleOperatorToken24, nil, nil 392 393 case ExampleOperatorTokenID25: 394 return ExampleOperatorToken25, nil, nil 395 396 default: 397 return nil, nil, errors.New("no such token") 398 } 399 } 400 401 // SetError is a helper method for configuring an error that will be returned 402 // on future calls to mocked methods. 403 func (m *MockACLsAPI) SetError(err error) { 404 m.lock.Lock() 405 defer m.lock.Unlock() 406 m.state.error = err 407 } 408 409 // TokenCreate is a mock of ACLsAPI.TokenCreate 410 func (m *MockACLsAPI) TokenCreate(token *api.ACLToken, opts *api.WriteOptions) (*api.ACLToken, *api.WriteMeta, error) { 411 index, created, meta, err := m.tokenCreate(token, opts) 412 413 services := func(token *api.ACLToken) []string { 414 if token == nil { 415 return nil 416 } 417 var names []string 418 for _, id := range token.ServiceIdentities { 419 names = append(names, id.ServiceName) 420 } 421 return names 422 }(created) 423 424 description := func(token *api.ACLToken) string { 425 if token == nil { 426 return "<nil>" 427 } 428 return token.Description 429 }(created) 430 431 accessor := func(token *api.ACLToken) string { 432 if token == nil { 433 return "<nil>" 434 } 435 return token.AccessorID 436 }(created) 437 438 secret := func(token *api.ACLToken) string { 439 if token == nil { 440 return "<nil>" 441 } 442 return token.SecretID 443 }(created) 444 445 m.logger.Trace("TokenCreate()", "description", description, "service_identities", services, "accessor", accessor, "secret", secret, "index", index, "error", err) 446 return created, meta, err 447 } 448 449 func (m *MockACLsAPI) tokenCreate(token *api.ACLToken, _ *api.WriteOptions) (uint64, *api.ACLToken, *api.WriteMeta, error) { 450 m.lock.Lock() 451 defer m.lock.Unlock() 452 453 m.state.index++ 454 455 if m.state.error != nil { 456 return m.state.index, nil, nil, m.state.error 457 } 458 459 secret := &api.ACLToken{ 460 CreateIndex: m.state.index, 461 ModifyIndex: m.state.index, 462 AccessorID: uuid.Generate(), 463 SecretID: uuid.Generate(), 464 Description: token.Description, 465 ServiceIdentities: token.ServiceIdentities, 466 Namespace: token.Namespace, 467 CreateTime: time.Now(), 468 } 469 470 m.state.tokens[secret.AccessorID] = secret 471 472 w := &api.WriteMeta{ 473 RequestTime: 1 * time.Millisecond, 474 } 475 476 return m.state.index, secret, w, nil 477 } 478 479 // TokenDelete is a mock of ACLsAPI.TokenDelete 480 func (m *MockACLsAPI) TokenDelete(accessorID string, opts *api.WriteOptions) (*api.WriteMeta, error) { 481 meta, err := m.tokenDelete(accessorID, opts) 482 m.logger.Trace("TokenDelete()", "accessor", accessorID, "error", err) 483 return meta, err 484 } 485 486 func (m *MockACLsAPI) tokenDelete(tokenID string, _ *api.WriteOptions) (*api.WriteMeta, error) { 487 m.lock.Lock() 488 defer m.lock.Unlock() 489 490 m.state.index++ 491 492 if m.state.error != nil { 493 return nil, m.state.error 494 } 495 496 if _, exists := m.state.tokens[tokenID]; !exists { 497 return nil, nil // consul no-ops delete of non-existent token 498 } 499 500 delete(m.state.tokens, tokenID) 501 502 m.logger.Trace("TokenDelete()") 503 504 return nil, nil 505 } 506 507 // TokenList is a mock of ACLsAPI.TokenList 508 func (m *MockACLsAPI) TokenList(_ *api.QueryOptions) ([]*api.ACLTokenListEntry, *api.QueryMeta, error) { 509 m.lock.Lock() 510 defer m.lock.Unlock() 511 512 //todo(shoenig): will need this for background token reconciliation 513 // coming in another issue 514 515 return nil, nil, nil 516 }