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  }