One Vocabulary: Why Iddio Policy Uses Rule IDs Over a Custom DSL for GCP
How we avoided reinventing the wheel by using the classifier's generated method identities directly in our policy engine, instead of building a redundant resource matching DSL.
The Identity Problem
When building a protocol-aware proxy for infrastructure access, the hardest problem isn't intercepting the traffic—it's understanding it.
In Iddio, our command classifier dissects every incoming request to determine its intent. For the gcloud CLI, this means mapping an HTTP request to one of thousands of GCP API methods. Recently, we rebuilt the gcloud HTTP classifier to emit fine-grained, method-level identity on every classification.
If a developer runs a command that ultimately hits the Secret Manager API, the classifier emits a RuleID like gcloud.method.secretmanager.projects.secrets.versions.access. This identity is generated directly from GCP Discovery documents.
This precise identification is fantastic for the classifier, but it immediately posed a question for the policy engine: how should operators write rules against this?
The Temptation of the DSL
The existing policy engine matched on tiers: (e.g., observe, modify), commands: (a glob over the classifier's high-level command), and scope sugar like projects: or namespaces:. This works perfectly for rules like "escalate all sensitive writes in production."
But what if an operator wants resource-scoped policy below the tier level? For example: "Allow reads on Secret Manager, but escalate everything that touches KMS."
The immediate, almost reflexive engineering instinct is to build a Domain Specific Language (DSL). We considered adding resources: and verbs: selectors to the policy schema:
# The rejected DSL approach
gcloud:
rules:
- resources: ["secretmanager.secrets"]
verbs: ["access"]
action: allow
This looks elegant. It feels familiar. But for an infrastructure gateway, it is structurally flawed.
The Flaws of a Second Language
Building a resources: and verbs: DSL introduces a severe architectural problem: it creates a second matching vocabulary with no generated source of truth.
The classifier already knows what a method is because it derives that identity directly from GCP Discovery via our code generator. If we built a DSL in the policy engine, someone would have to manually maintain a taxonomy of GCP resources, collections, and custom verbs to keep it in sync with Discovery.
Worse, it couples the policy schema directly to GCP's internal resource hierarchy. If GCP changes how it models resources, or if our classifier changes how it derives identity, the policy schema itself risks breaking. We would be blurring the line between "what Iddio knows about GCP" (which is data, living in the classifier) and "what the operator wants to happen" (which is intent, living in the policy).
The Simple Alternative: Rule ID Globbing
Instead of inventing a new DSL, we chose the simplest possible path. We added a single new selector to the existing policy target: a rule_ids: glob.
Because the classifier already emits RuleID = gcloud.method.<methodId>, the policy engine simply needs to match against that string.
# The chosen approach
gcloud:
groups:
secrets:
rule_ids: ["gcloud.method.secretmanager.*"]
crypto:
rule_ids: ["gcloud.method.cloudkms.*"]
projects:
- names: ["prod-*"]
rules:
escalate: { groups: [crypto] }
allow: { groups: [secrets], tiers: [observe] }
Why This Wins
This approach has three massive advantages:
- Reusing the Source of Truth: We piggyback entirely on the data we already maintain and test. The over 1,200 override rules come straight from the generator. There is nothing new to curate.
- One Matching Idiom: The
rule_ids:selector uses the exact same glob engine thatcommands:uses. Operators don't have to learn a new mini-language. The policy engine doesn't need a new parser. - Decoupling: The policy engine remains entirely ignorant of GCP's internals. It just matches opaque strings. The classifier can evolve its derivation logic freely, as long as the
gcloud.method.<id>shape remains stable.
By resisting the urge to build a "smart" DSL, we kept the policy engine fast, simple, and decoupled, while still delivering the fine-grained control operators need.
Try It Yourself
Iddio is open source. Deploy a zero-trust command proxy for your AI agents in minutes.