STACKIT Policy-as-Code Framework
Overview
This framework implements a three-layer Policy-as-Code (PaC) architecture for STACKIT, a German public-sector cloud provider. It enforces security, compliance, and operational policies across IaaS, PaaS, and managed Spring runtime workloads using Open Policy Agent (OPA) and Terraform.
Architecture
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: AUTHORING │
│ │
│ policies/iaas/ → IaaS networking & compute rules │
│ policies/paas/ → PaaS database & storage rules │
│ policies/spring/ → Managed Spring runtime rules │
│ policies/shared/ → Shared helpers and constants │
│ │
│ Each policy includes: │
│ • Metadata (id, severity, enforcement level) │
│ • Compliance annotations (BSI C5, GDPR) │
│ • Exception handling with expiry │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Layer 2: EVALUATION │
│ │
│ OPA evaluates Terraform plan JSON against Rego policies: │
│ │
│ terraform plan → JSON → OPA evaluate → deny[] / warn[] │
│ │
│ Evaluation modes: │
│ • deny[] — Hard enforcement, blocks deployment │
│ • warn[] — Soft enforcement, advisory only │
│ • Exceptions — Time-bound policy waivers with audit trail │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Layer 3: ENFORCEMENT │
│ │
│ CI/CD pipeline (.github/workflows/policy-ci.yml): │
│ │
│ 1. opa fmt --check → Lint Rego formatting │
│ 2. opa test → Run policy unit tests │
│ 3. terraform validate → Validate Terraform configs │
│ 4. checkov → Security scan Terraform │
│ 5. conftest test → Evaluate plan against policies │
│ │
│ Pre-commit hooks enforce formatting at dev time. │
└─────────────────────────────────────────────────────────────┘
Policy Layers
IaaS — Network Security (policies/iaas/network_security.rego)
Controls for STACKIT compute and networking resources:
| Rule | Severity | Enforcement | BSI C5 | GDPR |
|---|---|---|---|---|
| No public IPs in production | Critical | Hard | OPS-05 | — |
| Traffic via approved ingress only | Critical | Hard | OPS-05 | — |
| EU-region-only deployment | Critical | Hard | OPS-20 | Art. 44-49 |
| Encryption in transit (TLS) | Critical | Hard | CRY-01 | Art. 32 |
PaaS — Database Security (policies/paas/database_security.rego)
Controls for STACKIT managed database services:
| Rule | Severity | Enforcement | BSI C5 | GDPR |
|---|---|---|---|---|
| Encryption at rest | Critical | Hard | CRY-02 | Art. 32 |
| EU-region deployment | Critical | Hard | OPS-20 | Art. 44-49 |
| Daily backups minimum | Critical | Hard | OPS-08 | — |
| No public endpoints | Critical | Hard | OPS-05 | — |
| Multi-AZ for tier-1 (prod) | Critical | Hard | — | — |
| Multi-AZ for tier-2 (prod) | Medium | Soft (warn) | — | — |
Spring Runtime — Application Security (policies/spring/runtime_security.rego)
Controls for STACKIT managed Spring applications:
| Rule | Severity | Enforcement | BSI C5 | GDPR |
|---|---|---|---|---|
| LTS JDK versions only | High | Hard | — | — |
| Approved base images only | High | Hard | — | — |
| No secrets in env vars | Critical | Hard | IDM-01 | Art. 5(1)(c) |
| TLS for DB connections | Critical | Hard | CRY-01 | Art. 32 |
| JSON structured logging | Medium | Hard | OPS-13 | — |
| Central logging sink | Medium | Hard | OPS-13 | — |
| Actuator health endpoints | Medium | Hard | — | — |
Compliance Mapping
BSI C5 (Cloud Computing Compliance Criteria Catalogue)
The framework maps policies to BSI C5 controls:
- OPS-05 — Network segmentation and access controls
- OPS-08 — Backup and recovery procedures
- OPS-13 — Logging and monitoring
- OPS-20 — Data location and sovereignty
- CRY-01 — Encryption of data in transit
- CRY-02 — Encryption of data at rest
- IDM-01 — Identity and access management
GDPR
- Article 5(1)(c) — Data minimisation (no secrets in plain text)
- Article 25 — Data protection by design and by default
- Article 32 — Security of processing (encryption requirements)
- Articles 44-49 — Cross-border data transfers (EU-region enforcement)
Exception Handling
Policies support time-bound exceptions for justified deviations:
1
2
3
4
5
6
7
8
9
10
11
{
"exceptions": [
{
"policy_id": "STACKIT-IAAS-NET-001-PUB-IP",
"ticket_id": "SEC-1234",
"approver": "ciso@example.com",
"risk_category": "accepted",
"expiry_date": "2025-06-30T23:59:59Z"
}
]
}
Required fields:
ticket_id— Reference to the approval ticketapprover— Email of the person who approved the exceptionrisk_category— Classification (accepted, mitigated, transferred)expiry_date— RFC 3339 timestamp; exception is automatically invalidated after this date
Shared Components
Constants (policies/shared/constants.rego)
Centralised configuration for approved regions, JDK versions, base images, sensitive env var patterns, and compliance control mappings.
Helpers (policies/shared/helpers.rego)
Reusable functions: region validation, exception checking, violation message formatting, and sensitive pattern detection.