Infrastructure as Code (IaC) Security
„Infrastructure as Code – weil Fehlkonfigurationen jetzt versioniert und skaliert werden können."
Sinn & Zweck
Infrastructure as Code hat die Art verändert, wie wir Infrastruktur managen: Statt manuell Server zu konfigurieren, schreiben wir Code, der die Infrastruktur beschreibt. Das ist wunderbar für Automatisierung, Reproduzierbarkeit und Skalierung.
Das Problem? Ein Fehler im Code bedeutet einen Fehler in der Infrastruktur. Ein public = true an der falschen Stelle, und deine Datenbank ist für die ganze Welt erreichbar. Skaliert deployt.
IaC Security bedeutet: Sicherheitsprobleme finden, bevor die Infrastruktur provisioniert wird.
IaC-Tools im Überblick
| Tool | Anbieter | Sprache | Fokus |
|---|---|---|---|
| Terraform | HashiCorp | HCL | Multi-Cloud |
| CloudFormation | AWS | YAML/JSON | AWS only |
| Pulumi | Pulumi | Python/TS/Go | Multi-Cloud |
| ARM Templates | Microsoft | JSON | Azure only |
| Bicep | Microsoft | DSL | Azure only |
| CDK | AWS | TS/Python/Java | AWS (via CFN) |
| Ansible | Red Hat | YAML | Config Management |
| Chef/Puppet | Various | Ruby/DSL | Config Management |
Typische Security-Probleme
1. Öffentlich zugängliche Ressourcen
Terraform (AWS S3):
# SCHLECHT: Öffentlicher Bucket
resource "aws_s3_bucket" "data" {
bucket = "my-super-secret-data"
acl = "public-read" # 🚨 ALARM
}
# GUT: Privater Bucket mit Encryption
resource "aws_s3_bucket" "data" {
bucket = "my-super-secret-data"
}
resource "aws_s3_bucket_public_access_block" "data" {
bucket = aws_s3_bucket.data.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
2. Fehlende Verschlüsselung
CloudFormation:
# SCHLECHT: Unverschlüsselte RDS
Resources:
Database:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: db.t3.micro
Engine: mysql
# StorageEncrypted: false (default) 🚨
# GUT: Verschlüsselt
Resources:
Database:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: db.t3.micro
Engine: mysql
StorageEncrypted: true
KmsKeyId: !Ref DatabaseKey
3. Zu offene Security Groups
Terraform:
# SCHLECHT: Welt offen
resource "aws_security_group" "web" {
ingress {
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # 🚨 Alles, überall
}
}
# GUT: Nur was nötig ist
resource "aws_security_group" "web" {
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"] # Nur intern
}
}
4. Hardcodierte Secrets
# SCHLECHT: Secret im Code
resource "aws_db_instance" "db" {
username = "admin"
password = "SuperSecret123!" # 🚨 Im Git-History für immer
}
# GUT: Aus Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "prod/db/password"
}
resource "aws_db_instance" "db" {
username = "admin"
password = data.aws_secretsmanager_secret_version.db_password.secret_string
}
5. Fehlende Logging & Monitoring
# SCHLECHT: Kein Logging
resource "aws_s3_bucket" "app" {
bucket = "my-app-bucket"
}
# GUT: Logging aktiviert
resource "aws_s3_bucket_logging" "app" {
bucket = aws_s3_bucket.app.id
target_bucket = aws_s3_bucket.log_bucket.id
target_prefix = "s3-access-logs/"
}
IaC Security Tools
Checkov
Der Platzhirsch. Open Source, umfassend.
# Installation
pip install checkov
# Terraform scannen
checkov -d ./terraform
# Nur HIGH und CRITICAL
checkov -d ./terraform --check HIGH,CRITICAL
# Bestimmte Checks überspringen
checkov -d ./terraform --skip-check CKV_AWS_1,CKV_AWS_2
Output:
Passed checks: 42
Failed checks: 7
Check: CKV_AWS_19: "Ensure the S3 bucket has server-side-encryption enabled"
FAILED for resource: aws_s3_bucket.data
File: /main.tf:15-20
tfsec (Teil von Trivy)
Schnell, fokussiert auf Terraform.
# Installation
brew install tfsec
# Scannen
tfsec ./terraform
# Mit Custom Checks
tfsec ./terraform --custom-check-dir ./custom-checks
Terrascan
Multi-IaC-Support (Terraform, K8s, CloudFormation, etc.)
terrascan scan -i terraform -d ./terraform
KICS (Keeping Infrastructure as Code Secure)
Von Checkmarx, sehr umfassend.
docker run -v $(pwd):/path checkmarx/kics:latest scan -p /path
Snyk IaC
Commercial, gut integriert.
snyk iac test ./terraform
Tool-Vergleich
| Tool | Terraform | CloudFormation | K8s | Ansible | Preis |
|---|---|---|---|---|---|
| Checkov | ✓ | ✓ | ✓ | ✓ | Free |
| tfsec/Trivy | ✓ | ✓ | ✓ | - | Free |
| Terrascan | ✓ | ✓ | ✓ | - | Free |
| KICS | ✓ | ✓ | ✓ | ✓ | Free |
| Snyk IaC | ✓ | ✓ | ✓ | - | Commercial |
CI/CD Integration
GitHub Actions
name: IaC Security
on: [push, pull_request]
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: ./terraform
framework: terraform
soft_fail: false # Build bricht ab bei Findings
tfsec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: tfsec
uses: aquasecurity/tfsec-action@v1.0.0
with:
working_directory: ./terraform
GitLab CI
iac-security:
image: bridgecrew/checkov:latest
script:
- checkov -d ./terraform --output junitxml > checkov.xml
artifacts:
reports:
junit: checkov.xml
Pre-commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.83.5
hooks:
- id: terraform_tfsec
- id: terraform_checkov
- id: terraform_fmt
- id: terraform_validate
Policy as Code
Sentinel (HashiCorp)
Für Terraform Enterprise/Cloud.
# Sentinel Policy: S3 must be encrypted
import "tfplan"
main = rule {
all tfplan.resources.aws_s3_bucket as _, buckets {
all buckets as _, bucket {
bucket.applied.server_side_encryption_configuration is not null
}
}
}
OPA (Open Policy Agent) / Conftest
# policy/s3.rego
package main
deny[msg] {
resource := input.resource.aws_s3_bucket[name]
resource.acl == "public-read"
msg := sprintf("S3 bucket '%s' should not be public", [name])
}
conftest test ./terraform/main.tf
Terraform Cloud / Enterprise
# Sentinel Policy Set
policy "s3-encryption-required" {
source = "./policies/s3-encryption.sentinel"
enforcement_level = "hard-mandatory"
}
Best Practices
1. Shift Left – Früh scannen
IDE → Pre-commit → CI → Terraform Plan → Apply
↓ ↓ ↓ ↓ ↓
tfsec Checkov Checkov Sentinel OPA
Plugin Hook Job Policy Admission
2. Policy as Code definieren
# Zentrale Policies
module "security_baseline" {
source = "git::https://github.com/company/security-modules.git//baseline"
require_encryption = true
require_logging = true
allowed_instance_types = ["t3.micro", "t3.small"]
}
3. Module für Compliance
# Sichere S3-Bucket-Module statt Raw Resources
module "secure_s3_bucket" {
source = "git::https://github.com/company/terraform-modules.git//s3-secure"
bucket_name = "my-data"
# Encryption, Versioning, Logging standardmäßig aktiviert
}
4. State-File schützen
# Remote State mit Encryption
terraform {
backend "s3" {
bucket = "terraform-state-bucket"
key = "prod/terraform.tfstate"
region = "eu-central-1"
encrypt = true
kms_key_id = "alias/terraform-state-key"
dynamodb_table = "terraform-locks"
}
}
5. Secrets niemals im Code
# Secrets aus externen Quellen
variable "db_password" {
type = string
sensitive = true # Wird in Logs maskiert
}
# Übergabe via Environment Variable
# TF_VAR_db_password=... terraform apply
6. Drift Detection
# Regelmäßig Plan ausführen und Drift erkennen
terraform plan -detailed-exitcode
# Exit Code 2 = Changes detected (Drift!)
Risiken & Grenzen
False Positives
Checkov: "Security group allows unrestricted egress"
Reality: Das ist ein NAT Gateway, der soll das.
Lösung: Suppression mit Kommentaren:
#checkov:skip=CKV_AWS_24:NAT Gateway requires open egress
resource "aws_security_group" "nat" {
# ...
}
Komplexität
Terraform + Terragrunt + Atlantis + Sentinel + Checkov +
tfsec + OPA + Vault + 15 verschiedene AWS-Accounts =
"Das versteht niemand mehr"
Nicht alles ist scanbar
- Komplexe IAM-Policies
- Cross-Account-Beziehungen
- Business-Logik in Infrastruktur
State-File = Single Point of Failure
Wer den State kontrolliert, kontrolliert die Infrastruktur.
Plan ≠ Apply
Was im Plan steht, muss nicht das sein, was applied wird. Drift zwischen Scan und Deploy ist möglich.
Vorteile
Frühzeitige Erkennung
Kosten einer Fehlkonfiguration:
- Im Code gefunden: 10 Minuten Fix
- Nach Deploy: 10 Stunden + Incident + Postmortem
- Nach Breach: 10 Millionen + Anwälte + Reputation
Reproducibility
Dieselbe Policy gilt für alle Environments: Dev, Staging, Prod.
Audit Trail
Git-History zeigt, wer wann was geändert hat. Compliance liebt das.
Automatisierung
Kein manuelles Review jeder Ressource. Tools skalieren.
Shift Left
Security wird Teil des Entwicklungsprozesses, nicht Blocker am Ende.
Checkliste: IaC Security
Allgemein
- IaC-Scanner in CI/CD integriert
- Pre-commit Hooks eingerichtet
- Policies definiert (Checkov, Sentinel, OPA)
- State-File verschlüsselt und gesichert
- Secrets nicht im Code
AWS-spezifisch
- S3: Public Access blocked, Encryption enabled, Versioning
- RDS: Encryption at rest, nicht public, Backup
- EC2: IMDSv2 required, keine Public IPs wo nicht nötig
- IAM: Least Privilege, keine Wildcards
- VPC: Security Groups restriktiv, Flow Logs aktiviert
Azure-spezifisch
- Storage: HTTPS only, Encryption, Private Endpoints
- VMs: Managed Identity statt Service Principal wo möglich
- Networking: NSGs restriktiv, Azure Firewall/WAF
- Key Vault für Secrets
GCP-spezifisch
- GCS: Uniform bucket-level access, Encryption
- Compute: OS Login, Shielded VMs
- VPC: Firewall rules restriktiv
- IAM: Least Privilege
Fazit
IaC Security ist der Versuch, die "Move Fast and Break Things"-Mentalität von Infrastructure as Code mit den Security-Anforderungen der realen Welt in Einklang zu bringen. Die Tools sind da, die Policies können definiert werden – aber am Ende braucht es Menschen, die verstehen, was sie deployen.
"Infrastructure as Code" bedeutet auch "Security Bugs as Code". Versioniert, reviewt und skaliert deployt.
Weiterführende Ressourcen: