Part 1 — Build the template in Google Cloud
Everything in this part happens in your own Google Cloud project. TrustGate never creates or changes anything there.1
Choose a region and enable the API
Model Armor has no global endpoint. It is reachable only through regional
hosts, and the gateway derives the host from the Location you will enter in
the policy. Pick a region close to your gateway: every request makes this round
trip.Enable the API in the project that will own the template:Every resource below must be created in that same project and that same
region. A template created in a different region is invisible to the gateway
and calls fail with a template-not-found error.
2
Create the inspection template — the first half of masking
This step and the next one are a pair, and masking needs both. Skip both if
you only want to block sensitive data and never rewrite it; skipping only this
one leaves the next step with nothing to pair with, and the Model Armor template
in step 4 asks for the two paths together.In the Google Cloud console go to Security → Sensitive Data Protection →
Configuration → Templates → Create template.
Click Create and copy the template’s full resource path — you will paste it
into the Model Armor template:
3
Create the de-identify template (this is what makes masking work)
Return to Create template and this time choose De-identify (remove
sensitive data).
Click Create and copy its resource path:
4
Create the Model Armor template
Go to Security → Model Armor → Create template.
Then enable the detections you want:
CSAM detection is always on in Google’s template and cannot be turned off.Click Create.You now have the three values the policy needs: the project, the region,
and the template ID.
Part 2 — Grant the gateway access
TrustGate must prove to Google that it may call Model Armor in your project. It does that with a service account key: you create a service account in your project, give it access to Model Armor, and paste its key into the policy. You revoke access by deleting the key in Google Cloud and, if you want to replace it, pasting a new one into the policy.1
Create a service account and give it Model Armor access
2
Create a key for the service account
Part 3 — Configure the policy in TrustGate
Open Policies → Library → Google Model Armor.Google Cloud connection
Block on
Five toggles — Sensitive data, Responsible AI, Prompt injection & jailbreak, Malicious URIs, CSAM. A new policy in the console starts with no filter selected, and the console requires at least one before it will save.A stored policy with no
block_on at all blocks on all five. That shape
does not come from the console, which always saves an explicit selection — it
is what you get from a policy created directly through the API with the field
left out. Absent entirely, the plugin defaults to every filter Model Armor can
evaluate, rather than silently letting traffic through because nobody opted a
category in.Sensitive data
Sensitive data action — Block request (the default) or Anonymize. Anonymize reinjects the de-identified text and lets the request continue; it requires the de-identify template from Part 1.Inspection
The request is always screened. Every call on its way to the model goes through this policy — there is no control to turn that off, and it is one call to Model Armor per request. Inspect model responses, in this Inspection section — off by default. Turn it on and the model’s answer is screened too, under the same Block on toggles and Sensitive data action as the request: a second call to Model Armor on every turn. There is no way to screen the response only — the request is always the first call.With Inspect model responses on, a streamed response is inspected as it is
generated, and a failure of that check lets the stream continue.
Mode
Start in Observe, which records every decision without blocking anything, and switch to Enforce once the decisions look right.How the decision is made
1
Blocking filters are checked first
If any enabled filter matches and calls for a block, the request is refused and
never reaches the model. The caller gets
403. The refusal wording is fixed,
This content violates our usage policy., with nothing to configure, and it names the
filter that fired: sensitive
data, Responsible AI, prompt injection and jailbreak, malicious URIs, or CSAM.2
Masking applies only if nothing blocked
With Anonymize, the de-identified text replaces the original and the request
continues to the model.
3
Otherwise the request passes through untouched
Modes and failures
Observe never masks. It records what would have happened and forwards the
original text. Masking is only ever applied in Enforce.
The decision recorded on the event is
allowed, block,
anonymized, reported, failed_open or failed_closed (the
content caused the failure and Enforce refused it). anonymized is
Enforce-only: in Observe a prompt that would have been masked records
reported instead, which is also what Observe records in place of a block.
failed_open is the one to look for first on a new policy — it is what
Model Armor being unreachable, or a credential that cannot be resolved, records
on every request, in Enforce and Observe alike. The event’s failure_reason field says why: transport (the call
failed, timed out, or Model Armor answered with an error), verdict_incomplete
(a filter selected in Block on did not run), config_invalid (the stored
settings could not be used), or decode_failed (the gateway’s own body could
not be decoded before Model Armor was ever called).
A filter that did not run counts as a failure, not as a clean result. Model
Armor can answer successfully and still report that one of the filters you
selected in Block on never executed. Silence from a filter that did not run
looks exactly like silence from a filter that found nothing. If Model Armor
skipped it, for example because the content is above its token limit, the policy
refuses in Enforce with
failure_reason verdict_incomplete. If your template
does not enable the filter, that is not the content’s fault: the request
continues, recorded as failed_open. Deselect the filter if you do
not need it, or check it is still configured on the Model Armor template.Limits
- Only the last user message is inspected on the request leg. No system prompt, no conversation history, no tool definitions, no tool calls or results.
- Masking that fails is a block. If Model Armor returns no de-identified text, or the request format cannot be re-encoded with it, the request is refused in Enforce rather than forwarded. The original is never sent.
- A filter that did not run is not a result. Skipped by Model Armor, it blocks in Enforce; not enabled in the template, it fails open. See the note above.
- Inspect model responses is off by default. Only the request is screened until you turn it on; turning it on doubles the calls to Model Armor per turn.
- A streamed response is inspected as it is generated, with Inspect model responses on. If the check itself fails, the stream is not cut.
- Text only. Files, images, and audio are not sent to Model Armor. A request on a route that carries no chat is not inspected: it is forwarded and recorded as not inspected, never refused. The same holds for an upstream error response, which carries no completion to inspect.
- Size. Below 512 KiB the whole text goes to Model Armor, never a part of it. Above 512 KiB a buffered text is refused in Enforce, before the call. If Model Armor itself skips a detection, for example above its token limit, Enforce refuses too.
- LLM traffic only. The policy does not apply to MCP (Model Context Protocol) tool calls.
Verify the policy
Open the Playground, pick the application the policy applies to, and send these three prompts in this order. Starting with the control means a failure tells you something specific.1
Control — the path works at all
allowed. If this fails, the problem
is the application, the model or the provider — not the guardrail. Fix it before
going on. A decision of failed_open here means the gateway could not get an
answer out of Model Armor at all: the location, the credential, or the grant.
The reply looks normal, so read the decision.2
Sensitive data — masking works
anonymized. In Observe the same prompt records reported and the
original text still reaches the model, so switch to Enforce before reading
this step.Read the reply, not just the status. It must not contain the email address.
That is what proves the model never received it.Use an email address rather than a payment card number — see the warning above
about Responsible AI.3
Prompt injection — blocking works
block. To prove the request never reached the model,
open Activity, open the request, and read its Policies tab: the
Aggregated Latency breakdown there has a Provider row, and that row is
empty. The Playground shows a single latency figure and does not break it down.Troubleshooting
Related
- Guardrails — the other guardrail policies, and how to choose between them
- AWS Bedrock Guardrail — the other provider guardrail that can mask in place
- Azure Content Safety — severity scoring on the request leg, with no masking
- Policies overview — scope, modes and policy chains
- Event schema — the fields each decision records