github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/vsphere/permissions.go (about)

     1  package vsphere
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/pkg/errors"
     7  	"github.com/vmware/govmomi/object"
     8  	"github.com/vmware/govmomi/session"
     9  	"github.com/vmware/govmomi/vim25"
    10  	"github.com/vmware/govmomi/vim25/mo"
    11  	vim25types "github.com/vmware/govmomi/vim25/types"
    12  	"k8s.io/apimachinery/pkg/util/sets"
    13  
    14  	vspheretypes "github.com/openshift/installer/pkg/types/vsphere"
    15  )
    16  
    17  //go:generate mockgen -source=./permissions.go -destination=./mock/authmanager_generated.go -package=mock
    18  
    19  // AuthManager defines an interface to an implementation of the AuthorizationManager to facilitate mocking
    20  type AuthManager interface {
    21  	FetchUserPrivilegeOnEntities(ctx context.Context, entities []vim25types.ManagedObjectReference, userName string) ([]vim25types.UserPrivilegeResult, error)
    22  	Properties(ctx context.Context, r vim25types.ManagedObjectReference, ps []string, dst interface{}) error
    23  	Reference() vim25types.ManagedObjectReference
    24  }
    25  
    26  // SessionManager defines an interface to an implementation of the SessionManager to facilitate mocking.
    27  type SessionManager interface {
    28  	UserSession(ctx context.Context) (*vim25types.UserSession, error)
    29  }
    30  
    31  // permissionGroup is the group of permissions needed by cluster creation, operation, or teardown.
    32  type permissionGroup string
    33  
    34  // PermissionGroupDefinition defines a group of permissions and a related human friendly description
    35  type PermissionGroupDefinition struct {
    36  	/* Permissions array of privileges which correlate with the privileges listed in docs */
    37  	Permissions []string
    38  	/* Description friendly description of privilege group */
    39  	Description string
    40  }
    41  
    42  // PrivilegeRelevanceFunc returns true if the associated privilege group privileges should be verified
    43  type PrivilegeRelevanceFunc func(*vspheretypes.Platform) bool
    44  
    45  var (
    46  	permissionVcenter      permissionGroup = "vcenter"
    47  	permissionCluster      permissionGroup = "cluster"
    48  	permissionPortgroup    permissionGroup = "portgroup"
    49  	permissionDatacenter   permissionGroup = "datacenter"
    50  	permissionDatastore    permissionGroup = "datastore"
    51  	permissionResourcePool permissionGroup = "resourcepool"
    52  	permissionFolder       permissionGroup = "folder"
    53  )
    54  
    55  var permissions = map[permissionGroup]PermissionGroupDefinition{
    56  	// Base set of permissions required for cluster creation
    57  	permissionVcenter: {
    58  		Permissions: []string{
    59  			"Cns.Searchable",
    60  			"InventoryService.Tagging.AttachTag",
    61  			"InventoryService.Tagging.CreateCategory",
    62  			"InventoryService.Tagging.CreateTag",
    63  			"InventoryService.Tagging.DeleteCategory",
    64  			"InventoryService.Tagging.DeleteTag",
    65  			"InventoryService.Tagging.EditCategory",
    66  			"InventoryService.Tagging.EditTag",
    67  			"Sessions.ValidateSession",
    68  			"StorageProfile.Update",
    69  			"StorageProfile.View",
    70  		},
    71  		Description: "vSphere vCenter",
    72  	},
    73  	permissionCluster: {
    74  		Permissions: []string{
    75  			"Resource.AssignVMToPool",
    76  			"VApp.AssignResourcePool",
    77  			"VApp.Import",
    78  			"VirtualMachine.Config.AddNewDisk",
    79  		},
    80  		Description: "vSphere vCenter Cluster",
    81  	},
    82  	permissionPortgroup: {
    83  		Permissions: []string{
    84  			"Network.Assign",
    85  		},
    86  		Description: "vSphere Port Group",
    87  	},
    88  	permissionFolder: {
    89  		Permissions: []string{
    90  			"Resource.AssignVMToPool",
    91  			"VApp.Import",
    92  			"VirtualMachine.Config.AddExistingDisk",
    93  			"VirtualMachine.Config.AddNewDisk",
    94  			"VirtualMachine.Config.AddRemoveDevice",
    95  			"VirtualMachine.Config.AdvancedConfig",
    96  			"VirtualMachine.Config.Annotation",
    97  			"VirtualMachine.Config.CPUCount",
    98  			"VirtualMachine.Config.DiskExtend",
    99  			"VirtualMachine.Config.DiskLease",
   100  			"VirtualMachine.Config.EditDevice",
   101  			"VirtualMachine.Config.Memory",
   102  			"VirtualMachine.Config.RemoveDisk",
   103  			"VirtualMachine.Config.Rename",
   104  			"VirtualMachine.Config.ResetGuestInfo",
   105  			"VirtualMachine.Config.Resource",
   106  			"VirtualMachine.Config.Settings",
   107  			"VirtualMachine.Config.UpgradeVirtualHardware",
   108  			"VirtualMachine.Interact.GuestControl",
   109  			"VirtualMachine.Interact.PowerOff",
   110  			"VirtualMachine.Interact.PowerOn",
   111  			"VirtualMachine.Interact.Reset",
   112  			"VirtualMachine.Inventory.Create",
   113  			"VirtualMachine.Inventory.CreateFromExisting",
   114  			"VirtualMachine.Inventory.Delete",
   115  			"VirtualMachine.Provisioning.Clone",
   116  			"VirtualMachine.Provisioning.MarkAsTemplate",
   117  			"VirtualMachine.Provisioning.DeployTemplate",
   118  			"InventoryService.Tagging.ObjectAttachable",
   119  		},
   120  		Description: "Pre-existing Virtual Machine Folder",
   121  	},
   122  	permissionDatacenter: {
   123  		Permissions: []string{
   124  			"Resource.AssignVMToPool",
   125  			"VApp.Import",
   126  			"VirtualMachine.Config.AddExistingDisk",
   127  			"VirtualMachine.Config.AddNewDisk",
   128  			"VirtualMachine.Config.AddRemoveDevice",
   129  			"VirtualMachine.Config.AdvancedConfig",
   130  			"VirtualMachine.Config.Annotation",
   131  			"VirtualMachine.Config.CPUCount",
   132  			"VirtualMachine.Config.DiskExtend",
   133  			"VirtualMachine.Config.DiskLease",
   134  			"VirtualMachine.Config.EditDevice",
   135  			"VirtualMachine.Config.Memory",
   136  			"VirtualMachine.Config.RemoveDisk",
   137  			"VirtualMachine.Config.Rename",
   138  			"VirtualMachine.Config.ResetGuestInfo",
   139  			"VirtualMachine.Config.Resource",
   140  			"VirtualMachine.Config.Settings",
   141  			"VirtualMachine.Config.UpgradeVirtualHardware",
   142  			"VirtualMachine.Interact.GuestControl",
   143  			"VirtualMachine.Interact.PowerOff",
   144  			"VirtualMachine.Interact.PowerOn",
   145  			"VirtualMachine.Interact.Reset",
   146  			"VirtualMachine.Inventory.Create",
   147  			"VirtualMachine.Inventory.CreateFromExisting",
   148  			"VirtualMachine.Inventory.Delete",
   149  			"VirtualMachine.Provisioning.Clone",
   150  			"VirtualMachine.Provisioning.DeployTemplate",
   151  			"VirtualMachine.Provisioning.MarkAsTemplate",
   152  			"Folder.Create",
   153  			"Folder.Delete",
   154  			"InventoryService.Tagging.ObjectAttachable",
   155  		},
   156  		Description: "vSphere vCenter Datacenter",
   157  	},
   158  	permissionDatastore: {
   159  		Permissions: []string{
   160  			"Datastore.AllocateSpace",
   161  			"Datastore.Browse",
   162  			"Datastore.FileManagement",
   163  			"InventoryService.Tagging.ObjectAttachable",
   164  		},
   165  		Description: "vSphere vCenter Datastore",
   166  	},
   167  	permissionResourcePool: {
   168  		Permissions: []string{
   169  			"Resource.AssignVMToPool",
   170  			"VApp.AssignResourcePool",
   171  			"VApp.Import",
   172  			"VirtualMachine.Config.AddNewDisk",
   173  		},
   174  		Description: "vSphere vCenter Resource Pool",
   175  	},
   176  }
   177  
   178  // pruneToAvailablePermissions different versions of vCenter support different privileges.  the intent of this method
   179  // is to prune privileges from the check that don't exist.
   180  func pruneToAvailablePermissions(ctx context.Context, manager AuthManager) error {
   181  	var authManagerMo mo.AuthorizationManager
   182  	err := manager.Properties(ctx, manager.Reference(), []string{"privilegeList"}, &authManagerMo)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	availablePermissions := sets.NewString()
   188  	for _, availablePermission := range authManagerMo.PrivilegeList {
   189  		availablePermissions.Insert(availablePermission.PrivId)
   190  	}
   191  	for permissionGroupKey, permissionGroup := range permissions {
   192  		prunedPermissions := sets.NewString(permissionGroup.Permissions...)
   193  
   194  		prunedPermissions = prunedPermissions.Intersection(availablePermissions)
   195  		permissions[permissionGroupKey] = PermissionGroupDefinition{
   196  			Permissions: prunedPermissions.List(),
   197  			Description: permissionGroup.Description,
   198  		}
   199  	}
   200  	return nil
   201  }
   202  
   203  func newAuthManager(client *vim25.Client) AuthManager {
   204  	authManager := object.NewAuthorizationManager(client)
   205  	return authManager
   206  }
   207  
   208  func comparePrivileges(ctx context.Context, validationCtx *validationContext, moRef vim25types.ManagedObjectReference, permissionGroup PermissionGroupDefinition) error {
   209  	authManager := validationCtx.AuthManager
   210  	sessionMgr := session.NewManager(validationCtx.Client)
   211  	user, err := sessionMgr.UserSession(ctx)
   212  	if err != nil {
   213  		return errors.Wrap(err, "unable to get user session")
   214  	}
   215  	derived, err := authManager.FetchUserPrivilegeOnEntities(ctx, []vim25types.ManagedObjectReference{moRef}, user.UserName)
   216  	if err != nil {
   217  		return errors.Wrap(err, "unable to retrieve privileges")
   218  	}
   219  	var missingPrivileges = ""
   220  	for _, neededPrivilege := range permissionGroup.Permissions {
   221  		var hasPrivilege = false
   222  		for _, userPrivilege := range derived {
   223  			for _, assignedPrivilege := range userPrivilege.Privileges {
   224  				if assignedPrivilege == neededPrivilege {
   225  					hasPrivilege = true
   226  				}
   227  			}
   228  		}
   229  		if !hasPrivilege {
   230  			if missingPrivileges != "" {
   231  				missingPrivileges += ", "
   232  			}
   233  			missingPrivileges += neededPrivilege
   234  		}
   235  	}
   236  	if missingPrivileges != "" {
   237  		return errors.Errorf("privileges missing for %s: %s", permissionGroup.Description, missingPrivileges)
   238  	}
   239  	return nil
   240  }