Introduction to the Open Threat Model standard
Introduction to the Open Threat Model standard
The Open Threat Model (OTM) standard is a generic and tool agnostic way of describing a threat model in a simple to use and understand format. It has been designed to allow greater connectivity and interoperability between threat modeling and other parts of the Software Development Lifecycle (SDLC) and cybersecurity ecosystem. Released under Create Commons, anyone can contribute or use the standard.
Threat modeling as a practice is evolving, and so must the technology that surrounds the practice. If you look at what happened with DevOps, the key to scaling the creation and management of infrastructure was a combination of culture changes as well as the commoditisation of infrastructure such as through cloud and Infrastructure as Code (IaC). Threat modeling will inevitably go through a similar shift, and this standard has been to facilitate that evolution. By leveraging existing design artefacts such as IaC, we can automate the threat modeling process, increasing the scalability and maturity of threat modeling as a result.
Key use cases for an open threat modeling standard include:
- Easily supporting new sources of application and system design. Anyone can write and share parsers or other tools that take source formats such as CloudFormation, Visio, or Docker Compose files.
- Exchange threat model data within the SDLC and cyber security ecosystem. Having threat models represented in a common format means being able to use that data through integrations.
- Exchange between organisations. It would be a great outcome if open source projects or even commercial vendors were sharing threat models of their systems in a way that could be ingested and used by organisations adopting those systems.
In this article we’re going to take a close look at the specification and how IriusRisk implements and uses it to automatically create threat models from CloudFormation templates. For the full specification see the Open Threat Model project repository. To learn how to create a simple parser that generates OTM see How to create an OTM parser.
An overview of the OTM specification
It makes sense to start by looking at some key elements and features of the specification. The specification is written as YAML (or JSON) and is broken up into a number of high level objects:
- otmVersion - The version of the specification used in the file
- Project metadata - Name, identifier, description, owner of the thing you’re threat modeling
- Representations - E.g. diagram, code, JIRA story, user interface
- Assets - Things you care about, sensitive information. E.g. PCI or PII data
- Components - Bits that make up the representation such as an EC2 instance or an API
- Trustzones - The differing levels of security and trust. Internet vs Web vs App vs Data tier
- Dataflows - How information and assets move around between components
- Threats - The bad stuff, the things that can go wrong
- Mitigations - The good stuff, probably requires you to do some work
There are few other interesting things to note about the specification:
- Objects can have arbitrary “attributes”, use them however you like. E.g. custom IDs
- It provides basic properties to capture essential risk information (CIA triad, trustzone ratings, CWEs, likelihood and impact)
- Tags to help you classify or group different components etc.
- X and Y positions can be provided for diagrammatic representations
- Components and Trustzones can be arbitrarily nested
Project
The project object contains metadata about the thing being threat modelled. The name and id fields are required, but other useful fields include a description, owner, and owner contact. You can use the attributes field to link your project to documentation hosted elsewhere or to the relevant asset in something like a CMDB.
project:
name: Test project
id: test-project
description: This is a test project for the OTM development
owner: John Doe
ownerContact: john.doe@example.com
attributes:
documentation: “http://mydocs/my-app-123”
cmdbId: MyApp123
Representations
Any given system can be threat modeled in a number of different ways, and from a number of different perspectives. For example, you can threat model as system based on the cloud infrastructure, or you can threat model the functional elements of the application itself such as login, shopping cart, user comments etc. The OTM specification refers to these different perspectives as representations, and an OTM file can include one or more representations. An architecture diagram representation may have diagrammatic elements such as width and height, where as a code-based representation may have a source code repository and file line numbers.
Here we can see an example of an architecture diagram representation.
representations:
- name: Architecture Diagram
id: architecture-diagram
description: This is a diagram of the project's architecture
type: diagram
size:
width: 1000
height: 1000
attributes:
platform: drawio
unit: pixel
...
This is what a code representation might look like.
...
- name: Application Code
id: application-code
type: code
repository:
url: https://github.com/my-project
attributes:
language: java
platform: github
vcs: git
Because an OTM file can include multiple representations, that means you can include the full threat model of a given application or system, from each of the different perspectives.
Trustzones
Trustzones are a core part of any threat model. They provide key context about how components within a threat model are expected to behave and where threats are going to have the biggest impact. If you’ve got a completely untrusted zone such as the Internet connected directly to a highly trusted zone such as a data tier, you may find that a simple configuration error could easily expose the sensitive data to the world. The OTM specification uses a trustRating property to describe the expected level of trust and security of the trustzones.
trustZones:
- name: Internet
id: internet
description: This is the internet trust zone
risk:
trustRating: 20
representations:
representation: architecture-diagram
id: internet-box-shape
Components
Components are the building blocks of a threat model. They can include the architectural elements within system such as web servers, data bases, and firewalls. They can also include the functional elements with in a system such as the login page, a shopping cart, or an email sender.
Each component has a human readable name field, but also a type field. This type field helps to describe what type of object it is. For example, in a threat model you could have two different web services Web1 and Web2, both of the same web-service type. While they are different entities in the threat model itself, because they are the same type, we can expect similar threats and controls to apply to them.
Components also have a parent field. Typically this will be a trustzone, but a component can also be nested inside another component. For example, you may have a Rest API component inside an AWS EC2 instance component.
Tags are especially useful for components because they allow you to provide additional values that further describe the components in an arbitrary way. This can be useful for group or filtering.
components:
- name: Web Service
id: web-service
type: web-service
description: Runs our web application
parent:
trustZone: private
tags:
- tomcat
Dataflows
Finally we’ll look at dataflows. These are the literal flows of data between components within a threat model. They can be network-level flows such as HTTP or DNS, or they can be higher level flows such as “user login” or “product search”. Of course, a data flow needs a source and a destination component. It can be unidirectional or bidirectional. And similar to components, tags can be used to provide additional context useful for grouping and filtering.dataflows:
- name: Dataflow between webservice and mongo
id: cc-store-in-db
description: Credit card information being exchanged in between the web app and the database
bidirectional: true
source: web-service
destination: customer-database
tags:
- http
- https
Using OTM with IriusRisk
IriusRisk has released an OTM API in version 4.1 of the product. This API allows you to provide an OTM file and IriusRisk will automatically build a full threat model using the rules engine an extensive library of components and risk patterns. The first release of the API supports trustzones, components, and dataflows. Threats and mitigations are already in the specification, and support for them in IriusRisk will be coming soon.
The rest of this article will focus on building a threat model in IriusRisk using OTM. We’ll start off with a simple HelloWorld OTM file created by hand in an IDE, and then we’ll build one from a CloudFormation template using the open source Startleft tool. For both of these examples, we’ll need to set a couple of environment variables used to connect with the API:
$ env | grep IRIUS
IRIUS_API_TOKEN=abc-123
IRIUS_SERVER=https://dev.iriusrisk.com
HelloWorld
Here’s a very simple OTM file created by hand in an IDE. Yes, it’s that easy.
otmVersion: 0.1.0
project:
id: helloworld
name: Hello World
trustZones:
- name: Public
id: 6376d53e-6461-412b-8e04-7b3fe2b397de
risk:
trustRating: 10
- name: Private Secured
id: 2ab4effa-40b7-4cd2-ba81-8247d29a6f2d
risk:
trustRating: 90
components:
- name: Client
id: client
type: generic-client
parent:
trustZone: 6376d53e-6461-412b-8e04-7b3fe2b397de
- name: REST Service
id: rest-service
type: rest-full-web-service
parent:
trustZone: 2ab4effa-40b7-4cd2-ba81-8247d29a6f2d
dataflows:
- name: Client to REST service
id: client-to-rest
source: client
destination: rest-service
tags:
- HTTPS
It has two trustzones, two components, and a dataflow. This file can be sent straight to the IriusRisk OTM API using a simple curl command:
curl -XPOST -H "api-token: $IRIUS_API_TOKEN" -F 'otmFile=@helloworld.otm' 'https://dev.iriusrisk.com/api/v1/products/otm'
{ "ref":"helloworld",
"name":"Hello World",
"revision":"1",
"type":"STANDARD",
"status":"OPEN",
"priority":"0",
"tags":null,
"workflowState":"wsa",
"udts":[],
"groups":null,
"users":null
}
Here is the threat model created by IriusRisk:
As you can see, because the rules engine has executed, it has automatically pulled in threats and countermeasures that would apply to this threat model:
CloudFormation
Now let’s build a more complete threat model from a CloudFormation template. We will use the open source Startleft tool to parse the CloudFormation template into an OTM file, then we’ll upload that OTM file to the IriusRisk API. Finally we’ll look at the threat model created by IriusRisk as a result.
This code snippet shows a section of the CloudFormation template we’ll be using. As you can see, the file uses Amazon's Elastic Container Service as well as a number of other resources such as CloudWatch alarms.
service:
Type: 'AWS::ECS::Service'
DependsOn: ALBListener
Properties:
Cluster:
Ref: ECSCluster
DesiredCount: '1'
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- Ref: PrivateSubnet
SecurityGroups:
- Ref: EcsSecurityGroup
LoadBalancers:
- ContainerName: simple-app
ContainerPort: '80'
TargetGroupArn:
Ref: ECSTG
Role:
Ref: ECSServiceRole
TaskDefinition:
Ref: taskdefinition
Using the Startleft project we can parse it into OTM with a single command.
$ startleft parse --type CloudFormation --map default-cloudformation-mapping.yaml --name "ECS Example" --id ecs-example --otm ecs-otm.yaml ecs.yaml
Writing threat model to 'ecs-otm.yaml'
The mapping file provided describes how to find resources in a CloudFormation Template, and how to map them into an OTM threat model. This gives us an OTM file which look something like:
{
"otmVersion": "0.1.0",
"project": {
"name": "ECS Example",
"id": "ecs-example"
},
...
"components": [
{
"id": "1926dedc-c0e8-4539-b304-4fa359d9eeb9",
"name": "service",
"type": "elastic-container-service",
"parent": {
"component": "36f7c768-b05d-48b8-880f-da9bdaf41258"
},
"tags": [
"AWS::ECS::Service"
]
},
{
"id": "4ec0399f-8594-4bb3-9ee8-965153c07d33",
"name": "taskdefinition",
"type": "docker-container",
"parent": {
"component": "1926dedc-c0e8-4539-b304-4fa359d9eeb9"
},
"tags": [
"AWS::ECS::TaskDefinition"
]
},
We can now upload this OTM to IriusRisk using Startleft.
$ startleft threatmodel ecs-otm.yaml
Uploading OTM files and generating the IriusRisk threat model
Validating OTM file
OTM file is valid
OTM file has consistent IDs
Logging in to IriusRisk we can see it has built a full threat model. This isn’t just a visualisation of all of the resources in a CloudFormation template. What we can see here is an architectural view of the cloud infrastructure.
Conclusion
The Open Threat Model standard gives us a flexible way to describe threat models which can be used throughout the SDLC and cybersecurity ecosystem. It’s simple enough to be able to create threat models by hand, and powerful enough to represent full threat models generated from Infrastructure as Code.