Infrastructure as Code (IaC) Security

Von Boris Sander6. November 2025
Infrastructure as Code (IaC) Security

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

ToolAnbieterSpracheFokus
TerraformHashiCorpHCLMulti-Cloud
CloudFormationAWSYAML/JSONAWS only
PulumiPulumiPython/TS/GoMulti-Cloud
ARM TemplatesMicrosoftJSONAzure only
BicepMicrosoftDSLAzure only
CDKAWSTS/Python/JavaAWS (via CFN)
AnsibleRed HatYAMLConfig Management
Chef/PuppetVariousRuby/DSLConfig 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

ToolTerraformCloudFormationK8sAnsiblePreis
CheckovFree
tfsec/Trivy-Free
Terrascan-Free
KICSFree
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: