In a VMware Cloud on AWS (VMC-A) environment, a default CloudAdmin vCenter Server Role is provided to customers to manage and deploy workloads in vCenter Server. Typically, this vCenter Server Role is only granted to limited number of Cloud Administrators within your organization, which you get to control as an end user.
VMware also supports customers in creating additional custom vCenter Server Roles that limits the privileges for other usage such as auditing or workload provisioning. If you create a custom vCenter Server Role for VM provisioning and you are using vSphere Automation Tools that VMware supports including PowerCLI or even the popular vSphere Terraform Provider, you may come across the following error message during the VM deployment:
System.Read privilege required for config.distributedVirtualSwitch
As you can see from the error message, the current user does not have the Read-only privilege assigned to the Virtual Distributed Switch (VDS) which is required by the automation client, in this case the vSphere Terraform Provider, to be able to properly provisioned a VM.
Note: When using the default CloudAdmin role, VMware automatically applies the correct privileges to all applicable vSphere Inventory objects and this is the reason you do not see this problem when using an account with the default CloudAdmin role. For custom vCenter Server Roles that are created by customers, we can not apply this automation as the intention of the custom role(s) are unknown to VMware.
We can quickly fix this issue by following the instructions below which will guide you in properly assigning the correct vSphere permissions to enable VM provisioning when using a non-CloudAdmin role.
Step 1 - Create a new vCenter Server Role with the desired vSphere privileges by navigating to Administration->Access Control->Roles in the vSphere UI. You can only assign privileges that are either equal or less than what has already been defined by the default CloudAdmin role. In my example, I have create a new role called CloudLimitedAdmin
Step 2 - Assign a new vSphere Global Permission for the user/group and associate that with the new vCenter Server Role from the previous step including propagation by navigating to Administration->Access Control->Global Permissions in the vSphere UI.
Step 3 - Finally, we need to assign our user/group with the default Read-only role on the VDS and without propagation by navigating to the vSphere Networking Inventory and select the vmc-hostswitch and then click on Permissions to create a new assignment.
Once you have setup the correct permissions, you should now be able to run "terraform apply" and you will no longer see the error message and the VM deployment should now be successful as shown in screenshot below.
Note: For those interested, I have a Git repo with a basic vSphere Terraform Provider example which you can use for testing purposes.
For those intersted in automating the above, especially with creating a new vSphere Custom Role which can be tedious when using the vSphere UI, you can leverage the following PowerCLI snippet below which demonstrates how you can automate the exact same steps as above.
Step 0 - Use the Connect-VIServer connection string to connect to your VMC-A vCenter Server which you can find in the VMC Cloud Console under the Settings tab of your SDDC.
Step 1 - The following snippet will create a new custom vCenter Server Role called CloudLimitedAdmin and it uses a subset of the CloudAdmin privileges which you can see listed below.
Note: If wish to retrieve the default privileges for the CloudAdmin role, please see the documentation HERE for more details.
$new_vsphere_role_name = "CloudLimitedAdmin" $new_vsphere_privileges = @( "Alarm.Acknowledge" "Alarm.Create" "Alarm.Delete" "Alarm.DisableActions" "Alarm.Edit" "Alarm.SetStatus" "CertificateManagement.Manage" "Cns.Searchable" "ComputePolicy.Manage" "ContentLibrary.AddCertToTrustStore" "ContentLibrary.AddLibraryItem" "ContentLibrary.CheckInTemplate" "ContentLibrary.CheckOutTemplate" "ContentLibrary.CreateLocalLibrary" "ContentLibrary.CreateSubscribedLibrary" "ContentLibrary.DeleteCertFromTrustStore" "ContentLibrary.DeleteLibraryItem" "ContentLibrary.DeleteLocalLibrary" "ContentLibrary.DeleteSubscribedLibrary" "ContentLibrary.DownloadSession" "ContentLibrary.EvictLibraryItem" "ContentLibrary.EvictSubscribedLibrary" "ContentLibrary.GetConfiguration" "ContentLibrary.ImportStorage" "ContentLibrary.ProbeSubscription" "ContentLibrary.ReadStorage" "ContentLibrary.SyncLibrary" "ContentLibrary.SyncLibraryItem" "ContentLibrary.TypeIntrospection" "ContentLibrary.UpdateConfiguration" "ContentLibrary.UpdateLibrary" "ContentLibrary.UpdateLibraryItem" "ContentLibrary.UpdateLocalLibrary" "ContentLibrary.UpdateSession" "ContentLibrary.UpdateSubscribedLibrary" "Datastore.AllocateSpace" "Datastore.Browse" "Datastore.Config" "Datastore.DeleteFile" "Datastore.FileManagement" "Datastore.UpdateVirtualMachineFiles" "Datastore.UpdateVirtualMachineMetadata" "Folder.Create" "Folder.Delete" "Folder.Move" "Folder.Rename" "Global.CancelTask" "Global.GlobalTag" "Global.ManageCustomFields" "Global.ServiceManagers" "Global.SetCustomField" "Global.SystemTag" "InventoryService.Tagging.AttachTag" "InventoryService.Tagging.CreateCategory" "InventoryService.Tagging.CreateTag" "InventoryService.Tagging.DeleteCategory" "InventoryService.Tagging.DeleteTag" "InventoryService.Tagging.EditCategory" "InventoryService.Tagging.EditTag" "InventoryService.Tagging.ModifyUsedByForCategory" "InventoryService.Tagging.ModifyUsedByForTag" "InventoryService.Tagging.ObjectAttachable" "Namespaces.Configure" "Namespaces.SelfServiceManage" "Network.Assign" "Resource.ApplyRecommendation" "Resource.AssignVAppToPool" "Resource.AssignVMToPool" "Resource.ColdMigrate" "Resource.CreatePool" "Resource.EditPool" "Resource.HotMigrate" "Resource.QueryVMotion" "ScheduledTask.Create" "ScheduledTask.Delete" "ScheduledTask.Edit" "ScheduledTask.Run" "Sessions.GlobalMessage" "Sessions.ValidateSession" "StorageProfile.Update" "StorageProfile.View" "StorageViews.View" "System.Anonymous" "System.Read" "System.View" "VApp.ApplicationConfig" "VApp.AssignResourcePool" "VApp.AssignVApp" "VApp.AssignVM" "VApp.Clone" "VApp.Create" "VApp.Delete" "VApp.Export" "VApp.ExtractOvfEnvironment" "VApp.Import" "VApp.InstanceConfig" "VApp.ManagedByConfig" "VApp.Move" "VApp.PowerOff" "VApp.PowerOn" "VApp.Rename" "VApp.ResourceConfig" "VApp.Suspend" "VApp.Unregister" "VirtualMachine.Config.AddExistingDisk" "VirtualMachine.Config.AddNewDisk" "VirtualMachine.Config.AddRemoveDevice" "VirtualMachine.Config.AdvancedConfig" "VirtualMachine.Config.Annotation" "VirtualMachine.Config.CPUCount" "VirtualMachine.Config.ChangeTracking" "VirtualMachine.Config.DiskExtend" "VirtualMachine.Config.DiskLease" "VirtualMachine.Config.EditDevice" "VirtualMachine.Config.HostUSBDevice" "VirtualMachine.Config.ManagedBy" "VirtualMachine.Config.Memory" "VirtualMachine.Config.MksControl" "VirtualMachine.Config.QueryFTCompatibility" "VirtualMachine.Config.QueryUnownedFiles" "VirtualMachine.Config.RawDevice" "VirtualMachine.Config.ReloadFromPath" "VirtualMachine.Config.RemoveDisk" "VirtualMachine.Config.Rename" "VirtualMachine.Config.ResetGuestInfo" "VirtualMachine.Config.Resource" "VirtualMachine.Config.Settings" "VirtualMachine.Config.SwapPlacement" "VirtualMachine.Config.UpgradeVirtualHardware" "VirtualMachine.GuestOperations.Execute" "VirtualMachine.GuestOperations.Modify" "VirtualMachine.GuestOperations.ModifyAliases" "VirtualMachine.GuestOperations.Query" "VirtualMachine.GuestOperations.QueryAliases" "VirtualMachine.Hbr.ConfigureReplication" "VirtualMachine.Hbr.MonitorReplication" "VirtualMachine.Hbr.ReplicaManagement" "VirtualMachine.Interact.AnswerQuestion" "VirtualMachine.Interact.Backup" "VirtualMachine.Interact.ConsoleInteract" "VirtualMachine.Interact.CreateScreenshot" "VirtualMachine.Interact.DefragmentAllDisks" "VirtualMachine.Interact.DeviceConnection" "VirtualMachine.Interact.DnD" "VirtualMachine.Interact.GuestControl" "VirtualMachine.Interact.Pause" "VirtualMachine.Interact.PowerOff" "VirtualMachine.Interact.PowerOn" "VirtualMachine.Interact.PutUsbScanCodes" "VirtualMachine.Interact.Reset" "VirtualMachine.Interact.SESparseMaintenance" "VirtualMachine.Interact.SetCDMedia" "VirtualMachine.Interact.SetFloppyMedia" "VirtualMachine.Interact.Suspend" "VirtualMachine.Interact.ToolsInstall" "VirtualMachine.Inventory.Create" "VirtualMachine.Inventory.CreateFromExisting" "VirtualMachine.Inventory.Delete" "VirtualMachine.Inventory.Move" "VirtualMachine.Inventory.Register" "VirtualMachine.Inventory.Unregister" "VirtualMachine.Namespace.Event" "VirtualMachine.Namespace.EventNotify" "VirtualMachine.Namespace.Management" "VirtualMachine.Namespace.ModifyContent" "VirtualMachine.Namespace.Query" "VirtualMachine.Namespace.ReadContent" "VirtualMachine.Provisioning.Clone" "VirtualMachine.Provisioning.CloneTemplate" "VirtualMachine.Provisioning.CreateTemplateFromVM" "VirtualMachine.Provisioning.Customize" "VirtualMachine.Provisioning.DeployTemplate" "VirtualMachine.Provisioning.DiskRandomAccess" "VirtualMachine.Provisioning.DiskRandomRead" "VirtualMachine.Provisioning.FileRandomAccess" "VirtualMachine.Provisioning.GetVmFiles" "VirtualMachine.Provisioning.MarkAsTemplate" "VirtualMachine.Provisioning.MarkAsVM" "VirtualMachine.Provisioning.ModifyCustSpecs" "VirtualMachine.Provisioning.PromoteDisks" "VirtualMachine.Provisioning.PutVmFiles" "VirtualMachine.Provisioning.ReadCustSpecs" "VirtualMachine.State.CreateSnapshot" "VirtualMachine.State.RemoveSnapshot" "VirtualMachine.State.RenameSnapshot" "VirtualMachine.State.RevertToSnapshot" "VirtualMachineClasses.Manage" ) New-VIRole -Name $new_vsphere_role_name -Privilege (Get-VIPrivilege -Id $new_vsphere_privileges) (Get-VIRole -Name $new_vsphere_role_name).Id
Step 2 - Make a note of the ID for the new custom vCenter Server Role and refer to this blog post HERE for the PowerShell code to assign a vSphere Global Permission.
Step 3 - Finally, we assign the default Read-only role to the VDS by running the following snippet:
$user_principal = "LAB\wlam" $vmc_vds = "vmc-hostswitch" $readOnlyRole = Get-VIRole -Name ReadOnly Get-VDSwitch $vmc_vds | New-VIPermission -Principal $user_principal -Role $readOnlyRole -Propagate:$false
Thanks for the comment!