Connect Lens on Windows to GKE through WSL
In a WSL-first setup your gcloud, kubectl, and gke-gcloud-auth-plugin all live inside WSL. Lens runs on Windows and, to refresh a GKE token, must execute gke-gcloud-auth-plugin, which only exists in WSL. This guide wires the two sides together so the same kubeconfig works unmodified, with no second Google Cloud SDK on Windows.
NOTE
This is the condensed, copy-paste version. For the reasoning behind each step, and the alternatives ruled out, read the deep-dive: Lens on Windows, gcloud in WSL.
Prerequisites
- WSL with
gcloud,kubectl, andgke-gcloud-auth-plugininstalled inside WSL - Lens on Windows
yqin WSL (theubunturole installs it)
How the pieces fit
A GKE kubeconfig carries no token, only an exec stanza naming gke-gcloud-auth-plugin, which each client runs from its own PATH. Four things make that work across the Windows ↔ WSL boundary:
- a shim on the Windows PATH, named like the WSL binary, that forwards into WSL;
- the shim sources only the SDK PATH snippet (the non-login shell
wslstarts doesn't have it); - the account is baked into the kubeconfig's
exec.env; - WSLENV carries that account from the Windows process into WSL.
Manual setup
1. Shim the plugin onto the Windows PATH
Create %USERPROFILE%\bin, add it to your Windows user PATH, and save this as gke-gcloud-auth-plugin.cmd. The same two lines work for any tool, save them as kubectl.cmd or helm.cmd and they run kubectl/helm (%~n0 is the filename without extension):
@echo off
wsl bash -c ". ~/.profile.d/google.sh 2>/dev/null; %~n0 %*"Sourcing ~/.profile.d/googlecloud.sh puts the SDK on PATH in that non-login shell, and only that, so no stray shell state (a leftover CLOUDSDK_ACTIVE_CONFIG_NAME, say) can break the refresh.
2. Bake the account into the kubeconfig
A background token refresh has no shell, so the account can't be a per-shell variable. Put it in the kubeconfig's exec.env right after fetching credentials, with yq:
KUBECONFIG="$file" gcloud container clusters get-credentials "$cluster" --zone "$zone"
yq -i ".users[].user.exec.env = [
{\"name\": \"CLOUDSDK_CORE_ACCOUNT\", \"value\": \"${CLOUDSDK_CORE_ACCOUNT}\"},
{\"name\": \"CLOUDSDK_ACTIVE_CONFIG_NAME\", \"value\": \"default\"}]" "$file"Pinning CLOUDSDK_ACTIVE_CONFIG_NAME=default shields the refresh from whatever ~/.config/gcloud/active_config points at (environment beats file). Inside WSL this is already enough, kubectl injects exec.env when it spawns the plugin.
3. Bridge the account into WSL with WSLENV
Lens sets CLOUDSDK_CORE_ACCOUNT in the Windows process, but wsl starts a fresh Linux environment. Share the variable across with WSLENV, set in the Windows user environment:
[Environment]::SetEnvironmentVariable('WSLENV',
'CLOUDSDK_CORE_ACCOUNT/u:CLOUDSDK_ACTIVE_CONFIG_NAME/u', 'User')Then restart Lens fully (quit the tray icon too), WSLENV is read at launch.
WARNING
The flag names the destination, not the source: /u means "into WSL," even though it reads like "user/Windows." Get it wrong and every refresh fails silently with the same accountless error.
The automated path
The wsl and googlecloud roles do all of the above idempotently. Declare the shims and the bridged variables:
---
wsl_windows_shims:
- gke-gcloud-auth-plugin
- gcloud
- kubectl
- helm
wsl_wslenv:
- CLOUDSDK_CORE_ACCOUNT
- CLOUDSDK_ACTIVE_CONFIG_NAMEThe wsl role writes each shim into %USERPROFILE%\bin\, ensures it's on the Windows PATH, and merges the variables into WSLENV; the googlecloud role deploys ~/.profile.d/googlecloud.sh and the day-to-day commands. After one apply, connecting a new cluster is two commands in WSL:
gcp-account you@company.com # select the account for this shell
gcp-kubeconfig my-cluster # fetch credentials, account baked in via yqPoint Lens at the kubeconfig and it refreshes tokens through WSL indefinitely.
Debugging checklist
Walk the chain in order when something breaks:
- Shim found?
where gke-gcloud-auth-plugin(cmd) should print the.cmdpath. - Shim runs? Invoke
gke-gcloud-auth-plugindirectly, anExecCredentialJSON, or even a gcloud error, means the shim and PATH sourcing work. - Env bridge? In a new cmd window:
set CLOUDSDK_CORE_ACCOUNT=test@example.com, thenwsl bash -c "echo $CLOUDSDK_CORE_ACCOUNT", no output means WSLENV is missing, wrong, or the window predates the change. - WSLENV value?
powershell "[Environment]::GetEnvironmentVariable('WSLENV','User')". - Account in the kubeconfig?
yq '.users[].user.exec.env' <kubeconfig>. - Restart Lens fully: the tray icon keeps the old environment alive.
Next steps
- Lens on Windows, gcloud in WSL the reasoning, the full flow, and the alternatives considered
wslrole andgooglecloudrole, every variable and command- One repo for your Windows, Ubuntu, and macOS machines the cross-platform repo this slots into