IaC Security: Securing Terraform, Docker & Kubernetes Before Deployment
Infrastructure as Code Is Infrastructure as Vulnerability
Infrastructure as Code (IaC) transformed how we deploy systems — but it also codified our misconfigurations. According to Bridgecrew's 2025 State of IaC Security Report:
| Finding | Value |
|---|---|
| IaC templates with at least one misconfiguration | 67% |
| Average misconfigurations per template | 12.7 |
| Most common: overly permissive IAM policies | 38% of all misconfigs |
| Second: unencrypted data storage | 29% |
| Third: excessive network exposure | 22% |
The Advantage: Unlike manual infrastructure, IaC misconfigurations can be found and fixed before deployment. This is the power of shift-left for infrastructure — scan the code, not the running system.
Terraform Security
The 10 Most Common Terraform Misconfigurations
| # | Misconfiguration | Risk | Fix |
|---|---|---|---|
| 1 | S3 bucket public access | Data exposure | block_public_access = true |
| 2 | Security group 0.0.0.0/0 on SSH | Unauthorized access | Restrict to known CIDRs |
| 3 | No encryption at rest | Data exposure | Enable encryption on all storage |
| 4 | IAM * permissions | Privilege escalation | Least-privilege policies |
| 5 | No CloudTrail logging | No audit trail | Enable multi-region CloudTrail |
| 6 | Default VPC usage | Shared network risk | Create custom VPC |
| 7 | No MFA delete on S3 | Accidental/malicious deletion | Enable MFA delete |
| 8 | RDS publicly accessible | Database exposure | publicly_accessible = false |
| 9 | No lifecycle policies | Cost + stale resources | Set TTLs and rotation |
| 10 | Hardcoded secrets | Credential exposure | Use aws_secretsmanager_secret |
Secure Terraform Patterns
# SECURE — S3 bucket with full security hardening
resource "aws_s3_bucket" "data" {
bucket = "company-data-prod"
}
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"
kms_master_key_id = aws_kms_key.s3.arn
}
}
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration { status = "Enabled" }
}
resource "aws_s3_bucket_logging" "data" {
bucket = aws_s3_bucket.data.id
target_bucket = aws_s3_bucket.logs.id
target_prefix = "s3-access-logs/"
}
Terraform Security Scanning Tools
| Tool | Checks | Integration |
|---|---|---|
| Checkov | 2,500+ rules across AWS/Azure/GCP | CLI, CI/CD, IDE |
| tfsec | Terraform-specific security rules | CLI, GitHub Actions |
| Terrascan | Multi-IaC (Terraform, K8s, Helm) | CLI, CI/CD |
| Sentinel | HashiCorp policy-as-code | Terraform Cloud/Enterprise |
| OPA/Conftest | General purpose policy engine | Any IaC format |
Docker Security
Docker Security Hardening Checklist
# SECURE — Production-ready Dockerfile
# 1. Use specific, minimal base image (not 'latest')
FROM node:20-alpine AS builder
# 2. Create non-root user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
# 3. Set working directory
WORKDIR /app
# 4. Copy package files first (layer caching)
COPY package.json package-lock.json ./
# 5. Install dependencies (production only, ignore scripts)
RUN npm ci --only=production --ignore-scripts
# 6. Copy application code
COPY --chown=appuser:appgroup . .
# 7. Build application
RUN npm run build
# 8. Multi-stage build — production image
FROM node:20-alpine AS production
# 9. Install security updates
RUN apk update && apk upgrade --no-cache
# 10. Create non-root user in production image
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
WORKDIR /app
# 11. Copy only production artifacts
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
# 12. Drop all capabilities, run as non-root
USER appuser
# 13. Set read-only filesystem where possible
# (configure at runtime with --read-only flag)
# 14. Health check
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
# 15. Expose only required port
EXPOSE 3000
CMD ["node", "dist/server.js"]
Container Scanning
# Scan Docker image for vulnerabilities
trivy image myapp:latest --severity HIGH,CRITICAL
# Scan and fail on critical findings (CI/CD integration)
trivy image myapp:latest --severity CRITICAL --exit-code 1
# Scan Dockerfile for misconfigurations
trivy config ./Dockerfile
Kubernetes Security
K8s Security Fundamentals
| Area | Risk | Control |
|---|---|---|
| RBAC | Over-privileged service accounts | Least-privilege ClusterRoles |
| Pod Security | Containers running as root | Pod Security Standards (restricted) |
| Network | Unrestricted pod-to-pod traffic | Network Policies |
| Secrets | Secrets in etcd unencrypted | External secrets management |
| Images | Pulling untrusted images | Image allowlists, signing |
| Runtime | Container escape | Seccomp, AppArmor, read-only FS |
Secure Pod Configuration
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
# Don't use default service account
serviceAccountName: app-specific-sa
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1001
fsGroup: 1001
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myregistry.com/app:v1.2.3@sha256:abc123...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Kubernetes Network Policy (Zero-Trust Networking)
# Default deny all traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# Allow only specific traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 3000
protocol: TCP
IaC Security in CI/CD
Automated IaC Security Pipeline
# Combined IaC security scanning
name: IaC Security
on: [pull_request]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov Terraform scan
uses: bridgecrewio/checkov-action@master
with:
directory: ./terraform
framework: terraform
soft_fail: false # Block PR on failures
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Hadolint Dockerfile lint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
- name: Build and scan
run: |
docker build -t test:latest .
trivy image test:latest --exit-code 1 --severity HIGH,CRITICAL
kubernetes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: KubeSec scan
run: |
kubesec scan k8s/*.yaml
- name: Checkov K8s scan
uses: bridgecrewio/checkov-action@master
with:
directory: ./k8s
framework: kubernetes
Further Reading
- Container Security Best Practices — Docker and container runtime security
- Shift-Left Security — Integrating security into the SDLC
- DevSecOps Complete Guide — Full DevSecOps implementation
- Cloud Security Guide — Multi-cloud security hardening
Advertisement
Free Security Tools
Try our tools now
Expert Services
Get professional help
OWASP Top 10
Learn the top risks
Related Articles
Software Supply Chain Security: Defending Against Modern Threats
How to protect your applications from supply chain attacks targeting dependencies, build pipelines, and deployment processes.
Container Security Best Practices for Production
Secure your containerized applications from image building to runtime with these battle-tested practices.
DevSecOps: The Complete Guide 2025-2026
Master DevSecOps with comprehensive practices, automation strategies, real-world examples, and the latest trends shaping secure development in 2025.