When building a house, you carefully review the blueprint before laying the first brick. No one wants to discover later that the foundation is unstable or that a door opens into a wall. Infrastructure as Code works the same way: even a small misconfiguration—an open port here, overly permissive database access there—can later become a backdoor for attackers.
Threat modeling acts as the security blueprint. It reveals where weaknesses might exist: Where could an intruder get in? Is the door secure enough? Are there open windows? It creates transparency around potential risks before the “house”—the cloud infrastructure—is even built. This results in stable, secure environments where security is not added afterward but forms part of the foundation from the very beginning.
Security Challenges Specific to Infrastructure as Code
While traditional software development usually focuses on user interactions and application logic, Infrastructure as Code describes the entire technical foundation—networks, access permissions, and cloud services. A single line of code can suddenly determine whether a database is publicly accessible or properly secured.
Misconfigurations no longer spread gradually. With a single terraform apply or kubectl apply, they can immediately affect dozens or even hundreds of systems. What starts as a minor oversight can quickly turn into a widespread security vulnerability.
Another challenge is hidden dependencies between resources: IaC templates link many services and configurations—often implicitly and in ways that are difficult to trace. Even a small change to a security group rule can unintentionally expose entire service chains. These side effects overwhelm traditional code reviews and complicate threat modeling.
Infrastructure as Code introduces specific security challenges that traditional threat models often fail to fully cover [1]: API keys, access tokens, or passwords frequently end up—unintentionally and in plain text—in IaC repositories, module files, or CI/CD pipelines. If these secrets are reused across multiple systems or paired with overly permissive Identity and Access Management (IAM) policies, attackers can move laterally and, in the worst case, take over entire system landscapes.
This becomes especially critical when a module with excessive permissions is reused multiple times, multiplying the attack surface. This is a phenomenon known as secret sprawl.
Manual changes made to infrastructure after automated IaC deployment create discrepancies between the declarative IaC state and the actual runtime state—a phenomenon known as configuration drift. This opens new security gaps that cannot be detected by analyzing IaC templates alone. Using public third-party IaC modules or templates introduces further risks, as outdated or insecure defaults may silently enter production environments.
Many IaC templates rely on insecure default configurations for convenience, leading to systematic vulnerabilities when reused. Some IaC tools even store sensitive information such as resource IDs or configuration details in state files. I’ll leave it to you to imagine what happens if those files are exposed.
Identifying these threats is only the first step. The real challenge lies in addressing them systematically and designing infrastructure that is secure, transparent, and auditable from the outset. This is especially true in modern DevOps pipelines, where continuous delivery enables rapid, automated infrastructure changes. While this boosts productivity for development teams, it can be a nightmare for security teams. The more frequent the rollouts, the harder it becomes to perform timely threat analysis. One-off security workshops are no longer sufficient in this dynamic environment [2].
These three dimensions—scale, dependencies, and speed—require a rethink of IaC threat modeling. Instead of being an occasional workshop activity, threat modeling must become a fixed component of the DevOps lifecycle. Only then can threats be identified directly within IaC templates. Tools and automation help make attack vectors visible, prioritize risks, and detect issues already during design.
Shift-Left Security in Infrastructure as Code
Infrastructure as Code is a central element of modern DevOps processes. However, security is often not deeply embedded and is instead addressed late in the development cycle. DevSecOps extends DevOps by integrating security into processes, systems, and infrastructure from the very beginning. Security is “shifted left”: tests, security checks, and safeguards are applied as early as possible in the Software Development Lifecycle (SDLC).
This establishes security not as an obstacle but as an integral part of the DevOps workflow, with automation, clear processes, and shared responsibility.
When security checks occur only at the end of a pipeline, vulnerabilities are often discovered in already deployed environments, increasing remediation costs or allowing attackers to exploit them first. The shift-left approach reverses this: instead of costly post-deployment fixes, security is considered while writing Terraform code, Ansible playbooks, or Kubernetes manifests. Developers verify policy compliance while creating templates, making security part of the code itself.
DevSecOps is primarily a cultural shift. Security becomes a team responsibility. Developers take on more accountability, and security teams move closer to day-to-day development. Shared workshops and training sessions spread knowledge and best practices across teams.
In IaC environments, shift-left security is not optional; it is essential. Misconfigurations, hidden dependencies, and the speed of continuous delivery demand that security be embedded from the start.
Continuous Threat Modeling and Threat Modeling as Code
In traditional software development, threat modeling often happens once, in a workshop at the start of a project. That used to be reasonable. But with agile methods, microservices architectures, and continuous delivery pipelines now standard, this approach no longer works. With every commit, new container image, and updated Kubernetes configuration, the attack surface changes.
This makes continuous threat modeling necessary. Security models must evolve alongside the code. That means integrating threat analysis directly into CI/CD pipelines. With every commit, not only do unit and integration tests run, but they also check against defined security models [2].
Manual threat modeling is difficult. High-quality threat models require experienced specialists. Systems constantly grow and change. Every technology and dependency introduces new vulnerabilities. Maintaining consistency across tools, frameworks, and documentation formats is challenging.
This is where automation comes in. Software can dynamically represent systems, analyze dependencies, and evaluate rules. Just as infrastructure is defined using IaC, threat scenarios, assumptions, and risks can be represented in JSON or YAML, versioned, and validated [3]. Instead of manually updating diagrams, the model lives directly in the repository. Every change can be automatically validated, making threat modeling reproducible and scalable [2].
Two approaches are commonly distinguished: Threat Modeling from Code and Threat Modeling with Code:
- Threat Modeling from Code analyzes source code, configurations, or infrastructure definitions to derive a threat model. Tools compare these inputs against known risks or rules and generate reports identifying potential vulnerabilities. Code itself becomes the input for threat identification [4].
- Threat Modeling with Code describes existing systems—entities, data flows, dependencies, or event sequences—in code form. Developers model systems using programming languages or Architecture Description Languages (ADLs) such as AADL or Acme. These models are then interpreted to automatically identify threats [4].
In both approaches, output quality depends heavily on input quality: garbage in, garbage out. With clean input data and valid rules, two major pain points disappear: reliance on highly specialized expertise and manual maintenance of system models.
Combining these approaches with modern IaC and DevOps practices leads to Threat Modeling as Code. Threat models are described in machine-readable formats like YAML or JSON, versioned as source code, and automatically derived from existing code. They integrate directly into CI/CD pipelines, making threat modeling continuous, automated, and collaborative. Threat models are code [2].
Continuous threat modeling is a logical progression from threat modeling as code. This modern approach is based on a few key principles [4]:
- Team knowledge beats external knowledge: no one understands a system better than the product team.
- Agile, accessible, and practical: threat modeling must adapt to real workflows.
- Real-time learning curve: quality analysis improves as teams gain experience (“increasing returns learning curve”).
- Model and reality must match: threat models must always reflect the current system state.
- Continuous improvement: today’s model should be better than yesterday’s.
- Actionable value: insights must help identify and mitigate real risks.
With these principles, threat modeling becomes a continuous, team-driven process that embeds IaC security from the start and strengthens infrastructure resilience sustainably.
Common Threat-Modeling Methods for IaC
Not all threat-modeling methods are equally suitable for Infrastructure as Code. In practice, two approaches have proven effective: STRIDE and DREAD.
STRIDE stands for Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, and Elevation of Privilege. It systematically identifies potential attack vectors and translates well to infrastructure components such as storage, networking, and access management.
DREAD is a scoring-based framework evaluating Damage Potential, Reproducibility, Exploitability, Affected Users, and Discoverability. IaC environments benefit especially from DREAD for prioritization: scores can be automated, visualized in dashboards, and linked to SLAs or runbooks.
In practice, IaC threat modeling often combines both: STRIDE provides structured qualitative analysis, while DREAD turns findings into prioritized, operational measures. Small teams often start with pragmatic STRIDE workshops at the template or module level. Larger organizations complement this with DREAD scoring and automated CI/CD evaluations.
Example: Threat Modeling with IaC
To illustrate the approach, consider a simple example. Our system architecture is deployed in Azure and defined using Terraform, but the methodology applies to any cloud or IaC tool.
The architecture includes:
- Resource Group: Container for all resources
- Azure AD: Identity management and role-based access control
- Azure DNS: Name resolution in the network
- Virtual Network (VNet): Virtual network with two subnets
- App Subnet: Contains the application VM
- DB Subnet: Contains the database
- Network Security Groups (NSG): Network firewalls for app and DB subnets
- Azure Load Balancer: Distribution of HTTPS traffic
- Virtual Machine (VM): Application component that accesses the DB via HTTPS
- Azure Database (e.g., PostgreSQL): Persistent storage of application data
- Managed Identity: Ensures access to the database via Azure AD
- DNS zones and records: For name resolution between components
A generalized architecture is illustrated in Figure 1.

Figure 1: Generalized example architecture
We will now look at our Terraform configuration, define trust boundaries, and apply STRIDE and DREAD methods to them. The data flow diagram is omitted in this example because we already know how it works, and the process is exactly the same for IaC. Listing 1 shows an example of what this might look like. Of course, there are several trust boundaries and vulnerabilities, but if we want to describe them all, we’ll be busy all day.
Listing 1:
VNet-Subnets und Network Security Groups
resource "azurerm_subnet" "app_subnet" {
...
}
resource "azurerm_subnet" "db_subnet" {
...
}
resource "azurerm_network_security_group" "app_nsg" {
security_rule {
name = "HTTPS"
source_address_prefix = "*"
}
}
resource "azurerm_network_security_group" "db_nsg" {
security_rule {
name = "Internal-HTTPS"
source_address_prefix = azurerm_subnet.app_subnet.address_prefixes[0]
}
}
STRIDE
- Spoofing: External access to the app subnet enables identity spoofing
- Tampering: Overly permissive NSG rules allow packet manipulation
- Information Disclosure: Open NSGs increase data exposure risk
DREAD:
- Public SSH access to the VM (NSG rule with source_address_prefix = “*”, port 22)
o Damage Potential: 8
- Successful SSH access can mean root privileges on the VM and lead to complete system takeover
o Reproducibility: 10
- The open SSH port is easy to find via port scanning; attacks can be repeated as often as desired
o Exploitability: 9
- SSH is widely used, and automated exploits and brute force tools exist to exploit unsecured SSH access
o Affected Users: 10
- All users and services running on the VM would be potentially affected
o Discoverability: 9
- Port 22 is the standard port for SSH and, therefore, easy to discover
o Score: 9.2 (high)
Of course, it’s a lot of fun to do something like this manually. Unfortunately, life is too short, so smart people have made the process much faster, easier, and less error-prone with automation tools.
Tools and Best Practices
There are many open-source and enterprise tools that simplify IaC threat modeling. Here are a few examples:
- threatcl: a configuration language for threat modeling workflows [5]
- TerraScan: open-source tool for static code analysis of IaC, checks Terraform, Kubernetes, and CloudFormation configurations for security vulnerabilities and compliance violations [6]
- tfsec: open-source tool for static analysis of Terraform code, detects insecure configurations, dangerous patterns, and missing encryption [7]
- Checkov: checks for typical misconfigurations using predefined and user-defined rules; supports Terraform, AWS CloudFormation, Azure Resource Manager, and Kubernetes manifests [8]
- kube-review and kubeval: Tools specifically for Kubernetes that scan manifests for policy compliance and structural weaknesses, well-suited for microservices and container environments [9], [10]
- OWASP Threat Dragon: A comprehensive threat modeling tool that is not only suitable for IaC, but is also generally useful in DevSecOps processes [11]
Often, several of these tools are used in parallel to cover different aspects such as cloud specifications, containers, and rights management. However, before we get started and integrate automated threat modeling into our CI/CD pipeline, we should consider some best practices that will make life much easier for all of us. Techvzero suggests the following framework for integrating threat modeling into IaC workflows [1]:
- Delineate and inventory assets: define clear IaC boundaries, consider module boundaries as trust zones, segment development, test, and production environments, and capture critical assets (cloud accounts, IAM entities, CI/CD infrastructure)
- Identify sensitive data flows: recognize regulated data, intellectual property, and trade secrets in the infrastructure setup and document their flow.
- Apply threat modeling methods: use STRIDE to identify technical risks and DREAD for prioritization. PASTA, which was not mentioned in this article, combines threat analysis with business objectives and is usually used as a supplement.
- Implement mitigation as code: embed security policies in infrastructure templates, use secure, reusable modules, and integrate security scanners (e.g., Checkov, Terrascan) early in the pipeline.
- Security controls throughout the IaC lifecycle: pre-commit hooks and IDE plugins for early detection, CI/CD pipeline quality gates with static analysis and policy validation, as well as post-deployment monitoring, dynamic testing, and compliance monitoring.
Conclusion
Here are a few thoughts on what we, as platform engineers and developers, can do to better secure systems:
- Perform security checks during development, not just during review.
- Involve all stakeholders, from DevOps to development to security. Joint workshops and open communication are crucial.
- Automate checks and policy checks with every code change.
- Don’t treat security policies as a one-time task, but review and adjust them regularly.
- Configure the CI/CD pipeline so that unstable or insecure IaC changes automatically block deployment until the risks are addressed.
- Establish clear guidelines, versioning, and regular audits. This makes security a continuous process.
And that’s it. Threat modeling for Infrastructure as Code does not end with Terraform configuration files or Kubernetes manifests. The topic encompasses many different methods and insights into DevSecOps and can be expanded at any time. Good luck convincing the product owner that threat modeling is important for your project!
Further Readings
[1] https://techvzero.com/iac-threat-modeling-best-practices-guide/
[2] https://dev.to/vaib/continuous-threat-modeling-and-threat-modeling-as-code-tmasc-43c8
[4] Tarandach, I.; Coles, M. J.: „Threat Modeling“; O’Reilly Media, 2020
[5] https://threatcl.github.io
[7] https://aquasecurity.github.io/tfsec/v1.20.0/
[9] https://github.com/anderseknert/kube-review
Author
🔍 FAQ
1. What makes threat modeling for Infrastructure as Code (IaC) different from traditional threat modeling?
Traditional threat modeling usually focuses on software architecture, application logic, and user data flows. Threat modeling for IaC shifts the focus downstream to the system's foundational layer. It maps out cloud-native components, configurations, and deployment pipelines to identify vulnerabilities like overly permissive IAM policies, unencrypted storage buckets, and open security groups before the infrastructure is provisioned.
2. How do you implement "Threat Modeling as Code" in a DevSecOps pipeline?
Threat Modeling as Code involves using declarative syntax (such as Python, JSON, or YAML via tools like pytm or Open Threat Model formats) to describe your architecture. This allows threat models to live in the same Git repository as your Terraform, Ansible, or CloudFormation scripts. Changes to the infrastructure code trigger automated threat analysis checks directly within your CI/CD pipeline, catching security architectural flaws during pull requests.
3. Can automated tools completely replace human-led threat modeling for IaC?
No. While automated static analysis tools (like Checkov, Tfsec, or KICS) are excellent at catching known misconfigurations and compliance violations, they lack contextual business reasoning. Humans are still required to identify complex multi-step attack chains, evaluate trust boundaries, and understand the logic of who should have access to data, rather than just checking if a port is open.
4. How does IaC threat modeling address software supply chain risks?
Infrastructure often relies heavily on external modules, third-party GitHub actions, and base container images. IaC threat modeling maps these external dependencies as untrusted or semi-trusted boundaries. This helps teams identify potential injection points where a compromised third-party package or module could exploit administrative privileges within your cloud ecosystem.


