Skip to main content

tf-eu-guard

CI Python 3.10+ Checkov 3.3.13 License: MIT Mappings

EU compliance security linter for IaC — scans Terraform (source + plan JSON) and Kubernetes manifests, mapping infrastructure misconfigurations to NIS2 (Directive 2022/2555) and GDPR (Regulation 2016/679) requirements.


Problem

The NIS2 Directive requires covered entities to implement specific cybersecurity measures by October 2024. Article 21(2) mandates risk management measures including access control, encryption, incident handling, backup policies, and secure authentication. GDPR Article 32 imposes similar technical and organizational safeguards for processing personal data.

Most organizations scan infrastructure-as-code with tools like Checkov or tfsec, but the output is generic security findings — not compliance mappings. Security teams must manually trace each finding to the relevant NIS2 or GDPR article, a slow and error-prone process that blocks audit preparation.

tf-eu-guard solves this: it wraps Checkov, enriches each failed check with the exact NIS2/GDPR articles it violates, and produces reports structured for developers, security engineers, and auditors.


What It Does

  1. Scans IaC using Checkov — Terraform source, Terraform plan JSON (terraform show -json), and Kubernetes manifests (--iac-type)
  2. Enriches findings with NIS2 Article 21(2) and GDPR Article 32(1) / 44 mappings from a curated registry
  3. Filters to show only EU-compliance-relevant issues (drops unmapped findings)
  4. Generates three report formats from one scan:
    • Dev report (terminal/HTML): severity-sorted findings for engineers
    • Security dashboard (HTML): CRITICAL/HIGH/MEDIUM/LOW breakdown with stats
    • Auditor report (HTML): article-by-article view showing which NIS2/GDPR clauses have open findings
  5. Custom checks: Adds EU-specific rules (non-EU regions, hardcoded secrets) not in upstream Checkov

Note on flags: --iac-type selects what to scan (terraform, terraform_plan, kubernetes); --framework selects which compliance regime to report (nis2/gdpr). They are unrelated.


Quick Start

Installation

Requires Python ≥ 3.10 and uv. Installs Checkov 3.3.13 as a dependency.

uv tool install tf-eu-guard

(Also available on PyPI: tf-eu-guard if you prefer pip: pip install tf-eu-guard.)

For development (from a clone of this repo):

uv sync --extra dev

Basic Scan

# Scan a Terraform directory
tf-eu-guard scan ./terraform --output dev

# Generate all three HTML reports
tf-eu-guard scan ./terraform --output all

# Filter to GDPR-only findings and output JSON
tf-eu-guard scan ./terraform --output json --framework gdpr

# Fail the build (exit code 1) on HIGH or worse findings — for CI/CD
tf-eu-guard scan ./terraform --fail-on-severity HIGH

Try it: Run tf-eu-guard scan examples/vulnerable-aws/ --output all to see ~30 mapped findings, or tf-eu-guard scan examples/compliant-aws/ --output dev to see a clean scan.

Scan Terraform Plan JSON

Plan-mode scanning catches the configuration as it will actually be applied. Generate the plan JSON, then scan it:

terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > plan.json
tf-eu-guard scan plan.json --iac-type terraform_plan --output json

Plan mode runs Checkov against the plan file itself (checkov -f <plan.json> --framework terraform_plan). It reuses the same CKV_AWS_* check IDs as source mode (verified: a plan of examples/vulnerable-aws maps 31 findings, all to existing registry entries), minus lifecycle-block checks that plan JSON doesn't store. Findings report file_line_range: [0, 0] (the whole plan is one JSON line) — reports omit the line reference in that case. A committed fixture lives at examples/vulnerable-aws-plan/.

Note: --checkov-json is a different feature — it reuses Checkov JSON output you already generated (see below). Passing a raw terraform show -json plan file to --checkov-json is an error; scan the plan file directly as shown above.

Scan Kubernetes

tf-eu-guard scan ./k8s --iac-type kubernetes --output all

Try it: tf-eu-guard scan examples/vulnerable-kubernetes/ --iac-type kubernetes --output json returns ~24 mapped findings across pod security context, RBAC, network policy, secrets and resource limits. Kubernetes checks live in the separate CKV_K8S_* namespace, mapped in registry-kubernetes.yaml.

Use Pre-Generated Checkov JSON

If you already run Checkov in CI or with custom checks, feed tf-eu-guard the Checkov output JSON directly (not a raw Terraform plan file — that's what --iac-type terraform_plan is for):

# From a file
checkov -d ./terraform --output json --framework terraform --quiet > checkov.json
tf-eu-guard scan --checkov-json checkov.json --output security

# From stdin
checkov -d ./terraform --output json --framework terraform --quiet \
  | tf-eu-guard scan --checkov-json - --output auditor

Use --framework terraform in Checkov to get a single JSON object. tf-eu-guard also handles the multi-check-type array and extracts the terraform result automatically.

Use as a Claude Code Skill

This repo includes a Claude Code skill at .claude/skills/tf-eu-guard/. In Claude Code:

/tf-eu-guard ./terraform

Or just ask: "Check my Terraform for NIS2 and GDPR compliance" — Claude runs the scan and summarizes findings by framework and severity.


Usage

Developer Scan

Quick terminal output for engineers fixing issues:

tf-eu-guard scan ./terraform --output dev

Dev report terminal output

Security Dashboard

HTML report with severity breakdown and compliance tags:

tf-eu-guard scan ./terraform --output security

Security dashboard

Live HTML version: docs/screenshots/scan-report.html

Auditor Compliance Matrix

Article-by-article view for audit preparation:

tf-eu-guard scan ./terraform --output auditor

Auditor report

Live HTML version: docs/screenshots/auditor-report.html

JSON (CI/CD & Tooling)

Machine-readable output for pipelines:

tf-eu-guard scan ./terraform --output json --framework nis2

Generate All Reports at Once

tf-eu-guard scan ./terraform --output all

CI/CD Gating

Exit codes make tf-eu-guard usable as a pipeline gate. Exit code 1 is returned when findings meet the threshold; 0 otherwise:

tf-eu-guard scan ./terraform --fail-on-severity HIGH   # fail on HIGH or CRITICAL
tf-eu-guard scan ./terraform --fail-on-any             # fail on any finding

GitHub Action

- uses: 44aayush/tf-eu-guard@v1
  with:
    path: './infra'
    fail-on-severity: 'HIGH'

Pre-commit Hook

repos:
  - repo: https://github.com/44aayush/tf-eu-guard
    rev: v0.2.1
    hooks:
      - id: tf-eu-guard

Scope

Regulation Terraform source Terraform plan Kubernetes
NIS2 Article 21(2) ✅ 38 check mappings ✅ same checks apply ✅ 24 CKV_K8S_* mappings
GDPR Article 32(1) ✅ 38 check mappings ✅ same checks apply ✅ mapped (see registry-kubernetes.yaml)
GDPR Art. 44 (data residency) ✅ Custom check EUGUARD_GDPR_001 ✅ provider config visible in plan ❌ Out of scope — see note

Data residency on Kubernetes: K8s manifests are cloud-agnostic; region is decided at the cluster/cloud boundary, not in the manifest. Enforce residency there (cluster placement policy, provider constraints) — tf-eu-guard does not claim GDPR Art. 44 coverage for Kubernetes. See docs/DECISIONS.md.

Note: CRA and DORA are out of scope for this tool — they address product lifecycle and financial-sector operational resilience respectively, not cloud infrastructure configuration.

Current Registry

185 Checkov checks mapped — AWS: 116 mappings | Azure: 23 | GCP: 22 | Kubernetes: 24 — covering encryption at rest/in transit, logging & detection, backup & recovery, secure development/supply chain, secrets in code, IAM/access control, network segmentation, pod security context, RBAC, and resource limits:

  • IAM / access control: CKV_AWS_273, 287, 288, 62, 286, 63, 355, 289, 290, 274, 40, 9, 109, 111, 283, 356, 70, 79, 162, 359, CKV2_AWS_40, CKV2_AWS_41, CKV2_AWS_52
  • Encryption (rest + transit): CKV_AWS_145, 3, 8, 96, 5, 247, 44, 347, 279, 280, 327, 136, 189, 186, 173, 58, 7, 127, 376, 228, 379, CKV2_AWS_2, CKV2_AWS_64, CKV2_AWS_69
  • Logging / detection: CKV_AWS_18, 157, 101, 84, 317, 324, 325, 92, 37, 50, 126, 353, 158, 338, CKV2_AWS_11, CKV2_AWS_30, CKV2_AWS_62
  • Backup / resilience: CKV_AWS_21, 144, 326, 361, 139, 115, 116, 135, 318, 313, 362, CKV2_AWS_8, CKV2_AWS_58, CKV2_AWS_59, CKV2_AWS_60, CKV2_AWS_61
  • Secure development / secrets: CKV_AWS_226, 363, 272, 51, 163, 41, 45, 46
  • S3 / RDS / network exposure: CKV_AWS_20, 53–56, 16, 17, 133, 129, 161, 293, 118, 24, 25, 260, 382, 137, 248, 38, 39, 117, 23, CKV2_AWS_6, CKV2_AWS_12, CKV2_AWS_5
  • Custom: EUGUARD_GDPR_001 (non-EU regions), EUGUARD_NIS2_001 (hardcoded secrets — Terraform and Kubernetes variants)
  • Azure (23): tf_eu_guard/mapping/registry-azure.yaml — storage account encryption/public access, SQL firewall & public network access, Key Vault network rules, App Service HTTPS/auth/logging, NSG SSH rules, and more
  • GCP (22): tf_eu_guard/mapping/registry-gcp.yaml — GCS bucket CMEK/public IAM, Cloud SQL public IP/SSL/CMEK, GKE private clusters/ABAC/authorized networks, VPC flow logs, and more
  • Kubernetes (24): tf_eu_guard/mapping/registry-kubernetes.yaml — pod security context (privileged/root/capabilities), RBAC privilege escalation, missing NetworkPolicy, secrets as literals, resource requests/limits, image hygiene, health probes

The registry is split per namespace — registry-aws.yaml, registry-azure.yaml, registry-gcp.yaml, registry-kubernetes.yaml — and every entry is schema-validated in CI. The AWS registry covers both Terraform source and Terraform plan JSON (same CKV_AWS_* IDs fire in both modes).


Architecture

┌──────────────┐
│  Terraform   │
│    files     │
└──────┬───────┘
       │
       ▼
┌──────────────────────────────────────────────┐
│  tf-eu-guard                                  │
│  ┌─────────────────────────────────────────┐ │
│  │ 1. run_checkov() / load_checkov_json()  │ │
│  │    → Checkov results (passed + failed)  │ │
│  └──────────────┬──────────────────────────┘ │
│                 ▼                             │
│  ┌─────────────────────────────────────────┐ │
│  │ 2. extract_failed_checks()               │ │
│  │    → Filter to failed checks only        │ │
│  └──────────────┬──────────────────────────┘ │
│                 ▼                             │
│  ┌─────────────────────────────────────────┐ │
│  │ 3. load_registry()                       │ │
│  │    → NIS2/GDPR mapping registry          │ │
│  └──────────────┬──────────────────────────┘ │
│                 ▼                             │
│  ┌─────────────────────────────────────────┐ │
│  │ 4. enrich_findings()                     │ │
│  │    → Join checks ⟷ compliance articles  │ │
│  │    → Drop unmapped findings              │ │
│  └──────────────┬──────────────────────────┘ │
│                 ▼                             │
│  ┌─────────────────────────────────────────┐ │
│  │ 5. Optional: filter by framework         │ │
│  │    (--framework nis2 / gdpr)             │ │
│  └──────────────┬──────────────────────────┘ │
│                 ▼                             │
│  ┌─────────────────────────────────────────┐ │
│  │ 6. generate_report()                     │ │
│  │    → dev / json / security / auditor     │ │
│  └─────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
       │
       ▼
┌──────────────────────────────────────────┐
│  Reports:                                 │
│  • Terminal rich table                    │
│  • dev-report.html                        │
│  • scan-report.html (dashboard)           │
│  • auditor-report.html (by article)       │
│  • JSON (for CI/tooling)                  │
└──────────────────────────────────────────┘

Key differentiator: The EU compliance mapping registry. Without it, this is just another Checkov wrapper. With it, it's the bridge from "S3 bucket not encrypted" to "violates NIS2 Art. 21(2)(h) and GDPR Art. 32(1)(a)."


Contributing

See CONTRIBUTING.md for guidelines — especially on proposing new registry mappings. Contributions welcome:

  1. Registry expansion: Map more Checkov checks to NIS2/GDPR
  2. New custom checks: EU-specific patterns Checkov doesn't cover
  3. Report improvements: Better visualizations, export formats

License

MIT — see LICENSE


Acknowledgments

Metadata

Release files for tf-eu-guard 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tf-eu-guard 0.2.1
File Size Uploaded
tf_eu_guard-0.2.1.tar.gz 6.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for tf-eu-guard 0.2.1
File Interpreter ABI Platform
tf_eu_guard-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 6.2 MB

Release files / tf_eu_guard-0.2.1.tar.gz

Download URL tf_eu_guard-0.2.1.tar.gz
Size 6.2 MB
Tags Source
SHA-256 checksum
How to use checksums
84d649328e3cd577627d78b7ae0ba74d451b98e0054c1ca239c1f37440c27d7e
BLAKE2b-256 checksum
How to use checksums
5ae829d83c01e1d2a7b3821a32299b6dfec3c1bfad6625f7ccd328d055fe8a88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / tf_eu_guard-0.2.1-py3-none-any.whl

Download URL tf_eu_guard-0.2.1-py3-none-any.whl
Size 72.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d182447022e9e2112c285048dd4f6d57dc76129d614f82231ef4eec883d3f610
BLAKE2b-256 checksum
How to use checksums
b42cade60aa8a839f0e20328348f287eb7e68277e742acc9bef56e6b65c17390
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page