DEV Community

Alexander Ertli
Alexander Ertli

Posted on

Stop your Keys in .env: Securely Auto-Wire Vertex AI for Local Dev

Zero Plaintext Keys on Disk: Auto-Wiring GCP Vertex AI in Contenox with System Keyrings

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.


1. Create the GCP Service Account & Roles

First, spin up your service account and generate the JSON key via gcloud:

# 1. Create the service account
gcloud iam service-accounts create vertex-runner \
  --description="Service account for Contenox Vertex AI" \
  --display-name="Vertex Runner" \
  --project=YOUR_PROJECT_ID

# 2. Grant the Vertex AI User role (CRITICAL — without this every call 403s)
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
  --member="serviceAccount:vertex-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/aiplatform.user"

# 3. Generate and download the JSON key
gcloud iam service-accounts keys create service-account.json \
  --iam-account=vertex-runner@YOUR_PROJECT_ID.iam.gserviceaccount.com

Enter fullscreen mode Exit fullscreen mode

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 throw 403 PERMISSION_DENIED, this binding is usually what's missing.


2. Stash in Your System Keyring & Nuke the File

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):

# Store key inside your system keyring
secret-tool store --label="Contenox Vertex Key" service contenox key vertex_sa < service-account.json

# Delete the local plaintext file
rm service-account.json

Enter fullscreen mode Exit fullscreen mode

For macOS (Apple Keychain):

# Store key inside macOS Keychain
security add-generic-password -a "$USER" -s "contenox-vertex-sa" -w "$(cat service-account.json)"

# Delete the local plaintext file
rm service-account.json

Enter fullscreen mode Exit fullscreen mode

What about Windows?
If you are on Windows, using WSL (Windows Subsystem for Linux) is absolutely the way to go—it gives you the standard Linux toolchain so you can just use secret-tool exactly as shown above. If you must run Contenox natively in PowerShell, you can achieve this same memory-only injection using the Microsoft.PowerShell.SecretManagement module, or by leaning on cross-platform CLI tools like 1Password (op) or Bitwarden (bws).


3. Auto-Wire in Your Shell Profile

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):

# Auto-load Contenox Vertex SA Key into memory
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

Enter fullscreen mode Exit fullscreen mode

macOS (~/.zshrc or ~/.bashrc):

# Auto-load Contenox Vertex SA Key into memory
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

Enter fullscreen mode Exit fullscreen mode

Reload your shell:

source ~/.bashrc  # or source ~/.zshrc

Enter fullscreen mode Exit fullscreen mode

4. Register the Backend with Contenox

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

Enter fullscreen mode Exit fullscreen mode

The Gotcha: You must pass --api-key-env VERTEX_SA_JSON when adding the backend. If you omit it, Contenox ignores your environment variable and falls back to standard gcloud Application Default Credentials (ADC), causing provider auth rejections if ADC isn't logged in.

Test it out:

contenox chat "say hi"

Enter fullscreen mode Exit fullscreen mode

Why This Pattern Wins

  • Zero Plaintext Keys on Hard Drive: The JSON key is stored in your OS-level keyring and pulled into memory on shell init.
  • Auto-Locking: When your machine sleeps or your screen locks, the credential store locks with it.
  • Scales to Enterprise Vaults: The exact same env-injection pattern unlocks full remote enterprise vaults. If you need team-wide secret sharing, swap the native OS tools for 1Password CLI (op run), Bitwarden Secrets Manager (bws), or HashiCorp Vault without altering how Contenox consumes the environment variable.

A Quick Side Note on Local Hygiene: While we're talking about Contenox here, this keyring injection approach makes sense for any local 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!

Top comments (0)