Back to Blog
Policy 2026-02-14

Multi-Protocol Policy Engine

One policy engine, five protocols. How iddio evaluates access rules across Kubernetes, SSH, Terraform, Helm, and AWS CLI with protocol-specific scope matching.

One Engine, Many Protocols

Each protocol that iddio supports has its own classifier and its own concept of “scope.” Kubernetes uses namespaces. SSH uses hosts and principals. Terraform uses workspaces. AWS uses services, regions, and accounts. Helm uses namespaces and release names.

The policy engine evaluates them all through a single, unified pipeline. It doesn’t need to understand each protocol’s internals — it just matches scope fields and tier decisions.

Policy Rule Structure

A policy rule has three parts: protocol, scope, and tier decisions:

agents:
  claude-code:
    rules:
      - protocol: kubernetes
        namespaces: ["payments", "api-gateway"]
        tiers:
          0: allow
          2: escalate
          4: deny

      - protocol: ssh
        hosts: ["prod-web-*"]
        ssh_principals: ["deploy"]
        tiers:
          0: allow
          2: escalate

      - protocol: terraform
        workspaces: ["staging-*"]
        tiers:
          0: allow
          2: escalate
          4: deny

The protocol field selects which classifier is used. The scope fields are protocol-specific. The tiers map is universal — it works the same way for every protocol.

Scope Matching

Each protocol defines its own scope fields:

ProtocolScope FieldsExample
Kubernetesnamespaces["payments", "api-*"]
SSHhosts, ssh_principals["prod-web-*"], ["deploy"]
Terraformworkspaces["staging-*"]
Helmnamespaces, releases["default"], ["nginx-*"]
AWSservices, regions, accounts["s3"], ["us-east-1"]

All scope fields support glob patterns (* for wildcard, ? for single character). A scope matches if the request’s value matches any pattern in the list.

Evaluation Algorithm

When a request arrives, the policy engine:

  1. Identifies the protocol from the request context
  2. Filters rules to those matching the protocol
  3. Matches scope against each rule’s scope fields (all scope fields must match)
  4. Selects the first matching rule (rules are evaluated in order)
  5. Looks up the tier decision from the matching rule’s tiers map
  6. Falls back to default if no rule matches (default is deny)
func (e *PolicyEngine) Evaluate(ctx EvalContext) Decision {
    for _, rule := range e.rules[ctx.Agent] {
        if rule.Protocol != ctx.Protocol {
            continue
        }
        if !rule.MatchScope(ctx) {
            continue
        }
        decision, ok := rule.Tiers[ctx.Tier]
        if !ok {
            return Deny // Tier not in rule → deny
        }
        return decision
    }
    return e.defaultDecision
}

Cross-Protocol Rules

You can write rules that apply to all protocols by omitting the protocol field:

agents:
  claude-code:
    rules:
      # Protocol-specific rules first
      - protocol: kubernetes
        namespaces: ["payments"]
        tiers: { 0: allow, 2: escalate, 4: deny }

      # Catch-all for any protocol
      - tiers: { 0: allow, 2: deny, 4: deny }

Cross-protocol rules are useful for broad policies like “allow all reads, deny all break-glass” regardless of which tool the agent is using.

Rule Ordering

Rules are evaluated in order, and the first match wins. This means more specific rules should come first:

agents:
  claude-code:
    rules:
      # Specific: Kubernetes in payments — allow writes
      - protocol: kubernetes
        namespaces: ["payments"]
        tiers: { 0: allow, 2: allow, 4: deny }

      # Broad: Kubernetes anywhere — deny writes
      - protocol: kubernetes
        namespaces: ["*"]
        tiers: { 0: allow, 2: deny, 4: deny }

      # Fallback: everything else
      - tiers: { 0: allow, 2: deny, 4: deny }

With this configuration, writes in the payments namespace are allowed (first rule matches), but writes in any other namespace are denied (second rule matches).

Audit Trail

The policy decision includes the matched rule index and protocol, so the audit log shows exactly which rule was applied:

{
  "agent": "claude-code",
  "protocol": "kubernetes",
  "namespace": "payments",
  "tier": 2,
  "decision": "allow",
  "matched_rule": 0,
  "scope_match": { "namespaces": "payments" }
}

This makes policy debugging straightforward: you can see which rule matched and why.

Try It Yourself

Iddio is open source. Deploy a zero-trust command proxy for your AI agents in minutes.