Letting AI Agents Use the Google Cloud CLI Safely — Drop the Keys, Lock It Down with Impersonation and a Command Broker
Let a coding agent like Claude Code or Codex drive the gcloud command, and both investigation and operations get dramatically faster. Ask it to “list the Cloud Run services in this project” or “pull the recent logs for the failing Cloud Function,” and the agent composes the CLI calls itself and hands back the results. The convenience is undeniable.
The catch is that what you have handed the agent is both a shell and a set of Google Cloud credentials. Being able to run gcloud from a shell also means that an instruction buried in a README, an issue, a web page, a BigQuery table description, or a tool output the agent happens to read can turn directly into a cloud operation. As we will see, this is not a hypothetical concern. It is an attack class that has already caused real harm.
This post starts from a setup that lets an AI agent drive the Google Cloud CLI (gcloud), and it builds defense in depth on the Google Cloud side. The conclusion up front: short-lived credentials and least privilege, the direction Google officially recommends, is correct, but service account keys persist dangerously when leaked, and tool-side permission settings do not survive adversarial evasion. We design on the premise that the only trustworthy enforcement boundaries are IAM, organization policy, and OS sandboxes.
This is the Google Cloud companion to the AWS edition, “Letting AI Agents Use the AWS CLI Safely.” The skeleton of the thinking is shared, but Google Cloud has its own weapons (dual-identity audit logging from impersonation, and VPC Service Controls that work at the service-API layer), so the build-out is a different beast.
Google’s official guidance already sketches the answer
Google Cloud has shipped official tooling and guidance on the assumption that you will let AI agents drive gcloud. The AI-agent Skill for gcloud and the official MCP server gcloud-mcp (@google-cloud/gcloud-mcp) are exactly that, and both bake in safety conventions: command validation, explicit --project scoping, a destructive-operation denylist, and blocking of interactive/SSH commands. As a starting point, let us pin down the principles they encode.
- Authenticate without keys: avoid routine use of service account keys, and mint a fresh short-lived token each time via impersonation or Workload Identity Federation.
- Separate the identity: give the agent its own dedicated service account, distinct from the human’s broad access, and run it under least privilege.
- Do not trust the input: assume the agent can be hijacked by instructions embedded in fetched documents or command output, and bound the blast radius accordingly.
Conversely, the gaps are just as clear: key-based persistent authentication, free-form shell execution, broad outbound network egress, shared service accounts, default service accounts, and unenabled Data Access audit logs. There is no silver bullet that plugs all of these at once. So we layer.
Disarming “one input” with defense in depth
The principle running through this design is defense in depth. The aim is a state where even if the agent acts unexpectedly, that alone never reaches production. In other words, design permissions not around “what the agent needs to do” but around “how far the blast radius spreads if it acts unexpectedly.”
Concretely, we defend across five layers: authentication, authorization, execution, approval, and audit.
flowchart TD
A["AI agent generates a gcloud command"] --> B["Layer 1: Authentication — dedicated SA, impersonation/WIF"]
B --> C["Layer 2: Authorization — IAM least privilege, IAM Conditions, org policy"]
C --> D["Layer 3: Execution — a no-shell command broker"]
D --> E["Layer 4: Approval — human approval for destructive ops, deny policy"]
E --> F["Layer 5: Audit — Cloud Audit Logs, dual identity, SCC"]
F --> G{"All gates cleared?"}
G -- "No" --> H["Deny, record, notify"]
G -- "Yes" --> I["Execute Google Cloud API"]
The crucial point is that the layers are not equal in strength. Only IAM, organization policy, and OS sandboxes are enforcement boundaries that survive adversarial evasion; the tool-side permission and denylist rules are merely a convenience layer that reduces human error and low-effort misexecution. Put the latter in the lead role and you will misread the design. On top of that, Google Cloud has a defense line all its own: VPC Service Controls, which operates at the service-API layer and can stop exfiltration even when valid credentials are stolen. Let us build out each layer.
Drop the keys — impersonation and Workload Identity Federation
The first layer is authentication, and the top principle here is simple: do not use service account keys. Google itself clearly advises avoiding service account keys wherever possible. Keys are long-lived file credentials that by default have no expiry and stay valid until you delete them; they get committed to git, embedded in container layers, and leaked through logs, and Google cannot auto-rotate them. For organizations created on or after May 3, 2024, iam.disableServiceAccountKeyCreation is enforced by default.
There are two keyless alternatives.
- Service account impersonation:
gcloud config set auth/impersonate_service_account SA_EMAIL, or add--impersonate-service-account=SA_EMAILto each command. The caller (the human’s user account) must holdroles/iam.serviceAccountTokenCreatoron the target SA, and gcloud transparently mints 1-hour, non-refreshable, on-disk-free short-lived credentials. Google’s official guidance describes impersonation as “more secure than using a service account key because service account impersonation requires a prior authenticated identity, and the credentials that are created by using impersonation do not persist.” - Workload Identity Federation (WIF): for agents running in CI/CD or outside Google Cloud, exchange an external OIDC/SAML token for short-lived Google credentials with no key file. Always put attribute conditions on the provider, and narrow the principal identifier to the most specific value (repository ID, branch, and so on).
What matters with impersonation is granting Token Creator “on the target SA resource, not the project.” A project-level grant lets the principal impersonate every SA in the project. For agent use, the key point is to restrict impersonation to exactly one SA.
Do not confuse roles/iam.serviceAccountUser with roles/iam.serviceAccountTokenCreator. The former mainly grants the ability to attach an SA to a resource via iam.serviceAccounts.actAs, and it is not enough to run --impersonate-service-account. To mint short-lived OAuth tokens or OIDC ID tokens and impersonate an SA, you need the latter.
And avoid gcloud auth print-access-token: the raw token lands in shell history, the agent transcript, and your observability stack. Google warns that “any user with access to your file system can use the stored access credentials created by gcloud auth login… don’t use gcloud auth login for automated workloads on remote systems with persistent storage.” Allowed for a human’s one-off operation, not allowed for an unattended agent. That is the safe line.
Least privilege and guardrails — IAM, IAM Conditions, org policy
The second layer is authorization. This is one of the only trustworthy enforcement boundaries.
First, give the agent a dedicated service account. Separating agent-driven operations from human identities lets audit logs attribute actions to the agent and lets you scope permissions independently. The official gcloud-mcp doc says the same: “The permissions of the gcloud MCP are directly tied to the permissions of the active gcloud account. To operate with least privilege, authorize as a service account using impersonation and assign it a role with limited permissions.”
Avoid basic roles at all costs. Never grant roles/owner, roles/editor, or roles/viewer to the agent SA, because a compromised SA with Editor can delete any resource. Bind per-service predefined roles, or custom roles (gcloud iam roles create) built from gcloud iam list-testable-permissions, at the narrowest possible resource scope.
# Bind at the bucket scope, not across the whole project
gcloud storage buckets add-iam-policy-binding gs://agent-readonly-bucket \
--member="serviceAccount:agent-readonly@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"On top of that, default the agent identity to read-only roles and allow writes only through a separately approved escalation. For attribute-based constraints use IAM Conditions (time-bound, resource-name prefixes); to narrow the set of resources a principal can reach use Principal Access Boundary (PAB); and for temporary time-bound elevation use Privileged Access Manager.
Double these up with organization policy. Organization policy applies constraints with inheritance across organizations, folders, and projects, forming a hierarchy-wide guardrail that even a compromised project owner cannot override. It is the right vehicle for moving AI-agent usage off “the conscience of an individual project” and onto an organization-wide enforced rule.
| Org-level constraint | Purpose |
|---|---|
iam.disableServiceAccountKeyCreation | Forbid creating new long-lived keys, preventing key files from spreading into agent environments |
iam.disableServiceAccountKeyUpload | Forbid uploading external public keys, blocking bring-your-own keys |
iam.workloadIdentityPoolProviders | Restrict WIF provider creation to a dedicated project |
gcp.restrictNonCmekServices | Useful when you want to limit use of services without CMEK |
Beyond reducing grants, IAM deny policies let you forbid deviations. For example, you can attach enforced guardrails like “only a specific group may delete prod-tagged projects” or “creating service account keys is forbidden,” and they take precedence over allow policies.
The AI-agent-specific risk — prompt injection
Why scope permissions this hard? The essential risk of handing an AI agent gcloud is that natural-language input, fetched documents, and tool output translate directly into command-execution authority. OWASP ranks Prompt Injection as the #1 LLM risk and names tool-calling/MCP agents specifically as a major risk for unauthorized tool execution, data leakage, and persistent manipulation. OWASP also states plainly that, given how LLMs work, no foolproof prevention exists.
The especially nasty variant is indirect prompt injection. The attack input is not limited to the user’s direct prompt; it slips in through what looks like ordinary business data: a BigQuery table description, a document in Cloud Storage, a PDF, an email, an external web page. If the agent interprets an embedded instruction like “to accomplish this task, create a new key” or “to avoid auditing, delete the logs” as a command rather than as data, and runs gcloud iam service-accounts keys create, an IAM change, or a data-copy operation, it escalates into leakage or persistence.
This is not theoretical. In October 2025, instructions planted in a GitHub PR title, issue body, or comment were used to hijack Anthropic’s Claude Code Security Review, Google’s Gemini CLI Action, and GitHub Copilot’s agent across the board in the “Comment and Control” attack (researcher’s technical writeup, HackerOne #3387969, reported October 17, 2025). Confirmed exfiltration included ANTHROPIC_API_KEY and GITHUB_TOKEN on the Claude side, GEMINI_API_KEY posted as a public issue comment on the Gemini side, and GITHUB_TOKEN and others on the Copilot side. It is a direct demonstration of the structure: once the “lethal trifecta” of an LLM, code execution, and untrusted content is present, any agent becomes exploitable. So treat fetched content as untrusted and use least privilege plus an approval boundary to build a state where “even if it complies, nothing happens.”
Tool-side guardrails are a convenience layer (not an enforcement boundary)
The agent-side tools do have safety mechanisms, of course. But it is important to understand their position correctly.
Google’s official gcloud Skill prohibits the agent from autonomously running: any IAM policy/role/binding change (privilege-escalation risk), gcloud * delete (irreversible), gcloud billing * (cost), gcloud organizations * (governance), and gcloud kms * (can permanently lock data). On top of that, it imposes conventions: run --dry-run first where available, put explicit --project on every command, use no shell operators (|, $(...), >), run single commands only, and validate with gcloud help beforehand to avoid hallucinated flags.
The gcloud-mcp server exposes a run_gcloud_command tool and blocks interactive/SSH commands (compute ssh, compute start-iap-tunnel, cloud-shell ssh, interactive, and others) via a hard-coded denylist. But there is an important caveat: the gcloud-mcp denylist does not block delete or IAM changes. That is the Skill’s job, so you are meant to combine the two. And gcloud-mcp is in preview, with breaking changes explicitly possible.
Claude Code lets you set allow, ask, and deny under permissions in settings.json, evaluated deny → ask → allow, with deny taking precedence over any allow.
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(gcloud projects describe:*)",
"Bash(gcloud run services list:*)",
"Bash(gcloud logging read:*)"
],
"ask": [
"Bash(gcloud * create:*)",
"Bash(gcloud * update:*)"
],
"deny": [
"Bash(gcloud * delete:*)",
"Bash(gcloud iam *)",
"Bash(gcloud billing *)",
"Bash(gcloud organizations *)",
"Bash(gcloud kms *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(~/.config/gcloud/**)"
]
}
}At the org level, managed-settings.json can distribute non-overridable deny rules and set permissions.disableBypassPermissionsMode to "disable" to forbid the use of --dangerously-skip-permissions itself. Codex CLI likewise controls behavior with approval_policy (untrusted/on-request/never) and sandbox_mode (read-only/workspace-write/danger-full-access) in ~/.codex/config.toml, with a recommended baseline of approval_policy="on-request" plus sandbox_mode="workspace-write".
But the limits are just as clear.
- Glob matching is bypassable: a compound command like
cd x && gcloud … delete, or a multi-line command, can slip past a deny rule. A PreToolUse hook that sees the full command string is the reliable enforcement layer. - There are bugs where settings do not take effect: there are reports of
disableBypassPermissionsModenot taking effect, so verifying with/statusplus a hook is recommended for reliable enforcement. - A denylist is reactive by nature: it is weak against new evasion techniques, and leaning toward an allowlist is sturdier.
The conclusion: agent-side settings are a convenience layer that reduces human error and low-effort misexecution, while the enforcement boundaries against adversarial evasion are IAM, organization policy, and OS sandboxes. So the execution layer in the next section is the main event.
A no-shell command broker
In the third, execution layer, we cut command injection off at the root. Rather than let the AI agent run gcloud freely and directly, we use a three-layer structure: the LLM emits only intent; a broker decides what is allowed and assembles only structured gcloud subcommands; a sandbox executes them. Research likewise points to a structure where control flow is generated only from trusted input and untrusted data cannot influence program flow, and the broker approach follows that.
flowchart TB R[User request] --> P[LLM planner] D[Untrusted data<br/>Web/PDF/email/Storage/BigQuery] --> F[Input validation/sanitize] F --> P P --> Q[Structured action request<br/>intent, resource, scope] Q --> B[Command broker] B -->|allowed commands only| X[Execution sandbox] B -->|dangerous ops only| H[Human approval] H --> X X --> G[gcloud] G --> A[Google Cloud APIs] X --> L[Cloud Logging / Audit Logs / SCC]
Concretely, make it a wrapper that does not go through a shell and runs only allowlisted gcloud subcommands as an argument array. OWASP recommends, as the first defense against OS command injection, not invoking OS commands directly at all; if gcloud is required, this is the next best thing.
#!/usr/bin/env python3
import json
import subprocess
import sys
# Pin (group, command) with an allowlist. Read-only.
ALLOWED = {
("projects", "describe"),
("run", "services"), # narrow list/describe in downstream validation
("compute", "instances"), # only let list/describe through
("logging", "read"),
("secrets", "versions"), # validate the target Secret for access separately
}
IMPERSONATE = "agent-readonly@PROJECT_ID.iam.gserviceaccount.com"
PROJECT = "PROJECT_ID"
def main(argv: list[str]) -> int:
if len(argv) < 2:
print("usage: safe_gcloud.py <group> <command> [args...]", file=sys.stderr)
return 2
key = (argv[0], argv[1])
if key not in ALLOWED:
print(f"blocked: {key} is not allowlisted", file=sys.stderr)
return 3
base = [
"gcloud",
argv[0],
argv[1],
f"--project={PROJECT}",
f"--impersonate-service-account={IMPERSONATE}",
"--quiet", # read-only only; never on destructive ops
"--format=json",
]
# shell=False avoids shell metacharacter expansion
cmd = base + argv[2:]
proc = subprocess.run(cmd, shell=False, capture_output=True, text=True)
if proc.returncode != 0:
# do not pass stderr straight up; mask if needed
print(json.dumps({"ok": False, "returncode": proc.returncode, "stderr": proc.stderr[:2000]}, ensure_ascii=False))
return proc.returncode
print(proc.stdout)
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv[1:]))The points are: avoid metacharacter expansion with shell=False, pin group and command with an allowlist, have the broker inject --impersonate-service-account and --project every time, and validate the arguments separately. OWASP recommends controlling the command name with an allowlist and validating arguments with, for instance, regular expressions. Let only the CLI’s safe vocabulary through: an instance name as ^[a-z][-a-z0-9]*$, a Secret name as [A-Za-z0-9_-]+.
--quiet needs care. It disables all interactive prompts and auto-accepts even the “are you sure?” confirmation on an irreversible delete. An agent needs non-interactive execution so it does not hang, but --quiet removes the human-confirmation safety net. The resolution is to put --quiet on read operations only and route destructive ones to the human approval gate in the next section.
Isolate with a sandbox and default-deny egress
Isolate the execution environment itself, too. Anthropic ships a reference dev container that runs Claude Code inside an isolated container with a default-deny egress firewall (allow-listing only e.g. the Anthropic API, npm, and GitHub). But Anthropic itself states that “dev containers do not prevent exfiltrating anything accessible inside the container,” so use them only with trusted repositories and do not mount cloud credentials into the container. Layering Claude Code’s native sandbox (/sandbox; Seatbelt on macOS, bubblewrap on Linux/WSL2) further restricts the filesystem and network for Bash and child processes.
If you run on Google Cloud, the Cloud Run code-execution guide says you can run untrusted code in a sandbox while recommending that you restrict IAM permissions and cut internet reachability with a VPC firewall. If you put the gcloud executor in a Cloud Run Job or Service, make a dedicated SA, concurrency=1, internal ingress, and VPC-routed egress control the baseline. As an indirect-prompt-injection countermeasure, Google also suggests running the agent on Cloud Workstations with the internet disabled and no root.
And provision a dedicated OS user, dedicated HOME, and dedicated ~/.config/gcloud for the agent. gcloud keeps a sqlite cache of OAuth tokens in ~/.config/gcloud, readable by any process of the same user. The iron rule is to never let the agent read that directory.
VPC Service Controls — stop exfiltration at the service-API layer
This is a uniquely powerful defense line on Google Cloud. VPC Service Controls (VPC-SC) draws its boundary at the service-API layer, not the network layer. As a result, even if valid credentials are stolen, it can stop data from leaving the boundary. Per Google’s description, VPC-SC prevents service operations such as “a gcloud storage cp command copying to a public Cloud Storage bucket or a bq mk command copying to a permanent external BigQuery table.”
In other words, even if the agent is hijacked by prompt injection and can reach Cloud Storage, BigQuery, or Secret Manager with a valid token, you can close off the very path that pulls data outside the boundary. This is complementary: IAM least privilege constrains “what can be accessed,” while VPC-SC constrains “where what was accessed can be sent.” When introducing it, run in dry-run mode for at least 30 days to surface false positives before switching to enforce.
Combined with an enterprise egress proxy and the Organization Restriction Header, you can also block access to Google Cloud tenants outside your own organization entirely, narrowing the phishing and exfiltration paths even further.
Constrain high-risk operations with human approval
Since you cannot fully prevent prompt injection, gate high-risk operations behind human approval. Map destructive gcloud patterns to ask in Claude Code and to approval prompts in Codex, and keep the allowlist limited to read-only, idempotent operations. On the command-broker side as well, make a human approval gate mandatory for change, IAM, billing, delete, and Secret-access operations.
In addition, layer in IAM deny policies and PAB as guardrails on the API-permission side. For example:
gcloud projects get-iam-policyallowed;set-iam-policyalways forbidden.gcloud secrets versions accessallowed for specific Secrets only.gcloud iam service-accounts keys createfully forbidden.gcloud logging readallowed;gcloud logging buckets deleteforbidden as a rule.
By double-stacking the broker-side allowlist and the deny-policy-side enforcement, getting past one still stops at the other. Where the command supports it, running --dry-run first to preview the impact is also effective.
Audit and detection — Cloud Audit Logs, dual identity, SCC
The last layer is building a state where you can trace a misbehavior after the fact. A runaway agent cannot be contained without visibility.
Of the Cloud Audit Logs, Admin Activity logs (configuration changes including IAM) and System Event logs are always on and cannot be disabled. Data Access logs (reads of user data and metadata), on the other hand, are off by default for most services and must be explicitly enabled. To track what the agent read, enabling Data Access at the organization level is strongly recommended. Because what you enable on a parent cannot be disabled on a child, org-level application is also advantageous for governance.
A uniquely Google Cloud strength is impersonation’s dual-identity auditing. When the agent impersonates an SA, most audit logs record both identities: the impersonated SA in authenticationInfo.principalEmail, and the human/caller in serviceAccountDelegationInfo. Token minting appears as the GenerateAccessToken method of iamcredentials.googleapis.com, which security vendors use as a detection signal. This contrasts with key-based authentication, where only the SA is recorded, and it makes the non-repudiation and traceability that matter for AI-agent operations easier to achieve.
For detection, Security Command Center’s Event Threat Detection monitors the Cloud Logging stream in near real time. If you put the gcloud execution platform on Cloud Run, you can also use Cloud Run Threat Detection, which targets suspicious binaries and malicious Bash/Python. Put log-based alerts on GenerateAccessToken spikes, SetIamPolicy changes, deletes, and VPC-SC violations, and route logs to a SIEM with an org-level aggregated sink.
Do not forget to protect the logging platform itself. Because an attacker or the agent might try to erase traces, put the audit-log destination in a dedicated bucket separated from the operations project, and protect it with a retention period and --locked (an irreversible bucket lock). Keep in mind, too, that observability is forensics, not prevention; it tells you what happened after the fact.
In an emergency — service account tokens cannot be revoked, a sharp edge
When you suspect a compromise, Google Cloud has a pitfall worth knowing. A user’s token can be invalidated by removing the gcloud CLI from the user’s connected applications (revoking gcloud’s client ID). But a service account’s access token cannot be invalidated with gcloud auth revoke. To fully revoke it, you must disable the SA for the 60-minute token lifetime and delete its keys, or delete/replace the SA itself.
Furthermore, disabling a service account key does not revoke the short-lived credentials already issued based on that key. So if you suspect the agent SA is compromised, do not rest on key disablement alone: have a procedure ready that disables the SA, emergency-rotates the related secrets, and, if needed, temporarily halts destructive operations via a deny policy or organization policy. The Layer 1 policy of keeping token lifetimes short pays off right here.
Roll it out in stages
You do not have to add everything at once. Cut the stages in order of impact.
Stage 1 (immediate, within a week)
- Authenticate the agent by impersonating a dedicated, least-privilege service account, and grant Token Creator on the target SA resource only. Do not use service account keys.
- Default the agent SA to read-only roles, scoped to a non-production project. Deny
roles/owner|editor|viewer. - In the
settings.jsonof Claude Code, Codex, and so on, set deny rules forgcloud * delete,gcloud iam *,gcloud billing *, and the like, plus Read deny on~/.config/gcloudand.env, and reliably block destructive/compound commands with a PreToolUse hook. - Adopt the conventions of Google’s official
gcloudSkill (gcloud helpvalidation, explicit--project,--quieton reads only, no shell operators), and if you use MCP, usegcloud-mcppointed at the limited SA.
Stage 2 (within a month)
- Run the agent in a default-deny-egress container/dev container, and do not mount cloud credentials. Layer the native sandbox on top.
- With
managed-settings.json(disableBypassPermissionsMode: "disable", etc.) and Codex’srequirements.toml, prevent developers from loosening policy. - Migrate to a no-shell command broker, and put a human approval gate on destructive, IAM, billing, and Secret-access operations.
- Enable Data Access audit logs, route them to a SIEM via an org-level aggregated sink, and alert on
GenerateAccessTokenspikes,SetIamPolicy, deletes, and VPC-SC violations.
Stage 3 (quarterly)
- Enforce organization policy (
iam.disableServiceAccountKeyCreation,iam.disableServiceAccountKeyUpload, restrict allowed APIs) across the whole organization. - Draw VPC Service Controls perimeters around BigQuery, Cloud Storage, and Secret Manager (dry-run for at least 30 days first).
- Set the Google Cloud session length to a 1–24h reauthentication policy, and pair it with OS Login plus 2-step verification if needed.
- Run IAM Recommender and Policy Analyzer against the agent SA monthly, and tighten excess permissions.
Decide your thresholds, too. If the agent comes to need writes or production access routinely, escalate to Stages 2–3 before granting any write role. If you cannot sandbox network egress, do not use --dangerously-skip-permissions or danger-full-access.
Limits and known constraints
This design is not a cure-all either. Let me state the assumptions.
- Tool-side permission/denylist is not an enforcement boundary: it does not survive adversarial evasion via compound commands, obfuscation, or separate processes. The only trustworthy enforcement is IAM, organization policy, and OS sandboxes.
- The official tooling is still maturing:
gcloud-mcpis in preview with breaking changes possible. Its denylist covers only a handful of interactive/SSH commands and does not blockdeleteor IAM, so verify the current denylist in source before relying on it. - No single layer stops prompt injection: OWASP holds that no foolproof prevention exists. The controls here shrink the blast radius and exfiltration paths; they do not reduce the risk to zero.
- SA token revocation is a sharp edge: unlike user tokens, it cannot be revoked with
gcloud auth revokeand requires disabling, deleting, or replacing the SA. - Date-sensitive facts need re-verification: the default 16-hour session length, the May 3, 2024 key-creation default, and the availability stage of various preview features should be checked against your organization’s current state.
These are design trade-offs rather than defects. When the requirements exceed the assumptions, take it as a signal to escalate: to isolation in a dedicated non-production project, or to kernel separation with microVMs.
Note that this post is not compliance advice. Make the final compliance call with your own audit and legal teams.
Conclusion
Handing an AI agent a shell and Google Cloud credentials at the same time: we built a design that catches the downside of that convenience in layers. Let me summarize.
- For authentication, drop the keys and mint a fresh short-lived token each time with impersonation or WIF. Grant Token Creator on the target SA resource only.
- Build least privilege into IAM and organization policy, the only enforcement boundaries, and double them up with IAM Conditions, PAB, and deny policies.
- Treat the agent-side Skill, denylist, and permissions as a convenience layer, and put a command broker that never lets the LLM run a free shell, plus a sandbox, in the lead role.
- Use Google Cloud’s own VPC Service Controls to stop data exfiltration even when valid credentials are stolen.
- Make “who did what, when” always traceable with Cloud Audit Logs’ dual-identity auditing and SCC detection, and prepare for the sharp edge that SA tokens cannot be revoked.
To put it in one sentence: impersonate a dedicated SA from a human identity only when needed, hand the agent structured commands rather than a free shell, inside a sandbox with an approval flow and a VPC-SC boundary, and make everything traceable with dual-identity audit logs. Build a state where seizing a single input never reaches production. It is more work, but if you are going to entrust Google Cloud to an agent, defense in depth at this level is worth making the default.
That is a from-the-field design for letting AI agents use the Google Cloud CLI safely.
References
- Google Cloud CLI overview (gcloud)
- Use service account impersonation
- Workload Identity Federation
- Best practices for managing service account keys
- Introduction to the Organization Policy Service
- IAM deny policies overview
- VPC Service Controls overview
- Cloud Audit Logs overview
- Event Threat Detection overview
- gcloud-mcp (GitHub)
- OWASP: LLM01 Prompt Injection
- Comment and Control attack (researcher’s technical writeup)
- Claude Code: settings