DORA went live: turning EU financial resilience rules into policy-as-code guardrails

If your org touches European finance in any way—bank, payment processor, insurer, fintech vendor—January 17, 2025 wasn’t just another Friday. That’s the day DORA, the EU’s Digital Operational Resilience Act, started applying. It’s a sweeping set of rules for how financial entities build, run, test, and monitor tech, including their third-party providers. In plain English: resilience and risk controls can’t live only in slide decks anymore—they need to show up in your pipelines and clusters. (esma.europa.eu)

This post distills what “good” looks like when you translate DORA into policy-as-code. We’ll map key obligations to concrete enforcement points and show quick examples you can drop into CI/CD and Kubernetes.

What DORA actually asks you to do (in tech terms)

DORA creates uniform requirements across the EU for:

Under the hood, the EU has also published delegated regulations that spell out the nuts and bolts—like how to classify a “major” incident and exactly what you must report. Treat those as machine‑readable requirements you can encode and test. (eur-lex.europa.eu)

Why policy-as-code is your best friend

Policies that live in wikis drift. Policies encoded as tests get run on every change. DORA is tailor-made for this approach:

Think of it like putting your controls on a click track: the band (your teams) still plays, but the tempo (compliance) never wavers.

Map DORA obligations to enforcement points

Here’s a pragmatic way to slice it.

1) Tag what matters, then apply stronger rules
You can’t protect what you haven’t labeled. Start by standardizing a business‑criticality tag (for example, dora.tier=critical). Everything else flows from it.

2) Encrypt, back up, and prove it (IaC checks)
For critical data stores, enforce encryption at rest and minimal backup retention. Use OPA/Conftest against Terraform plan JSON so you fail a build before risk ships:

# conftest test -p policy dora.rego --input plan.json
package dora.tf

deny[msg] {
  some r
  rc := input.resource_changes[r]
  rc.type == "aws_db_instance"
  rc.change.after.tags["dora.tier"] == "critical"
  not rc.change.after.storage_encrypted
  msg := sprintf("%s: critical DB must enable storage_encrypted", [rc.address])
}

deny[msg] {
  some r
  rc := input.resource_changes[r]
  rc.type == "aws_db_instance"
  rc.change.after.tags["dora.tier"] == "critical"
  not rc.change.after.backup_retention_period
  msg := sprintf("%s: critical DB must set backup_retention_period >= 7", [rc.address])
}

deny[msg] {
  some r
  rc := input.resource_changes[r]
  rc.type == "aws_db_instance"
  rc.change.after.tags["dora.tier"] == "critical"
  to_number(rc.change.after.backup_retention_period) < 7
  msg := sprintf("%s: critical DB must retain backups >= 7 days", [rc.address])
}

3) Bake resilience into runtime (Kubernetes without webhooks)
Kubernetes 1.30 made ValidatingAdmissionPolicy (VAP) generally available. It lets you enforce rules with fast, in‑tree CEL expressions instead of running a full webhook service—great for “always‑on” guardrails like anti‑single‑zone risk for critical pods. (v1-32.docs.kubernetes.io)

Example: require topology spread for critical workloads.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: enforce-critical-pod-spread
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE","UPDATE"]
        resources: ["pods"]
  validations:
    - expression: "object.metadata.labels['dora.tier'] != 'critical' || (has(object.spec.topologySpreadConstraints) && size(object.spec.topologySpreadConstraints) > 0)"
      message: "Critical workloads must define topologySpreadConstraints to avoid single-zone risk."
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: enforce-critical-pod-spread
spec:
  policyName: enforce-critical-pod-spread
  validationActions: ["Deny"]

4) Classify incidents and wire your SIEM to the thresholds
DORA’s delegated regulation 2024/1772 defines criteria and materiality thresholds for reporting, including factors like client impact, downtime, geography, data loss, and economic impact. Encode these thresholds as detection rules (e.g., SIEM correlation searches or alert routing policies) so a “major” incident is automatically flagged for the right report template and timer. (eur-lex.europa.eu)

5) Control third‑party exposure in code
Maintain your register of ICT providers, and couple it with egress allowlists and contract checks:

6) Build TLPT‑readiness into your environments
Threat‑led penetration testing under DORA has its own regulatory technical standards, with an application date of July 8, 2025. Prep by keeping “red‑team‑ready” toggles (e.g., safe‑lists, logging amplification, traffic mirroring) as code so you can enable them without risky change windows. (eba.europa.eu)

A lightweight rollout playbook

Common pitfalls (and how to dodge them)

The punchline

DORA is here, and it’s opinionated about real‑world resilience: how you manage incidents, test your defenses, and wrangle third‑party risk. The good news is you don’t need to boil the ocean. Start by tagging criticality, push a handful of high‑value controls into CI and your clusters, and make exceptions self‑service but temporary. The rest becomes a rhythm you can keep.

If you do one thing this week: add two policies—as‑code—to protect your most critical data store and to spread your most critical pods. You’ll be measurably closer to compliance, and—more importantly—to resilience.

Sources and further reading: