github.com/vmware/govmomi@v0.51.0/simulator/crypto_manager_kmip.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package simulator 6 7 import ( 8 "slices" 9 10 "github.com/google/uuid" 11 12 "github.com/vmware/govmomi/crypto" 13 "github.com/vmware/govmomi/vim25/methods" 14 "github.com/vmware/govmomi/vim25/mo" 15 "github.com/vmware/govmomi/vim25/soap" 16 "github.com/vmware/govmomi/vim25/types" 17 ) 18 19 const ( 20 nativeKeyProvider = string(types.KmipClusterInfoKmsManagementTypeNativeProvider) 21 ) 22 23 type CryptoManagerKmip struct { 24 mo.CryptoManagerKmip 25 26 keyIDToProviderID map[string]string 27 } 28 29 func (m *CryptoManagerKmip) init(r *Registry) { 30 if m.keyIDToProviderID == nil { 31 m.keyIDToProviderID = map[string]string{} 32 } 33 } 34 35 func (m *CryptoManagerKmip) ListKmipServers( 36 ctx *Context, req *types.ListKmipServers) soap.HasFault { 37 38 body := methods.ListKmipServersBody{ 39 Res: &types.ListKmipServersResponse{}, 40 } 41 42 if len(m.KmipServers) > 0 { 43 limit := len(m.KmipServers) 44 if req.Limit != nil { 45 if reqLimit := int(*req.Limit); reqLimit >= 0 && reqLimit < limit { 46 limit = reqLimit 47 } 48 } 49 body.Res.Returnval = m.KmipServers[0:limit] 50 } 51 52 return &body 53 54 } 55 56 // TODO: Implement req.DefaultsToParent 57 func (m *CryptoManagerKmip) GetDefaultKmsCluster( 58 ctx *Context, req *types.GetDefaultKmsCluster) soap.HasFault { 59 60 var ( 61 providerID string 62 body methods.GetDefaultKmsClusterBody 63 ) 64 65 for i := range m.KmipServers { 66 c := m.KmipServers[i] 67 if req.Entity != nil { 68 for j := range c.UseAsEntityDefault { 69 if *req.Entity == c.UseAsEntityDefault[j] { 70 providerID = c.ClusterId.Id 71 } 72 } 73 } else if c.UseAsDefault { 74 providerID = c.ClusterId.Id 75 } 76 if providerID != "" { 77 break 78 } 79 } 80 81 if providerID == "" { 82 body.Fault_ = Fault("No default provider", &types.RuntimeFault{}) 83 } else { 84 body.Res = &types.GetDefaultKmsClusterResponse{ 85 Returnval: &types.KeyProviderId{Id: providerID}, 86 } 87 } 88 89 return &body 90 } 91 92 type retrieveKmipServerStatusTask struct { 93 *CryptoManagerKmip 94 get []types.KmipClusterInfo 95 ctx *Context 96 } 97 98 func (c *retrieveKmipServerStatusTask) Run( 99 task *Task) (types.AnyType, types.BaseMethodFault) { 100 101 var result []types.CryptoManagerKmipClusterStatus 102 103 if len(c.get) == 0 { 104 c.get = make([]types.KmipClusterInfo, len(c.KmipServers)) 105 copy(c.get, c.KmipServers) 106 } 107 108 for i := range c.get { 109 g := &c.get[i] 110 if len(g.Servers) == 0 { 111 for j := range c.KmipServers { 112 if g.ClusterId.Id == c.KmipServers[j].ClusterId.Id { 113 g.Servers = make( 114 []types.KmipServerInfo, len(c.KmipServers[j].Servers)) 115 copy(g.Servers, c.KmipServers[j].Servers) 116 } 117 } 118 } 119 } 120 121 for i := range c.KmipServers { 122 for j := range c.get { 123 if c.KmipServers[i].ClusterId.Id == c.get[j].ClusterId.Id { 124 clusterStatus := types.CryptoManagerKmipClusterStatus{ 125 ClusterId: types.KeyProviderId{ 126 Id: c.KmipServers[i].ClusterId.Id, 127 }, 128 ManagementType: c.KmipServers[i].ManagementType, 129 OverallStatus: types.ManagedEntityStatusGreen, 130 } 131 for k := range c.KmipServers[i].Servers { 132 for l := range c.get[j].Servers { 133 if c.KmipServers[i].Servers[k].Name == c.get[j].Servers[l].Name { 134 clusterStatus.Servers = append( 135 clusterStatus.Servers, 136 types.CryptoManagerKmipServerStatus{ 137 Name: c.KmipServers[i].Servers[k].Name, 138 Status: types.ManagedEntityStatusGreen, 139 }, 140 ) 141 } 142 } 143 } 144 result = append(result, clusterStatus) 145 } 146 } 147 } 148 149 return types.ArrayOfCryptoManagerKmipClusterStatus{ 150 CryptoManagerKmipClusterStatus: result, 151 }, nil 152 } 153 154 func (m *CryptoManagerKmip) RetrieveKmipServersStatusTask( 155 ctx *Context, req *types.RetrieveKmipServersStatus_Task) soap.HasFault { 156 157 var body methods.RetrieveKmipServersStatus_TaskBody 158 159 runner := &retrieveKmipServerStatusTask{ 160 CryptoManagerKmip: m, 161 ctx: ctx, 162 get: req.Clusters, 163 } 164 task := CreateTask( 165 runner.Reference(), 166 "retrieveKmipServerStatus", 167 runner.Run) 168 169 body.Res = &types.RetrieveKmipServersStatus_TaskResponse{ 170 Returnval: task.Run(ctx), 171 } 172 173 return &body 174 } 175 176 func (m *CryptoManagerKmip) MarkDefault( 177 ctx *Context, req *types.MarkDefault) soap.HasFault { 178 179 return m.SetDefaultKmsCluster( 180 ctx, 181 &types.SetDefaultKmsCluster{ 182 This: req.This, 183 ClusterId: &types.KeyProviderId{ 184 Id: req.ClusterId.Id, 185 }, 186 }) 187 188 } 189 190 func (m *CryptoManagerKmip) SetDefaultKmsCluster( 191 ctx *Context, req *types.SetDefaultKmsCluster) soap.HasFault { 192 193 var ( 194 validClusterID bool 195 body methods.SetDefaultKmsClusterBody 196 ) 197 198 for i := range m.KmipServers { 199 c := &m.KmipServers[i] 200 if req.ClusterId != nil && req.ClusterId.Id != "" { 201 if c.ClusterId.Id != req.ClusterId.Id { 202 c.UseAsDefault = false 203 c.UseAsEntityDefault = nil 204 } else { 205 validClusterID = true 206 if req.Entity == nil { 207 c.UseAsDefault = true 208 } else { 209 found := false 210 for j := range c.UseAsEntityDefault { 211 if *req.Entity == c.UseAsEntityDefault[j] { 212 found = true 213 break 214 } 215 } 216 if !found { 217 c.UseAsEntityDefault = append( 218 c.UseAsEntityDefault, 219 *req.Entity) 220 } 221 } 222 } 223 } else if req.Entity != nil { 224 x := -1 225 for j := range c.UseAsEntityDefault { 226 if *req.Entity == c.UseAsEntityDefault[j] { 227 x = j 228 break 229 } 230 } 231 if x >= 0 { 232 c.UseAsEntityDefault = slices.Delete( 233 c.UseAsEntityDefault, x, x+1) 234 } 235 } else { 236 c.UseAsDefault = false 237 } 238 } 239 240 if req.ClusterId != nil && req.ClusterId.Id != "" && !validClusterID { 241 body.Fault_ = Fault("Invalid cluster ID", &types.RuntimeFault{}) 242 } else { 243 body.Res = &types.SetDefaultKmsClusterResponse{} 244 } 245 246 return &body 247 } 248 249 // real vCenter only allows TrustAuthority, but we allow more to simplify test setup 250 var validClusterTypes = []string{ 251 string(types.KmipClusterInfoKmsManagementTypeTrustAuthority), 252 string(types.KmipClusterInfoKmsManagementTypeUnknown), 253 string(types.KmipClusterInfoKmsManagementTypeNativeProvider), 254 } 255 256 func (m *CryptoManagerKmip) RegisterKmsCluster( 257 ctx *Context, req *types.RegisterKmsCluster) soap.HasFault { 258 259 var body methods.RegisterKmsClusterBody 260 261 if slices.Contains(validClusterTypes, req.ManagementType) { 262 for i := range m.KmipServers { 263 if req.ClusterId.Id == m.KmipServers[i].ClusterId.Id { 264 body.Fault_ = Fault("Already registered", &types.RuntimeFault{}) 265 } 266 } 267 } else { 268 body.Fault_ = Fault("", &types.InvalidArgument{ 269 InvalidProperty: "managementType", 270 }) 271 } 272 if body.Fault_ == nil { 273 body.Res = &types.RegisterKmsClusterResponse{} 274 m.KmipServers = append(m.KmipServers, 275 types.KmipClusterInfo{ 276 ClusterId: types.KeyProviderId{ 277 Id: req.ClusterId.Id, 278 }, 279 ManagementType: req.ManagementType, 280 }) 281 } 282 283 return &body 284 } 285 286 func (m *CryptoManagerKmip) UnregisterKmsCluster( 287 ctx *Context, req *types.UnregisterKmsCluster) soap.HasFault { 288 289 var body methods.UnregisterKmsClusterBody 290 291 x := -1 292 for i := range m.KmipServers { 293 if req.ClusterId.Id == m.KmipServers[i].ClusterId.Id { 294 x = i 295 } 296 } 297 298 if x < 0 { 299 body.Fault_ = Fault("Invalid cluster ID", &types.RuntimeFault{}) 300 } else { 301 m.KmipServers = slices.Delete(m.KmipServers, x, x+1) 302 body.Res = &types.UnregisterKmsClusterResponse{} 303 } 304 305 return &body 306 } 307 308 func (m *CryptoManagerKmip) RegisterKmipServer( 309 ctx *Context, req *types.RegisterKmipServer) soap.HasFault { 310 311 var ( 312 validClusterID bool 313 alreadyRegistered bool 314 body methods.RegisterKmipServerBody 315 ) 316 317 if req.Server.Info.Name == "" { 318 body.Fault_ = Fault("", &types.InvalidArgument{InvalidProperty: "server.info.name"}) 319 return &body 320 } 321 322 for i := range m.KmipServers { 323 c := &m.KmipServers[i] 324 325 if req.Server.ClusterId.Id == c.ClusterId.Id { 326 validClusterID = true 327 for j := range c.Servers { 328 if req.Server.Info.Name == c.Servers[j].Name { 329 alreadyRegistered = true 330 break 331 } 332 } 333 if !alreadyRegistered { 334 c.Servers = append(c.Servers, req.Server.Info) 335 } 336 } 337 338 if validClusterID || alreadyRegistered { 339 break 340 } 341 } 342 343 if alreadyRegistered { 344 body.Fault_ = Fault("Already registered", &types.RuntimeFault{}) 345 } else { 346 if !validClusterID { 347 m.KmipServers = append(m.KmipServers, 348 types.KmipClusterInfo{ 349 ClusterId: types.KeyProviderId{ 350 Id: req.Server.ClusterId.Id, 351 }, 352 ManagementType: string(types.KmipClusterInfoKmsManagementTypeVCenter), 353 Servers: []types.KmipServerInfo{req.Server.Info}, 354 }) 355 } 356 357 body.Res = &types.RegisterKmipServerResponse{} 358 } 359 360 return &body 361 } 362 363 func (m *CryptoManagerKmip) RemoveKmipServer( 364 ctx *Context, req *types.RemoveKmipServer) soap.HasFault { 365 366 var ( 367 validClusterID bool 368 validServerName bool 369 body methods.RemoveKmipServerBody 370 ) 371 372 for i := range m.KmipServers { 373 c := &m.KmipServers[i] 374 375 if req.ClusterId.Id == c.ClusterId.Id { 376 validClusterID = true 377 378 x := -1 379 for j := range c.Servers { 380 if req.ServerName == c.Servers[j].Name { 381 x = j 382 break 383 } 384 } 385 386 if x >= 0 { 387 validServerName = true 388 c.Servers = slices.Delete(c.Servers, x, x+1) 389 } 390 } 391 392 if validClusterID { 393 break 394 } 395 } 396 397 if !validClusterID { 398 body.Fault_ = Fault("Invalid cluster ID", &types.RuntimeFault{}) 399 } else if !validServerName { 400 body.Fault_ = Fault("Invalid server name", &types.RuntimeFault{}) 401 } else { 402 body.Res = &types.RemoveKmipServerResponse{} 403 } 404 405 return &body 406 } 407 408 func (m *CryptoManagerKmip) UpdateKmipServer( 409 ctx *Context, req *types.UpdateKmipServer) soap.HasFault { 410 411 var ( 412 validClusterID bool 413 validServerName bool 414 body methods.UpdateKmipServerBody 415 ) 416 417 for i := range m.KmipServers { 418 c := &m.KmipServers[i] 419 420 if req.Server.ClusterId.Id == c.ClusterId.Id { 421 validClusterID = true 422 for j := range c.Servers { 423 if req.Server.Info.Name == c.Servers[j].Name { 424 validServerName = true 425 c.Servers[j] = req.Server.Info 426 break 427 } 428 } 429 } 430 431 if validClusterID { 432 break 433 } 434 } 435 436 if !validClusterID { 437 body.Fault_ = Fault("Invalid cluster ID", &types.RuntimeFault{}) 438 } else if !validServerName { 439 body.Fault_ = Fault("Invalid server name", &types.RuntimeFault{}) 440 } else { 441 body.Res = &types.UpdateKmipServerResponse{} 442 } 443 444 return &body 445 } 446 447 func (m *CryptoManagerKmip) GenerateKey( 448 ctx *Context, req *types.GenerateKey) soap.HasFault { 449 450 var ( 451 provider types.KmipClusterInfo 452 body methods.GenerateKeyBody 453 ) 454 455 for i := range m.KmipServers { 456 c := m.KmipServers[i] 457 if req.KeyProvider == nil { 458 if c.UseAsDefault { 459 provider = c 460 } 461 } else if req.KeyProvider.Id == c.ClusterId.Id { 462 provider = c 463 } 464 if provider.ClusterId.Id != "" { 465 break 466 } 467 } 468 469 if provider.ClusterId.Id == "" { 470 body.Fault_ = Fault("No default provider", &types.RuntimeFault{}) 471 } else if provider.ManagementType == nativeKeyProvider { 472 body.Fault_ = Fault( 473 "Cannot generate keys with native key provider", 474 &types.RuntimeFault{}) 475 } else { 476 newKey := uuid.NewString() 477 m.keyIDToProviderID[newKey] = provider.ClusterId.Id 478 479 body.Res = &types.GenerateKeyResponse{ 480 Returnval: types.CryptoKeyResult{ 481 Success: true, 482 KeyId: types.CryptoKeyId{ 483 KeyId: newKey, 484 ProviderId: &types.KeyProviderId{ 485 Id: provider.ClusterId.Id, 486 }, 487 }, 488 }, 489 } 490 } 491 492 return &body 493 } 494 495 func (m *CryptoManagerKmip) ListKeys( 496 ctx *Context, req *types.ListKeys) soap.HasFault { 497 498 body := methods.ListKeysBody{ 499 Res: &types.ListKeysResponse{}, 500 } 501 502 if len(m.keyIDToProviderID) > 0 { 503 var ( 504 i int 505 limit = len(m.keyIDToProviderID) 506 ) 507 if req.Limit != nil { 508 if reqLimit := int(*req.Limit); reqLimit >= 0 && reqLimit < limit { 509 limit = reqLimit 510 } 511 } 512 for keyID, providerID := range m.keyIDToProviderID { 513 if i >= limit { 514 break 515 } 516 i++ 517 body.Res.Returnval = append(body.Res.Returnval, types.CryptoKeyId{ 518 KeyId: keyID, 519 ProviderId: &types.KeyProviderId{ 520 Id: providerID, 521 }, 522 }) 523 } 524 } 525 526 return &body 527 } 528 529 func (m *CryptoManagerKmip) QueryCryptoKeyStatus( 530 ctx *Context, req *types.QueryCryptoKeyStatus) soap.HasFault { 531 532 status := make([]types.CryptoManagerKmipCryptoKeyStatus, len(req.KeyIds)) 533 534 servers := make(map[string]types.KmipClusterInfo, len(m.KmipServers)) 535 for _, p := range m.KmipServers { 536 servers[p.KeyId] = p 537 } 538 539 for i, id := range req.KeyIds { 540 s := types.CryptoManagerKmipCryptoKeyStatus{KeyId: id} 541 542 if req.CheckKeyBitMap&crypto.CheckKeyAvailable != 0 { 543 s.KeyAvailable = types.NewBool(false) 544 s.Reason = string(types.CryptoManagerKmipCryptoKeyStatusKeyUnavailableReasonKeyStateMissingInKMS) 545 546 providerID := "" 547 if id.ProviderId != nil { 548 providerID = id.ProviderId.Id 549 } 550 cluster := servers[providerID] 551 if pid, ok := m.keyIDToProviderID[id.KeyId]; ok { 552 if cluster.ManagementType == string(types.KmipClusterInfoKmsManagementTypeNativeProvider) { 553 s.Reason = string(types.CryptoManagerKmipCryptoKeyStatusKeyUnavailableReasonKeyStateManagedByNKP) 554 } else if pid == providerID { 555 *s.KeyAvailable = true 556 s.Reason = "" 557 } 558 } 559 } 560 561 if req.CheckKeyBitMap&crypto.CheckKeyUsedByVms != 0 { 562 for _, obj := range ctx.Map.All("VirtualMachine") { 563 ctx.WithLock(obj, func() { 564 if key := obj.(*VirtualMachine).Config.KeyId; key != nil { 565 if *key == id { 566 status[i].EncryptedVMs = append(status[i].EncryptedVMs, obj.Reference()) 567 } 568 } 569 }) 570 } 571 } 572 573 status[i] = s 574 } 575 576 return &methods.QueryCryptoKeyStatusBody{ 577 Res: &types.QueryCryptoKeyStatusResponse{ 578 Returnval: status, 579 }, 580 } 581 } 582 583 func getDefaultProvider( 584 ctx *Context, 585 vm *VirtualMachine, 586 generateKey bool) (string, string) { 587 588 m := ctx.Map.CryptoManager() 589 if m == nil { 590 return "", "" 591 } 592 593 var ( 594 providerID string 595 keyID string 596 ) 597 598 ctx.WithLock(m, func() { 599 // Lookup the default provider ID via the VM's parent entities: 600 // host, host folder, cluster. 601 if host := vm.Runtime.Host; host != nil { 602 for i := range m.KmipServers { 603 kmipCluster := m.KmipServers[i] 604 for j := range kmipCluster.UseAsEntityDefault { 605 parent := host 606 for providerID == "" && parent != nil { 607 if kmipCluster.UseAsEntityDefault[j] == *parent { 608 providerID = kmipCluster.ClusterId.Id 609 break 610 } else { 611 // TODO (akutz): Support looking up the 612 // default entity via the host 613 // folder and cluster. 614 parent = nil 615 } 616 } 617 if providerID != "" { 618 break 619 } 620 } 621 if providerID != "" { 622 break 623 } 624 } 625 } 626 627 // If the default provider ID has not been discovered, see if 628 // any of the providers are the global default. 629 if providerID == "" { 630 for i := range m.KmipServers { 631 if providerID == "" && m.KmipServers[i].UseAsDefault { 632 providerID = m.KmipServers[i].ClusterId.Id 633 break 634 } 635 } 636 } 637 }) 638 639 if providerID != "" && generateKey { 640 keyID = generateKeyForProvider(ctx, providerID) 641 } 642 643 return providerID, keyID 644 } 645 646 func generateKeyForProvider(ctx *Context, providerID string) string { 647 m := ctx.Map.CryptoManager() 648 if m == nil { 649 return "" 650 } 651 var keyID string 652 ctx.WithLock(m, func() { 653 keyID = uuid.NewString() 654 m.keyIDToProviderID[keyID] = providerID 655 }) 656 return keyID 657 }