mirror of
https://github.com/google/skills.git
synced 2026-09-14 20:00:20 +08:00
Various updates to align with new GEAP platform releases related to agent troubleshooting skill.
PiperOrigin-RevId: 978227804
This commit is contained in:
committed by
Copybara-Service
parent
4b40feb8ca
commit
a407c6bf56
@@ -21,22 +21,25 @@ Diagnose issues across the Google Cloud Gemini Enterprise Agent Platform: Agent
|
||||
Gateway, Agent Registry (Agents / MCP Servers / Endpoints), Agent Identity,
|
||||
Policies, IAP-delegated authorization, and service extensions.
|
||||
|
||||
## MANDATORY PRE-FLIGHT CHECKLIST (CHECK BEFORE ANY TOOL CALLS)
|
||||
## MANDATORY PRE-FLIGHT CHECKLIST (CHECK BEFORE RESPONDING OR CALLING TOOLS)
|
||||
|
||||
Before making any tool calls, executing any bash commands, or writing any code,
|
||||
match the user's prompt against these pre-flight rules:
|
||||
CRITICAL: Before generating ANY response or calling any tools, you MUST evaluate
|
||||
the user's prompt against these mandatory pre-flight rules. If a rule matches,
|
||||
you MUST execute its directive immediately and STOP.
|
||||
|
||||
### Rule 1: Out-of-Scope GCP IAM / GCS Queries
|
||||
|
||||
If the prompt mentions GCE, GCS, GCS bucket, or generic GCP IAM 403 Access
|
||||
Denied errors (e.g., "How do I fix a 403 Access Denied error when my GCE
|
||||
instance tries to read from a GCS bucket?"):
|
||||
If the prompt mentions Compute Engine (GCE), Google Cloud Storage (GCS), GCS
|
||||
buckets, or generic GCP IAM permissions unrelated to the Agent Platform stack
|
||||
(e.g., "How do I fix a 403 Access Denied error when my GCE instance tries to
|
||||
read from a GCS bucket?"):
|
||||
|
||||
- **CRITICAL MANDATE: DO NOT CALL ANY TOOLS. DO NOT PROVIDE ANY
|
||||
TROUBLESHOOTING STEPS OR GUIDES.**
|
||||
- **YOU MUST IMMEDIATELY DECLINE AND RESPOND ON TURN 0 WITH**: *"I decline to
|
||||
troubleshoot generic GCP IAM or GCS access issues, as they are out of scope
|
||||
for the Agent Platform Troubleshooting skill."*
|
||||
- **CRITICAL MANDATE: YOU MUST IMMEDIATELY DECLINE. DO NOT CALL ANY TOOLS. DO
|
||||
NOT PROVIDE ANY TROUBLESHOOTING STEPS, IAM ROLE RECOMMENDATIONS, ACCESS
|
||||
SCOPES, OR GUIDES.**
|
||||
- **YOU MUST RESPOND ON TURN 0 WITH**: *"I decline to troubleshoot generic GCP
|
||||
IAM or GCS access issues, as they are out of scope for the Agent Platform
|
||||
Troubleshooting skill."*
|
||||
|
||||
### Rule 2: Strict Prohibition on Custom Discovery Scripts
|
||||
|
||||
@@ -63,9 +66,7 @@ in Agent Registry (e.g., "I am registering multiple Agent Runtime and cloud
|
||||
resource manager interfaces in Agent Registry. What's the best way to do
|
||||
this?"):
|
||||
|
||||
- **DO NOT CALL ANY TOOLS OR EXECUTE ANY COMMANDS. DO NOT WRITE TERRAFORM OR
|
||||
SEPARATE SERVICE BLOCKS.**
|
||||
- **IMMEDIATELY RESPOND ON TURN 0 WITH**:
|
||||
- **DO NOT CALL ANY TOOLS OR EXECUTE COMMANDS. RESPOND ON TURN 0 WITH**:
|
||||
1. Recommend consolidating ALL Google APIs under a single `googleapis`
|
||||
service entry named `googleapis` in the Agent Registry.
|
||||
2. Explicitly state: *"Do NOT register each Google API as a separate
|
||||
@@ -81,8 +82,9 @@ this?"):
|
||||
- `https://{region}-aiplatform.mtls.googleapis.com`
|
||||
- `https://{region}-aiplatform.googleapis.com`
|
||||
- `https://aiplatform.{region}.rep.googleapis.com`
|
||||
4. Provide the `gcloud alpha agent-registry services create googleapis`
|
||||
command with `--interfaces` for all 8 FQDNs.
|
||||
4. Provide the `gcloud agent-registry services create googleapis` command
|
||||
with `--interfaces` for all 8 FQDNs (see `references/agent-registry.md`
|
||||
§2).
|
||||
|
||||
### Rule 4: Cloud Run / Cloud Functions Egress 403 / MCP Calls
|
||||
|
||||
@@ -108,16 +110,13 @@ reaching `telemetry.mtls.googleapis.com` or telemetry endpoints:
|
||||
|
||||
- In your **Diagnostic Report / Evidence gathered**, you **MUST explicitly
|
||||
check and list all 4 required monitoring and tracing endpoints**:
|
||||
1. `telemetry.mtls.googleapis.com`
|
||||
2. `monitoring.googleapis.com`
|
||||
3. `trace.mtls.googleapis.com`
|
||||
4. `cloudtrace.googleapis.com`
|
||||
- In your **Recommended Fix**, you **MUST ALWAYS explicitly include ALL of the
|
||||
following**:
|
||||
`telemetry.mtls.googleapis.com`, `monitoring.googleapis.com`,
|
||||
`trace.mtls.googleapis.com`, and `cloudtrace.googleapis.com`.
|
||||
- In your **Recommended Fix**, you **MUST ALWAYS explicitly include**:
|
||||
1. Registering `telemetry.mtls.googleapis.com` (and checking
|
||||
`monitoring.googleapis.com`, `trace.mtls.googleapis.com`,
|
||||
`cloudtrace.googleapis.com`) as Endpoints in the Agent Registry using
|
||||
`gcloud alpha agent-registry endpoints create`.
|
||||
`gcloud agent-registry endpoints create`.
|
||||
2. Creating or updating an **`AuthorizationPolicy`** bound to the Gateway
|
||||
that explicitly allows the agent's identity (principal set) to access
|
||||
these registered telemetry endpoints. State clearly: *"Create or update
|
||||
@@ -125,21 +124,31 @@ reaching `telemetry.mtls.googleapis.com` or telemetry endpoints:
|
||||
identity (principal set) to access the telemetry endpoints."* Refer to
|
||||
`references/known-issues.md` BKI 23 for details.
|
||||
|
||||
### Rule 6: IAP Denial Troubleshooting
|
||||
### Rule 6: IAP Denial Troubleshooting (403 to MCP Server or Endpoint)
|
||||
|
||||
Whenever diagnosing IAP egress denial errors (`403 Forbidden` / `Egress request
|
||||
is not authorized` via IAP):
|
||||
Whenever diagnosing logs or findings where the agent is getting a `403
|
||||
Forbidden` / `Egress request is not authorized` error calling an MCP server or
|
||||
endpoint via IAP:
|
||||
|
||||
- Your response **MUST ALWAYS**:
|
||||
1. Identify that IAP is denying the request.
|
||||
2. Recommend checking IAP audit logs
|
||||
(`protoPayload.serviceName="iap.googleapis.com"`).
|
||||
3. Verify that the agent identity has the **`roles/iap.egressor`**
|
||||
(IAP-secured Egressor) role bound to the resource/registry.
|
||||
4. Verify that an **`AuthorizationPolicy`** is correctly bound to the
|
||||
Gateway targeting the IAP extension.
|
||||
5. Explicitly warn: *"Do NOT use `roles/iap.tunnelResourceAccessor`"* and
|
||||
*"Do NOT bypass IAP authentication"*.
|
||||
- Your response **MUST ALWAYS** prioritize this step-by-step resolution:
|
||||
1. **Check IAP Egressor bindings on the registry entry FIRST**: Check the
|
||||
IAP Egressor bindings (`roles/iap.egressor`) on the matching resource in
|
||||
the Agent Registry.
|
||||
2. **Ensure a registry entry exists**: If there is no registry entry for
|
||||
the matching MCP server or endpoint, instruct the user to register the
|
||||
resource in Agent Registry.
|
||||
3. **Ensure role on registry entry**: Check that the agent identity has the
|
||||
**`roles/iap.egressor`** role bound to that specific registry entry.
|
||||
4. **Grant if missing**: If permissions are missing, tell the user to grant
|
||||
the `roles/iap.egressor` role against the registry entry.
|
||||
5. **Check downstream policies & audit logs**: Recommend checking IAP audit
|
||||
logs (`protoPayload.serviceName="iap.googleapis.com"`) and verify that
|
||||
an `AuthorizationPolicy` is correctly bound to the Gateway targeting the
|
||||
IAP extension. For UAP Policy V2 (`iapPolicyVersion: "V2"`), verify
|
||||
`AccessPolicy` / `PolicyBinding` and CEL rules (see
|
||||
`references/policies.md` §2).
|
||||
6. **Explicitly warn**: *"Do NOT use `roles/iap.tunnelResourceAccessor`"*
|
||||
and *"Do NOT bypass IAP authentication"*.
|
||||
|
||||
### Rule 7: PSC Subnet Exhaustion Speed Rule
|
||||
|
||||
@@ -147,10 +156,8 @@ When diagnosing gateway provisioning failures (PSC subnet exhaustion):
|
||||
|
||||
- **DO NOT execute loops or list all regions.**
|
||||
- Run **ONLY** these 4 commands in `us-central1`:
|
||||
1. `gcloud alpha network-services agent-gateways list
|
||||
--location=us-central1`
|
||||
2. `gcloud alpha network-services agent-gateways describe
|
||||
--location=us-central1`
|
||||
1. `gcloud network-services agent-gateways list --location=us-central1`
|
||||
2. `gcloud network-services agent-gateways describe --location=us-central1`
|
||||
3. `gcloud compute network-attachments describe --region=us-central1`
|
||||
4. `gcloud compute networks subnets describe --region=us-central1`
|
||||
- Immediately calculate free IPs (`Usable IPs - Allocated IPs = Free IPs`),
|
||||
@@ -175,19 +182,113 @@ multi-region locations (`us` or `eu`):
|
||||
Whenever diagnosing VPC Service Controls (VPC-SC) perimeter blocks or denied
|
||||
requests:
|
||||
|
||||
- Your response **MUST ALWAYS explicitly state ALL of the following**:
|
||||
1. Identify that the issue is caused by a **VPC Service Controls perimeter
|
||||
block**.
|
||||
2. Recommend creating VPC-SC **ingress policies** allowing both service
|
||||
accounts:
|
||||
- **Your response MUST ALWAYS explicitly state ALL of the following**:
|
||||
1. Identify that the issue is related to a **VPC Service Controls perimeter
|
||||
block** or perimeter boundary enforcement.
|
||||
2. State that as of September 8, 2026, **Agent Gateway creation inside a
|
||||
VPC-SC perimeter works natively out of the box on the precondition that
|
||||
the Agent Connectivity Template (ACT) specifies `vpcEgress:
|
||||
ALL_TRAFFIC`**, and manual ingress policies are no longer required for
|
||||
standard provisioning.
|
||||
3. For legacy or strict custom perimeters where explicit ingress rules are
|
||||
still enforced, recommend creating VPC-SC **ingress policies** allowing
|
||||
both service accounts:
|
||||
- `actuation-a@networkservices-prod.iam.gserviceaccount.com`
|
||||
- `cloud-aiplatform-pipeline-robot-prod.iam.gserviceaccount.com`
|
||||
3. Explicitly state: *"Do NOT disable VPC Service Controls or delete
|
||||
4. Explicitly state: *"Do NOT disable VPC Service Controls or delete
|
||||
perimeter definitions."*
|
||||
5. Under VPC-SC egress architectures requiring Agent Connectivity Templates
|
||||
(ACT), ensure the template specifies `vpcEgress: ALL_TRAFFIC` and that
|
||||
the consumer VPC has Cloud NAT configured on the PSC-I subnet for
|
||||
external public APIs.
|
||||
|
||||
Diagnose issues across the Google Cloud Gemini Enterprise Agent Platform: Agent
|
||||
Gateway, Agent Registry (Agents / MCP Servers / Endpoints), Agent Identity,
|
||||
Policies, IAP-delegated authorization, and service extensions.
|
||||
### Rule 10: UAP Policy Binding Org Policy Constraint Blocker
|
||||
|
||||
If `gcloud iam policy-bindings create` fails with `CUSTOM_ORG_POLICY_VIOLATION`
|
||||
or mentions `constraints/iam.managed.disableAccessPolicyBinding`:
|
||||
|
||||
- **Your response MUST ALWAYS explicitly state ALL of the following**:
|
||||
1. Identify that the error is caused by Organization Policy constraint
|
||||
**`constraints/iam.managed.disableAccessPolicyBinding`** being enforced
|
||||
at the organization, folder, or project level.
|
||||
2. Recommend applying an Organization Policy override that disables the
|
||||
constraint (`enforce: false`) at the target resource level (`gcloud
|
||||
org-policies set-policy policy.yaml --project=$PROJECT_ID`).
|
||||
3. Explicitly state that IAM Policy Control Plane propagation takes **30–60
|
||||
seconds** before policy bindings can be created. Refer to
|
||||
`references/known-issues.md` BKI 24.
|
||||
|
||||
### Rule 11: Agent Gateway Dual-Registry Validation Invariants
|
||||
|
||||
If configuring, updating, or validating registry associations on an Agent
|
||||
Gateway:
|
||||
|
||||
- **Your response MUST ALWAYS explicitly state ALL of the following**:
|
||||
1. An Agent Gateway supports a **maximum of two registries**.
|
||||
2. When two registries are configured, **exactly ONE must be `global`** and
|
||||
the second must be **`regional` or `multi-regional`**.
|
||||
3. Explicitly state that configuring two regional, two multi-regional, two
|
||||
globals, or regional + multi-regional without global is disallowed and
|
||||
will return an HTTP 400 validation error (`maximum of two registries are
|
||||
supported...`). Refer to `references/agent-gateway.md` §4.
|
||||
|
||||
### Rule 12: Cross-Project Runtime-to-Gateway Binding Diagnosis
|
||||
|
||||
Whenever diagnosing errors where an Agent Runtime (Reasoning Engine) in Project
|
||||
A fails to deploy against, bind to, or route traffic through an Agent Gateway in
|
||||
Centralized Governance Project B:
|
||||
|
||||
- **Your response MUST ALWAYS explicitly check and state ALL of the
|
||||
following**:
|
||||
1. **Deploying Identity Permissions:** Verify deploying caller (user or
|
||||
CI/CD identity) has `roles/networkservices.viewer` (or
|
||||
`networkservices.agentGateways.get` and
|
||||
`networkservices.agentGateways.use`) on the gateway in Project B.
|
||||
2. **Vertex AI Service Agent Permissions:** Verify that Project A's service
|
||||
agent (`service-PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com`)
|
||||
is granted `roles/networkservices.viewer` or custom role
|
||||
`ae_agw_cross_project_sa` (with `networkservices.agentGateways.get` and
|
||||
`networkservices.operations.get`) in Project B.
|
||||
3. **Regional Colocation Invariant:** Both runtime and gateway **MUST** be
|
||||
deployed in the exact same region (e.g. `us-central1`). Cross-region
|
||||
bindings fail control plane validation with `INVALID_ARGUMENT`.
|
||||
4. **CAA Token Sharing Opt-Out:** Verify runtime deployment config sets
|
||||
`"GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES": False`.
|
||||
5. Refer to `references/known-issues.md` BKI 10 and
|
||||
`references/agent-gateway.md` §11 for server-generated resource IDs,
|
||||
perimeters, and full configs.
|
||||
|
||||
### Rule 13: Downstream Secure Web Proxy (SWP) and Policy-Based Routing (PBR) Egress
|
||||
|
||||
Whenever diagnosing errors where traffic exiting an Agent Gateway Network
|
||||
Attachment fails to reach or route through a downstream Secure Web Proxy (SWP),
|
||||
drops silently, or returns HTTP 403 / HTTP 503 / timeout errors:
|
||||
|
||||
- **Your response MUST ALWAYS explicitly check and state ALL of the
|
||||
following**:
|
||||
1. **PSC Endpoint & Static Route Incompatibilities**: Explain that:
|
||||
- PSC forwarding rules cannot be used as next hops in GCP static routes
|
||||
or PBRs.
|
||||
- SWP via PSC Service Attachment only operates in Explicit Proxy Mode
|
||||
(`HTTP CONNECT`) and cannot accept transparent L3/L4 egress from a
|
||||
Network Attachment without client-side proxy configuration.
|
||||
- Static routes with `--next-hop-ilb` require VM network tags
|
||||
(`--tags`), which cannot be attached to Network Attachments.
|
||||
2. **Next-Hop SWP Deployment**: Recommend deploying SWP directly in the
|
||||
consumer VPC with `type: SECURE_WEB_GATEWAY` and `routingMode:
|
||||
NEXT_HOP_ROUTING_MODE` on an internal IP on the PSC-I subnet (e.g.
|
||||
`10.20.1.250`).
|
||||
3. **Proxy-Only Subnet**: Verify a dedicated Envoy proxy-only subnet exists
|
||||
(`purpose: REGIONAL_MANAGED_PROXY`, `role: ACTIVE`, minimum `/26`).
|
||||
4. **Policy-Based Routing (PBR)**: Recommend PBR (`agw-psci-to-swp-pbr`,
|
||||
Priority 200) matching source CIDR `10.20.1.0/24` to the SWP next-hop
|
||||
ILB IP (`10.20.1.250`), with fallback PBR to `DEFAULT_ROUTING`.
|
||||
5. **Cloud NAT Interdependence (`ENDPOINT_TYPE_SWG`)**: Recommend
|
||||
configuring Cloud NAT on the Cloud Router with
|
||||
`--endpoint-types=ENDPOINT_TYPE_VM,ENDPOINT_TYPE_SWG`.
|
||||
6. Refer to `references/known-issues.md` BKI 33 and
|
||||
`references/agent-gateway.md` §6 for CEL allowlists and the ADK
|
||||
streaming session trap.
|
||||
|
||||
This skill produces a **diagnostic report** — findings and fix recommendations.
|
||||
It does not apply fixes. The user owns the change.
|
||||
@@ -225,90 +326,39 @@ When *not* to use:
|
||||
Before doing anything else, pin down the basics. If the user hasn't supplied
|
||||
them, ask. Don't guess.
|
||||
|
||||
| Item | Why it's needed |
|
||||
| :----------------------------------- | :------------------------------------ |
|
||||
| `PROJECT_ID` and `PROJECT_NUMBER` | Most API calls take one or the other; |
|
||||
: : some take both :
|
||||
| `LOCATION` (region) | Registry, gateway, and IAM scope are |
|
||||
: : regional. `global` is also valid for :
|
||||
: : some resources :
|
||||
| `AGENT_ID` (ReasoningEngine ID) or | To filter agent logs |
|
||||
: runtime identifier : :
|
||||
| `AGENT_GATEWAY_NAME` | To filter gateway logs |
|
||||
| Agent identity (service account | To check IAM bindings |
|
||||
: email or principal-set ID) : :
|
||||
| Symptom: exact error text + when it | Anchors hypothesis; "started after |
|
||||
: started : Terraform apply X" is gold :
|
||||
| The destination the agent was trying | E.g. `aiplatform`, `discoveryengine`, |
|
||||
: to reach : an MCP server, another agent :
|
||||
| Item | Why it's needed |
|
||||
| :--- | :--- |
|
||||
| `PROJECT_ID` and `PROJECT_NUMBER` | Most API calls take one or both |
|
||||
| `LOCATION` (region) | Regional scope; `global` valid for some resources |
|
||||
| `AGENT_ID` or runtime identifier | To filter agent logs |
|
||||
| `AGENT_GATEWAY_NAME` | To filter gateway logs |
|
||||
| Agent identity (SA or principal-set ID) | To check IAM bindings |
|
||||
| Symptom: exact error text + timestamp | Anchors hypothesis ("started after Terraform apply X") |
|
||||
| Target destination | E.g. `aiplatform`, `discoveryengine`, MCP server, peer agent |
|
||||
|
||||
If only some are known, proceed but call out the unknowns in the report. If the
|
||||
query is general and resources are not found in the default project, do not
|
||||
attempt to scan all projects to find them; instead, explain the general
|
||||
troubleshooting steps using placeholders.
|
||||
If only some are known, proceed but call out unknowns in the report. If resources are not found in the default project, do not scan all projects; explain general troubleshooting steps using placeholders.
|
||||
|
||||
## Hypothesis Generation Rules
|
||||
|
||||
Before executing diagnostic queries beyond Step 0, you **MUST** formulate at
|
||||
most 3 plausible hypotheses for the failure. For each hypothesis, explicitly
|
||||
correlate it with recent changes (e.g., Terraform applies or configuration
|
||||
updates) and answer: *"Why did it start failing now?"*
|
||||
|
||||
Limit your diagnostics to validating these hypotheses. Do not execute random
|
||||
queries.
|
||||
updates) and answer: *"Why did it start failing now?"* Limit diagnostics to
|
||||
validating these hypotheses.
|
||||
|
||||
## Diagnostic flow
|
||||
|
||||
This is a **process skill** — follow the steps in order.
|
||||
This is a **process skill** — follow the steps in order. See `references/field-manual.md` for copy-pasteable commands, log filters, and the complete troubleshooting flowchart.
|
||||
|
||||
- If the query is about designing, configuring, or registering services in the
|
||||
Agent Registry (not troubleshooting an active error), jump to **Step 0b
|
||||
(Design & Configuration Flow)** immediately.
|
||||
- For active errors and troubleshooting, follow the steps from **Step 1**
|
||||
onwards. Most 403s resolve at step 2 or 4. Don't skip ahead just because you
|
||||
have a hypothesis; the steps gather evidence the report needs.
|
||||
|
||||
1. **Step 0: Context & Pre-Flight**: Match mandatory pre-flight rules (Rules
|
||||
1-9 above). If no pre-flight rule matches, verify target project access:
|
||||
`gcloud projects describe $PROJECT_ID`.
|
||||
2. **Step 1: Agent Logs**: Confirm error type (403 vs connection vs crash).
|
||||
- Connection Error -> Check PSC Subnet Exhaustion (Step 3c).
|
||||
- Container Crash -> Perform Runtime Health Check (Step 1b).
|
||||
3. **Step 2: Gateway Logs**: Find exact failing hostname.
|
||||
4. **Step 3: IAP Logs**: Check DRY_RUN vs enforced mode and allow/deny
|
||||
decision.
|
||||
5. **Step 4: Registry State**: Verify if exact hostname is registered.
|
||||
- Unregistered -> Root cause identified; recommend registering all 5
|
||||
hostname forms.
|
||||
6. **Step 5: Identity & IAM**: Verify agent identity has `roles/iap.egressor`
|
||||
on the registered resource.
|
||||
7. **Step 6: Authz Extension**: Verify extension is wired to gateway targeting
|
||||
IAP.
|
||||
8. **Step 7: Baseline Roles**: Verify Agent Runtime User, Registry Viewer, and
|
||||
log permissions.
|
||||
9. **Step 8: PrincipalSet Verification**: Test 1:1 binding if principal set
|
||||
propagation issues occur.
|
||||
|
||||
The exact log queries, gcloud commands, and curl invocations live in
|
||||
`references/field-manual.md` (which includes the full flowchart). Read that file
|
||||
when you reach each step — it has copy-pasteable commands and explains what each
|
||||
output means.
|
||||
|
||||
### Step 0b — Design & Configuration Flow
|
||||
|
||||
If the user asks for guidance on designing, configuring, or registering services
|
||||
in the Agent Registry (especially Google APIs like Agent Runtime, Cloud Resource
|
||||
Manager, etc.):
|
||||
|
||||
1. **Read Reference**: Immediately read `references/agent-registry.md`
|
||||
Section 2.
|
||||
2. **Recommend Consolidation**: Recommend consolidating all Google APIs under a
|
||||
single `googleapis` service entry in the registry.
|
||||
3. **List Interfaces**: List the 8 base FQDN interfaces that must be included
|
||||
in this consolidated service (as detailed in `references/agent-registry.md`
|
||||
Section 2).
|
||||
4. **Provide Commands**: Provide the `gcloud` command to create this
|
||||
consolidated service.
|
||||
- **Step 0: Context & Pre-Flight**: Match mandatory pre-flight rules (Rules 1-13). Verify project access via `gcloud projects describe $PROJECT_ID`. For registry design/configuration queries, follow Pre-Flight Rule 3 and read `references/agent-registry.md` §2.
|
||||
- **Step 1: Agent Logs**: Confirm error type (403 vs connection vs crash). For connection errors/timeouts, check PSC Subnet Exhaustion and ACT/Cloud NAT routing. For container crashes, perform runtime health check.
|
||||
- **Step 2: Gateway Logs**: Find exact failing hostname.
|
||||
- **Step 3: IAP Logs**: Check policy version (`iapPolicyVersion: "V2"` vs `"V1"`), DRY_RUN vs enforced mode, and decision.
|
||||
- **Step 4: Registry State**: Verify if exact hostname is registered. If unregistered, recommend registering all hostname forms.
|
||||
- **Step 5: Identity & Policies**: Verify agent identity has `roles/iap.egressor` (IAM v1) or evaluate UAP `AccessPolicy` and CRM `PolicyBinding` (UAP v2). Check `constraints/iam.managed.disableAccessPolicyBinding` blocker.
|
||||
- **Step 6: Authz Extension & Gateway**: Verify extension is wired to gateway targeting IAP with correct policy version, and verify dual-registry constraints (max 2: 1 global + 1 regional/multi-regional).
|
||||
- **Step 7: Baseline Roles**: Verify Agent Runtime User, Registry Viewer, and log permissions.
|
||||
- **Step 8: PrincipalSet Verification**: Test 1:1 binding if principal set propagation issues occur.
|
||||
|
||||
## Tools to use
|
||||
|
||||
@@ -404,50 +454,38 @@ Always produce a structured report. Use this template exactly.
|
||||
destination.
|
||||
- **DRY_RUN changes everything.** If IAP is in dry-run, denials are logged but
|
||||
not enforced.
|
||||
- **The role is `roles/iap.egressor`.**
|
||||
- **Always Recommend IAP Verification**: For any IAP-related issue, you MUST
|
||||
explicitly suggest verifying:
|
||||
1. The agent identity has `roles/iap.httpsGatewayUser` (for gateway-level
|
||||
access) AND `roles/iap.egressor` (for endpoint-level access).
|
||||
2. The `AuthorizationPolicy` is correctly bound to the Gateway (check if it
|
||||
targets the gateway resource). Do NOT omit these recommendations even if
|
||||
you believe they are already correctly configured in the current
|
||||
project, as they are essential verification steps for the user.
|
||||
- **Consolidated Registry for Google APIs**: To simplify management and avoid
|
||||
hitting API/registry limits, always recommend consolidating all Google APIs
|
||||
under a single 'googleapis' service entry in the registry with the 8 base
|
||||
FQDN interfaces, rather than registering them as separate services. Refer to
|
||||
`references/agent-registry.md` Section 2 for details.
|
||||
- **The role is `roles/iap.egressor` (for IAM v1) and FQDN permission
|
||||
`iap.googleapis.com/resources.egressViaIAP` (for UAP v2).**
|
||||
- **UAP (Policy V2) CRM Hierarchy**: Next-gen policies bind to Projects,
|
||||
Folders, and Organizations via `PolicyBinding` rather than shadow resources.
|
||||
Evaluation follows absolute DENY precedence and additive ALLOW aggregation
|
||||
across the CRM tree.
|
||||
- **Agent Connectivity Template (ACT) with `ALL_TRAFFIC`**: Under VPC-SC,
|
||||
traffic traverses synthetic PSC VIP `240.0.0.2:443`. External public API
|
||||
traffic exiting the consumer VPC requires Cloud NAT on the PSC-I subnet to
|
||||
avoid silent connection hangs.
|
||||
- **Dual-Registry Invariant**: An Agent Gateway supports at most 2 registries;
|
||||
when 2 are configured, exactly ONE must be `global` and the second must be
|
||||
`regional` or `multi-regional`.
|
||||
- **Read evidence, don't assume.** Pull logs first.
|
||||
- **Cite exact resource names in the report.**
|
||||
- **Stay in diagnosis mode.** Don't apply Terraform changes or run destructive
|
||||
gcloud commands. Read-only inspection only.
|
||||
- **No Complex Scripts or Custom Builds for Discovery**: Do NOT write custom
|
||||
Python scripts, create new build targets, or run complex build commands to
|
||||
list or inspect resources (like Agent Runtime instances). Doing so consumes
|
||||
too many turns and causes timeouts. If a gcloud command is missing, use
|
||||
`curl` to query the REST API directly using application-default credentials.
|
||||
- **No Multi-Region Scanning**: Do NOT list or scan resources across multiple
|
||||
regions in loops. Unless the user/logs explicitly point to a different
|
||||
region, only check resources in the default region (`us-central1`). Running
|
||||
regional loops will cause timeouts.
|
||||
- **Avoid interactive commands and disable prompts.** Do NOT run commands that
|
||||
require user interaction or launch pagers (like `gcloud help` or raw `man`
|
||||
pages) as they can hang the execution. Always disable prompts for CLI tools
|
||||
(e.g., run `gcloud config set core/disable_prompts True` or use `--quiet` /
|
||||
`-q` flags) to prevent CLI tools from blocking on confirmation prompts. Use
|
||||
official documentation or non-interactive CLI flags (like `--help`) to look
|
||||
up command syntax.
|
||||
regions in loops. Check default region (`us-central1`) unless logs point
|
||||
elsewhere.
|
||||
- **Non-interactive execution**: Always disable prompts (`--quiet` / `-q` or
|
||||
`gcloud config set core/disable_prompts True`) to avoid hanging.
|
||||
|
||||
## Supporting Links
|
||||
|
||||
- [Agent Runtime Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/agents)
|
||||
- [Agent Gateway Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/gateways/agent-gateway-overview)
|
||||
- [Policies Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/policies/overview)
|
||||
- [Agent Identity Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/agent-identity-overview)
|
||||
- [Agent Registry Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/agent-registry)
|
||||
- [Deploy Agent Gateway Runtime](https://docs.cloud.google.com/gemini-enterprise-agent-platform/scale/runtime/agent-gateway-runtime-deploy)
|
||||
- [Private Service Connect Interface](https://docs.cloud.google.com/gemini-enterprise-agent-platform/scale/runtime/private-service-connect-interface)
|
||||
- [Troubleshoot Agent Gateway](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/troubleshoot-agent-gateway)
|
||||
- [Troubleshoot Agent Deployment](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/agent-deployment)
|
||||
- [Troubleshoot Runtime Setup](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/runtime-setup)
|
||||
- [Agent Runtime Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/agents.md.txt)
|
||||
- [Agent Gateway Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/gateways/agent-gateway-overview.md.txt)
|
||||
- [Policies Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/policies/overview.md.txt)
|
||||
- [Agent Identity Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/agent-identity-overview.md.txt)
|
||||
- [Agent Registry Overview](https://docs.cloud.google.com/gemini-enterprise-agent-platform/govern/agent-registry.md.txt)
|
||||
- [Deploy Agent Gateway Runtime](https://docs.cloud.google.com/gemini-enterprise-agent-platform/scale/runtime/agent-gateway-runtime-deploy.md.txt)
|
||||
- [Private Service Connect Interface](https://docs.cloud.google.com/gemini-enterprise-agent-platform/scale/runtime/private-service-connect-interface.md.txt)
|
||||
- [Troubleshoot Agent Gateway](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/troubleshoot-agent-gateway.md.txt)
|
||||
- [Troubleshoot Agent Deployment](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/agent-deployment.md.txt)
|
||||
- [Troubleshoot Runtime Setup](https://docs.cloud.google.com/gemini-enterprise-agent-platform/troubleshooting/runtime-setup.md.txt)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -140,13 +140,25 @@ Source:
|
||||
|
||||
Source: <https://docs.cloud.google.com/iam/docs/principal-identifiers>
|
||||
|
||||
Scope | Identifier
|
||||
:---------------------------------- | :---------
|
||||
Single agent | `principal://<TRUST_DOMAIN>/resources/<SERVICE>/<RESOURCE_PATH>`
|
||||
All agents in a trust domain | `principalSet://<TRUST_DOMAIN>/*`
|
||||
All agents in a project | `principalSet://<TRUST_DOMAIN>/attribute.platformContainer/aiplatform/projects/<PROJECT_NUMBER>`
|
||||
All agents in an org | `principalSet://agents.global.org-<ORG_ID>.system.id.goog/attribute.platform/aiplatform`
|
||||
DIY agents (workload identity pool) | `principal://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL>/subject/ns/<NS>/sa/<SA>`
|
||||
| Scope | Identifier |
|
||||
| :-------- | :------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Single | `principal://<TRUST_DOMAIN>/resources/<SERVICE>/<RESOURCE_PATH>` |
|
||||
: agent : :
|
||||
| All | `principalSet://<TRUST_DOMAIN>/*` |
|
||||
: agents in : :
|
||||
: a trust : :
|
||||
: domain : :
|
||||
| All | `principalSet://<TRUST_DOMAIN>/attribute.platformContainer/aiplatform/projects/<PROJECT_NUMBER>` |
|
||||
: agents in : :
|
||||
: a project : :
|
||||
| All | `principalSet://agents.global.org-<ORG_ID>.system.id.goog/attribute.platform/aiplatform` |
|
||||
: agents in : :
|
||||
: an org : :
|
||||
| DIY | `principal://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL>/subject/ns/<NS>/sa/<SA>` |
|
||||
: agents : :
|
||||
: (workload : :
|
||||
: identity : :
|
||||
: pool) : :
|
||||
|
||||
Tips when debugging:
|
||||
|
||||
@@ -157,6 +169,39 @@ Tips when debugging:
|
||||
for sensitive resources.
|
||||
- The `attribute.platform/aiplatform` set covers an *entire org*.
|
||||
|
||||
### Principal Identifiers in Unified Access Policy (UAP / Policy V2)
|
||||
|
||||
Under **Unified Access Policy** (`iam.googleapis.com/v3` `AccessPolicy` and
|
||||
`PolicyBinding`), principal identifiers are specified directly in the
|
||||
`rules[].principals` array:
|
||||
|
||||
```yaml
|
||||
# In AccessPolicy rule definition:
|
||||
rules:
|
||||
- description: "Allow project agents to access registered weather service"
|
||||
principals:
|
||||
- "principalSet://agents.global.org-123456789012.system.id.goog/attribute.platformContainer/aiplatform/projects/9876543210"
|
||||
- "principal://agents.global.org-123456789012.system.id.goog/resources/aiplatform/projects/9876543210/locations/us-central1/reasoningEngines/weather-agent"
|
||||
operations:
|
||||
- permissions:
|
||||
- "iap.googleapis.com/resources.egressViaIAP"
|
||||
```
|
||||
|
||||
Important rules for UAP principal matching:
|
||||
|
||||
1. **Direct Principal vs. PrincipalSet**: You can specify either specific
|
||||
`principal://...` URIs or broad `principalSet://...` group URIs in the
|
||||
`principals` array.
|
||||
2. **Audit Log Correlation**: In Cloud Audit Logs
|
||||
(`protoPayload.authenticationInfo.principalSubject`), the runtime always
|
||||
logs the exact `principal://` URI of the calling agent, which satisfies
|
||||
either a direct `principal://` rule or a container-level `principalSet://`
|
||||
rule.
|
||||
3. **Service Accounts in UAP**: If an agent runs with a custom Service Account
|
||||
(`SERVICE_ACCOUNT` mode), the principal string in UAP is
|
||||
`serviceAccount:name@project.iam.gserviceaccount.com` (or
|
||||
`principal://iam.googleapis.com/projects/...`).
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## How identities are created and bound to ReasoningEngines
|
||||
@@ -480,8 +525,8 @@ principal as `members`. Per the policy assignment doc:
|
||||
}
|
||||
```
|
||||
|
||||
Apply with `gcloud beta iap web set-iam-policy ...
|
||||
--resource-type=agent-registry` or `--endpoint=ENDPOINT_ID` depending on target.
|
||||
Apply with `gcloud iap web set-iam-policy ... --resource-type=agent-registry` or
|
||||
`--endpoint=ENDPOINT_ID` depending on target.
|
||||
|
||||
### Agent can't use an auth provider (auth manager)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ registered in Google Cloud Agent Registry are not accepting traffic through
|
||||
Agent Gateway / IAP.
|
||||
|
||||
Scope: Gemini Enterprise Agent Platform — Agent Registry (Preview). All commands
|
||||
use `gcloud alpha agent-registry`.
|
||||
use `gcloud agent-registry`.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -34,11 +34,18 @@ use `gcloud alpha agent-registry`.
|
||||
Read these first when something is broken.
|
||||
|
||||
1. **Agent Registry is default-deny at the gateway.** Agent Gateway uses
|
||||
Identity-Aware Proxy (IAP) to enforce IAM allow/deny policies bound to Agent
|
||||
Registry resources. If a target hostname is not registered as a `Service`
|
||||
(and a matching `roles/iap.egressor` binding does not exist for the calling
|
||||
agent's principal), egress is blocked. Source:
|
||||
`docs.cloud.google.com/iap/docs/agent-overview`.
|
||||
Identity-Aware Proxy (IAP) to enforce authorization:
|
||||
|
||||
- **UAP (Policy V2)**: When the gateway uses `iapPolicyVersion: "V2"`,
|
||||
Gatekeeper queries the attached registries. If the destination matches,
|
||||
Gatekeeper sets `destination.is_registered = true` and exposes rich CEL
|
||||
metadata under `destination.agent_registry.*`. If not cataloged,
|
||||
`destination.is_registered = false`.
|
||||
- **Legacy IAM v1**: When using legacy v1, if a target hostname is not
|
||||
registered as a `Service` (and a matching `roles/iap.egressor` binding
|
||||
does not exist on the registry entry for the calling agent's principal),
|
||||
egress is blocked. Source:
|
||||
`docs.cloud.google.com/iap/docs/agent-overview`.
|
||||
|
||||
2. **There are exactly three discoverable resource types**, and they are
|
||||
*projections* of the same writable `Service`:
|
||||
@@ -69,7 +76,7 @@ Read these first when something is broken.
|
||||
6. **Traffic permissions live on IAP, bound to registry resources.** The role
|
||||
that actually permits an agent to *use* a registered service is
|
||||
`roles/iap.egressor` (`iap.webServiceVersions.egressViaIAP`), bound via
|
||||
`gcloud beta iap web set-iam-policy` with one of:
|
||||
`gcloud iap web set-iam-policy` with one of:
|
||||
`--resource-type=agent-registry` (registry-wide), `--agent=`,
|
||||
`--mcp-server=`, or `--endpoint=` (per-resource). Source:
|
||||
`docs.cloud.google.com/gemini-enterprise-agent-platform/govern/policies/assign-identity-iam`,
|
||||
@@ -96,7 +103,7 @@ Read these first when something is broken.
|
||||
third-party MCP) is *manual*.
|
||||
|
||||
10. **First debug command** is almost always: list the resource type and confirm
|
||||
the hostname permutation you expect is actually present. `gcloud alpha
|
||||
the hostname permutation you expect is actually present. `gcloud
|
||||
agent-registry endpoints list --project=$PROJECT_ID --location=$LOCATION`
|
||||
|
||||
11. **Boundary controls visibility.** Agents are only discoverable if they are
|
||||
@@ -104,6 +111,18 @@ Read these first when something is broken.
|
||||
of the Management Project. If an agent is missing from the list, check the
|
||||
boundary configuration.
|
||||
|
||||
12. **Agent Gateway Dual-Registry Binding**: An Agent Gateway can link up to
|
||||
**two** registries in its `registries` array, provided that **exactly one
|
||||
registry is `global`**, and the second registry is either `regional` (e.g.
|
||||
`us-central1`) or `multi-regional` (e.g. `us`, `eu`). Two regional
|
||||
registries without a global are rejected by the control plane.
|
||||
|
||||
13. **REST API Path Extensions (`.json`)**: When registering REST APIs (like
|
||||
Zendesk), note that SDK clients append `.json` (e.g.
|
||||
`/api/v2/tickets.json`). Ensure your UAP CEL rules or registry endpoint
|
||||
interfaces account for exact paths, `/` subpaths, `.json` extensions, and
|
||||
`?` query strings.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 1. The Data Model in One Picture
|
||||
@@ -234,7 +253,7 @@ scheme, or extra subdomain mismatch will cause denial.
|
||||
#### Creating Consolidated Service via gcloud
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services create googleapis \
|
||||
gcloud agent-registry services create googleapis \
|
||||
--project=$PROJECT_ID --location=$LOCATION \
|
||||
--display-name="Google APIs" \
|
||||
--endpoint-spec-type=no-spec \
|
||||
@@ -251,7 +270,7 @@ gcloud alpha agent-registry services create googleapis \
|
||||
### Quick "is the hostname registered?" check
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services list \
|
||||
gcloud agent-registry services list \
|
||||
--project=$PROJECT_ID \
|
||||
--location=$LOCATION \
|
||||
--format="table(name.basename(), interfaces.url)" \
|
||||
@@ -286,7 +305,7 @@ functional-type annotation. Everything else is manual.
|
||||
### List
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry agents list \
|
||||
gcloud agent-registry agents list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -294,7 +313,7 @@ gcloud alpha agent-registry agents list \
|
||||
Filter:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry agents list \
|
||||
gcloud agent-registry agents list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--filter="displayName='DISPLAY_NAME'"
|
||||
@@ -303,7 +322,7 @@ gcloud alpha agent-registry agents list \
|
||||
### Describe
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry agents describe AGENT_NAME \
|
||||
gcloud agent-registry agents describe AGENT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -317,7 +336,7 @@ IAM.
|
||||
Display name / description:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services update AGENT_NAME \
|
||||
gcloud agent-registry services update AGENT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--display-name="New name" \
|
||||
@@ -327,7 +346,7 @@ gcloud alpha agent-registry services update AGENT_NAME \
|
||||
Endpoint URL:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services update AGENT_NAME \
|
||||
gcloud agent-registry services update AGENT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--interfaces=url=ENDPOINT_URL,protocolBinding=PROTOCOL
|
||||
@@ -339,7 +358,7 @@ Agent spec payload (max size 10 KB to satisfy gRPC control plane metadata header
|
||||
limits):
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services update AGENT_NAME \
|
||||
gcloud agent-registry services update AGENT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--agent-spec-content=@AGENT_SPEC
|
||||
@@ -351,7 +370,7 @@ For automatically registered agents: delete from the source runtime -- registry
|
||||
entry follows. For manually registered agents:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services delete AGENT_NAME \
|
||||
gcloud agent-registry services delete AGENT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -368,7 +387,7 @@ gcloud alpha agent-registry services delete AGENT_NAME \
|
||||
the *target* agent resource:
|
||||
|
||||
```bash
|
||||
gcloud beta iap web set-iam-policy agents-iap-policy.json \
|
||||
gcloud iap web set-iam-policy agents-iap-policy.json \
|
||||
--project=PROJECT_ID \
|
||||
--agent=AGENT_ID \
|
||||
--region=REGION
|
||||
@@ -422,7 +441,7 @@ manual registration with a tool spec.
|
||||
### Register
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services create SERVER_NAME \
|
||||
gcloud agent-registry services create SERVER_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--display-name="DISPLAY_NAME" \
|
||||
@@ -438,7 +457,7 @@ gcloud alpha agent-registry services create SERVER_NAME \
|
||||
### List
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry mcp-servers list \
|
||||
gcloud agent-registry mcp-servers list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -449,7 +468,7 @@ Useful filters: - `displayName='NAME'` - `mcpServerId='urn:mcp:SERVER_URN'`
|
||||
### Describe
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry mcp-servers describe SERVER_NAME \
|
||||
gcloud agent-registry mcp-servers describe SERVER_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -463,7 +482,7 @@ Tool spec changes are not auto-detected -- re-upload when the server
|
||||
adds/changes tools:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services update SERVER_NAME \
|
||||
gcloud agent-registry services update SERVER_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--mcp-server-spec-content=@TOOL_SPEC
|
||||
@@ -472,7 +491,7 @@ gcloud alpha agent-registry services update SERVER_NAME \
|
||||
### Delete
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services delete SERVER_NAME \
|
||||
gcloud agent-registry services delete SERVER_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -488,7 +507,7 @@ gcloud alpha agent-registry services delete SERVER_NAME \
|
||||
resource:
|
||||
|
||||
```bash
|
||||
gcloud beta iap web set-iam-policy agents-iap-policy.json \
|
||||
gcloud iap web set-iam-policy agents-iap-policy.json \
|
||||
--project=PROJECT_ID \
|
||||
--mcp-server=MCP_SERVER_ID \
|
||||
--region=REGION
|
||||
@@ -544,7 +563,7 @@ REST APIs, internal HTTP services. Always manually registered.
|
||||
### Register
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services create SERVICE_NAME \
|
||||
gcloud agent-registry services create SERVICE_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--display-name="DISPLAY_NAME" \
|
||||
@@ -565,7 +584,7 @@ gcloud alpha agent-registry services create SERVICE_NAME \
|
||||
### List
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints list \
|
||||
gcloud agent-registry endpoints list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -573,7 +592,7 @@ gcloud alpha agent-registry endpoints list \
|
||||
Filter:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints list \
|
||||
gcloud agent-registry endpoints list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--filter="displayName='NAME'"
|
||||
@@ -583,7 +602,7 @@ For URL-substring search, list `services` instead and filter on
|
||||
`interfaces.url`:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services list \
|
||||
gcloud agent-registry services list \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--format="table(name.basename(), interfaces.url, interfaces.protocolBinding)" \
|
||||
@@ -593,7 +612,7 @@ gcloud alpha agent-registry services list \
|
||||
### Describe
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints describe ENDPOINT_NAME \
|
||||
gcloud agent-registry endpoints describe ENDPOINT_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -601,7 +620,7 @@ gcloud alpha agent-registry endpoints describe ENDPOINT_NAME \
|
||||
### Update
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services update SERVICE_NAME \
|
||||
gcloud agent-registry services update SERVICE_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION \
|
||||
--interfaces=url=ENDPOINT_URL,protocolBinding=PROTOCOL
|
||||
@@ -610,7 +629,7 @@ gcloud alpha agent-registry services update SERVICE_NAME \
|
||||
### Delete
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry services delete SERVICE_NAME \
|
||||
gcloud agent-registry services delete SERVICE_NAME \
|
||||
--project=PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
@@ -626,7 +645,7 @@ gcloud alpha agent-registry services delete SERVICE_NAME \
|
||||
agent's principal on the endpoint resource:
|
||||
|
||||
```bash
|
||||
gcloud beta iap web set-iam-policy agents-iap-policy.json \
|
||||
gcloud iap web set-iam-policy agents-iap-policy.json \
|
||||
--project=PROJECT_ID \
|
||||
--endpoint=ENDPOINT_ID \
|
||||
--region=REGION
|
||||
@@ -659,8 +678,8 @@ role -- confirm against `docs.cloud.google.com/iam/docs/roles-permissions/iap`.
|
||||
- **Endpoint registered in `global` but agent calls a regional URL**: registry
|
||||
location doesn't have to match the destination URL location, but the IAM
|
||||
binding's `--region` must match where the resource is registered. Check that
|
||||
`--region=` on `gcloud beta iap web set-iam-policy` equals the location used
|
||||
at creation.
|
||||
`--region=` on `gcloud iap web set-iam-policy` equals the location used at
|
||||
creation.
|
||||
- **Endpoint not appearing in `endpoints list`**: created with the wrong spec
|
||||
type. Must use `--endpoint-spec-type=no-spec`.
|
||||
|
||||
@@ -690,11 +709,47 @@ Project-scoped, granted via standard IAM:
|
||||
These let humans and CI register and inspect entries. They do **not** grant
|
||||
runtime traffic.
|
||||
|
||||
### Layer B — IAP egress permissions (let an agent actually send traffic)
|
||||
### Layer B — Traffic Authorization (Legacy v1 vs. UAP Policy V2)
|
||||
|
||||
Bound on Agent Registry resources via `gcloud beta iap web set-iam-policy`. The
|
||||
role is always `roles/iap.egressor`. The scope of the binding determines which
|
||||
target resources the source agent can reach:
|
||||
Depending on the gateway's `iapPolicyVersion` setting, registry resources
|
||||
authorize traffic through one of two mechanisms:
|
||||
|
||||
#### Mechanism B1: Unified Access Policy (UAP / Policy V2)
|
||||
|
||||
When the attached IAP Authz Extension specifies `iapPolicyVersion: "V2"`,
|
||||
policies are decoupled from individual registry resources:
|
||||
|
||||
- `AccessPolicy` and `PolicyBinding` (`iam.googleapis.com/v3`) attach to the
|
||||
Resource Manager hierarchy (Organization, Folder, Project) targeting numeric
|
||||
resource URIs (e.g.
|
||||
`//cloudresourcemanager.googleapis.com/projects/${PROJECT_NUMBER}`).
|
||||
- Rules grant FQDN permission `iap.googleapis.com/resources.egressViaIAP`.
|
||||
- Agent Registry entries dynamically populate the
|
||||
`destination.agent_registry.*` CEL attributes evaluated at runtime:
|
||||
- `destination.is_registered` (boolean): `true` if target matches a
|
||||
registry service.
|
||||
- `destination.agent_registry.resource_type`: `'ENDPOINT'`,
|
||||
`'MCP_SERVER'`, `'AGENT'`, `'SKILL'`.
|
||||
- `destination.agent_registry.location`: region of registry resource.
|
||||
- `destination.agent_registry.mcp_server.name`: full MCP server resource
|
||||
name.
|
||||
- `destination.agent_registry.mcp_server.method`: `'tools'`, `'prompts'`,
|
||||
`'resources'`.
|
||||
- `destination.agent_registry.mcp_server.tool.name`: specific tool name
|
||||
(e.g. `'updateTicket'`).
|
||||
- `destination.agent_registry.mcp_server.tool.annotations.read_only_hint`:
|
||||
boolean.
|
||||
- **Mandatory CEL Guard**: Always guard tool annotations with:
|
||||
`(destination.agent_registry.mcp_server.method == 'tools') &&
|
||||
(destination.agent_registry.mcp_server.tool.annotations.read_only_hint ==
|
||||
true)`.
|
||||
|
||||
#### Mechanism B2: Legacy IAM v1 (Per-Resource Bindings)
|
||||
|
||||
In legacy v1, permissions are bound directly on Agent Registry resources via
|
||||
`gcloud iap web set-iam-policy`. The role is always `roles/iap.egressor`. The
|
||||
scope of the binding determines which target resources the source agent can
|
||||
reach:
|
||||
|
||||
| Scope | gcloud target flag | Grants egress to |
|
||||
| ----------------- | -------------------------------- | --------------------- |
|
||||
@@ -744,17 +799,28 @@ Source:
|
||||
|
||||
When debugging "wrong principal" errors: the principal is built from the agent's
|
||||
**resource URI**, not its display name and not its URN. View the resource URI
|
||||
via `gcloud alpha agent-registry agents describe`.
|
||||
via `gcloud agent-registry agents describe`.
|
||||
|
||||
### Full IAP role reference (relevant subset)
|
||||
|
||||
Role | Permission grants the role provides | When to use
|
||||
---------------------------------- | ----------------------------------------------------------------------- | -----------
|
||||
`roles/iap.egressor` (Beta) | `iap.webServiceVersions.egressViaIAP` | **Agent egress through Agent Gateway**
|
||||
`roles/iap.httpsResourceAccessor` | `iap.webServiceVersions.accessViaIAP` | Human/service ingress to an IAP-protected web app
|
||||
`roles/iap.tunnelResourceAccessor` | `iap.tunnelDestGroups.accessViaIAP`, `iap.tunnelInstances.accessViaIAP` | Classic IAP TCP tunnels to GCE -- **not** for agent gateway
|
||||
`roles/iap.admin` | Full IAP admin (`iap.tunnel.*`, all getIam/setIam) | Manage IAP policies
|
||||
`roles/iap.viewer` | Read IAP settings | Audit
|
||||
| Role | Permission grants the role provides | When to use |
|
||||
| ---------------------------------- | ------------------------------------- | ------------- |
|
||||
| `roles/iap.egressor` (Beta) | `iap.webServiceVersions.egressViaIAP` | **Agent |
|
||||
: : : egress :
|
||||
: : : through Agent :
|
||||
: : : Gateway** :
|
||||
| `roles/iap.httpsResourceAccessor` | `iap.webServiceVersions.accessViaIAP` | Human/service |
|
||||
: : : ingress to an :
|
||||
: : : IAP-protected :
|
||||
: : : web app :
|
||||
| `roles/iap.tunnelResourceAccessor` | `iap.tunnelDestGroups.accessViaIAP`, | Classic IAP |
|
||||
: : `iap.tunnelInstances.accessViaIAP` : TCP tunnels :
|
||||
: : : to GCE -- :
|
||||
: : : **not** for :
|
||||
: : : agent gateway :
|
||||
| `roles/iap.admin` | Full IAP admin (`iap.tunnel.*`, all | Manage IAP |
|
||||
: : getIam/setIam) : policies :
|
||||
| `roles/iap.viewer` | Read IAP settings | Audit |
|
||||
|
||||
Source: `docs.cloud.google.com/iam/docs/roles-permissions/iap`.
|
||||
|
||||
@@ -762,21 +828,46 @@ Source: `docs.cloud.google.com/iam/docs/roles-permissions/iap`.
|
||||
|
||||
## 7. Common Registration Errors and Where to Look
|
||||
|
||||
Symptom | Likely cause | Where to check
|
||||
--------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------------
|
||||
`services create` fails: "manual registration not supported" | Used `--location=us` or `--location=eu` (multi-regions) | Switch to a region (e.g. `us-central1`) or `global`
|
||||
`services create` succeeds but resource missing from `endpoints list` | Wrong `*-spec-type`. `--endpoint-spec-type=no-spec` produces an `Endpoint`. | Re-create with the correct spec-type, or check `services list`
|
||||
`services update --mcp-server-spec-content` rejects file | Spec > 10 KB | Trim the tool spec
|
||||
Agent calls API X, IAP returns 403 | Hostname variant not registered (commonly REP `*.LOCATION.rep.googleapis.com`) | `services list --filter="interfaces.url:FRAGMENT"`
|
||||
Agent calls API X, IAP returns 403 even though hostname is registered | Missing `roles/iap.egressor` binding for the source agent's principal | `gcloud beta iap web get-iam-policy --project= --region= --endpoint=...` (or `--mcp-server=`, `--agent=`, `--resource-type=agent-registry`)
|
||||
MCP tool call succeeds for one tool, denied for another | IAP policy condition restricts `mcp.toolName` or `mcp.tool.isReadOnly` | Inspect the IAP policy on the MCP server resource
|
||||
Auto-registered Agent Runtime agent missing from registry | Agent deployed via custom code, not Agent Runtime SDK | Re-deploy via Agent Runtime, or register manually as a `Service`
|
||||
A2A agent has no skills in registry | `agent-card.json` unreachable from Google's crawler | Curl the Agent Card URL from a public network; verify content type and schema
|
||||
Agent principal mismatch in IAP policy | Principal built from wrong resource URI / project number / SA identifier | `gcloud alpha agent-registry agents describe` -> use Resource URI to construct
|
||||
`roles/iap.tunnelResourceAccessor` granted, still denied | Wrong role -- agent egress requires `roles/iap.egressor` | Replace the binding
|
||||
Endpoint Google Cloud console "Test connection" fails on private URL | Connection test only works for public URLs (by design) | Test via the agent itself or `curl` from a peered network
|
||||
`agents-iap-policy.json` set, still denied | Wrong `--region` flag on `set-iam-policy` -- must match resource location | Re-issue with the correct `--region`
|
||||
Cannot find URN for binding | Use `mcp-servers describe` / `agents describe` and read the `name` field; format per section 1 | See URN formats in section 1
|
||||
| Symptom | Likely cause | Where to check |
|
||||
| ---------------------------------- | -------------------------------- | ------------------------------------ |
|
||||
| `services create` fails: "manual | Used `--location=us` or | Switch to a region (e.g. |
|
||||
: registration not supported" : `--location=eu` (multi-regions) : `us-central1`) or `global` :
|
||||
| `services create` succeeds but | Wrong `*-spec-type`. | Re-create with the correct |
|
||||
: resource missing from `endpoints : `--endpoint-spec-type=no-spec` : spec-type, or check `services list` :
|
||||
: list` : produces an `Endpoint`. : :
|
||||
| `services update | Spec > 10 KB | Trim the tool spec |
|
||||
: --mcp-server-spec-content` rejects : : :
|
||||
: file : : :
|
||||
| Agent calls API X, IAP returns 403 | Hostname variant not registered | `services list |
|
||||
: : (commonly REP : --filter="interfaces.url\:FRAGMENT"` :
|
||||
: : `*.LOCATION.rep.googleapis.com`) : :
|
||||
| Agent calls API X, IAP returns 403 | Missing `roles/iap.egressor` | `gcloud iap web get-iam-policy |
|
||||
: even though hostname is registered : binding for the source agent's : --project= --region= --endpoint=...` :
|
||||
: : principal : (or `--mcp-server=`, `--agent=`, :
|
||||
: : : `--resource-type=agent-registry`) :
|
||||
| MCP tool call succeeds for one | IAP policy condition restricts | Inspect the IAP policy on the MCP |
|
||||
: tool, denied for another : `mcp.toolName` or : server resource :
|
||||
: : `mcp.tool.isReadOnly` : :
|
||||
| Auto-registered Agent Runtime | Agent deployed via custom code, | Re-deploy via Agent Runtime, or |
|
||||
: agent missing from registry : not Agent Runtime SDK : register manually as a `Service` :
|
||||
| A2A agent has no skills in | `agent-card.json` unreachable | Curl the Agent Card URL from a |
|
||||
: registry : from Google's crawler : public network; verify content type :
|
||||
: : : and schema :
|
||||
| Agent principal mismatch in IAP | Principal built from wrong | `gcloud agent-registry agents |
|
||||
: policy : resource URI / project number / : describe` -> use Resource URI to :
|
||||
: : SA identifier : construct :
|
||||
| `roles/iap.tunnelResourceAccessor` | Wrong role -- agent egress | Replace the binding |
|
||||
: granted, still denied : requires `roles/iap.egressor` : :
|
||||
| Endpoint Google Cloud console | Connection test only works for | Test via the agent itself or `curl` |
|
||||
: "Test connection" fails on private : public URLs (by design) : from a peered network :
|
||||
: URL : : :
|
||||
| `agents-iap-policy.json` set, | Wrong `--region` flag on | Re-issue with the correct `--region` |
|
||||
: still denied : `set-iam-policy` -- must match : :
|
||||
: : resource location : :
|
||||
| Cannot find URN for binding | Use `mcp-servers describe` / | See URN formats in section 1 |
|
||||
: : `agents describe` and read the : :
|
||||
: : `name` field; format per section : :
|
||||
: : 1 : :
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -813,50 +904,50 @@ Source: `docs.cloud.google.com/agent-registry/use-agentregistry-mcp`.
|
||||
|
||||
```bash
|
||||
# READ
|
||||
gcloud alpha agent-registry agents list --project=P --location=L
|
||||
gcloud alpha agent-registry agents describe NAME --project=P --location=L
|
||||
gcloud alpha agent-registry mcp-servers list --project=P --location=L
|
||||
gcloud alpha agent-registry mcp-servers describe NAME --project=P --location=L
|
||||
gcloud alpha agent-registry endpoints list --project=P --location=L
|
||||
gcloud alpha agent-registry endpoints describe NAME --project=P --location=L
|
||||
gcloud alpha agent-registry services list --project=P --location=L
|
||||
gcloud alpha agent-registry services describe NAME --project=P --location=L
|
||||
gcloud agent-registry agents list --project=P --location=L
|
||||
gcloud agent-registry agents describe NAME --project=P --location=L
|
||||
gcloud agent-registry mcp-servers list --project=P --location=L
|
||||
gcloud agent-registry mcp-servers describe NAME --project=P --location=L
|
||||
gcloud agent-registry endpoints list --project=P --location=L
|
||||
gcloud agent-registry endpoints describe NAME --project=P --location=L
|
||||
gcloud agent-registry services list --project=P --location=L
|
||||
gcloud agent-registry services describe NAME --project=P --location=L
|
||||
|
||||
# WRITE (always 'services'; the projection follows from --*-spec-type)
|
||||
gcloud alpha agent-registry services create NAME \
|
||||
gcloud agent-registry services create NAME \
|
||||
--project=P --location=L --display-name="..." \
|
||||
--endpoint-spec-type=no-spec \
|
||||
--interfaces=url=URL,protocolBinding=HTTP_JSON|GRPC|JSONRPC
|
||||
|
||||
gcloud alpha agent-registry services create NAME \
|
||||
gcloud agent-registry services create NAME \
|
||||
--project=P --location=L --display-name="..." \
|
||||
--mcp-server-spec-type=tool-spec \
|
||||
--mcp-server-spec-content=@toolspec.json \
|
||||
--interfaces=url=URL,protocolBinding=JSONRPC
|
||||
|
||||
gcloud alpha agent-registry services create NAME \
|
||||
gcloud agent-registry services create NAME \
|
||||
--project=P --location=L --display-name="..." \
|
||||
--agent-spec-content=@agent-card.json \
|
||||
--interfaces=url=URL,protocolBinding=HTTP_JSON
|
||||
|
||||
gcloud alpha agent-registry services update NAME \
|
||||
gcloud agent-registry services update NAME \
|
||||
--project=P --location=L \
|
||||
[ --display-name="..." | --description="..." \
|
||||
| --interfaces=url=URL,protocolBinding=... \
|
||||
| --mcp-server-spec-content=@spec.json \
|
||||
| --agent-spec-content=@card.json ]
|
||||
|
||||
gcloud alpha agent-registry services delete NAME --project=P --location=L
|
||||
gcloud agent-registry services delete NAME --project=P --location=L
|
||||
|
||||
# IAP egress policy bindings (separate API, separate gcloud surface)
|
||||
gcloud beta iap web set-iam-policy POLICY.json \
|
||||
gcloud iap web set-iam-policy POLICY.json \
|
||||
--project=P --region=L \
|
||||
[ --resource-type=agent-registry
|
||||
| --agent=AGENT_ID
|
||||
| --mcp-server=MCP_SERVER_ID
|
||||
| --endpoint=ENDPOINT_ID ]
|
||||
|
||||
gcloud beta iap web get-iam-policy \
|
||||
gcloud iap web get-iam-policy \
|
||||
--project=P --region=L \
|
||||
[ same target flags ]
|
||||
```
|
||||
|
||||
@@ -35,11 +35,23 @@ permits it:
|
||||
resource, otherwise the authz extension won't actually run.
|
||||
3. **Service-extension (delegated authz)** — the gateway calls IAP to make an
|
||||
allow/deny decision.
|
||||
4. **IAP / IAM** — the agent's identity must have the **IAP egressor role**
|
||||
(`roles/iap.egressor`, display name "IAP-secured Egressor") on the
|
||||
registered resource, or be in a principal set that does.
|
||||
5. **Principal Access Boundary (PAB)** — even with the IAM binding correct, a
|
||||
PAB policy on the principal set can restrict which resources it can reach.
|
||||
4. **IAP / IAM Policy Evaluation** — the agent's identity must be authorized by
|
||||
IAP:
|
||||
* **IAM v1 (Legacy Policy Model)**: Evaluated when `iapPolicyVersion:
|
||||
"V1"` (or unset). The agent identity must have the **IAP egressor role**
|
||||
(`roles/iap.egressor`, display name "IAP-secured Egressor") directly
|
||||
bound on the registered resource shadow resource in IAP.
|
||||
* **Unified Access Policy (UAP / Policy V2 / IAM v3)**: Evaluated when the
|
||||
gateway's IAP Authz Extension metadata specifies `iapPolicyVersion:
|
||||
"V2"`. Next-gen access control bound directly to Resource Manager
|
||||
hierarchy nodes (Organizations, Folders, Projects) via `PolicyBinding`
|
||||
(`iam.googleapis.com/v3`). Evaluates `AccessPolicy` rules with CEL
|
||||
expressions on deep attributes (`destination.agent_registry.*` or
|
||||
`destination.unregistered.*`). Follows strict evaluation invariants:
|
||||
absolute DENY precedence (cannot be overridden by downstream projects),
|
||||
and additive ALLOW aggregation across the CRM tree.
|
||||
5. **Principal Access Boundary (PAB)** — even with the IAM/UAP binding correct,
|
||||
a PAB policy on the principal set can restrict which resources it can reach.
|
||||
**PAB takes precedence over IAM Allow** — a correct egressor binding does
|
||||
nothing if a PAB scopes the principal away from the target.
|
||||
|
||||
@@ -50,14 +62,28 @@ authz policies. Denials *can* originate at this proxy layer before IAP runs (no
|
||||
IAP audit entry exists for those calls); those show up in load-balancer logs
|
||||
(see Step 3b).
|
||||
|
||||
**Proxy Routing & TLS SNI:** The proxy performs TLS inspection and looks inside
|
||||
the HTTPS call for the SNI hostname. In Private Service Connect (PSC)
|
||||
environments, the client resolves APIs to internal VIPs, so the outer tunnel
|
||||
request is naturally logged as `CONNECT 240.0.0.2:443`. This is expected. The
|
||||
proxy intercepts this and evaluates routing based on the inner SNI hostname. If
|
||||
the corresponding hostname (e.g., `us-central1-aiplatform.googleapis.com`) is
|
||||
NOT registered, the proxy cannot route the traffic, resulting in a
|
||||
`default_denied` action on the `CONNECT` request before IAP is ever reached.
|
||||
**Proxy Routing, TLS SNI & Agent Connectivity Templates (ACT):** The proxy
|
||||
performs TLS inspection and looks inside the HTTPS call for the SNI hostname. In
|
||||
Private Service Connect (PSC) environments, the client resolves APIs to internal
|
||||
VIPs, so the outer tunnel request is naturally logged as `CONNECT
|
||||
240.0.0.2:443`. This is expected. The proxy intercepts this and evaluates
|
||||
routing based on the inner SNI hostname. If the corresponding hostname (e.g.,
|
||||
`us-central1-aiplatform.googleapis.com`) is NOT registered, the proxy cannot
|
||||
route the traffic, resulting in a `default_denied` action on the `CONNECT`
|
||||
request before IAP is ever reached.
|
||||
|
||||
Under **VPC Service Controls (VPC-SC)**, Agent Gateway requires an **Agent
|
||||
Connectivity Template (ACT)** configured with `vpcEgress: ALL_TRAFFIC`:
|
||||
|
||||
- Traffic destined for external public APIs (e.g. `api.ipify.org`,
|
||||
`api.weather.gov`) resolves to the synthetic PSC VIP `240.0.0.2:443`,
|
||||
traverses the gateway, and egresses through the consumer VPC PSC-I Network
|
||||
Attachment subnet via **Cloud NAT** (`gateway-nat-gateway`) using static
|
||||
IPs. If Cloud NAT is missing or misconfigured, external traffic hangs or
|
||||
resets silently.
|
||||
- Traffic destined for Google APIs (e.g., Vertex AI, Cloud Run default domains
|
||||
`*.run.app`) routes directly through Andromeda/Private Google Access to
|
||||
Google Front Ends (GFE), bypassing Cloud NAT.
|
||||
|
||||
### Don't confuse `roles/iap.egressor` with other IAP roles
|
||||
|
||||
@@ -216,7 +242,8 @@ xychart-beta
|
||||
no │ yes │
|
||||
│ ▼
|
||||
│ ┌────────────────────────────────┐
|
||||
│ │ 3c. PSC Subnet Exhaustion Check│
|
||||
│ │ 3c. PSC Subnet Exhaustion & │
|
||||
│ │ 3d. ACT ALL_TRAFFIC / Cloud NAT│
|
||||
│ └────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
@@ -238,8 +265,8 @@ xychart-beta
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ 3. Pull IAP logs — DRY_RUN or │
|
||||
│ enforced? Allow or deny? │
|
||||
│ 3. Pull IAP logs — Check V1 vs V2, │
|
||||
│ DRY_RUN vs enforced, allow/deny? │
|
||||
└────────────────┬────────────────────┘
|
||||
│
|
||||
▼
|
||||
@@ -251,17 +278,17 @@ xychart-beta
|
||||
no │ yes │
|
||||
▼ ▼
|
||||
┌──────────────────┐ ┌─────────────────────────────┐
|
||||
│ Root cause: │ │ 5. Does the agent identity │
|
||||
│ unregistered │ │ (or its principal set) │
|
||||
│ hostname permu- │ │ have IAP egressor on │
|
||||
│ term. Recommend │ │ the registered resource? │
|
||||
│ Root cause: │ │ 5. Check IAM / UAP Policies:│
|
||||
│ unregistered │ │ - V1: roles/iap.egressor │
|
||||
│ hostname permu- │ │ - V2: AccessPolicy & CRM │
|
||||
│ term. Recommend │ │ PolicyBinding (CEL) │
|
||||
│ registering all │ └────────┬────────────────────┘
|
||||
│ five forms. │ │
|
||||
└──────────────────┘ ▼
|
||||
┌─────────────────────────────┐
|
||||
│ 6. Authz extension wired to │
|
||||
│ the gateway? Pointing at │
|
||||
│ IAP? │
|
||||
│ 6. Authz extension wired? │
|
||||
│ iapPolicyVersion V1/V2? │
|
||||
│ Dual-registry valid? │
|
||||
└────────┬────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────┐
|
||||
@@ -310,9 +337,9 @@ commands from hanging:
|
||||
> ```bash
|
||||
> ACTIVE_PROJ=$(gcloud config get-value project)
|
||||
> # Check for gateways
|
||||
> gcloud alpha network-services agent-gateways list --location=us-central1 --project=$ACTIVE_PROJ
|
||||
> gcloud network-services agent-gateways list --location=us-central1 --project=$ACTIVE_PROJ
|
||||
> # Check for agents
|
||||
> gcloud alpha agent-registry agents list --location=us-central1 --project=$ACTIVE_PROJ
|
||||
> gcloud agent-registry agents list --location=us-central1 --project=$ACTIVE_PROJ
|
||||
> ```
|
||||
>
|
||||
> If you find the target resources in the active project, **proceed
|
||||
@@ -320,12 +347,12 @@ commands from hanging:
|
||||
|
||||
If resources are not in the active project, check prioritized dev projects:
|
||||
`bash for proj in duncanjames-tf-dev duncanjames-agw-tf; do # Check gateways
|
||||
res_gw=$(gcloud alpha network-services agent-gateways list
|
||||
--location=us-central1 --project=$proj 2>&1) if [[ "$res_gw" == *"NAME"* ]];
|
||||
then echo "FOUND Gateways in project: $proj" echo "$res_gw" fi # Check
|
||||
agents res_ag=$(gcloud alpha agent-registry agents list
|
||||
--location=us-central1 --project=$proj 2>&1) if [[ "$res_ag" == *"NAME"* ]];
|
||||
then echo "FOUND Registry in project: $proj" echo "$res_ag" fi done`
|
||||
res_gw=$(gcloud network-services agent-gateways list --location=us-central1
|
||||
--project=$proj 2>&1) if [[ "$res_gw" == *"NAME"* ]]; then echo "FOUND
|
||||
Gateways in project: $proj" echo "$res_gw" fi # Check agents res_ag=$(gcloud
|
||||
alpha agent-registry agents list --location=us-central1 --project=$proj
|
||||
2>&1) if [[ "$res_ag" == *"NAME"* ]]; then echo "FOUND Registry in project:
|
||||
$proj" echo "$res_ag" fi done`
|
||||
|
||||
If you cannot find the target resource (e.g. the stuck gateway or the
|
||||
failing agent) in the default project:
|
||||
@@ -367,7 +394,7 @@ startup/`set_up()`):
|
||||
Registry. **You MUST also explicitly suggest checking whether other
|
||||
required monitoring/tracing endpoints (such as
|
||||
`monitoring.googleapis.com` or `trace.mtls.googleapis.com`) are
|
||||
registered as Endpoints**, and provide the `gcloud alpha agent-registry
|
||||
registered as Endpoints**, and provide the `gcloud agent-registry
|
||||
endpoints create` commands for them.
|
||||
* **Verify/Create Authorization Policy**: Explain that an
|
||||
`AuthorizationPolicy` must allow the agent's principal set to access the
|
||||
@@ -395,14 +422,19 @@ If the logs you find do **not** match the symptom described in the user's prompt
|
||||
only issue.
|
||||
2. In your diagnostic report, you MUST address the user's described symptom.
|
||||
3. Explain that while you found a different error in the active logs (and
|
||||
diagnose it), the user's described symptom (IAP denial) is typically caused
|
||||
by:
|
||||
* Missing `roles/iap.egressor` or `roles/iap.httpsGatewayUser` on the
|
||||
agent identity.
|
||||
* `AuthorizationPolicy` not being correctly bound to the Gateway.
|
||||
4. Include the general troubleshooting steps for IAP denials (checking IAP
|
||||
audit logs, verifying roles, checking policy bindings) as recommended fixes,
|
||||
even if you couldn't verify them in the current log state.
|
||||
diagnose it), for any logs or findings where the agent is getting a 403 to
|
||||
an MCP server or endpoint, you must **check the IAP Egressor bindings on the
|
||||
matching resource in the registry first**:
|
||||
* If there is no registry entry for the MCP server or endpoint, ensure
|
||||
there is one created.
|
||||
* Ensure that the agent has the `roles/iap.egressor` role bound to the
|
||||
registry entry. If there are no permissions matching, tell the user to
|
||||
grant `roles/iap.egressor` against the registry entry.
|
||||
* Verify that an `AuthorizationPolicy` is correctly bound to the Gateway.
|
||||
4. Include these prioritized troubleshooting steps for IAP denials (checking
|
||||
registry entries and `roles/iap.egressor` bindings first, checking IAP audit
|
||||
logs, and verifying Gateway policies) as recommended fixes, even if you
|
||||
couldn't verify them in the current log state.
|
||||
|
||||
### Step 1 — Confirm the symptom in agent logs
|
||||
|
||||
@@ -542,21 +574,33 @@ What to read out of each entry:
|
||||
- **`labels."iap.googleapis.com/audited_resource_name"`** — if this is
|
||||
`unregisteredResource`, the destination hostname isn't in the registry. Go
|
||||
to Step 4.
|
||||
- **The enforcement mode** — is IAP in dry-run?
|
||||
- **The policy version & enforcement mode** — check `iapPolicyVersion` and
|
||||
`iamEnforcementMode`:
|
||||
|
||||
```yaml
|
||||
service: iap.googleapis.com
|
||||
failOpen: true
|
||||
timeout: 1s
|
||||
metadata:
|
||||
iamEnforcementMode: "DRY_RUN"
|
||||
iapPolicyVersion: "V1"
|
||||
iamEnforcementMode: "DRY_RUN" # or "ENFORCED"
|
||||
iapPolicyVersion: "v2" # "v2" for UAP Policy V2; "V1" for legacy IAM v1
|
||||
```
|
||||
|
||||
In `DRY_RUN` mode, denials are logged but the request proceeds. If your
|
||||
agent is failing with a real 403 *and* IAP is in dry-run, the denial is
|
||||
coming from somewhere else — most often the gateway's underlying egress
|
||||
proxy (see Step 3b) or the destination service itself.
|
||||
* **In `DRY_RUN` mode**, denials are logged but the request proceeds. If
|
||||
your agent is failing with a real 403 *and* IAP is in dry-run, the
|
||||
denial is coming from somewhere else — most often the gateway's
|
||||
underlying egress proxy (see Step 3b) or the destination service itself.
|
||||
* **Under UAP (`iapPolicyVersion: "v2"`)**, check
|
||||
`protoPayload.metadata.policyEvaluationResults[]` and audit log entries.
|
||||
UAP logs will display the evaluation outcomes across the Resource
|
||||
Manager hierarchy (Organization, Folder, Project).
|
||||
* If an **explicit DENY** matched anywhere in the hierarchy (e.g., at
|
||||
Org or Folder level), the request is rejected immediately, even if a
|
||||
project-level policy allows it.
|
||||
* If **no ALLOW matched**, the request is denied by default-deny.
|
||||
* Check for CEL attribute mismatches (e.g., calling an unregistered
|
||||
host when policies only allow `destination.agent_registry.*`, or
|
||||
path mismatches like missing `.json` extensions in REST API paths).
|
||||
|
||||
### Step 3b — If there's no IAP audit entry for the failing call, pull the gateway proxy load-balancer log
|
||||
|
||||
@@ -607,14 +651,14 @@ Connect (PSC) subnet might be out of IP addresses.
|
||||
project to find the one that is stuck or relevant:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways list --location=$LOCATION --project=$PROJECT_ID
|
||||
gcloud network-services agent-gateways list --location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
2. **Identify the Network Attachment**: Describe the Agent Gateway to find the
|
||||
Network Attachment in use:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways describe AGENT_GATEWAY_NAME --location=$LOCATION --project=$PROJECT_ID
|
||||
gcloud network-services agent-gateways describe AGENT_GATEWAY_NAME --location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
Look for `networkConfig.egress.networkAttachment` or
|
||||
@@ -654,38 +698,146 @@ Connect (PSC) subnet might be out of IP addresses.
|
||||
a `/28` subnet is too small and easily exhausted, and recommend
|
||||
expanding the CIDR range to at least `/26` as a best practice.
|
||||
|
||||
### Step 3d — Diagnosing Agent Connectivity Template (ACT) & Network Routing
|
||||
|
||||
Under VPC Service Controls (VPC-SC), Agent Gateway relies on an **Agent
|
||||
Connectivity Template (ACT)**. If the agent experiences timeouts, silent
|
||||
connection hangs, or connection drops when attempting to reach public internet
|
||||
endpoints or internal services, check the ACT and consumer network
|
||||
configuration:
|
||||
|
||||
1. **Inspect the Agent Connectivity Template**:
|
||||
|
||||
```bash
|
||||
gcloud network-services agent-connectivity-templates describe ACT_NAME \
|
||||
--location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
Verify the `vpcEgress` mode:
|
||||
|
||||
- `vpcEgress: ALL_TRAFFIC`: Intercepts and routes all traffic (Google APIs
|
||||
and public Internet) into the consumer VPC network attachment.
|
||||
- `vpcEgress: DEFAULT`: Only Private Google Access traffic routes through
|
||||
the template.
|
||||
|
||||
2. **Verify Consumer Cloud NAT for External Endpoints (BKI 28)**: When
|
||||
`vpcEgress: ALL_TRAFFIC` is enabled, external internet traffic (e.g.,
|
||||
`api.ipify.org`, `api.weather.gov`, third-party SaaS) resolves via synthetic
|
||||
PSC VIP `240.0.0.2:443`, traverses the gateway, and exits through the
|
||||
consumer VPC PSC-I subnet.
|
||||
|
||||
- **Cloud NAT Requirement**: The consumer VPC **MUST** have a Cloud NAT
|
||||
gateway configured that covers the PSC-I subnet range (e.g.,
|
||||
`gateway-nat-gateway` with static IP).
|
||||
- If Cloud NAT is missing or does not cover the PSC-I subnet, TCP
|
||||
connections to external internet endpoints will **hang silently or
|
||||
reset** without any proxy error log!
|
||||
- Verify NAT status:
|
||||
|
||||
```bash
|
||||
gcloud compute routers nats list --router=ROUTER_NAME --region=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
3. **Verify Cloud DNS Peering**: Ensure the consumer VPC has Cloud DNS peering
|
||||
configured so that Google API hostnames and registered domains correctly
|
||||
resolve to the synthetic PSC VIP (`240.0.0.2:443`).
|
||||
|
||||
4. **Dangling ACT References on Teardown (BKI 30)**: If deleting an Agent
|
||||
Connectivity Template fails with `FAILED_PRECONDITION: Resource ... is
|
||||
already being used by resource(s) .../agentGateways/...` after the gateway
|
||||
was already deleted, Network Services retained a dangling reference
|
||||
(`FROM_AGENT_GATEWAY<ID>`). Clear it using Stubby:
|
||||
|
||||
```bash
|
||||
stubby call blade:network-services-prod-${REGION} google.internal.cloud.reference.References.DeleteReference \
|
||||
"{name: 'projects/${PROJECT_NUMBER}/locations/${REGION}/references/FROM_AGENT_GATEWAY${GW_ID}'}"
|
||||
```
|
||||
|
||||
### Step 4 — Verify the hostname is registered (in the form the agent used)
|
||||
|
||||
List registry entries — pick the right resource type for the destination:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints list --project=$PROJECT_ID --location=$LOCATION
|
||||
gcloud alpha agent-registry mcp-servers list --project=$PROJECT_ID --location=$LOCATION
|
||||
gcloud alpha agent-registry agents list --project=$PROJECT_ID --location=$LOCATION
|
||||
gcloud agent-registry endpoints list --project=$PROJECT_ID --location=$LOCATION
|
||||
gcloud agent-registry mcp-servers list --project=$PROJECT_ID --location=$LOCATION
|
||||
gcloud agent-registry agents list --project=$PROJECT_ID --location=$LOCATION
|
||||
```
|
||||
|
||||
Grep the output for the exact hostname from step 2. If it's missing, that's the
|
||||
root cause.
|
||||
|
||||
### Step 5 — Verify IAM bindings on the registered resource and gateway
|
||||
### Step 5 — Verify IAM / UAP bindings on the registered resource
|
||||
|
||||
To authorize egress, the agent's identity needs roles granted on both the
|
||||
gateway and the registry resources:
|
||||
Depending on whether your gateway uses **IAM v1** or **Unified Access Policy
|
||||
(UAP / Policy V2)** (determined by `iapPolicyVersion` in the Authz Extension),
|
||||
verify the corresponding authorization bindings:
|
||||
|
||||
1. **Gateway Access**: The agent needs `roles/iap.httpsGatewayUser` to connect
|
||||
to the gateway. Verify or grant this role (often at the project level):
|
||||
#### Option A: Unified Access Policy (UAP / Policy V2 / IAM v3)
|
||||
|
||||
In UAP, access policies are bound directly to the **Google Cloud Resource
|
||||
Manager (CRM) hierarchy** (Project, Folder, or Organization) rather than IAP
|
||||
shadow resources.
|
||||
|
||||
1. **List Policy Bindings on the Target Project**:
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding $PROJECT_ID \
|
||||
--member="principalSet://agents.global.org-${ORG_ID}.system.id.goog/attribute.platformContainer/aiplatform/projects/${PROJECT_NUMBER}" \
|
||||
--role="roles/iap.httpsGatewayUser"
|
||||
gcloud iam policy-bindings list \
|
||||
--target="//cloudresourcemanager.googleapis.com/projects/${PROJECT_ID}" \
|
||||
--location=global
|
||||
```
|
||||
|
||||
2. **Registry/Destination Access**: The agent needs `roles/iap.egressor` on the
|
||||
registered resource. Bindings can live at the **registry level** or on a
|
||||
**specific resource**.
|
||||
2. **List Policy Bindings on Parent Folders / Organization**:
|
||||
|
||||
#### Registry-level IAM policy
|
||||
```bash
|
||||
# Folder level
|
||||
gcloud iam policy-bindings list \
|
||||
--target="//cloudresourcemanager.googleapis.com/folders/${FOLDER_ID}" \
|
||||
--location=global
|
||||
|
||||
# Organization level
|
||||
gcloud iam policy-bindings list \
|
||||
--target="//cloudresourcemanager.googleapis.com/organizations/${ORGANIZATION_ID}" \
|
||||
--location=global
|
||||
```
|
||||
|
||||
3. **Inspect the Referenced AccessPolicy**:
|
||||
|
||||
```bash
|
||||
gcloud iam access-policies get ACCESS_POLICY_ID --location=global
|
||||
```
|
||||
|
||||
* Verify the rule uses the full FQDN permission:
|
||||
`iap.googleapis.com/resources.egressViaIAP`.
|
||||
* Verify the agent's principal or principal set matches
|
||||
`rules[].principals`.
|
||||
* Inspect CEL conditions: check for null dereferences, missing `.json`
|
||||
extensions in REST API paths, or overly broad
|
||||
`destination.is_registered == false` DENY rules that crash
|
||||
unauthenticated agent boot routines.
|
||||
|
||||
4. **Check for Org Policy Constraint Blockers (BKI 24)**: If `gcloud iam
|
||||
policy-bindings create` failed with `CUSTOM_ORG_POLICY_VIOLATION`, check
|
||||
whether `constraints/iam.managed.disableAccessPolicyBinding` is enforced:
|
||||
|
||||
```bash
|
||||
gcloud org-policies describe constraints/iam.managed.disableAccessPolicyBinding --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
To unblock, apply an override disabling the constraint (`enforce: false`).
|
||||
|
||||
5. **REST API Fallback for UAP Bindings**:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
"https://iam.googleapis.com/v3/projects/${PROJECT_ID}/locations/global/policyBindings"
|
||||
```
|
||||
|
||||
#### Option B: IAM v1 (Legacy Policy Model)
|
||||
|
||||
In IAM v1, `roles/iap.egressor` is bound directly to the IAP shadow resource at
|
||||
the registry or endpoint level:
|
||||
|
||||
##### Registry-level IAM policy
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
@@ -694,7 +846,7 @@ curl -H "Authorization: Bearer $(gcloud auth application-default print-access-to
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
#### Per-endpoint IAM policy
|
||||
##### Per-endpoint IAM policy
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
@@ -703,7 +855,7 @@ curl -H "Authorization: Bearer $(gcloud auth application-default print-access-to
|
||||
-H "Content-Type: application/json"
|
||||
```
|
||||
|
||||
#### Same call, but for global registry:
|
||||
##### Same call, but for global registry:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
@@ -720,22 +872,51 @@ service account or principal set with role `roles/iap.egressor`.
|
||||
#### List authz extensions
|
||||
|
||||
```bash
|
||||
gcloud beta service-extensions authz-extensions list \
|
||||
gcloud service-extensions authz-extensions list \
|
||||
--location=$LOCATION --project=$PROJECT_ID
|
||||
|
||||
gcloud beta service-extensions authz-extensions describe RESOURCE_NAME \
|
||||
gcloud service-extensions authz-extensions describe RESOURCE_NAME \
|
||||
--location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
#### Verify AuthorizationPolicy Binding
|
||||
#### Verify AuthorizationPolicy & AuthzExtension Wiring
|
||||
|
||||
Verify that the `AuthorizationPolicy` is correctly bound to your `Gateway`. The
|
||||
policy must target the gateway resource. If it is not bound, the authorization
|
||||
logic will not be applied to the gateway traffic.
|
||||
1. **Check `iapPolicyVersion` in Authz Extension**: Describe the Authz
|
||||
Extension and inspect the `metadata` map:
|
||||
|
||||
1. Inspect the `AuthorizationPolicy` resource (retrieved from the API via
|
||||
`gcloud` if available).
|
||||
2. Ensure the policy's target matches the gateway's name and location.
|
||||
```bash
|
||||
gcloud service-extensions authz-extensions describe RESOURCE_NAME \
|
||||
--location=$LOCATION --project=$PROJECT_ID --format="yaml(metadata)"
|
||||
```
|
||||
|
||||
- If using **UAP (Policy V2)**: `iapPolicyVersion` MUST be explicitly set
|
||||
to `"V2"`.
|
||||
- If using **IAM v1**: `iapPolicyVersion` is `"V1"` or unset.
|
||||
- Check `iamEnforcementMode`: `"DRY_RUN"` logs evaluations without
|
||||
blocking; `"ENFORCED"` actively blocks.
|
||||
|
||||
2. **Verify AuthorizationPolicy Binding**: Verify that the
|
||||
`AuthorizationPolicy` is correctly bound to your `Gateway`. The policy must
|
||||
target the gateway resource. If it is not bound, the authorization logic
|
||||
will not be applied to the gateway traffic.
|
||||
|
||||
- Inspect the `AuthorizationPolicy` resource.
|
||||
- Ensure the policy's target matches the gateway's name and location.
|
||||
|
||||
3. **Verify Multi-Registry Gateway Constraints (BKI 26)**: Inspect the Agent
|
||||
Gateway description:
|
||||
|
||||
```bash
|
||||
gcloud network-services agent-gateways describe AGENT_GATEWAY_NAME \
|
||||
--location=$LOCATION --project=$PROJECT_ID --format="yaml(registries)"
|
||||
```
|
||||
|
||||
- Network Services permits at most **2 registries** bound to an Agent
|
||||
Gateway.
|
||||
- When 2 registries are configured, **exactly ONE must be `global`** and
|
||||
the second must be **`regional` or `multi-regional`**.
|
||||
- Configuring two regional, two multi-regional, or two global registries
|
||||
will be rejected with HTTP 400 validation failure.
|
||||
|
||||
#### List authz policies, agent gateways, and authz extensions via raw API
|
||||
|
||||
@@ -815,6 +996,99 @@ Run:**
|
||||
If permissions seem flaky, suspect the **PrincipalSet** binding. Move to a **1:1
|
||||
Principal binding** (bind the specific service account directly) to verify.
|
||||
|
||||
### Step 9 — Cross-Project Runtime-to-Gateway Binding Verification
|
||||
|
||||
When an Agent Runtime (Reasoning Engine) in Project A (`AE_PROJECT_NUMBER`)
|
||||
binds to an Agent Gateway in Centralized Governance Project B
|
||||
(`AGW_PROJECT_ID`):
|
||||
|
||||
1. **Check Deployer Caller Permissions:** Verify the deploying identity has
|
||||
`roles/networkservices.viewer` (or `networkservices.agentGateways.get` and
|
||||
`networkservices.agentGateways.use`) on the gateway in Project B:
|
||||
|
||||
```bash
|
||||
gcloud network-services agent-gateways describe GATEWAY_NAME \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
2. **Check Vertex AI Service Agent IAM in Gateway Project:** Ensure Project A's
|
||||
service agent is authorized in Project B:
|
||||
|
||||
```bash
|
||||
gcloud projects get-iam-policy AGW_PROJECT_ID \
|
||||
--flatten="bindings[].members" \
|
||||
--filter="bindings.members:service-AE_PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com" \
|
||||
--format="table(bindings.role)"
|
||||
```
|
||||
|
||||
Must have `roles/networkservices.viewer` or custom role
|
||||
`ae_agw_cross_project_sa`
|
||||
(`networkservices.agentGateways.get,networkservices.operations.get`).
|
||||
3. **Validate Regional Colocation Invariant:** Both the runtime and the gateway
|
||||
**MUST** be deployed in the exact same region (e.g. `us-central1`).
|
||||
Cross-region bindings fail control plane validation with `INVALID_ARGUMENT`.
|
||||
4. **Verify Context-Aware Access (CAA) Token Sharing Opt-Out:** Verify that the
|
||||
agent runtime was deployed with:
|
||||
`"GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES": False` Without
|
||||
this, bound token enforcement drops credentials during cross-project egress,
|
||||
returning `401 Context-Aware Access requirements are not met`.
|
||||
5. **Validate IAP Policy Target (Server-Generated Resource ID vs Friendly
|
||||
Name):** Ensure IAP policies (`gcloud iap web add-iam-policy-binding`)
|
||||
target the server-generated resource ID (`agentregistry-00000000-...`
|
||||
extracted via `registryResource`), NOT the friendly service name:
|
||||
|
||||
```bash
|
||||
gcloud agent-registry services describe MCP_SERVICE_NAME \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--location=REGION \
|
||||
--format='value(registryResource)'
|
||||
```
|
||||
6. **Verify Cross-Project VPC Service Controls (VPC-SC):** If Project A and
|
||||
Project B are in separate perimeters, ensure a perimeter bridge or
|
||||
ingress/egress rules cover `aiplatform.googleapis.com`,
|
||||
`networkservices.googleapis.com`, and `agentregistry.googleapis.com`.
|
||||
|
||||
### Step 10 — Diagnose Secure Web Proxy (SWP) and Policy-Based Routing (PBR) Egress
|
||||
|
||||
If the consumer VPC employs a downstream Secure Web Proxy (SWP) behind an Agent
|
||||
Gateway Network Attachment for Layer 7 inspection:
|
||||
|
||||
1. **Verify Next-Hop SWP Deployment Mode**: Confirm SWP is deployed directly in
|
||||
the consumer VPC with `type: SECURE_WEB_GATEWAY` and
|
||||
`routingMode: NEXT_HOP_ROUTING_MODE`. Do NOT attempt to use PSC Service
|
||||
Attachments (which only support explicit `HTTP CONNECT` proxies) or static
|
||||
routes (which fail because Network Attachments cannot bear VM instance tags).
|
||||
2. **Verify Policy-Based Routing (PBR) Matching**:
|
||||
Ensure a PBR exists with priority 200 matching source CIDR of the PSC-I subnet
|
||||
(`10.20.1.0/24`) and destination `0.0.0.0/0` routing to `--next-hop-ilb-ip=<SWP_IP>`:
|
||||
|
||||
```bash
|
||||
gcloud network-connectivity policy-based-routes create agw-psci-to-swp-pbr \
|
||||
--network=projects/PROJECT_ID/global/networks/VPC_NAME \
|
||||
--source-range=10.20.1.0/24 \
|
||||
--destination-range=0.0.0.0/0 \
|
||||
--next-hop-ilb-ip=10.20.1.250 \
|
||||
--priority=200 \
|
||||
--project=PROJECT_ID
|
||||
```
|
||||
|
||||
Ensure a default fallback PBR exists with priority 1000 routing to `DEFAULT_ROUTING`.
|
||||
3. **Verify Cloud NAT `ENDPOINT_TYPE_SWG` on Proxy Subnet**:
|
||||
Ensure the Cloud NAT covering the proxy-only subnet (`REGIONAL_MANAGED_PROXY`)
|
||||
includes `--endpoint-types=ENDPOINT_TYPE_VM,ENDPOINT_TYPE_SWG`. Without this,
|
||||
SWP proxy backends cannot establish outbound connections to the internet.
|
||||
4. **Verify GatewaySecurityPolicy CEL Allowlist**:
|
||||
Check SWP logs for `DENIED` decisions under `networkservices.googleapis.com/Gateway`.
|
||||
Verify that both external target domains and the regional AI Platform session
|
||||
endpoint (`<region>-aiplatform.mtls.googleapis.com`) are allowed in CEL rules:
|
||||
|
||||
```cel
|
||||
inUrlList(host(), ['api.weather.gov', 'api.ipify.org', 'REGION-aiplatform.mtls.googleapis.com'])
|
||||
```
|
||||
|
||||
Omission of the regional AI Platform endpoint breaks ADK streaming queries
|
||||
with HTTP 503 (`remote connection failure`).
|
||||
|
||||
## Quick reference: the checks in order
|
||||
|
||||
When triaging a 403 or connection failure, walk these in order:
|
||||
@@ -822,18 +1096,44 @@ When triaging a 403 or connection failure, walk these in order:
|
||||
1. Confirm the error in the agent log (403 vs SSL Handshake Timeout vs
|
||||
Connection Reset).
|
||||
2. Find the *exact hostname* in the gateway log (if 403).
|
||||
3. Check IAP audit log: decision, principal, `iamEnforcementMode`, and watch
|
||||
for `unregisteredResource`. 3b. If no IAP audit entry, pull gateway proxy
|
||||
load-balancer log. 3c. If SSL Handshake Timeout or Connection Reset, run the
|
||||
PSC Subnet Exhaustion Check.
|
||||
3. Check IAP audit log: decision, principal, policy version
|
||||
(`iapPolicyVersion="v2"` vs `"V1"`), `iamEnforcementMode`, and watch for
|
||||
`unregisteredResource`.
|
||||
|
||||
- 3b. If no IAP audit entry, pull gateway proxy load-balancer log.
|
||||
- 3c. If SSL Handshake Timeout or Connection Reset, run the PSC Subnet
|
||||
Exhaustion Check.
|
||||
- 3d. If timeouts or silent connection drops to public internet under
|
||||
VPC-SC, verify Agent Connectivity Template (`vpcEgress: ALL_TRAFFIC`)
|
||||
and Consumer Cloud NAT routing.
|
||||
|
||||
4. Confirm hostname is registered.
|
||||
|
||||
5. Check IAM on the registry/resource (`roles/iap.egressor`).
|
||||
5. Check IAM / UAP Policies on the target:
|
||||
|
||||
6. Check authz extensions and policies.
|
||||
- IAM v1: Check `roles/iap.egressor` on the registry/endpoint shadow
|
||||
resource.
|
||||
- UAP (Policy V2): Check CRM `PolicyBinding` and `AccessPolicy` across
|
||||
Project, Folder, and Org. Verify CEL rules and check for Org Policy
|
||||
blocker `constraints/iam.managed.disableAccessPolicyBinding`.
|
||||
|
||||
6. Check authz extensions (`iapPolicyVersion: "V2"` vs `"V1"`),
|
||||
AuthorizationPolicy targets, and multi-registry constraints (max 2: 1
|
||||
global + 1 regional/multi-regional).
|
||||
|
||||
7. Confirm agent identity has baseline roles. 7b. Check PAB policies. 7c. Check
|
||||
Cloud Run egress auth (impersonation).
|
||||
|
||||
8. If behavior is flaky, switch to direct Principal bindings.
|
||||
|
||||
9. If cross-project runtime binding (Project A -> Gateway in Project B), verify
|
||||
deployer and service agent viewer permissions on Project B, regional
|
||||
colocation, CAA opt-out
|
||||
(`GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES: False`), and
|
||||
server-generated resource ID in IAP bindings.
|
||||
|
||||
10. If routing egress through a downstream Secure Web Proxy (SWP), verify Next-Hop
|
||||
SWP mode (NOT PSC endpoint/service attachment), PBR source-range matching
|
||||
on the PSC-I subnet (priority 200) to next-hop ILB IP, Cloud NAT with
|
||||
`ENDPOINT_TYPE_SWG` on the proxy-only subnet, and GatewaySecurityPolicy CEL
|
||||
allowlist for external domains and regional aiplatform sessions.
|
||||
|
||||
@@ -10,12 +10,10 @@ these patterns; it's faster than walking the full diagnostic flow.
|
||||
(Lines 54-76)
|
||||
- [2. ReasoningEngine startup: Assembly Service init](#2-reasoningengine-startup-assembly-service-failed-to-initialize)
|
||||
(Lines 77-89)
|
||||
- [3. Private-preview limit: one RE per project](#3-private-preview-limit-one-reasoning-engine-per-project-bonded-to-an-agent-gateway)
|
||||
- [3. Private-preview limit: one RE per project](#3-private-preview-limit-one-agent-runtime-instance-per-project-bonded-to-an-agent-gateway)
|
||||
(Lines 90-102)
|
||||
- [4. 403 / Egress not authorized — missing authz_policy](#egress-not-authorized)
|
||||
(Lines 103-124)
|
||||
- [5. IAP ENFORCE mode blocks Agent Runtime startup](#5-iap-enforce-mode-blocks-agent-runtime-startup)
|
||||
(Lines 125-143)
|
||||
- [4. 403 / Egress not authorized — missing authz_policy or UAP binding](#egress-not-authorized)
|
||||
- [5. IAP ENFORCE / Blanket DENY blocks Agent Runtime startup](#5-iap-enforce-mode-blocks-agent-runtime-startup)
|
||||
- [6. Self-signed / Private CA destinations](#6-self-signed-private-ca-destinations-not-supported-early-versions)
|
||||
(Lines 144-156)
|
||||
- [7. Principal Access Boundary (PAB) override](#7-principal-access-boundary-pab-policies-overriding-iam-allow)
|
||||
@@ -24,6 +22,7 @@ these patterns; it's faster than walking the full diagnostic flow.
|
||||
(Lines 189-239)
|
||||
- [9. Cross-Project Gateway import failing (Code 13)](#9-cross-project-agent-gateway-import-creation-failing-code-13-internal-error)
|
||||
(Lines 240-295)
|
||||
- [10. Cross-Project Runtime-to-Gateway Binding Failures](#10-cross-project-runtime-to-gateway-binding-failures-permission_denied-invalid_argument-or-caa-token-suppression)
|
||||
- [11. RE Container Crash: Dependency Mismatch](#11-reasoning-engine-container-crash-python-dependency-mismatch-startup-exceptions)
|
||||
(Lines 296-318)
|
||||
- [12. mTLS Egress Failure: Expired Cert](#12-mtls-egress-failure-invalid-or-expired-client-certificate)
|
||||
@@ -45,9 +44,17 @@ these patterns; it's faster than walking the full diagnostic flow.
|
||||
- [21. Agent Identity Egress to Cloud Run/Funcs (JWT issue)](#21-agent-identity-egress-to-cloud-run-functions-fails-with-401403-jwt-auth-issue)
|
||||
(Lines 680-725)
|
||||
- [22. Agent deployed but not visible in Registry](#22-agent-deployed-but-not-visible-in-registry-boundary-issue)
|
||||
(Lines 726-754)
|
||||
- [23. Telemetry Egress Blocked by Egress Gateway](#23-telemetry-egress-blocked-by-egress-agent-gateway-startup-failure)
|
||||
(Lines 755-779)
|
||||
- [24. UAP Org Policy Blocker (disableAccessPolicyBinding)](#24-uap-org-policy-blocker-constraintsiammanageddisableaccesspolicybinding)
|
||||
- [25. UAP Policy Binding Destruction Race Condition](#25-uap-policy-binding-destruction-race-condition-400-failed_precondition)
|
||||
- [26. Agent Gateway Multi-Registry Validation Error](#26-agent-gateway-multi-registry-validation-error-missing-global-registry)
|
||||
- [27. CEL Null Dereference Crash on Non-Tool MCP Methods](#27-cel-null-dereference-crash-on-non-tool-mcp-methods)
|
||||
- [28. ACT ALL_TRAFFIC Silent Outbound Hang (Missing Cloud NAT)](#28-act-all_traffic-silent-outbound-hang-missing-cloud-nat)
|
||||
- [29. CCFE Agent Gateway Mutation Concurrency Lock (HTTP 409 ABORTED)](#29-ccfe-agent-gateway-mutation-concurrency-lock-http-409-aborted)
|
||||
- [30. Dangling Reference on ACT Deletion (FROM_AGENT_GATEWAY)](#30-dangling-reference-on-act-deletion-from_agent_gateway)
|
||||
- [31. Reasoning Engine Deletion Preconditions (Active Sessions)](#31-reasoning-engine-deletion-preconditions-active-sessions-require-forcetrue)
|
||||
- [32. REST API Path Matching Gotcha (.json and Query Strings)](#32-rest-api-path-matching-gotcha-json-extensions-and-query-strings)
|
||||
- [33. Secure Web Proxy (SWP) & Policy-Based Routing (PBR) Egress Failures](#33-secure-web-proxy-swp--policy-based-routing-pbr-egress-failures)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -100,44 +107,67 @@ for any new REs.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 4. 403 / "Egress request is not authorized" — missing `authz_policy` targeting the gateway {#egress-not-authorized}
|
||||
## 4. 403 / "Egress request is not authorized" — missing `authz_policy` or UAP binding {#egress-not-authorized}
|
||||
|
||||
**Symptom:** Audit logs show `GatekeeperAuthorizer.AuthorizeUser` returning
|
||||
`Permission Denied` for `iap.webServiceVersions.egressViaIAP`.
|
||||
`Permission Denied` for `iap.webServiceVersions.egressViaIAP` or
|
||||
`iap.googleapis.com/resources.egressViaIAP`.
|
||||
|
||||
**Cause:** The IAP authz extension exists but no `authz_policy` actually
|
||||
attaches it to the specific Agent Gateway. The extension is configured but the
|
||||
policy that targets the gateway resource is missing.
|
||||
**Cause:**
|
||||
|
||||
**Fix:** Verify there's an `authz_policy` in the consumer project that targets
|
||||
the specific `agentGateway` resource. Check with:
|
||||
1. **Missing AuthzPolicy Attachment**: The IAP authz extension exists, but no
|
||||
`authz_policy` targets the specific Agent Gateway (`target.resources[]`).
|
||||
2. **Missing or Misconfigured UAP Binding (Policy V2)**: When the gateway uses
|
||||
`iapPolicyVersion: "V2"`, no `PolicyBinding` binds an `AccessPolicy` to the
|
||||
target CRM node
|
||||
(`//cloudresourcemanager.googleapis.com/projects/${PROJECT_NUMBER}`), or the
|
||||
target resource was specified using the string project ID instead of the
|
||||
numeric project number.
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
|
||||
"https://networksecurity.googleapis.com/v1alpha1/projects/${PROJECT_ID}/locations/${LOCATION}/authzPolicies"
|
||||
```
|
||||
**Fix:**
|
||||
|
||||
Look for a policy whose `target.resources[]` includes the gateway's full
|
||||
resource name.
|
||||
1. Verify the `authz_policy` targets the gateway:
|
||||
|
||||
```bash
|
||||
gcloud network-security authz-policies list --location=${LOCATION}
|
||||
```
|
||||
2. If using UAP, verify the policy binding targets the numeric project number:
|
||||
|
||||
```bash
|
||||
gcloud iam policy-bindings list \
|
||||
--target-resource="//cloudresourcemanager.googleapis.com/projects/${PROJECT_NUMBER}" \
|
||||
--location=global
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 5. IAP `ENFORCE` mode blocks Agent Runtime startup
|
||||
## 5. IAP `ENFORCE` mode / Blanket DENY blocks Agent Runtime startup
|
||||
|
||||
**Symptom:** Agent Runtime instances fail to deploy or start, with 403s in
|
||||
startup logs.
|
||||
**Symptom:** Agent Runtime instances fail to deploy or start, with 403s or
|
||||
connection resets in startup logs (`reasoning_engine_stderr`).
|
||||
|
||||
**Cause:** With IAP in `ENFORCE` mode on the Agent Gateway, all egress is denied
|
||||
by default — including the bootstrap calls the agent runtime makes to
|
||||
`cloudresourcemanager`, `aiplatform`, `logging`, `monitoring`, etc. If those
|
||||
endpoints aren't registered AND the agent identity isn't granted
|
||||
`roles/iap.egressor` on them, startup never completes.
|
||||
**Cause:**
|
||||
|
||||
**Fix:** Make sure the bootstrap service set is registered in the Agent Registry
|
||||
(see field-manual's "Recommended Registry Structure: Consolidated Google APIs"
|
||||
section) and the agent identity has `roles/iap.egressor` on them. While
|
||||
debugging, flipping IAP to `DRY_RUN` lets you observe the failing destinations
|
||||
without blocking startup.
|
||||
1. **Default-Deny without Bootstrap Endpoints**: With IAP in `ENFORCE` mode on
|
||||
the Agent Gateway, all egress is denied by default — including bootstrap
|
||||
calls the agent runtime makes to `telemetry.mtls.googleapis.com`,
|
||||
`cloudresourcemanager`, `aiplatform`, `logging`, `monitoring`, etc.
|
||||
2. **Blanket Unregistered DENY in UAP**: An Org or Folder Admin created an
|
||||
explicit `effect: DENY` rule on `(destination.is_registered == false)`.
|
||||
Because DENY has absolute precedence and cannot be overridden by
|
||||
project-level rules, Reasoning Engine boot traffic to
|
||||
`telemetry.mtls.googleapis.com` is dropped immediately.
|
||||
|
||||
**Fix:**
|
||||
|
||||
- Ensure all required monitoring/telemetry endpoints
|
||||
(`telemetry.mtls.googleapis.com`, `monitoring.googleapis.com`,
|
||||
`trace.mtls.googleapis.com`, `cloudtrace.googleapis.com`) are registered in
|
||||
the Agent Registry and permitted by policy.
|
||||
- **Never create a blanket DENY on `destination.is_registered == false`**.
|
||||
Rely on gateway default-deny instead.
|
||||
- Set IAP to `DRY_RUN` (`iamEnforcementMode: "DRY_RUN"`) to observe failing
|
||||
destinations without blocking container initialization.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -241,11 +271,11 @@ registry entries to dynamically build its routing table.
|
||||
|
||||
**Symptom:**
|
||||
|
||||
- Happening during `gcloud alpha network-services agent-gateways import` or
|
||||
- Happening during `gcloud network-services agent-gateways import` or
|
||||
creation.
|
||||
- CLI rejects the command with a synchronous error: `ERROR:
|
||||
(gcloud.alpha.network-services.agent-gateways.import) { "code": 13,
|
||||
"message": "an internal error has occurred" }`
|
||||
(gcloud.network-services.agent-gateways.import) { "code": 13, "message": "an
|
||||
internal error has occurred" }`
|
||||
- Gateway YAML specifies **cross-project** infrastructure targets (e.g. a PSC
|
||||
network attachment or target DNS peering network residing inside another
|
||||
network host project, e.g., Project B).
|
||||
@@ -256,24 +286,45 @@ authorized to map the target resource. The validation is executed under the
|
||||
**Agent Gateway Control Plane Service Agent** identity:
|
||||
`service-GATEWAY_PROJECT_NUMBER@gcp-sa-agentgateway.iam.gserviceaccount.com`
|
||||
|
||||
If this service agent lacks read permissions on the target network project, the
|
||||
validation fails, causing the import command to exit with a synchronous `Code
|
||||
13` internal error.
|
||||
If this service agent lacks read permissions on the target network project, or
|
||||
if the network configuration itself is invalid, the validation fails, causing
|
||||
the import command to exit with a synchronous `Code 13` internal error.
|
||||
|
||||
Specifically, the following network configuration rules must be honored:
|
||||
|
||||
- **VPC Network Mismatch:** The VPC network containing the PSC network
|
||||
attachment and the target network specified in the DNS peering configuration
|
||||
(`dnsPeeringConfig.targetNetwork`) must be the exact same VPC network. If
|
||||
they point to different VPC networks, the configuration validation fails.
|
||||
- **DNS Zone Validation Failure:** The domains specified in
|
||||
`dnsPeeringConfig.domains` must exist as private DNS zones (e.g., private
|
||||
zones or forwarding zones) in the target VPC network. If they do not exist,
|
||||
validation fails.
|
||||
|
||||
**Investigation:**
|
||||
|
||||
1. Verify the caller has full Owner/Editor rights on both projects.
|
||||
1. Verify the caller (user EUC) has `roles/compute.networkViewer` and
|
||||
`roles/dns.reader` (or basic Owner/Editor/Viewer roles) on the target
|
||||
network host project.
|
||||
2. Check if the network attachment `connectionPreference` is set to
|
||||
`ACCEPT_AUTOMATIC`.
|
||||
3. Check the IAM policy in the target network project. Verify if the gateway's
|
||||
**control-plane service agent** is missing:
|
||||
**control-plane service agent** is missing the required roles:
|
||||
`service-GATEWAY_PROJECT_NUMBER@gcp-sa-agentgateway.iam.gserviceaccount.com`
|
||||
4. Confirm if the **egress proxy service agent**
|
||||
(`service-GATEWAY_PROJECT_NUMBER@gcp-sa-dep.iam.gserviceaccount.com`) is
|
||||
present (typically holds `roles/compute.networkUser` and `roles/dns.peer`).
|
||||
*Note:* The egress proxy service agent
|
||||
(`service-GATEWAY_PROJECT_NUMBER@gcp-sa-dep.iam.gserviceaccount.com`) does
|
||||
**not** require these permissions manually granted on the host project.
|
||||
4. Verify that the PSC network attachment's network matches the DNS peering
|
||||
target network exactly.
|
||||
5. Check if all domains specified under `dnsPeeringConfig.domains` correspond
|
||||
to existing private DNS zones associated with the target network VPC (e.g.,
|
||||
they align with the DNS forwarding zone, or use `.` if a catch-all peering
|
||||
zone is configured).
|
||||
|
||||
**Fix:** You must grant the control-plane service agent the required validation
|
||||
permissions inside the target network host project:
|
||||
permissions inside the target network host project, ensure the target operator
|
||||
has required reader roles, and align the VPC networks and domains in the
|
||||
configuration:
|
||||
|
||||
1. Grant `roles/compute.networkUser` to validate the PSC network attachment:
|
||||
|
||||
@@ -291,6 +342,240 @@ permissions inside the target network host project:
|
||||
--role="roles/dns.peer"
|
||||
```
|
||||
|
||||
3. Ensure the operator has `roles/compute.networkViewer` and `roles/dns.reader`
|
||||
on the target network project:
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding TARGET_NETWORK_PROJECT_ID \
|
||||
--member="user:OPERATOR_EMAIL" \
|
||||
--role="roles/compute.networkViewer"
|
||||
|
||||
gcloud projects add-iam-policy-binding TARGET_NETWORK_PROJECT_ID \
|
||||
--member="user:OPERATOR_EMAIL" \
|
||||
--role="roles/dns.reader"
|
||||
```
|
||||
|
||||
4. Configure the gateway YAML definition such that the VPC network containing
|
||||
the network attachment match the target network for DNS peering
|
||||
(`dnsPeeringConfig.targetNetwork`) exactly.
|
||||
|
||||
5. Ensure any domain configured under `dnsPeeringConfig.domains` is registered
|
||||
as a private DNS zone in the target VPC network (e.g. matching the exact
|
||||
peered zone or using `.` for root/catch-all peering).
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 10. Cross-Project Runtime-to-Gateway Binding Failures: PERMISSION_DENIED, INVALID_ARGUMENT, or CAA Token Suppression
|
||||
|
||||
**Symptom:**
|
||||
|
||||
- **Symptom A (Deployer PERMISSION_DENIED):** Calling Vertex AI
|
||||
`client.agent_engines.create(...)` or REST API in Project 1
|
||||
(`AE_PROJECT_ID`) referencing an Agent Gateway in Project 2
|
||||
(`AGW_PROJECT_ID`) fails synchronously with: `ERROR:
|
||||
(gcloud.ai.reasoning-engines.create) PERMISSION_DENIED: Permission
|
||||
'networkservices.agentGateways.use' denied on resource
|
||||
'//networkservices.googleapis.com/projects/AGW_PROJECT_ID/locations/REGION/agentGateways/GATEWAY_NAME'`
|
||||
- **Symptom B (Control-Plane INVALID_ARGUMENT):** Deployment fails with:
|
||||
`INVALID_ARGUMENT: Agent Gateway project in
|
||||
spec.deployment_spec.agent_gateway_config.agent_to_anywhere_config.agent_gateway
|
||||
must match the Vertex AI project.` or region mismatch `INVALID_ARGUMENT:
|
||||
Agent Gateway location in spec... must match the Vertex AI location.`
|
||||
- **Symptom C (CAA 401 Unauthenticated Egress):** Runtime container deploys
|
||||
successfully, but egress requests to external endpoints or MCP tools fail
|
||||
immediately with: `Error Code: "401", Error Details: "Context-Aware Access
|
||||
requirements are not met"` or `Request had invalid authentication
|
||||
credentials.`
|
||||
- **Symptom D (Proxy 403 PERMISSION_DENIED on MCP Tool / Service Name):**
|
||||
Egress through the gateway fails with HTTP 403 `PERMISSION_DENIED`, even
|
||||
though `roles/iap.egressor` was granted to the friendly service name in
|
||||
Agent Registry.
|
||||
- **Symptom E (Unsupported Folder-Level principalSet):** Policy binding using
|
||||
`principalSet://TRUST_DOMAIN/attribute.platformContainer/aiplatform/folders/FOLDER_NUMBER`
|
||||
fails silently or is rejected as an invalid principal identifier.
|
||||
- **Symptom F (VPC-SC Perimeter Block):** Egress calls fail with
|
||||
`VPC_SERVICE_CONTROLS_VIOLATION` across project boundaries.
|
||||
|
||||
**Cause:**
|
||||
|
||||
1. **Cross-Project Feature Rollout & Colocation Invariants:** Following the
|
||||
`EnableCrossProjectAgentGateway_Default_Launch` rollout, cross-project
|
||||
binding
|
||||
(`spec.deploymentSpec.agentGatewayConfig.agentToAnywhereConfig.agentGateway`)
|
||||
is supported. However, **both the runtime and the gateway must reside in the
|
||||
exact same Google Cloud region** (e.g. `us-central1`). Cross-region bindings
|
||||
are rejected with `INVALID_ARGUMENT`. Furthermore, all runtimes in a given
|
||||
project and region must bind to the identical gateway instance.
|
||||
2. **Missing Deployer and Service Agent IAM Permissions:**
|
||||
- The **deploying principal** (user EUC, Cloud Build SA, or pipeline
|
||||
identity) must have `networkservices.agentGateways.use` and
|
||||
`networkservices.agentGateways.get` on the gateway in `AGW_PROJECT_ID`.
|
||||
- The runtime project's **Vertex AI Service Agent**
|
||||
(`service-AE_PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com`)
|
||||
must hold `roles/networkservices.viewer` (or custom role
|
||||
`ae_agw_cross_project_sa` with `networkservices.agentGateways.get` and
|
||||
`networkservices.operations.get`) on `AGW_PROJECT_ID`.
|
||||
3. **Context-Aware Access (CAA) Token Suppression:** By default, Google Cloud
|
||||
SDKs and `google-auth` enforce bound token protection. In cross-project
|
||||
egress, bound token requirements reject requests unless the runtime
|
||||
explicitly sets the environment variable
|
||||
`GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES: False`.
|
||||
4. **Friendly Service Name vs. Server-Generated Resource ID Trap:** In Agent
|
||||
Registry, services, endpoints, and mcp-servers are written via `gcloud
|
||||
agent-registry services create`. However, IAP authorization (`gcloud iap web
|
||||
add-iam-policy-binding`) must bind to the **server-generated resource ID**
|
||||
(`agentregistry-00000000-...`, extracted from the `registryResource` field),
|
||||
NOT the friendly service name (`[MCP_SERVICE_NAME]`). Binding to the
|
||||
friendly service name attaches the policy to a non-existent IAP resource.
|
||||
5. **SPIFFE principalSet Syntax Limitation:**
|
||||
`attribute.platformContainer/aiplatform/folders/FOLDER_NUMBER` is **not** an
|
||||
indexed attribute in IAM SPIFFE URI evaluation. Scoping must strictly use
|
||||
project-level syntax
|
||||
(`attribute.platformContainer/aiplatform/projects/PROJECT_NUMBER`) or
|
||||
trust-domain-wide syntax (`principalSet://TRUST_DOMAIN/*`), or use Principal
|
||||
Access Boundary (PAB) policies.
|
||||
6. **VPC Service Controls Perimeter Boundary:** If Project 1 (`AE_PROJECT_ID`)
|
||||
and Project 2 (`AGW_PROJECT_ID`) reside in different perimeters, perimeter
|
||||
bridging or bidirectional ingress/egress rules covering
|
||||
`aiplatform.googleapis.com`, `networkservices.googleapis.com`, and
|
||||
`agentregistry.googleapis.com` are required.
|
||||
|
||||
**Investigation:**
|
||||
|
||||
1. **Check Deployer Permissions on Gateway:**
|
||||
|
||||
```bash
|
||||
gcloud network-services agent-gateways describe GATEWAY_NAME \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--location=REGION
|
||||
```
|
||||
|
||||
If this fails with `PERMISSION_DENIED`, the deployer lacks read/use
|
||||
permissions.
|
||||
2. **Check Vertex AI Service Agent IAM on Gateway Project:**
|
||||
|
||||
```bash
|
||||
gcloud projects get-iam-policy AGW_PROJECT_ID \
|
||||
--flatten="bindings[].members" \
|
||||
--filter="bindings.members:service-AE_PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com" \
|
||||
--format="table(bindings.role)"
|
||||
```
|
||||
|
||||
Verify that `roles/networkservices.viewer` or custom role
|
||||
`ae_agw_cross_project_sa` is present.
|
||||
3. **Verify Runtime Region vs. Gateway Region:** Ensure both the Reasoning
|
||||
Engine runtime and the Agent Gateway are deployed in the same region.
|
||||
4. **Inspect Runtime CAA Environment Variable:** Inspect the Reasoning Engine
|
||||
deployment spec or Python definition. Verify that `env_vars` contains
|
||||
`"GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES": False`.
|
||||
5. **Verify IAP Binding Target Resource ID:**
|
||||
|
||||
```bash
|
||||
# Fetch the server-generated registryResource identifier
|
||||
gcloud agent-registry services describe MCP_SERVICE_NAME \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--location=REGION \
|
||||
--format='value(registryResource)'
|
||||
```
|
||||
|
||||
Confirm that `gcloud iap web add-iam-policy-binding` used the trailing UUID
|
||||
(`agentregistry-00000000-...`) as `--mcp-server` or `--agent`, not the
|
||||
friendly name.
|
||||
6. **Check VPC-SC Status:** Confirm whether `AE_PROJECT_ID` and
|
||||
`AGW_PROJECT_ID` reside in the same VPC-SC perimeter or have perimeter
|
||||
ingress/egress rules allowing communication.
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. **Grant Deployer Permissions:** Grant `roles/networkservices.viewer` (or
|
||||
permissions `networkservices.agentGateways.use` and
|
||||
`networkservices.agentGateways.get`) to the deploying identity on
|
||||
`AGW_PROJECT_ID`:
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding AGW_PROJECT_ID \
|
||||
--member="user:DEPLOYER_EMAIL" \
|
||||
--role="roles/networkservices.viewer"
|
||||
```
|
||||
2. **Grant Vertex AI Service Agent Permissions:** Grant the Agent Runtime's
|
||||
service agent access to the governance project: *Option A (Standard Viewer
|
||||
Role):*
|
||||
|
||||
```bash
|
||||
gcloud projects add-iam-policy-binding AGW_PROJECT_ID \
|
||||
--member="serviceAccount:service-AE_PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com" \
|
||||
--role="roles/networkservices.viewer"
|
||||
```
|
||||
|
||||
*Option B (Least-Privilege Custom Role):*
|
||||
|
||||
```bash
|
||||
gcloud iam roles create ae_agw_cross_project_sa \
|
||||
--project="AGW_PROJECT_ID" \
|
||||
--title="AE AGW Cross Project SA" \
|
||||
--description="Custom role for cross-project service agent to access Agent Gateways and Operations" \
|
||||
--permissions="networkservices.agentGateways.get,networkservices.operations.get" \
|
||||
--stage="GA"
|
||||
|
||||
gcloud projects add-iam-policy-binding AGW_PROJECT_ID \
|
||||
--member="serviceAccount:service-AE_PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com" \
|
||||
--role="projects/AGW_PROJECT_ID/roles/ae_agw_cross_project_sa"
|
||||
```
|
||||
3. **Configure Runtime with CAA Opt-Out:** In the agent runtime deployment
|
||||
configuration:
|
||||
|
||||
```python
|
||||
remote_agent = client.agent_engines.create(
|
||||
agent=local_agent,
|
||||
config={
|
||||
"agent_gateway_config": {
|
||||
"agent_to_anywhere_config": {
|
||||
"agent_gateway": (
|
||||
"projects/AGW_PROJECT_ID/locations/REGION/agentGateways/AGENT_GATEWAY_TO_ANYWHERE_NAME"
|
||||
)
|
||||
},
|
||||
},
|
||||
"identity_type": types.IdentityType.AGENT_IDENTITY,
|
||||
"env_vars": {
|
||||
"GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES": (
|
||||
False
|
||||
),
|
||||
},
|
||||
},
|
||||
)
|
||||
```
|
||||
4. **Bind IAP Role to the Server-Generated Resource ID:**
|
||||
|
||||
```bash
|
||||
REGISTRY_RESOURCE=$(gcloud agent-registry services describe MCP_SERVICE_NAME \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--location=REGION \
|
||||
--format='value(registryResource)')
|
||||
RESOURCE_ID=$(basename "$REGISTRY_RESOURCE")
|
||||
|
||||
AGENT_PRINCIPAL="principal://agents.global.org-ORG_ID.system.id.goog/resources/aiplatform/projects/AE_PROJECT_NUMBER/locations/REGION/reasoningEngines/ENGINE_ID"
|
||||
|
||||
gcloud iap web add-iam-policy-binding \
|
||||
--project=AGW_PROJECT_ID \
|
||||
--region=REGION \
|
||||
--resource-type=agent-registry \
|
||||
--mcp-server="${RESOURCE_ID}" \
|
||||
--member="$AGENT_PRINCIPAL" \
|
||||
--role="roles/iap.egressor"
|
||||
```
|
||||
5. **Use Valid principalSet Syntax:** For baseline Google APIs access, avoid
|
||||
folder-level scoping. Use project-level scoping:
|
||||
|
||||
```
|
||||
principalSet://agents.global.org-ORG_ID.system.id.goog/attribute.platformContainer/aiplatform/projects/AE_PROJECT_NUMBER
|
||||
```
|
||||
|
||||
or trust-domain-wide scoping:
|
||||
|
||||
```
|
||||
principalSet://agents.global.org-ORG_ID.system.id.goog/*
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 11. Reasoning Engine Container Crash: Python Dependency Mismatch / Startup Exceptions
|
||||
@@ -423,7 +708,7 @@ the registry level.
|
||||
2. Apply the policy to the Agent Registry:
|
||||
|
||||
```bash
|
||||
gcloud alpha iap web set-iam-policy policy.json \
|
||||
gcloud iap web set-iam-policy policy.json \
|
||||
--resource-type=agent-registry \
|
||||
--project=YOUR_PROJECT_ID
|
||||
```
|
||||
@@ -454,14 +739,14 @@ the registry level.
|
||||
gateway.
|
||||
|
||||
```bash
|
||||
gcloud beta ai reasoning-engines delete <REASONING_ENGINE_ID> --region=LOCATION
|
||||
curl -X DELETE -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" "https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/reasoningEngines/${REASONING_ENGINE_ID}?force=true"
|
||||
```
|
||||
|
||||
2. If the old Reasoning Engines are already deleted but routes are stuck,
|
||||
delete the old gateway resource to force cleanup:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways delete OLD_GATEWAY_NAME --location=LOCATION --project=PROJECT_ID
|
||||
gcloud network-services agent-gateways delete OLD_GATEWAY_NAME --location=LOCATION --project=PROJECT_ID
|
||||
```
|
||||
|
||||
3. Retry deployment bonded to the new gateway.
|
||||
@@ -503,7 +788,7 @@ baked into the container.
|
||||
certificates are ready:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways describe GATEWAY_NAME \
|
||||
gcloud network-services agent-gateways describe GATEWAY_NAME \
|
||||
--location=LOCATION \
|
||||
--format="value(agentGatewayCard.rootCertificates)"
|
||||
```
|
||||
@@ -512,7 +797,7 @@ baked into the container.
|
||||
pipeline will automatically bake them in.
|
||||
|
||||
- **For Custom Container / Prebuilt Image Deployments:** Export the gateway's
|
||||
root certificates using the `gcloud beta network-services gateways
|
||||
root certificates using the `gcloud network-services gateways
|
||||
export-cacerts` command and manually copy/bake them into your Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
@@ -527,21 +812,43 @@ baked into the container.
|
||||
|
||||
## 18. VPC Service Controls (VPC-SC) Perimeter Blocks Agent Gateway Provisioning
|
||||
|
||||
> [!NOTE]
|
||||
> **Native VPC-SC Creation Support:** As of September 8, 2026, Agent Gateway
|
||||
> creation inside a VPC-SC perimeter **works natively out of the box** without
|
||||
> requiring manual control plane ingress policies, provided that the Agent
|
||||
> Connectivity Template (ACT) specifies `vpcEgress: ALL_TRAFFIC`. The requirement
|
||||
> for manual ingress policies is no longer needed for standard provisioning.
|
||||
|
||||
**Symptom:**
|
||||
|
||||
- Deployment of Agent Gateway fails when the project is inside a VPC-SC
|
||||
perimeter.
|
||||
- Deployment of Agent Gateway fails or runtime egress is blocked when the
|
||||
project is inside a VPC-SC perimeter.
|
||||
- Violation logs show `NETWORK_NOT_IN_SAME_SERVICE_PERIMETER` or similar
|
||||
VPC-SC blocks for calls between the consumer project and Google-managed
|
||||
projects.
|
||||
infrastructure.
|
||||
|
||||
**Cause:** The Agent Gateway provisioning workflow uses Google-managed
|
||||
infrastructure outside the customer's VPC-SC perimeter. Because the calls target
|
||||
resources inside the perimeter using Google-managed service accounts, VPC-SC
|
||||
blocks them as unauthorized ingress.
|
||||
**Cause:**
|
||||
|
||||
**Fix:** Configure ingress policies in your VPC-SC perimeter to allow the
|
||||
actuation identities. Two ingress rules are required:
|
||||
1. **ACT Egress Mode Misconfiguration (Primary Cause):** The Agent Connectivity
|
||||
Template is configured with `vpcEgress: PRIVATE_RANGES_ONLY` or the gateway is
|
||||
deployed in Standalone mode (without an ACT). In these modes, traffic bypasses
|
||||
the customer's VPC perimeter boundaries, causing VPC-SC to reject the
|
||||
deployment or egress calls.
|
||||
2. **Legacy or Strict Custom Perimeters (Historical):** Prior to September 8, 2026,
|
||||
control plane provisioning workflows required explicit ingress policies for
|
||||
Google-managed service agents. In legacy or custom perimeters that block
|
||||
Google-managed actuation identities, explicit ingress policies may still be
|
||||
required.
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. **Verify ACT specifies `ALL_TRAFFIC`:** Ensure the Agent Connectivity Template
|
||||
uses `vpcEgress: ALL_TRAFFIC` and binds to a valid PSC-I Network Attachment in
|
||||
the consumer VPC with Cloud NAT configured on the subnet.
|
||||
2. **Configure Ingress Policies (Legacy / Restrictive Perimeters Fallback):** If
|
||||
operating in a strict perimeter where Google-managed actuation identities are
|
||||
blocked, configure ingress policies in your VPC-SC perimeter to allow the
|
||||
actuation identities. Two ingress rules are required:
|
||||
|
||||
### Rule 1: Gateway Control Plane Actuation
|
||||
|
||||
@@ -620,14 +927,14 @@ gateway cannot allocate the necessary interfaces and deployment fails.
|
||||
project:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways list --location=$LOCATION --project=$PROJECT_ID
|
||||
gcloud network-services agent-gateways list --location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
2. **Identify the subnetwork used by the gateway's Network Attachment**:
|
||||
Describe the gateway:
|
||||
|
||||
```bash
|
||||
gcloud alpha network-services agent-gateways describe AGENT_GATEWAY_NAME --location=$LOCATION --project=$PROJECT_ID
|
||||
gcloud network-services agent-gateways describe AGENT_GATEWAY_NAME --location=$LOCATION --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
Look for `networkConfig.egress.networkAttachment` or
|
||||
@@ -653,8 +960,8 @@ gateway cannot allocate the necessary interfaces and deployment fails.
|
||||
|
||||
## 20. Config Validation Failure: Missing Agent Registry API enablement
|
||||
|
||||
**Symptom:** During `gcloud alpha network-services agent-gateways import`, the
|
||||
command fails with:
|
||||
**Symptom:** During `gcloud network-services agent-gateways import`, the command
|
||||
fails with:
|
||||
|
||||
```
|
||||
ERROR: (gcloud.alpha.network-services.agent-gateways.import) {
|
||||
@@ -736,7 +1043,7 @@ an OIDC ID token to authenticate with Cloud Run.
|
||||
|
||||
**Symptom:** You have successfully deployed an agent (e.g., via Agent Runtime
|
||||
SDK), but when you list agents from your designated Management Project using
|
||||
`gcloud alpha agent-registry agents list`, the agent is missing.
|
||||
`gcloud agent-registry agents list`, the agent is missing.
|
||||
|
||||
**Cause:** The Agent Registry uses a "Management Boundary" to define which
|
||||
projects' agents are governed and visible. If the project where the agent was
|
||||
@@ -782,7 +1089,7 @@ allow access via policy.
|
||||
Endpoints in the Agent Registry:
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints list --location=us-central1 --project=$PROJECT_ID
|
||||
gcloud agent-registry endpoints list --location=us-central1 --project=$PROJECT_ID
|
||||
```
|
||||
|
||||
If any of them are missing, create endpoint entries for them (e.g.
|
||||
@@ -790,7 +1097,7 @@ allow access via policy.
|
||||
`trace.mtls.googleapis.com`, `cloudtrace.googleapis.com`):
|
||||
|
||||
```bash
|
||||
gcloud alpha agent-registry endpoints create google-telemetry \
|
||||
gcloud agent-registry endpoints create google-telemetry \
|
||||
--fqdn=telemetry.mtls.googleapis.com \
|
||||
--location=us-central1
|
||||
```
|
||||
@@ -798,3 +1105,281 @@ allow access via policy.
|
||||
2. **Authorize the Egress:** Ensure your `AuthorizationPolicy` is correctly
|
||||
bound to the Gateway and allows the agent's principal set to egress to these
|
||||
endpoints.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 24. UAP Org Policy Blocker (constraints/iam.managed.disableAccessPolicyBinding)
|
||||
|
||||
**Symptom:** Creating an IAM Policy Binding (`gcloud iam policy-bindings create`
|
||||
or Terraform `google_iam_policy_binding`) fails with:
|
||||
|
||||
```text
|
||||
ERROR: (gcloud.beta.iam.policy-bindings.create) CUSTOM_ORG_POLICY_VIOLATION: Operation violates organization policy constraint 'constraints/iam.managed.disableAccessPolicyBinding'.
|
||||
```
|
||||
|
||||
**Cause:** Enterprise Google Cloud organizations often enforce
|
||||
`constraints/iam.managed.disableAccessPolicyBinding` by default to prevent
|
||||
unauthorized IAM v3 bindings.
|
||||
|
||||
**Fix:** An Organization or Folder Administrator must apply an Org Policy V2
|
||||
override setting `enforce: false` at the target resource level:
|
||||
|
||||
```bash
|
||||
gcloud org-policies set-policy --project=${PROJECT_ID} override.yaml
|
||||
```
|
||||
|
||||
Where `override.yaml` defines:
|
||||
|
||||
```yaml
|
||||
name: projects/PROJECT_ID/policies/iam.managed.disableAccessPolicyBinding
|
||||
spec:
|
||||
rules:
|
||||
- enforce: false
|
||||
```
|
||||
|
||||
Allow 30–60 seconds for IAM policy control plane propagation before retrying.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 25. UAP Policy Binding Destruction Race Condition (400 FAILED_PRECONDITION)
|
||||
|
||||
**Symptom:** During automated teardown or `terraform destroy`, destroying
|
||||
`google_iam_access_policy` fails with:
|
||||
|
||||
```text
|
||||
HTTP 400 FAILED_PRECONDITION: Access policy is referenced by active policy binding(s).
|
||||
```
|
||||
|
||||
**Cause:** Deleting a `PolicyBinding` is subject to a 10–30 second replication
|
||||
delay in the IAM control plane. If an orchestrator deletes the binding and
|
||||
immediately issues a deletion for the parent `AccessPolicy`, IAM rejects the
|
||||
call because the binding is still visible in eventual consistency.
|
||||
|
||||
**Fix:** Ensure teardown workflows poll `GET` on the `PolicyBinding` resource
|
||||
URL until an HTTP 404 is confirmed before deleting the referenced
|
||||
`AccessPolicy`. In Terraform scripts or destroy provisioners, never exit 0 on
|
||||
timeout.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 26. Agent Gateway Multi-Registry Validation Error (Missing Global Registry)
|
||||
|
||||
**Symptom:** `gcloud network-services agent-gateways import` or Terraform apply
|
||||
fails with:
|
||||
|
||||
```text
|
||||
Invalid argument: maximum of two registries are supported. When it's two registries, one of them must be global, the other one can be either regional or multi-regional.
|
||||
```
|
||||
|
||||
**Cause:** The Agent Gateway was configured with two registries, but neither was
|
||||
`global` (e.g. two regional registries like `us-central1` and `us-west1`), or
|
||||
both were `global`.
|
||||
|
||||
**Fix:** In multi-registry mode, ensure **exactly one registry is `global`**,
|
||||
and the second registry is regional or multi-regional:
|
||||
|
||||
```yaml
|
||||
registries:
|
||||
- //agentregistry.googleapis.com/projects/PROJECT_NUMBER/locations/global
|
||||
- //agentregistry.googleapis.com/projects/PROJECT_NUMBER/locations/us-central1
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 27. CEL Null Dereference Crash on Non-Tool MCP Methods
|
||||
|
||||
**Symptom:** Gatekeeper returns HTTP 500 or `PERMISSION_DENIED` with internal
|
||||
evaluation error logs when an agent invokes MCP lifecycle or non-tool methods
|
||||
(`prompts/list`, `resources/read`).
|
||||
|
||||
**Cause:** When invoking non-tool MCP operations, the `tool` message inside
|
||||
`mcp_server` is `null`. A CEL rule that dereferences
|
||||
`destination.agent_registry.mcp_server.tool.annotations.*` or `tool.name`
|
||||
without first checking the method throws an unhandled null-dereference exception
|
||||
in the CEL evaluator.
|
||||
|
||||
**Fix:** Guard all tool attribute dereferences with a method check:
|
||||
|
||||
```cel
|
||||
(destination.agent_registry.mcp_server.method == 'tools') && (destination.agent_registry.mcp_server.tool.annotations.read_only_hint == true)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 28. ACT ALL_TRAFFIC Silent Outbound Hang (Missing Cloud NAT)
|
||||
|
||||
**Symptom:** When an Agent Gateway uses an Agent Connectivity Template with
|
||||
`vpcEgress: ALL_TRAFFIC`, Reasoning Engine calls to public external APIs
|
||||
(`api.weather.gov`, `api.ipify.org`, SaaS tools) hang and eventually fail with
|
||||
connection timeouts. Egress to Google APIs continues to function normally.
|
||||
|
||||
**Cause:** In `ALL_TRAFFIC` mode, all non-Google outbound packets exit the PSC-I
|
||||
Network Attachment into the consumer VPC subnet (`agw-psci-subnet`). If that
|
||||
subnet does not have an active Cloud NAT gateway, public traffic is dropped.
|
||||
(Google APIs bypass Cloud NAT via Andromeda Private Google Access).
|
||||
|
||||
**Fix:** Configure Cloud Router and Cloud NAT on the consumer VPC covering the
|
||||
PSC-I subnet:
|
||||
|
||||
```bash
|
||||
gcloud compute routers nats create agw-cloud-nat \
|
||||
--router=agw-nat-router \
|
||||
--region=LOCATION \
|
||||
--nat-custom-subnet-ip-ranges=agw-psci-subnet \
|
||||
--auto-allocate-nat-external-ips
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 29. CCFE Agent Gateway Mutation Concurrency Lock (HTTP 409 ABORTED)
|
||||
|
||||
**Symptom:** Submitting a PATCH, update, or import command against an Agent
|
||||
Gateway returns:
|
||||
|
||||
```text
|
||||
HTTP 409 ABORTED: unable to queue the operation
|
||||
```
|
||||
|
||||
**Cause:** Cloud Control Forwarding Engine (CCFE) enforces strict mutual
|
||||
exclusion per Agent Gateway resource. Concurrent mutations are aborted while an
|
||||
asynchronous update operation is already active.
|
||||
|
||||
**Fix:** Wait ~1.5 to 2 minutes for the in-flight Long-Running Operation (LRO)
|
||||
to reach `done: true` before initiating another mutation.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 30. Dangling Reference on ACT Deletion (FROM_AGENT_GATEWAY)
|
||||
|
||||
**Symptom:** Attempting to delete an Agent Connectivity Template fails with:
|
||||
|
||||
```text
|
||||
HTTP 400 FAILED_PRECONDITION: Resource projects/.../agentConnectivityTemplates/... is already being used by resource(s) projects/.../agentGateways/...
|
||||
```
|
||||
|
||||
even after the referenced Agent Gateway has been deleted.
|
||||
|
||||
**Cause:** Network Services retained an internal cross-reference protection
|
||||
(`FROM_AGENT_GATEWAY<ID>`) after gateway deletion.
|
||||
|
||||
**Fix:** Delete the dangling reference via Stubby:
|
||||
|
||||
```bash
|
||||
stubby call blade:network-services-prod-${REGION} google.internal.cloud.reference.References.DeleteReference \
|
||||
"name: 'projects/${PROJECT_NUMBER}/locations/${REGION}/agentConnectivityTemplates/${ACT_NAME}/references/FROM_AGENT_GATEWAY_${GATEWAY_ID}'"
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 31. Reasoning Engine Deletion Preconditions (Active Sessions Require ?force=true)
|
||||
|
||||
**Symptom:** Deleting a Vertex AI Reasoning Engine instance fails with:
|
||||
|
||||
```text
|
||||
HTTP 400 FAILED_PRECONDITION: Cannot delete ReasoningEngine with active sessions.
|
||||
```
|
||||
|
||||
**Cause:** Active agent sessions or conversations remain attached to the engine
|
||||
runtime.
|
||||
|
||||
**Fix:** Append `?force=true` to the delete API call or use the force flag in
|
||||
the CLI/REST client to cascade session cleanup.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 32. REST API Path Matching Gotcha (.json Extensions and Query Strings)
|
||||
|
||||
**Symptom:** An agent calling an external REST API (e.g. Zendesk) receives HTTP
|
||||
403 `Egress request is not authorized`, even though a UAP rule allows
|
||||
`/api/v2/tickets`.
|
||||
|
||||
**Cause:** SDK clients typically append `.json` (e.g. `/api/v2/tickets.json`) or
|
||||
query strings (`?page=1`). Strict equality checks reject these variations, while
|
||||
naive `.startsWith('/api/v2/tickets')` introduces security escapes to
|
||||
`/api/v2/tickets_delete_all`.
|
||||
|
||||
**Fix:** Construct explicit boundary-aware CEL path conditions:
|
||||
|
||||
```cel
|
||||
((destination.unregistered.path == '/api/v2/tickets') ||
|
||||
(destination.unregistered.path == '/api/v2/tickets.json') ||
|
||||
(destination.unregistered.path.startsWith('/api/v2/tickets/')) ||
|
||||
(destination.unregistered.path.startsWith('/api/v2/tickets?')) ||
|
||||
(destination.unregistered.path.startsWith('/api/v2/tickets.json?')))
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
## 33. Secure Web Proxy (SWP) & Policy-Based Routing (PBR) Egress Failures
|
||||
|
||||
**Symptom:** When attempting to route egress traffic from an Agent Gateway
|
||||
Network Attachment through a downstream Secure Web Proxy (SWP) for Layer 7 URL
|
||||
filtering, packets drop silently, connections time out, or requests fail with
|
||||
`HTTP 403 Forbidden`, `HTTP 503 Service Unavailable: remote connection failure`,
|
||||
or `INVALID_ARGUMENT`.
|
||||
|
||||
**Causes & Platform Constraints:**
|
||||
|
||||
1. **PSC Endpoints Cannot Be Route Next-Hops**: Google Cloud route tables (both
|
||||
static routes and Policy-Based Routes) do **not** allow Private Service
|
||||
Connect (PSC) forwarding rules (`--load-balancing-scheme=""`) or service
|
||||
attachments as next hops.
|
||||
2. **SWP via PSC Service Attachment Lacks Next-Hop Mode**: Publishing Secure
|
||||
Web Proxy behind a PSC Service Attachment operates strictly in **Explicit
|
||||
Proxy Mode** (`HTTP CONNECT`). Packets emerging from an Agent Gateway
|
||||
Network Attachment are Layer 3/Layer 4 transparent IP packets; they cannot
|
||||
reach an explicit proxy without client-side proxy configuration (which
|
||||
Vertex AI Reasoning Engine containers do not support).
|
||||
3. **Static Route Tag Defect**: Next-hop routing mode with static routes
|
||||
requires VM network tags (`--tags`). Network Attachments
|
||||
(`compute network-attachments`) are consumer network interfaces, not VM
|
||||
instances, and cannot bear network tags. Static routes cannot match or steer
|
||||
traffic originating from an Agent Gateway Network Attachment.
|
||||
4. **SWP Gateway Resource Definition Syntax Error**: Creating an SWP gateway
|
||||
with `type: SECURE_WEB_PROXY` fails validation. The Cloud Control Forwarding
|
||||
Engine API requires `type: SECURE_WEB_GATEWAY` and
|
||||
`routingMode: NEXT_HOP_ROUTING_MODE`.
|
||||
5. **Cloud NAT Missing `ENDPOINT_TYPE_SWG`**: SWP Envoy proxy instances reside
|
||||
on the private proxy-only subnet and lack external IPs. Outbound internet
|
||||
egress requires Cloud NAT configured with
|
||||
`--endpoint-types=ENDPOINT_TYPE_VM,ENDPOINT_TYPE_SWG`. If
|
||||
`ENDPOINT_TYPE_SWG` is omitted, proxy outbound traffic hangs silently.
|
||||
6. **ADK Streaming Session Allowlist Omission**: In `ALL_TRAFFIC` ACT mode,
|
||||
Agent Development Kit (ADK) streaming queries initialize sessions via
|
||||
`POST https://<region>-aiplatform.mtls.googleapis.com/.../sessions`. Because
|
||||
`ALL_TRAFFIC` forces all runtime egress to the Network Attachment, PBR
|
||||
steers this session call to SWP. If `<region>-aiplatform.mtls.googleapis.com`
|
||||
is omitted from the GatewaySecurityPolicy allowlist, SWP drops it
|
||||
(`default_denied`), causing ADK streaming queries to fail with HTTP 503
|
||||
(`remote connection failure`), while direct `query()` calls succeed.
|
||||
|
||||
**Fix:**
|
||||
|
||||
1. **Deploy Next-Hop SWP directly in the consumer VPC**:
|
||||
Create an Envoy proxy-only subnet (`purpose: REGIONAL_MANAGED_PROXY`, `role: ACTIVE`,
|
||||
minimum `/26`) and deploy SWP listening on an internal IP on the PSC-I
|
||||
subnet (e.g. `10.20.1.250`) with `type: SECURE_WEB_GATEWAY` and
|
||||
`routingMode: NEXT_HOP_ROUTING_MODE`.
|
||||
2. **Configure Policy-Based Routing (PBR)**:
|
||||
Create a PBR matching source CIDR `10.20.1.0/24` (the Network Attachment
|
||||
subnet) and destination `0.0.0.0/0` with `--next-hop-ilb-ip=10.20.1.250`
|
||||
(priority 200). Add a default fallback PBR with priority 1000:
|
||||
|
||||
```bash
|
||||
gcloud network-connectivity policy-based-routes create agw-psci-to-swp-pbr \
|
||||
--network=projects/PROJECT_ID/global/networks/VPC_NAME \
|
||||
--source-range=10.20.1.0/24 \
|
||||
--destination-range=0.0.0.0/0 \
|
||||
--next-hop-ilb-ip=10.20.1.250 \
|
||||
--priority=200 \
|
||||
--project=PROJECT_ID
|
||||
```
|
||||
|
||||
3. **Configure Cloud NAT with `ENDPOINT_TYPE_SWG`**:
|
||||
Update the Cloud NAT on the Cloud Router to include
|
||||
`--endpoint-types=ENDPOINT_TYPE_VM,ENDPOINT_TYPE_SWG`.
|
||||
4. **Allowlist External Domains and Regional AI Platform in GatewaySecurityPolicy**:
|
||||
Ensure the CEL policy rule permits both external target domains and the
|
||||
regional AI platform session endpoint:
|
||||
`inUrlList(host(), ['api.weather.gov', 'api.ipify.org', '<region>-aiplatform.mtls.googleapis.com'])`.
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user