Infrastructure as Code for Legal Tech: Terraform, OpenTofu, and Policy-Driven Automation
Why IaC is critical for legal Compliance and auditability
For Rechtsunternehmen, "compliant by default" requires controls that are deterministic, repeatable, and provable. Infrastructure as Code (IaC) operationalizes this:
- Auditability: Every material infrastructure change is peer-reviewed, versioned, and linked to a plan diff and change ticket. This provides evidence for DSGVO Article 5(2) accountability, Article 32 security of processing, ISO 27001 Annex A, and SOC 2 CC series controls. - Repeatability and least privilege: Environment builds are reproducible across regions with consistent guardrails (Verschlüsselung, Netzwerksegmentierung, private endpoints, Logging). Access is scoped through roles assumed by CI. - Drift detection and remediation: Deviation from "declared state" is detected continuously and reconciled. Cloud-level controls complement IaC drift checks. - Chain-of-custody for evidence: Plans, applies, and attestations (who/what/when) are preserved immutably, enabling defensible Audit posture and client assurance.
Terraform vs OpenTofu for enterprises
Licensing and Governance:
- Terraform: Core is Geschäft Source License (BSL) since Aug 2023. Allowed for internal use; restrictions apply to creating competing services. Many enterprises continue to use Terraform, including Terraform Cloud/Unternehmen. - OpenTofu: Community fork under MPL 2.0 (permissive open-source), aiming for drop-in compatibility with Terraform languages and state. Attractive for organizations requiring permissive OSS and vendor neutrality.Compatibility:
- State and provider ecosystems are largely compatible; validate pinned versions in a staging environment. Most codebases can switch binaries after Testing.Unternehmen features:
- Terraform Cloud/Unternehmen: Remote state, policy checks, drift detection, cost estimation, SSO, RBAC, private registries, run tasks. - OpenTofu with ecosystem: Combine OIDC-based CI, remote state backends, policy in CI, and a registry. Third-party platforms fill orchestration gaps.Secure state management and Verschlüsselung
State is sensitive: it can include resource names, ARNs, and sometimes secrets. Treat it as confidential legal data.
AWS remote state (S3 + KMS + DynamoDB locking)
```hcl terraform { backend "s3" { bucket = "org-legal-iac-state-eu" key = "envs/prod/platform.tfstate" region = "eu-west-1" dynamodb_table = "org-legal-iac-locks" encrypt = true kms_key_id = "arn:aws:kms:eu-west-1:111122223333:key/abcd-1234" } } ```
Bootstrap module to create secure backend
```hcl resource "aws_kms_key" "state" { description = "KMS for IaC state at rest" deletion_window_in_days = 30 enable_key_rotation = true }
resource "aws_s3_bucket" "state" { bucket = "org-legal-iac-state-eu" object_lock_enabled = true }
resource "aws_s3_bucket_versioning" "state" { bucket = aws_s3_bucket.state.id versioning_configuration { status = "Enabled" } }
resource "aws_s3_bucket_server_side_encryption_configuration" "state" { bucket = aws_s3_bucket.state.id rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" kms_master_key_id = aws_kms_key.state.arn } } } ```
Modular design for legal environments (client/matter isolation)
Design principles
- Resource hierarchy isolation: Separate accounts per client or per sensitivity tier; use Organizations OUs with SCPs - Namespacing and tagging: Required keys: client_id, matter_id, data_residency, classification, retention, owner - KMS key Strategie: Keys per client, optionally per matter for evidence - Netzwerksegmentierung: Private endpoints only; traffic egress constrainedExample: Reusable module for evidence bucket
```hcl
variables.tf
variable "client_id" { type = string } variable "matter_id" { type = string } variable "region" { type = string } variable "kms_key_arn" { type = string }main.tf
locals { name = "evidence-${var.client_id}-${var.matter_id}" tags = { client_id = var.client_id matter_id = var.matter_id classification = "Restricted" data_residency = "EU" owner = "legal-platform" } }resource "aws_s3_bucket" "evidence" { bucket = local.name object_lock_enabled = true tags = local.tags } ```
CI/CD pipelines with approval workflows and policy gates
Key practices
- No long-lived credentials in CI. Use OIDC to assume cloud roles - Separate plan and apply jobs. Plans run on pull requests; applies require explicit approvals - Preserve evidence artifacts: planfile, JSON plan, policy outputs stored immutably - Environment pinning: enforce workspace and variable whitelistingExample: GitHub Actions with OIDC and approval gates
```yaml name: iac-deploy on: pull_request: paths: ["infra/**"] push: branches: ["main"] paths: ["infra/**"]
permissions: id-token: write contents: read
jobs: plan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Configure AWS via OIDC uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::111122223333:role/CiCdDeployer aws-region: eu-west-1 - name: Install OpenTofu uses: opentofu/setup-opentofu@v1 - name: Plan working-directory: infra/envs/prod run: tofu plan -out=tfplan.binary - name: Policy checks (Conftest) uses: instrumenta/conftest-action@v1 with: files: infra/envs/prod/tfplan.json policy: policy/rego
apply: needs: [plan] if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest environment: name: prod steps: - name: Apply (requires environment approval) run: tofu apply -input=false tfplan.binary ```
Policy as code with OPA/Conftest (guardrails)
Example Rego policies
```rego package terraform.s3
deny[msg] { some r input.resource_changes[r].type == "aws_s3_bucket" not has_sse_kms(r) msg := sprintf("S3 bucket %s must enforce SSE-KMS", [input.resource_changes[r].name]) }
has_sse_kms(r) { planned := input.resource_changes[r].change.after planned.server_side_encryption_configuration.rule[_].apply_server_side_encryption_by_default.sse_algorithm == "aws:kms" } ```
Testing and verification
Static and semantic checks:
- `tofu validate` or `terraform validate` - tflint for idiomatic HCL - Checkov for IaC misconfigurations - Infracost for cost guardrailsIntegration tests:
- Terratest (Go) to provision ephemeral stacks and assert runtime controlsDrift detection:
- Scheduled plan with `-detailed-exitcode` and alert on exit code 2 (drift) - Cloud-native policies detect out-of-band driftCase studies
EU Kanzlei (700 employees)
Before IaC: Manual provisioning, inconsistent Verschlüsselung and tags, 6 weeks of Audit prep After adopting OpenTofu + GitHub Actions + OPA: - 100% KMS/CMEK enforcement via policy gates - Region drift reduced to near-zero - Audit prep cut by 75% through automated evidence bundles - Time-to-provision: from 5 days to 6 hoursGlobal eDiscovery provider
Adopted Terraform Unternehmen: - Manual changes eliminated; 98% of applies originate from reviewed PRs - Drift auto-detected and remediated for baseline controls - DLP false positives cut by 30% via consistent tagging - Annual external Audit findings reduced from 9 to 2Measurable outcomes and ROI
- Compliance coverage: >95% of resources pass baseline policy checks pre-apply - Drift reduction: <1% of resources with unmanaged drift - Provisioning efficiency: new client matter environments provisioned in hours, not days; 60–80% reduction in manual effort - Audit readiness: evidence assembly time cut 70–90% - Risk reduction: immutable state and evidence reduce blast radius of insider or misconfiguration risks
Conclusion
For Rechtsunternehmen, IaC is more than efficiency—it is a Compliance and assurance engine. Combining Terraform/OpenTofu with policy-as-code, immutable evidence, and approval-centric CI/CD yields defensible, region-locked, encrypted cloud environments that auditors and clients can trust. Start with state security and policy gates, modularize around client/matter isolation, and build out continuous assurance.