Setting up GCP Vertex AI locally usually ends up with a service-account.json
key sitting in your home directory or a raw export VERTEX_SA_JSON=$(cat ...)
shoved into your .bashrc
.
It works, but it's sloppy. Files get accidentally committed to git repositories, keys rot on disk, and plaintext credentials just sit there waiting to be read by any local process.
Here’s how to auto-wire Vertex AI into Contenox cleanly using your system’s native encrypted keyring (Linux or macOS), keeping credentials strictly in memory—along with the common configuration traps to avoid.
First, spin up your service account and generate the JSON key via gcloud
:
gcloud iam service-accounts create vertex-runner \
--description="Service account for Contenox Vertex AI" \
--display-name="Vertex Runner" \
--project=YOUR_PROJECT_ID
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:vertex-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
gcloud iam service-accounts keys create service-account.json \
--iam-account=vertex-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com
The IAM Trap:Step 2 is easy to miss. Creating the account and key succeeds without it, but the key has zero permissions by default. If your requests throw403 PERMISSION_DENIED
, this binding is usually what's missing.
Instead of leaving service-account.json
floating around in your user directory, pipe it directly into your OS's native encrypted keyring and delete the file immediately.
For Linux (GNOME Keyring / KWallet):
secret-tool store --label="Contenox Vertex Key" service contenox key vertex_sa < service-account.json
rm service-account.json
For macOS (Apple Keychain):
security add-generic-password -a "$USER" -s "contenox-vertex-sa" -w "$(cat service-account.json)"
rm service-account.json
What about Windows?
If you are on Windows, usingWSL(Windows Subsystem for Linux) is absolutely the way to go—it gives you the standard Linux toolchain so you can just usesecret-tool
exactly as shown above. If youmustrun Contenox natively in PowerShell, you can achieve this same memory-only injection using theMicrosoft.PowerShell.SecretManagement
module, or by leaning on cross-platform CLI tools like 1Password (op
) or Bitwarden (bws
).
Add a non-blocking check to the end of your shell profile (~/.bashrc
on Linux, ~/.zshrc
on macOS). When your shell fires up, it decrypts the key straight into RAM:
Linux ( ~/.bashrc):
if secret-tool lookup service contenox key vertex_sa >/dev/null 2>&1; then
export VERTEX_SA_JSON=$(secret-tool lookup service contenox key vertex_sa)
fi
macOS ( ~/.zshrc or ~/.bashrc):
if security find-generic-password -a "$USER" -s "contenox-vertex-sa" >/dev/null 2>&1; then
export VERTEX_SA_JSON=$(security find-generic-password -a "$USER" -s "contenox-vertex-sa" -w)
fi
Reload your shell:
source ~/.bashrc # or source ~/.zshrc
Now add the backend to Contenox and explicitly point it to VERTEX_SA_JSON
:
contenox backend add vertex --type vertex-google \
--url "https://aiplatform.googleapis.com/v1/projects/YOUR_PROJECT_ID/locations/global" \
--api-key-env VERTEX_SA_JSON
contenox config set default-provider vertex-google
contenox config set default-model gemini-3.6-flash
The Gotcha:Youmustpass--api-key-env VERTEX_SA_JSON
when adding the backend. If you omit it, Contenox ignores your environment variable and falls back to standardgcloud
Application Default Credentials (ADC), causing provider auth rejections if ADC isn't logged in.
Test it out:
contenox chat "say hi"
op run
), bws
), or
A Quick Side Note on Local Hygiene:While we're talking about Contenox here, this keyring injection approach makes sense foranylocal environment variable or credential, regardless of the harness, tool, or framework you're using. Whether it's a standalone CLI script, an agent harness, or custom tooling, keeping raw keys off your filesystem and out of plaintext.env
files should be standard operating procedure across your entire local dev setup.
P.S. If you've got unused GCP cloud credits sitting around in a project, this setup is a super convenient way to put them to work through Contenox instead of paying out-of-pocket for standard API endpoints!