Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions docs/user/vsphere/per-component-credentials-troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Troubleshooting: Per-Component vCenter Credentials

This guide covers the four error scenarios you may encounter when using per-component
vCenter credentials during OpenShift installation.

---

## 1. Missing Privilege

**Error example:**

```text
Credential validation failed for machineAPI on vcenter1.example.com: missing privileges: [VirtualMachine.Inventory.Create]
```

The service account assigned to that component is missing one or more required vCenter privileges.

### Remediation

Identify the missing privilege from the error message and grant it to the role using
one of the following methods.

**Using govc:**

```bash
# List current privileges on the role
govc role.ls openshift-vsphere-machineapi

# Add a missing privilege to the role
govc role.update openshift-vsphere-machineapi VirtualMachine.Inventory.Create

# Verify the permission assignment for the user
govc permissions.ls /
```

**Using the vCenter UI:**

1. Navigate to **Administration > Access Control > Roles**.
2. Select the role (e.g. `openshift-vsphere-machineapi`).
3. Click **Edit** and find the missing privilege in the hierarchy.
4. Enable the checkbox and click **Save**.

### Canonical privilege sets per component

The table below lists every required privilege. Use it to cross-check your roles.

#### machineAPI (19 privileges)

| Privilege |
|-----------|
| `Datastore.AllocateSpace` |
| `Network.Assign` |
| `Resource.AssignVMToPool` |
| `VirtualMachine.Config.AddExistingDisk` |
| `VirtualMachine.Config.AddNewDisk` |
| `VirtualMachine.Config.AddRemoveDevice` |
| `VirtualMachine.Config.AdvancedConfig` |
| `VirtualMachine.Config.CPUCount` |
| `VirtualMachine.Config.DiskExtend` |
| `VirtualMachine.Config.EditDevice` |
| `VirtualMachine.Config.Memory` |
| `VirtualMachine.Config.RemoveDisk` |
| `VirtualMachine.Config.Resource` |
| `VirtualMachine.Config.Settings` |
| `VirtualMachine.Interact.PowerOff` |
| `VirtualMachine.Interact.PowerOn` |
| `VirtualMachine.Interact.Reset` |
| `VirtualMachine.Inventory.Create` |
| `VirtualMachine.Inventory.Delete` |

#### csiDriver (6 privileges)

| Privilege |
|-----------|
| `Datastore.AllocateSpace` |
| `Datastore.FileManagement` |
| `StoragePod.Config` |
| `VirtualMachine.Config.AddExistingDisk` |
| `VirtualMachine.Config.AddNewDisk` |
| `VirtualMachine.Config.RemoveDisk` |

#### cloudController (3 privileges)

| Privilege |
|-----------|
| `System.Read` |
| `System.View` |
| `VirtualMachine.Inventory.Create` |

#### diagnostics (2 privileges)

| Privilege |
|-----------|
| `Sessions.ValidateSession` |
| `StorageProfile.View` |

---

## 2. Authentication Failure

**Error example:**

```text
Credential validation failed for machineAPI on vcenter1.example.com: authentication error: 535 5.7.8 Error: authentication credentials invalid
```

The username or password for a component service account is incorrect.

### Remediation

Verify the credentials are valid by testing them with `govc`:

```bash
export GOVC_URL=vcenter1.example.com
export GOVC_USERNAME=svc-machineapi@vsphere.local
export GOVC_PASSWORD=<password>

govc about
```

If `govc about` returns an error, the credentials are invalid. Check that:

- `GOVC_USERNAME` matches the account name exactly (including domain suffix, e.g. `@vsphere.local`).
- `GOVC_PASSWORD` does not contain shell metacharacters that could be misinterpreted; quote it.
- The account is not locked out in vCenter (**Administration > Single Sign On > Users and Groups**).

Update `~/.vsphere/credentials` with the corrected values and re-run the installer.

---

## 3. File Permission Error

**Error example:**

```text
credentials file ~/.vsphere/credentials has insecure permissions 0644; expected 0600
```

The credentials file must be readable only by the current user to protect passwords.

### Remediation

```bash
chmod 0600 ~/.vsphere/credentials
chmod 0700 ~/.vsphere
```

Verify the result:

```bash
ls -la ~/.vsphere/credentials
# Expected: -rw------- 1 <user> ...
```

If the file was accidentally committed to version control or copied with broad permissions,
rotate all passwords referenced in the file before correcting permissions.

---

## 4. Partial Configuration

**Error example:**

```text
install-config.yaml: componentCredentials.machineAPI is set but componentCredentials.csiDriver is missing
```

A partial configuration — where some but not all required components have credentials — is rejected
to prevent runtime failures caused by missing credentials discovered only after installation.

### Remediation

Either provide credentials for **all** components listed in `~/.vsphere/credentials`, or
remove the `componentCredentials` block entirely to fall back to a single shared credential.

Use `generate-credentials.sh` to create a complete template:

```bash
export VSPHERE_HOSTNAMES="vcenter1.example.com"
bash upi/vsphere/per-component-credentials/generate-credentials.sh
```

Fill in all four password fields in the generated file before running the installer.
99 changes: 99 additions & 0 deletions docs/user/vsphere/troubleshooting_guide_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package vsphere_test

import (
"os"
"strings"
"testing"
)

var guidePrivileges = []string{
// machineAPI (19)
"Datastore.AllocateSpace",
"Network.Assign",
"Resource.AssignVMToPool",
"VirtualMachine.Config.AddExistingDisk",
"VirtualMachine.Config.AddNewDisk",
"VirtualMachine.Config.AddRemoveDevice",
"VirtualMachine.Config.AdvancedConfig",
"VirtualMachine.Config.CPUCount",
"VirtualMachine.Config.DiskExtend",
"VirtualMachine.Config.EditDevice",
"VirtualMachine.Config.Memory",
"VirtualMachine.Config.RemoveDisk",
"VirtualMachine.Config.Resource",
"VirtualMachine.Config.Settings",
"VirtualMachine.Interact.PowerOff",
"VirtualMachine.Interact.PowerOn",
"VirtualMachine.Interact.Reset",
"VirtualMachine.Inventory.Create",
"VirtualMachine.Inventory.Delete",
// csiDriver (6)
"Datastore.FileManagement",
"StoragePod.Config",
// cloudController (3)
"System.Read",
"System.View",
// diagnostics (2)
"Sessions.ValidateSession",
"StorageProfile.View",
}

const guidePath = "per-component-credentials-troubleshooting.md"

func readGuide(t *testing.T) string {
t.Helper()
data, err := os.ReadFile(guidePath)
if err != nil {
t.Fatalf("read %s: %v", guidePath, err)
}
return string(data)
}

func TestTroubleshootingGuide_CoversAllFourErrorScenarios(t *testing.T) {
content := strings.ToLower(readGuide(t))
scenarios := []struct {
keyword, label string
}{
{"missing privilege", "missing privileges scenario"},
{"authentication", "authentication failure scenario"},
{"file permission", "file permissions scenario"},
{"partial", "partial configuration scenario"},
}
for _, s := range scenarios {
if !strings.Contains(content, s.keyword) {
t.Errorf("troubleshooting guide missing %s (keyword: %q)", s.label, s.keyword)
}
}
}

func TestTroubleshootingGuide_HasGovcCommandOrUIPathForMissingPrivilege(t *testing.T) {
content := readGuide(t)
hasGovcCmd := strings.Contains(content, "govc role.update") || strings.Contains(content, "govc permissions.set")
hasUIPath := strings.Contains(content, "Administration") && strings.Contains(content, "Access Control")
if !hasGovcCmd && !hasUIPath {
t.Error("troubleshooting guide lacks both govc command and vCenter UI navigation path for granting privileges")
}
}

func TestTroubleshootingGuide_AllCanonicalPrivilegesIndexed(t *testing.T) {
content := readGuide(t)
for _, priv := range guidePrivileges {
if !strings.Contains(content, priv) {
t.Errorf("troubleshooting guide does not index privilege %q", priv)
}
}
}

func TestTroubleshootingGuide_AuthFailureHasCredentialCheckCommand(t *testing.T) {
content := readGuide(t)
if !strings.Contains(content, "govc about") && !strings.Contains(content, "GOVC_USERNAME") {
t.Error("authentication failure section lacks govc credential verification command (e.g., govc about)")
}
}

func TestTroubleshootingGuide_FilePermissionSectionHasChmodCommand(t *testing.T) {
content := readGuide(t)
if !strings.Contains(content, "chmod 0600") && !strings.Contains(content, "chmod 600") {
t.Error("file permissions section does not provide chmod remediation command")
}
}
82 changes: 82 additions & 0 deletions upi/vsphere/per-component-credentials/create-roles.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/pwsh
# create-roles.ps1 — create per-component vCenter roles for OpenShift installation (PowerCLI).
#
# Requirements:
# VMware PowerCLI module (Install-Module -Name VMware.PowerCLI)
#
# Usage:
# Connect-VIServer -Server vcenter.example.com -User administrator@vsphere.local -Password secret
# .\create-roles.ps1

param(
[string]$Server = $env:GOVC_URL
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# --------------------------------------------------------------------------
# openshift-vsphere-machineapi — 19 privileges required by the Machine API
# --------------------------------------------------------------------------
$machineAPIPrivileges = @(
"Datastore.AllocateSpace",
"Network.Assign",
"Resource.AssignVMToPool",
"VirtualMachine.Config.AddExistingDisk",
"VirtualMachine.Config.AddNewDisk",
"VirtualMachine.Config.AddRemoveDevice",
"VirtualMachine.Config.AdvancedConfig",
"VirtualMachine.Config.CPUCount",
"VirtualMachine.Config.DiskExtend",
"VirtualMachine.Config.EditDevice",
"VirtualMachine.Config.Memory",
"VirtualMachine.Config.RemoveDisk",
"VirtualMachine.Config.Resource",
"VirtualMachine.Config.Settings",
"VirtualMachine.Interact.PowerOff",
"VirtualMachine.Interact.PowerOn",
"VirtualMachine.Interact.Reset",
"VirtualMachine.Inventory.Create",
"VirtualMachine.Inventory.Delete"
)
New-VIRole -Name "openshift-vsphere-machineapi" -Privilege (Get-VIPrivilege -Id $machineAPIPrivileges)
Write-Host "Created role: openshift-vsphere-machineapi (19 privileges)"

# --------------------------------------------------------------------------
# openshift-vsphere-csidriver — 6 privileges required by the CSI driver
# --------------------------------------------------------------------------
$csiDriverPrivileges = @(
"Datastore.AllocateSpace",
"Datastore.FileManagement",
"StoragePod.Config",
"VirtualMachine.Config.AddExistingDisk",
"VirtualMachine.Config.AddNewDisk",
"VirtualMachine.Config.RemoveDisk"
)
New-VIRole -Name "openshift-vsphere-csidriver" -Privilege (Get-VIPrivilege -Id $csiDriverPrivileges)
Write-Host "Created role: openshift-vsphere-csidriver (6 privileges)"

# --------------------------------------------------------------------------
# openshift-vsphere-cloudcontroller — 3 privileges required by Cloud Controller Manager
# --------------------------------------------------------------------------
$cloudControllerPrivileges = @(
"System.Read",
"System.View",
"VirtualMachine.Inventory.Create"
)
New-VIRole -Name "openshift-vsphere-cloudcontroller" -Privilege (Get-VIPrivilege -Id $cloudControllerPrivileges)
Write-Host "Created role: openshift-vsphere-cloudcontroller (3 privileges)"

# --------------------------------------------------------------------------
# openshift-vsphere-diagnostics — 2 privileges required by vSphere Problem Detector
# --------------------------------------------------------------------------
$diagnosticsPrivileges = @(
"Sessions.ValidateSession",
"StorageProfile.View"
)
New-VIRole -Name "openshift-vsphere-diagnostics" -Privilege (Get-VIPrivilege -Id $diagnosticsPrivileges)
Write-Host "Created role: openshift-vsphere-diagnostics (2 privileges)"

Write-Host ""
Write-Host "All four per-component vCenter roles created successfully."
Write-Host "Assign each role to the corresponding service account on the appropriate vCenter objects."
Loading