Skip to content

Pillar 2 / Policy-as-code compliance engine

Enforce global data privacy laws with Policy-as-Code.

Residency rules written as Open Policy Agent Rego, versioned in Git, signed, and evaluated on every request in under 3 ms median. Your DPO reads the plain-language view; your engineers review the code.

Why declarative policy

Transfer rules in most organisations live in three places that disagree: a DPA annex, a wiki page and an if-statement somebody wrote during an incident. Policy-as-code puts the rule in one artefact that the gateway executes and the auditor can read.

YTT Secunet embeds Open Policy Agent in every regional data plane. For each request the gateway builds a structured input (tenant, domicile, client location, candidate endpoint, data class, residual identifiers) and asks the pack for a decision. The answer is a set of deny reasons; an empty set means allow. Because Rego is declarative, adding a rule can only add a reason to deny, so packs compose without ordering surprises.

Decisions are deterministic: the same input and the same bundle revision always give the same result. That is what lets you replay last month's traffic against a proposed change and see exactly what it would have blocked.

jsonopa eval: input and result
// input (built by the gateway, no prompt text)
{
  "tenant": { "id": "tnt_de_4417", "domicile": "DE" },
  "endpoint": { "id": "ep_bedrock_use1", "country": "US",
                "zdr": true, "tenancy": "shared" },
  "data_class": "general",
  "pii": { "unmasked": [] }
}

// data.yttsecunet.eu_gdpr_strict
{
  "allow": false,
  "deny": ["endpoint ep_bedrock_use1 is in US, outside the EEA"]
}

Pre-built policy packs

v4.2.0OPA v1 Rego

EU GDPR strict

Blocks all inference egress outside the EU/EEA, requires zero data retention and masked direct identifiers. No reliance on the EU-US Data Privacy Framework or Article 49 derogations.

Enforces

  • GDPR Articles 44 to 46 (Chapter V)
  • Article 5(1)(c) data minimisation
  • Article 9 special category routing
regopacks/eu-gdpr-strict/policy.rego
package yttsecunet.eu_gdpr_strict

# Blocks inference egress outside the EU/EEA.
# Input: request context built by the gateway (tenant, endpoint, pii, data_class).

eea := {
	"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
	"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
	"PL", "PT", "RO", "SK", "SI", "ES", "SE", "IS", "LI", "NO",
}

direct_identifiers := {"IBAN", "PASSPORT", "NATIONAL_ID", "TAX_ID", "HEALTH_ID"}

default allow := false

allow if count(deny) == 0

deny contains msg if {
	not input.endpoint.country in eea
	msg := sprintf("endpoint %s is in %s, outside the EEA", [input.endpoint.id, input.endpoint.country])
}

deny contains msg if {
	not input.endpoint.zdr
	msg := sprintf("endpoint %s does not guarantee zero data retention", [input.endpoint.id])
}

deny contains msg if {
	some entity in input.pii.unmasked
	entity.type in direct_identifiers
	msg := sprintf("unmasked %s in outbound prompt", [entity.type])
}

deny contains msg if {
	input.data_class == "health"
	input.endpoint.tenancy == "shared"
	msg := "Article 9 data requires a dedicated endpoint pool"
}

allowed_zones := {"EU"}

Visual policy editor: toggle rules, regenerate Rego, evaluate

The editor is built for compliance and legal teams. Each block maps to a Rego rule; toggling it rewrites the policy on the right and re-runs the selected request context, the same way the test runner does before a pack is signed.

Rule blocks

denydecision dec_cb2d3434 / 1.3 ms
  • deny: endpoint country US not allowed
regogenerated from rule blocks
package yttsecunet.custom.claims_assistant

# EEA
allowed_countries := {
	"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
	"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
	"PL", "PT", "RO", "SK", "SI", "ES", "SE", "IS", "LI", "NO",
}

direct_identifiers := {"IBAN", "PASSPORT", "NATIONAL_ID", "TAX_ID"}

default allow := false

allow if count(deny) == 0

deny contains msg if {
	not input.endpoint.country in allowed_countries
	msg := sprintf("endpoint country %s not allowed", [input.endpoint.country])
}

deny contains "zero data retention required" if {
	not input.endpoint.zdr
}

deny contains msg if {
	some t in input.pii.unmasked
	t in direct_identifiers
	msg := sprintf("unmasked %s in prompt", [t])
}
decision log entry
{
  "decision_id": "dec_cb2d3434",
  "path": "yttsecunet/custom/claims_assistant",
  "input": {
    "endpoint": {
      "id": "ep_bedrock_use1",
      "country": "US",
      "zdr": true,
      "tenancy": "shared"
    },
    "data_class": "general",
    "pii": {
      "unmasked": []
    },
    "request": {
      "oversight_hook": true
    }
  },
  "result": {
    "allow": false,
    "deny": [
      "endpoint country US not allowed"
    ]
  },
  "bundle_revision": "pack-2d3434"
}
< 3 ms
median OPA policy evaluation per request
YTT Secunet production telemetry, 2026
8 packs
maintained by YTT Secunet policy engineering for EU, UK, Swiss, AI Act, Saudi, UAE, HIPAA and ITAR/FedRAMP regimes
YTT Secunet pack catalogue, 2026
EUR 15M or 3%
of worldwide annual turnover: EU AI Act ceiling for breaching high-risk and other operator obligations
Regulation (EU) 2024/1689, Art. 99(4)

Full pack catalogue

Policy lifecycle

  1. 01

    Author

    Legal and privacy teams compose rule blocks in the visual editor; engineers can edit the Rego directly. Both views stay in sync because the editor writes Rego.

  2. 02

    Test

    Each pack ships with opa test cases. Your additions run against a corpus of recorded request contexts so you can see which past traffic a change would have denied.

  3. 03

    Review

    Changes open a pull request in your Git repository with a plain-language diff for the DPO and a Rego diff for engineering. Two approvals by default.

  4. 04

    Sign and publish

    Approved packs are built into an OPA bundle, signed, and versioned. Gateways only load bundles whose signature verifies against your tenant key.

  5. 05

    Enforce

    Every data plane evaluates the pack in-process for each request. The X-YTT-Policy header pins the exact version, so a rollout never changes behaviour silently.

  6. 06

    Evidence

    Decision logs record the input hash, result and bundle revision. The receipt on each response names the same pack id and version, closing the loop for auditors.

Customer engineering note

“We wrote custom Rego to keep medical data from leaving France. The policy engine enforces it deterministically, and the decision log shows our auditors every request it stopped.”
Head of AI GovernanceFrench digital health group

Frequently asked questions

Why Open Policy Agent rather than a proprietary rules engine?

OPA is a graduated CNCF project with a documented language, Rego, and a test framework. Your policies are portable text files you can review, version and run outside YTT Secunet with the same results, which matters when an auditor wants to reproduce a decision.

Which Rego syntax do the packs use?

OPA v1 syntax, where the if and contains keywords are required for rule bodies and multi-value rules. Packs are tested against current OPA releases and published as signed bundles.

Can legal teams change policy without writing code?

Yes. The visual editor exposes rule blocks such as allowed countries, retention requirements and identifier masking, and generates the Rego. Every change still goes through review and signing before any gateway enforces it.

What does the engine evaluate on each request?

A structured input built by the gateway: tenant and domicile, client geo, the candidate endpoint with its country, tenancy and retention terms, the data class from the classifier, and any identifiers left unmasked. Prompt text is not part of the policy input.

Is a policy pack legal advice?

No. Packs encode common, documented readings of the law, written by our policy engineering team with external counsel review. Which pack applies to your processing, and any exceptions, is a decision for your DPO and counsel.

Sovereign route ready

Stop risking 4% global turnover GDPR fines on AI inference.

Deploy sovereign, cryptographically proven AI routing in 15 minutes.