Skip to main content
The Sidecar runs on a GKE cluster, in front of one Postgres database. Your clients connect to the Sidecar instead of the database. It refuses writes, records each statement in its pod’s log, which Cloud Logging collects, and passes the rest to the database. A NetworkPolicy makes the Sidecar the only way to the database. There are two ways to use it:
  • On GKE: an app, a job or an agent in the cluster connects to the Sidecar. One Terraform module from the hoop repository installs it.
  • From Agent Runtime: an ADK agent on Gemini Enterprise Agent Platform reaches the Sidecar over Private Service Connect and has no route to the database. A template for agents-cli creates the agent and its Sidecar.
The quick starts use Postgres. The Sidecar also fronts MySQL, SQL Server, MongoDB, ClickHouse, Oracle and HTTP APIs: see Other databases and APIs. The Sidecar is free to run, with no license and no account: one guardrail rule and one masking rule. A license lifts the limits and adds the Control Plane. See Free and Enterprise.
hoop is not on Google Cloud Marketplace yet. Install from the command line, as below. The Marketplace form runs the same module.

The values on this page

Words in capitals are values you replace. The second column is what they are in the demo:

Why a client cannot skip the Sidecar

  • On GKE. A NetworkPolicy in the database’s namespace admits connections from the Sidecar’s pods only. A connection from any other pod times out. Autopilot clusters enforce NetworkPolicies. A Standard cluster needs Dataplane V2 or network policy enforcement.
  • From Agent Runtime. The agent’s network attachment reaches the Sidecar’s internal load balancer. The same NetworkPolicy keeps the agent from the database.
The Sidecar passes the client’s database login through, so the client holds the password. The lock keeps the client on the Sidecar’s path, not the password.

On GKE

Requirements

  • A GKE cluster on x86 nodes, where you can create namespaces, and a Postgres database that its pods reach. For example, a Postgres Deployment in the same cluster. To try it with neither, see A demo cluster and database.
  • gcloud with the gke-gcloud-auth-plugin component, kubectl, and Terraform 1.5 or later:
    CLUSTER and LOCATION are your cluster’s name and region. With no cluster yet, skip this line: the demo below runs it for you.
  • hoop 1.281.0 or later. Every release is on GitHub.
A new Autopilot cluster in us-east1, the region where agents-cli deploys agents, and a Postgres Deployment with invented customers. The database is appdb with a table customers (id, name, email, plan) and a login agent that can only read it, which is what the Agent Runtime template’s agent expects.
appdb.yaml
The rest of this page uses its values: upstream appdb.default.svc.cluster.local:5432, the labels app: appdb, the login app for writes and agent for reads. Change the passwords before you use it for more than a test.
1

Write main.tf

In an empty directory, replace the capitals: RELEASE with a hoop release, the project, the cluster and its location, and upstream with your database’s host:port.
main.tf
  • Keep both slashes in source: Terraform reads // as the end of the repository and the start of the module’s folder in it.
  • guardrail_preset = "read-only" adds one rule that refuses writes. Without it, the Sidecar only records.
  • goog_cm_deployment_name names the install. The Sidecar’s Deployment is appdb-sidecar-hoopsidecar and the Service clients use is appdb-sidecar-hoopsidecar-lanes, in the namespace hoop-sidecar.
  • The module’s other variables are in its README.
2

Install the Sidecar

The apply waits until the Sidecar is ready, about two minutes on an existing cluster. Its log says it runs free and enforces the rule:
The lane ready line holds "enforcing":true and "rules":1.
3

Lock the database to the Sidecar

Set the namespace and the labels of your database’s pods, then apply:
database-policy.yaml
A selector that matches nothing locks nothing, and kubectl reports no error. NetworkPolicies add up: another policy that selects the database’s pods and admits other clients keeps them in. List them with kubectl -n default get networkpolicy. Verify checks it.
4

Point your clients at the Sidecar

Clients connect to appdb-sidecar-hoopsidecar-lanes.hoop-sidecar.svc.cluster.local, port 5432, with the same login and database as before. The Sidecar passes the login through.

Verify

From a pod in the cluster, replace USER, PASSWORD, DATABASE and the table. In the demo: app, change-me-app, appdb. Use a login that can write, so a refused write shows the Sidecar at work, not the database:
On Autopilot, kubectl run can print a warning that it set the pod’s CPU: it is harmless. The audit trail is the Sidecar’s log. Each statement is one JSON line, and a refused one has "kind":"violation" and the rule. Trimmed to its main fields:
Cloud Logging keeps the same lines:

What the rule refuses, and what it misses

read-only refuses the statements that the Sidecar’s classifier reads as insert, update, delete, create, drop, alter, truncate, grant, revoke, call (DO, CALL, EXECUTE) or other. Today the classifier:
  • reads some writes as reads, so they pass: EXPLAIN ANALYSE and EXPLAIN ("analyze") run the statement they explain, SELECT ... INTO creates a table, and SELECT f() runs whatever f writes. Give the client’s login only the privileges it needs: SELECT on its tables, no CREATE.
  • reads SAVEPOINT, LISTEN and DISCARD ALL as other, so they are refused. A client that opens a nested transaction on a read path loses its connection.
The preset is for Postgres. For another protocol, or another rule, set config_source = "document" and write the config. See the module’s README and Guardrail Rules.

From Agent Runtime

The gcp-agent-runtime/postgres template is an ADK agent whose SQL tool reaches Postgres through the Sidecar. The Sidecar runs on GKE behind an internal load balancer, and the agent reaches it over PSC-I. The steps below are checked on Agent Runtime; the template’s README explains each file. You need uv, agents-cli 1.11 or later (uv tool install google-agents-cli), and the requirements of On GKE. Keep the agent, the network attachment and the GKE cluster in one region: agents-cli deploy uses us-east1, where the demo cluster runs. Run the steps in one shell: they share the variable ATTACHMENT. The template installs its own Sidecar, named appdb-sidecar like the one in On GKE. On a cluster where you followed On GKE, run its Clean up first, or use another cluster.
1

Create the project

  • RELEASE is a hoop release tag, 1.281.1 or later. Older tags install an older Sidecar.
  • --root-agent-name support_agent is required: app/agent.py defines that agent.
  • Gemini platform connection failed: Status 404 ... gemini-2.5-flash is harmless. agents-cli tests your login with its own default model; the agent uses its own model (gemini-3.8-flash, set by AGENT_MODEL).
2

Install the Sidecar and lock the database

Set your database as upstream in deploy/sidecar/sidecar.yaml, then:
The last command prints the Sidecar’s internal IP, the agent’s SIDECAR_IP. Set the podSelector in deploy/sidecar/database-policy.yaml to your database pods’ labels (app: appdb in the demo), then apply it in the database’s namespace. The file names no namespace:
3

Create the network attachment

In the Sidecar’s VPC and the agent’s region, and let the Agent Platform service agent use it:
  • Keep 192.168.10.0/28 if it is free in your VPC. The subnet must reach the Sidecar’s IP on port 15432.
  • The name is new each run. On an attachment whose name was deleted and created again in the project, Agent Runtime failed to deploy the agent and logged no cause.
  • If roles create says the role exists in a deleted state, run gcloud iam roles undelete agentRuntimePsci --project PROJECT. If it says the role already exists, go on.
4

Deploy the agent

  • APPDB_PASSWORD is the agent login’s password, change-me-agent in the demo.
  • A project with no organization uses agents.global.proj-PROJECT_NUMBER.system.id.goog.
5

Ask the agent

The agent reads the customers. The DELETE comes back as hoop: this agent may read appdb, not change it, and the Sidecar’s log holds the violation with the ADK session id in postgres.option.adk.session.id:
deployment_metadata.json in the project directory records the agent’s id. After a time with no requests, the agent stops. The first call starts it again and can fail with Read timed out: run it again.
PSC-I does not stop the agent from calling Google front ends, such as *.run.app. A VPC Service Controls perimeter does.

Other databases and APIs

The module fronts more than Postgres. With the simple fields, set protocol to mysql, mssql, mongodb, oracle, clickhouse or http: the Sidecar records every statement or request and refuses nothing. The read-only preset is for Postgres only. On the other protocols, the same rule refuses some reads and misses some writes. To refuse something on another protocol, write the Sidecar’s config yourself. For example, a MySQL database where no client may drop or empty a table:
main.tf
sidecar.yaml
  • admin.listen must be 0.0.0.0:19000.
  • The Sidecar’s Service publishes each listener’s port. Clients connect to appdb-sidecar-hoopsidecar-lanes.hoop-sidecar.svc.cluster.local:13306.
  • Lock the database the same way, with its port in the NetworkPolicy.
  • One guardrail rule and one masking rule are free. One rule can name several operations.
What each protocol inspects and refuses: MySQL, SQL Server, MongoDB, ClickHouse, HTTP. Every rule type: Guardrail Rules. Every config key: Config File.

Limits

  • One database per install. The simple fields front one Postgres database. For more listeners, use a config document.
  • Plain text inside the VPC. The listener has no TLS in the simple fields, so the module offers an internal load balancer and never a public one.
  • The lock covers a database in the cluster. A database outside it, such as Cloud SQL or a VM, needs its own firewall rule. This page does not cover it.
  • The audit trail is the pod’s log. Cloud Logging keeps it for its log bucket’s retention, 30 days by default.

Clean up

In the directory of main.tf:
For Agent Runtime, from the project directory. Delete the agent first: it holds the network attachment.
  • AGENT_ID is in deployment_metadata.json. In a new shell, set ATTACHMENT again: gcloud compute network-attachments list --filter='name~^agent-psci-' lists it.
  • A project with no organization uses agents.global.proj-PROJECT_NUMBER.system.id.goog in AGENT.
Google frees the attachment a few minutes after you delete the agent. An attachment that an agent moved off, for example by a redeploy, can stay held for more than a day: the delete fails with Network Attachment with connected endpoints cannot be deleted. Run the two attachment lines again later. The demo cluster: gcloud container clusters delete hoop-demo --location us-east1.

Free and Enterprise

Free tier: one Data Masking rule and one Guardrail per Sidecar are free, forever. Running more than one rule per feature, or managing rules centrally across Sidecars, requires Enterprise.
  • No license, no account. The Sidecar enforces one guardrail rule and one masking rule. read-only is the guardrail rule. A config over the cap does not start.
  • A license lifts the caps. Pass it in the module’s license variable. See Licensing.
  • The Control Plane needs an Enterprise license. It adds approvals, shared rule sets and one view of many Sidecars. The module’s control_plane mode connects the Sidecar to it. See Control Plane.
  • The Sidecar logs its rule limits when it starts:

Next

Postgres

What the postgres listener inspects and refuses.

Guardrail Rules

operation, table and pattern_match rules.

Kubernetes

The Sidecar’s Helm chart on any cluster.

Amazon Bedrock AgentCore

The same idea for an agent on AWS.