Prefer Proxmox guest-agent privileges

Refs #1466
This commit is contained in:
rcourtman 2026-05-24 22:28:29 +01:00
parent 117ec901da
commit 8046b5035d
12 changed files with 170 additions and 30 deletions

View file

@ -110,11 +110,10 @@ pveum user permissions <user>@pam
At minimum, ensure the user/token has read access for inventory and metrics:
- `Sys.Audit`
- `VM.Monitor`
- `VM.GuestAgent.Audit` and `VM.GuestAgent.FileRead` when available
- `VM.Monitor` only as a legacy fallback on older Proxmox 8 systems
- `Datastore.Audit`
For VM disk usage via QEMU guest agent, also ensure `VM.GuestAgent.Audit` (PVE 9+).
### Recovery Mode
If you are completely locked out, you can trigger a recovery token from localhost:
```bash

View file

@ -17,14 +17,14 @@ Monitor actual disk usage inside your VMs using the QEMU Guest Agent.
## ⚙️ Requirements
* **QEMU Guest Agent**: Must be installed and running inside the VM.
* **Proxmox Permissions**: `VM.Monitor` (Proxmox 8) or `VM.GuestAgent.Audit` (Proxmox 9+).
* **Proxmox Permissions**: `VM.GuestAgent.Audit` plus `VM.GuestAgent.FileRead` when available, with `VM.Monitor` only as a legacy fallback on older Proxmox 8 systems.
## 🔧 Troubleshooting
| Issue | Solution |
| :--- | :--- |
| **Disk shows "-"** | Hover over the dash for details. Common causes: Agent not running, disabled in config, or permission denied. |
| **Permission Denied** | Ensure your Proxmox token/user has `VM.GuestAgent.Audit` (PVE 9+) or `VM.Monitor` (PVE 8). |
| **Permission Denied** | Ensure your Proxmox token/user has `VM.GuestAgent.Audit` plus `VM.GuestAgent.FileRead` where available, or `VM.Monitor` on older Proxmox 8 systems. |
| **Agent Timeout** | Increase the guest-agent filesystem timeout if network or guest responsiveness is slow: `GUEST_AGENT_FSINFO_TIMEOUT=30s`. |
| **Windows VMs** | Ensure the **QEMU Guest Agent** service is running in Windows Services. |

View file

@ -29,7 +29,7 @@ export function DiskList(props: DiskListProps) {
case 'agent-timeout':
return 'Guest agent timeout. Agent may need to be restarted.';
case 'permission-denied':
return 'Permission denied. Check that your Pulse user/token has VM.Monitor permission (PVE 8) or VM.GuestAgent.Audit permission (PVE 9).';
return 'Permission denied. Check that your Pulse user/token has VM.GuestAgent.Audit and VM.GuestAgent.FileRead permissions, or legacy VM.Monitor on older Proxmox 8 systems.';
case 'agent-disabled':
return 'Guest agent is disabled in VM configuration. Enable it in VM Options.';
case 'no-filesystems':

View file

@ -673,7 +673,7 @@ export function GuestRow(props: GuestRowProps) {
case 'agent-timeout':
return 'Guest agent timeout. Agent may need to be restarted.';
case 'permission-denied':
return 'Permission denied. Check that your Pulse user/token has VM.Monitor permission (PVE 8) or VM.GuestAgent.Audit permission (PVE 9).';
return 'Permission denied. Check that your Pulse user/token has VM.GuestAgent.Audit and VM.GuestAgent.FileRead permissions, or legacy VM.Monitor on older Proxmox 8 systems.';
case 'agent-disabled':
return 'Guest agent is disabled in VM configuration. Enable it in VM Options.';
case 'no-filesystems':

View file

@ -1160,7 +1160,7 @@ export const NodeModal: Component<NodeModalProps> = (props) => {
type="button"
onClick={async () => {
const cmd =
'pveum aclmod / -user pulse-monitor@pam -role PVEAuditor && if pveum role list 2>/dev/null | grep -q "VM.Monitor" || pveum role add TestMonitor -privs VM.Monitor 2>/dev/null; then pveum role delete TestMonitor 2>/dev/null; pveum role delete PulseMonitor 2>/dev/null; pveum role add PulseMonitor -privs VM.Monitor; pveum aclmod / -user pulse-monitor@pam -role PulseMonitor; fi';
'pveum aclmod / -user pulse-monitor@pam -role PVEAuditor && EXTRA_PRIVS=(); if pveum role list 2>/dev/null | grep -q "VM.GuestAgent.Audit" || pveum role add PulseTmpGuestAudit -privs VM.GuestAgent.Audit 2>/dev/null; then EXTRA_PRIVS+=("VM.GuestAgent.Audit"); pveum role delete PulseTmpGuestAudit 2>/dev/null || true; if pveum role list 2>/dev/null | grep -q "VM.GuestAgent.FileRead" || pveum role add PulseTmpGuestFileRead -privs VM.GuestAgent.FileRead 2>/dev/null; then EXTRA_PRIVS+=("VM.GuestAgent.FileRead"); pveum role delete PulseTmpGuestFileRead 2>/dev/null || true; fi; elif pveum role list 2>/dev/null | grep -q "VM.Monitor" || pveum role add PulseTmpVMMonitor -privs VM.Monitor 2>/dev/null; then EXTRA_PRIVS+=("VM.Monitor"); pveum role delete PulseTmpVMMonitor 2>/dev/null || true; fi; if [ ${#EXTRA_PRIVS[@]} -gt 0 ]; then PRIV_STRING="$(IFS=,; echo "${EXTRA_PRIVS[*]}")"; pveum role modify PulseMonitor -privs "$PRIV_STRING" 2>/dev/null || pveum role add PulseMonitor -privs "$PRIV_STRING"; pveum aclmod / -user pulse-monitor@pam -role PulseMonitor; fi';
if (await copyToClipboard(cmd)) {
notificationStore.success('Command copied!');
}
@ -1189,7 +1189,7 @@ export const NodeModal: Component<NodeModalProps> = (props) => {
</button>
<code class="text-gray-800 dark:text-gray-200 whitespace-pre-line">
{
'# Apply monitoring permissions - use built-in PVEAuditor role\npveum aclmod / -user pulse-monitor@pam -role PVEAuditor\n\n# Gather additional privileges for VM metrics\nEXTRA_PRIVS=()\n\n# Sys.Audit (Ceph, cluster status)\nif pveum role list 2>/dev/null | grep -q "Sys.Audit"; then\n EXTRA_PRIVS+=(\"Sys.Audit\")\nelse\n if pveum role add PulseTmpSysAudit -privs Sys.Audit 2>/dev/null; then\n EXTRA_PRIVS+=(\"Sys.Audit\")\n pveum role delete PulseTmpSysAudit 2>/dev/null\n fi\nfi\n\n# VM guest agent / monitor privileges\nVM_PRIV=\"\"\nif pveum role list 2>/dev/null | grep -q "VM.Monitor"; then\n VM_PRIV=\"VM.Monitor\"\nelif pveum role list 2>/dev/null | grep -q "VM.GuestAgent.Audit"; then\n VM_PRIV=\"VM.GuestAgent.Audit\"\nelse\n if pveum role add PulseTmpVMMonitor -privs VM.Monitor 2>/dev/null; then\n VM_PRIV=\"VM.Monitor\"\n pveum role delete PulseTmpVMMonitor 2>/dev/null\n elif pveum role add PulseTmpGuestAudit -privs VM.GuestAgent.Audit 2>/dev/null; then\n VM_PRIV=\"VM.GuestAgent.Audit\"\n pveum role delete PulseTmpGuestAudit 2>/dev/null\n fi\nfi\n\nif [ -n \"$VM_PRIV\" ]; then\n EXTRA_PRIVS+=(\"$VM_PRIV\")\nfi\n\nif [ ${#EXTRA_PRIVS[@]} -gt 0 ]; then\n PRIV_STRING=\"${EXTRA_PRIVS[*]}\"\n pveum role delete PulseMonitor 2>/dev/null\n pveum role add PulseMonitor -privs \"$PRIV_STRING\"\n pveum aclmod / -user pulse-monitor@pam -role PulseMonitor\nfi'
'# Apply monitoring permissions - use built-in PVEAuditor role\npveum aclmod / -user pulse-monitor@pam -role PVEAuditor\n\n# Gather additional privileges for VM metrics\nEXTRA_PRIVS=()\n\n# Sys.Audit (Ceph, cluster status)\nif pveum role list 2>/dev/null | grep -q "Sys.Audit"; then\n EXTRA_PRIVS+=(\"Sys.Audit\")\nelse\n if pveum role add PulseTmpSysAudit -privs Sys.Audit 2>/dev/null; then\n EXTRA_PRIVS+=(\"Sys.Audit\")\n pveum role delete PulseTmpSysAudit 2>/dev/null\n fi\nfi\n\n# Prefer Proxmox guest-agent privileges; VM.Monitor is a legacy fallback.\nif pveum role list 2>/dev/null | grep -q "VM.GuestAgent.Audit" || pveum role add PulseTmpGuestAudit -privs VM.GuestAgent.Audit 2>/dev/null; then\n EXTRA_PRIVS+=(\"VM.GuestAgent.Audit\")\n pveum role delete PulseTmpGuestAudit 2>/dev/null || true\n\n if pveum role list 2>/dev/null | grep -q "VM.GuestAgent.FileRead" || pveum role add PulseTmpGuestFileRead -privs VM.GuestAgent.FileRead 2>/dev/null; then\n EXTRA_PRIVS+=(\"VM.GuestAgent.FileRead\")\n pveum role delete PulseTmpGuestFileRead 2>/dev/null || true\n fi\nelif pveum role list 2>/dev/null | grep -q "VM.Monitor" || pveum role add PulseTmpVMMonitor -privs VM.Monitor 2>/dev/null; then\n EXTRA_PRIVS+=(\"VM.Monitor\")\n pveum role delete PulseTmpVMMonitor 2>/dev/null || true\nfi\n\nif [ ${#EXTRA_PRIVS[@]} -gt 0 ]; then\n PRIV_STRING=\"$(IFS=,; echo \"${EXTRA_PRIVS[*]}\")\"\n pveum role modify PulseMonitor -privs \"$PRIV_STRING\" 2>/dev/null || pveum role add PulseMonitor -privs \"$PRIV_STRING\"\n pveum aclmod / -user pulse-monitor@pam -role PulseMonitor\nfi'
}
</code>
</div>
@ -1232,9 +1232,9 @@ export const NodeModal: Component<NodeModalProps> = (props) => {
</div>
<p class="text-gray-600 dark:text-gray-400 text-xs mt-1">
Note: PVEAuditor gives read-only API access. PulseMonitor adds
Sys.Audit plus either VM.Monitor (PVE 8) or VM.GuestAgent.Audit
(PVE 9+) for disk and guest metrics. PVEDatastoreAdmin on
/storage adds backup visibility.
Sys.Audit plus VM.GuestAgent.Audit when available, with
VM.Monitor only as an older PVE 8 fallback. PVEDatastoreAdmin
on /storage adds backup visibility.
</p>
</div>

View file

@ -4541,8 +4541,10 @@ fi
echo "Setting up permissions..."
pveum aclmod / -user pulse-monitor@pam -role PVEAuditor%s
# Detect Proxmox version and apply appropriate permissions
# Method 1: Try to check if VM.Monitor exists (reliable for PVE 8 and below)
# Detect Proxmox privileges and apply appropriate permissions
# VM.Monitor is deprecated for the Proxmox 9 upgrade path, so prefer the
# newer guest-agent privileges whenever they are available and fall back to
# VM.Monitor only on older PVE 8 systems.
HAS_VM_MONITOR=false
if pveum role list 2>/dev/null | grep -q "VM.Monitor" ||
pveum role add TestMonitor -privs VM.Monitor 2>/dev/null; then
@ -4550,7 +4552,7 @@ if pveum role list 2>/dev/null | grep -q "VM.Monitor" ||
pveum role delete TestMonitor 2>/dev/null || true
fi
# Detect availability of newer guest agent privileges (PVE 9+)
# Detect availability of newer guest agent privileges
HAS_VM_GUEST_AGENT_AUDIT=false
if pveum role list 2>/dev/null | grep -q "VM.GuestAgent.Audit"; then
HAS_VM_GUEST_AGENT_AUDIT=true
@ -4561,7 +4563,7 @@ else
fi
fi
# VM.GuestAgent.FileRead (PVE 9+): needed for reading /proc/meminfo
# VM.GuestAgent.FileRead: needed for reading /proc/meminfo
# via the guest agent for accurate memory reporting
HAS_VM_GUEST_AGENT_FILE_READ=false
if pveum role list 2>/dev/null | grep -q "VM.GuestAgent.FileRead"; then
@ -4597,15 +4599,13 @@ if [ "$HAS_SYS_AUDIT" = true ]; then
EXTRA_PRIVS+=("Sys.Audit")
fi
if [ "$HAS_VM_MONITOR" = true ]; then
# PVE 8 or below - VM.Monitor exists
EXTRA_PRIVS+=("VM.Monitor")
elif [ "$HAS_VM_GUEST_AGENT_AUDIT" = true ]; then
# PVE 9+ - VM.Monitor removed, prefer VM.GuestAgent.Audit for guest data
if [ "$HAS_VM_GUEST_AGENT_AUDIT" = true ]; then
EXTRA_PRIVS+=("VM.GuestAgent.Audit")
if [ "$HAS_VM_GUEST_AGENT_FILE_READ" = true ]; then
EXTRA_PRIVS+=("VM.GuestAgent.FileRead")
fi
elif [ "$HAS_VM_MONITOR" = true ]; then
EXTRA_PRIVS+=("VM.Monitor")
fi
if [ ${#EXTRA_PRIVS[@]} -gt 0 ]; then

View file

@ -3,6 +3,7 @@ package api
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
@ -145,6 +146,39 @@ func TestPVESetupScript_ConfiguresPulseMonitorRoleSafely(t *testing.T) {
}
}
func TestPVESetupScript_PrefersGuestAgentPrivileges(t *testing.T) {
tempDir := t.TempDir()
cfg := &config.Config{
DataPath: tempDir,
ConfigPath: tempDir,
}
handlers := newTestConfigHandlers(t, cfg)
req := httptest.NewRequest(http.MethodGet,
"/api/setup-script?type=pve&host=http://SENTINEL_HOST:8006&pulse_url=http://SENTINEL_URL:7656", nil)
rr := httptest.NewRecorder()
handlers.HandleSetupScript(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected 200 OK, got %d (%s)", rr.Code, rr.Body.String())
}
script := rr.Body.String()
guestIdx := strings.Index(script, `if [ "$HAS_VM_GUEST_AGENT_AUDIT" = true ]; then`)
monitorIdx := strings.Index(script, `elif [ "$HAS_VM_MONITOR" = true ]; then`)
if guestIdx < 0 || monitorIdx < 0 {
t.Fatalf("expected generated script to contain guest-agent preference with VM.Monitor fallback")
}
if guestIdx > monitorIdx {
t.Fatalf("expected generated script to prefer VM.GuestAgent.Audit before VM.Monitor fallback")
}
if !containsString(script, `EXTRA_PRIVS+=("VM.GuestAgent.FileRead")`) {
t.Fatalf("expected generated script to include VM.GuestAgent.FileRead when available")
}
}
func TestPVESetupScript_PreservesAuthorizedKeysSymlinkAndQuotesSensorsKey(t *testing.T) {
tempDir := t.TempDir()
cfg := &config.Config{

View file

@ -1349,7 +1349,7 @@ func (r *Router) checkVMDiskMonitoring(ctx context.Context, client *proxmox.Clie
} else if strings.Contains(errStr, "403") || strings.Contains(errStr, "401") {
result.Recommendations = append(result.Recommendations,
"Ensure API token has PVEAuditor role for baseline access",
"Add VM.GuestAgent.Audit+VM.GuestAgent.FileRead (PVE 9) or VM.Monitor (PVE 8) privileges; Pulse setup adds these via the PulseMonitor role",
"Add VM.GuestAgent.Audit+VM.GuestAgent.FileRead when available, or VM.Monitor only on older Proxmox 8 systems; Pulse setup adds these via the PulseMonitor role",
"Include Sys.Audit when available for Ceph metrics",
)
} else {
@ -1379,7 +1379,7 @@ func (r *Router) checkVMDiskMonitoring(ctx context.Context, client *proxmox.Clie
result.TestResult = "Permission denied accessing guest agent"
result.Recommendations = append(result.Recommendations,
"Ensure API token has PVEAuditor role for baseline access",
"Add VM.GuestAgent.Audit+VM.GuestAgent.FileRead (PVE 9) or VM.Monitor (PVE 8) privileges; Pulse setup adds these via the PulseMonitor role",
"Add VM.GuestAgent.Audit+VM.GuestAgent.FileRead when available, or VM.Monitor only on older Proxmox 8 systems; Pulse setup adds these via the PulseMonitor role",
"Include Sys.Audit when available for Ceph metrics")
} else if errors.Is(err, context.DeadlineExceeded) || strings.Contains(errStr, "context deadline exceeded") {
result.TestResult = "Guest agent request timed out"

View file

@ -183,7 +183,7 @@ func (p *ProxmoxSetup) configurePVEPermissions(ctx context.Context) {
// Extra privileges are optional, but enable additional features:
// - Sys.Audit: required for pending apt updates + some cluster/ceph visibility
// - VM.Monitor (PVE 8) or VM.GuestAgent.Audit+VM.GuestAgent.FileRead (PVE 9+): guest agent data
// - VM.GuestAgent.Audit+VM.GuestAgent.FileRead (preferred) or legacy VM.Monitor: guest agent data
// - Datastore.Audit: improved storage visibility
var extraPrivs []string
@ -191,15 +191,15 @@ func (p *ProxmoxSetup) configurePVEPermissions(ctx context.Context) {
extraPrivs = append(extraPrivs, "Sys.Audit")
}
if p.probePVEPrivilege(ctx, "VM.Monitor") {
extraPrivs = append(extraPrivs, "VM.Monitor")
} else if p.probePVEPrivilege(ctx, "VM.GuestAgent.Audit") {
if p.probePVEPrivilege(ctx, "VM.GuestAgent.Audit") {
extraPrivs = append(extraPrivs, "VM.GuestAgent.Audit")
// VM.GuestAgent.FileRead is needed for reading /proc/meminfo via the
// guest agent file-read endpoint (accurate memory excluding buff/cache).
if p.probePVEPrivilege(ctx, "VM.GuestAgent.FileRead") {
extraPrivs = append(extraPrivs, "VM.GuestAgent.FileRead")
}
} else if p.probePVEPrivilege(ctx, "VM.Monitor") {
extraPrivs = append(extraPrivs, "VM.Monitor")
}
if p.probePVEPrivilege(ctx, "Datastore.Audit") {

View file

@ -554,6 +554,113 @@ func TestProxmoxSetup_PVEPrivilegeProbe_FallsBackToGuestAgentAudit(t *testing.T)
}
}
func TestProxmoxSetup_PVEPrivilegeProbe_PrefersGuestAgentAudit(t *testing.T) {
mc := &mockCollector{}
var pulseMonitorPrivs string
mc.commandCombinedOutputFn = func(ctx context.Context, name string, arg ...string) (string, error) {
if name != "pveum" {
return "", nil
}
if len(arg) >= 5 && arg[0] == "role" && (arg[1] == "modify" || arg[1] == "add") && arg[2] == proxmoxMonitorRole {
for i := 0; i < len(arg)-1; i++ {
if arg[i] == "-privs" {
pulseMonitorPrivs = arg[i+1]
}
}
return "", nil
}
if len(arg) > 2 && arg[0] == "user" && arg[1] == "token" && arg[2] == "add" {
return "│ value │ my-token │", nil
}
return "", nil
}
p := &ProxmoxSetup{
logger: zerolog.Nop(),
collector: mc,
}
tokenID, tokenValue, err := p.setupPVEToken(context.Background(), "pulse-test")
if err != nil {
t.Fatalf("setupPVEToken returned error: %v", err)
}
if tokenID == "" || tokenValue == "" {
t.Fatalf("expected tokenID and tokenValue to be set, got tokenID=%q tokenValue=%q", tokenID, tokenValue)
}
if !strings.Contains(pulseMonitorPrivs, "VM.GuestAgent.Audit") {
t.Fatalf("expected PulseMonitor privileges to include VM.GuestAgent.Audit, got %q", pulseMonitorPrivs)
}
if !strings.Contains(pulseMonitorPrivs, "VM.GuestAgent.FileRead") {
t.Fatalf("expected PulseMonitor privileges to include VM.GuestAgent.FileRead, got %q", pulseMonitorPrivs)
}
if strings.Contains(pulseMonitorPrivs, "VM.Monitor") {
t.Fatalf("did not expect PulseMonitor privileges to include deprecated VM.Monitor when guest-agent privileges are available, got %q", pulseMonitorPrivs)
}
}
func TestProxmoxSetup_PVEPrivilegeProbe_UsesLegacyVMMonitorFallback(t *testing.T) {
mc := &mockCollector{}
var pulseMonitorPrivs string
mc.commandCombinedOutputFn = func(ctx context.Context, name string, arg ...string) (string, error) {
if name != "pveum" {
return "", nil
}
if len(arg) >= 5 && arg[0] == "role" && arg[1] == "add" && strings.HasPrefix(arg[2], "PulseTmpPrivCheck_") {
for i := 0; i < len(arg)-1; i++ {
if arg[i] == "-privs" {
priv := arg[i+1]
if priv == "VM.GuestAgent.Audit" || priv == "VM.GuestAgent.FileRead" {
return "", fmt.Errorf("unknown privilege")
}
return "", nil
}
}
}
if len(arg) >= 5 && arg[0] == "role" && (arg[1] == "modify" || arg[1] == "add") && arg[2] == proxmoxMonitorRole {
for i := 0; i < len(arg)-1; i++ {
if arg[i] == "-privs" {
pulseMonitorPrivs = arg[i+1]
}
}
return "", nil
}
if len(arg) > 2 && arg[0] == "user" && arg[1] == "token" && arg[2] == "add" {
return "│ value │ my-token │", nil
}
return "", nil
}
p := &ProxmoxSetup{
logger: zerolog.Nop(),
collector: mc,
}
tokenID, tokenValue, err := p.setupPVEToken(context.Background(), "pulse-test")
if err != nil {
t.Fatalf("setupPVEToken returned error: %v", err)
}
if tokenID == "" || tokenValue == "" {
t.Fatalf("expected tokenID and tokenValue to be set, got tokenID=%q tokenValue=%q", tokenID, tokenValue)
}
if !strings.Contains(pulseMonitorPrivs, "VM.Monitor") {
t.Fatalf("expected PulseMonitor privileges to include legacy VM.Monitor fallback, got %q", pulseMonitorPrivs)
}
if strings.Contains(pulseMonitorPrivs, "VM.GuestAgent.Audit") {
t.Fatalf("did not expect VM.GuestAgent.Audit when privilege probe fails, got %q", pulseMonitorPrivs)
}
}
func TestProxmoxSetup_RunAll(t *testing.T) {
mc := &mockCollector{}

View file

@ -682,7 +682,7 @@ func (m *Monitor) pollVMsWithNodes(ctx context.Context, instanceName string, clu
Str("instance", instanceName).
Str("vm", vm.Name).
Int("vmid", vm.VMID).
Msg("Permission denied accessing guest agent. Verify Pulse user has VM.Monitor (PVE 8) or VM.GuestAgent.Audit+VM.GuestAgent.FileRead (PVE 9) permissions")
Msg("Permission denied accessing guest agent. Verify Pulse user has VM.GuestAgent.Audit+VM.GuestAgent.FileRead permissions, or legacy VM.Monitor on older Proxmox 8 systems")
} else if strings.Contains(errStr, "500") {
// Generic 500 error without clear indicators - likely agent unavailable
// Refs #596: Proxmox returns 500 errors when guest agent isn't installed/running

View file

@ -129,8 +129,8 @@ Next steps:
• If the guest agent is disabled, enable it in the VM Options tab (set "QEMU Guest Agent" to "Enabled").
• Inside the guest OS, ensure the qemu-guest-agent service is installed, running, and has access to disk information.
• Verify the pulse_monitor@pam user (or your service account) has proper permissions:
- Proxmox 9: VM.GuestAgent.Audit privilege (Pulse setup adds via PulseMonitor role)
- Proxmox 8: VM.Monitor privilege (Pulse setup adds via PulseMonitor role)
- Preferred: VM.GuestAgent.Audit plus VM.GuestAgent.FileRead when available (Pulse setup adds via PulseMonitor role)
- Legacy fallback: VM.Monitor on older Proxmox 8 systems
- Sys.Audit is recommended for Ceph metrics and included when available
- Both API tokens and passwords work fine for guest agent access