Threat Modeling with HCL
hcltm has been renamed to threatcl
. Welcome!
Tip
Want to read the new documentation? Head over to threatcl.github.io
There are many different ways in which a threat model can be documented. From a simple text file, to more in-depth word documents, to fully instrumented threat models in a centralised solution. Two of the most valuable attributes of a threat model are being able to clearly document the threats, and to be able to drive valuable change.
threatcl
aims to provide a DevOps-first approach to documenting a system threat model by focusing on the following goals:
- Simple text-file format
- Simple cli-driven user experience
- Integration into version control systems (VCS)
This repository is the home of the threatcl
cli software. The threatcl
spec is based on HCL2, HashiCorp's Configuration Language, which aims to be "pleasant to read and write for humans, and a JSON-based variant that is easier for machines to generate and parse". The threatcl
spec lives at github.com/threatcl/spec. Combining the threatcl
cli software and the threatcl
spec allows practitioners to define a system threat model in HCL, for example:
threatmodel "Tower of London" {
description = "A historic castle"
author = "@xntrik"
attributes {
new_initiative = "true"
internet_facing = "true"
initiative_size = "Small"
}
information_asset "crown jewels" {
description = "including the imperial state crown"
information_classification = "Confidential"
}
usecase {
description = "The Queen can fetch the crown"
}
third_party_dependency "community watch" {
description = "The community watch helps guard the premise"
uptime_dependency = "degraded"
}
threat {
description = "Someone who isn't the Queen steals the crown"
impacts = ["Confidentiality"]
expanded_control "Guards" {
description = "Trained guards patrol tower"
risk_reduction = 75
}
}
data_flow_diagram_v2 "dfd name" {
// ... see below for more information
}
}
See Data Flow Diagram for more information on how to construct data flow diagrams that may be converted to PNGs automatically.
To see an example of how to reference pre-defined control libraries for the OWASP Proactive Controls and AWS Security Checklist see examples/tm3.hcl. We also have the MITRE ATT&CK Controls here.
You can also include an external threatmodel into your own, to reference and use all its information. You can see examples/including-example/corp-app.hcl as an example.
To see a full description of the spec, see here or run:
threatcl generate boilerplate
threatcl
will also process JSON files, but the only caveat is that import modules and variables won't work. You can see examples/tm1.json as an example.
HCL is the primary configuration language used in the products by HashiCorp, in-particularly, Terraform - their open-source Infrastructure-as-Code software. I worked at HashiCorp for a while and the language really grew on me, plus, if DevOps and Software engineers are using the language, then simplifying how they document threat models aligns with threatcl
's goals.
You can use threatcl
with JSON, but you lose some of the features. For more, see the examples/ folder.
I liked the idea of using a format that could be programmatically interacted with.
One of the features of threatcl
is the automatic generation of data flow diagrams from HCL files. This leverages the go-dfd package by Marqeta and Blake Hitchcock. Definitely check out their blog post on Threat models at the speed of DevOps.
Additionally I'd like to extend thanks to Jamie Finnigan and Talha Tariq at HashiCorp for allowing me to continue working on this open-source tool even after I'd finished up with HashiCorp.
Also thanks to the IriusRisk folks for the OpenThreatModel specification.
Download the latest version from releases and move the threatcl
binary into your PATH.
The following will add a local tap, and install threatcl
with Homebrew
brew install threatcl/repo/threatcl
docker run --rm -it ghcr.io/threatcl/threatcl:latest
threatcl
can be integrated directly into your GitHub repos with https://github.com/threatcl/threatcl-action. This is one of the ideal methods to manage your threat models, and helps meet the goal of integrating into your version control systems.
- Clone this repository.
- Change into the directory,
threatcl
make bootstrap
make build
For further help on contributing to threatcl
please see the CHANGELOG.md.
For help on any subcommands use the -h
flag.
$ threatcl
Usage: threatcl [--version] [--help] <command> [<args>]
Available commands are:
dashboard Generate markdown files from existing HCL threatmodel file(s)
dfd Generate Data Flow Diagram PNG or DOT files from existing HCL threatmodel file(s)
export Export threat models into other formats
generate Generate an HCL Threat Model
list List Threatmodels found in HCL file(s)
terraform Parse output from 'terraform show -json'
validate Validate existing HCL Threatmodel file(s)
view View existing HCL Threatmodel file(s)
Most of the threatcl
commands have a -config
flag that allows you to specify a config.hcl
file. HCL within this file may be used to overwrite some of threatcl
's default attributes. These are listed below:
- Initiative Sizes - defaults to "Undefined", "Small", "Medium", "Large"
- Default Initiative Size - defaults to "Undefined
- Information Classifications - defaults to "Restricted", "Confidential", "Public"
- Default Information Classification - defaults to "Confidential"
- Impact Types - defaults to "Confidentiality", "Integrity", "Availability"
- STRIDE Elements - defaults to "Spoofing", "Tampering", "Info Disclosure", "Denial Of Service", "Elevation Of Privilege"
- Uptime Dependency Classifications - defaults to "none", "degraded", "hard", "operational"
- Default Uptime Depency Classification - defaults to "none"
For example:
initiative_sizes = ["S", "M", "L"]
default_initiative_size = "M"
info_classifications = ["1", "2"]
default_info_classification = "1"
impact_types = ["big", "small"]
strides = ["S", "T"]
uptime_dep_classifications = ["N", "D"]
default_uptime_dep_classification = "N"
If you modify these attributes, you'll need to remember to provide the config file for other operations, as this may impact validation or dashboard creation.
The threatcl list
and threatcl view
commands can be used to list and view data from threatcl
spec HCL files.
$ threatcl list examples/*
# File Threatmodel Author
1 examples/tm1.hcl Tower of London @xntrik
2 examples/tm1.hcl Fort Knox @xntrik
3 examples/tm2.hcl Modelly model @xntrik
The threatcl validate
command is used to validate a threatcl
spec HCL file.
$ threatcl validate examples/*
Validated 3 threatmodels in 3 files
The threatcl export
command is used to export a threatcl
threat model (or models) into the native JSON representation (by default), or into the OTM json representation, or even back into hcl
(Which is useful to output fresh HCL from dynamic threat models). You can also directly save them into a file with the -output
flag.
$ threatcl export -format=otm examples/tm1.hcl
[{"assets":[{"description":"including the imperial state crown","id":"crown-jewels","name":"crown jewels","risk":{"availability":0,"confidentiality":0,"integrity":0}}],"mitigations":[{"attributes":{"implementation_notes":"They are trained to be guards as well","implemented":true},"description":"Lots of guards patrol the area","id":"lots-of-guards","name":"Lots of Guards","riskReduction":80}],"otmVersion":"0.2.0","project":{"attributes":{"initiative_size":"Small","internet_facing":true,"network_segment":"dmz","new_initiative":true},"description":"A historic castle","id":"tower-of-london","name":"Tower of London","owner":"@xntrik"},"threats":[{"categories":["Confidentiality"],"description":"Someone who isn't the Queen steals the crown","id":"threat-1","name":"Threat 1","risk":{"impact":0,"likelihood":null}}]},{"assets":[{"description":"Lots of gold","id":"gold","name":"Gold","risk":{"availability":0,"confidentiality":0,"integrity":0}}],"mitigations":[{"attributes":{"implemented":true},"description":"A large wall surrounds the fort","id":"big-wall","name":"Big Wall","riskReduction":80}],"otmVersion":"0.2.0","project":{"attributes":{"initiative_size":"Small","internet_facing":true,"new_initiative":false},"description":"A .. fort?","id":"fort-knox","name":"Fort Knox","owner":"@xntrik"},"threats":[{"categories":["Confidentiality"],"description":"Someone steals the gold","id":"threat-1","name":"Threat 1","risk":{"impact":0,"likelihood":null}}]}]
The threatcl generate
command is used to either output a generic boilerplate
threatcl
spec HCL file, or, interactively ask the user questions to then output a threatcl
spec HCL file.
See the following example of:
threatcl generate interactive
If you prefer to work directly in your $EDITOR
then run:
threatcl generate interactive editor
This will open your editor with a barebones HCL threat model. If you want to validate the model after creation, then use the -validate
flag.
The threatcl dashboard
command takes threatcl
spec HCL files, and generates a number of markdown and png files, dropping them into a selected folder.
$ threatcl dashboard -overwrite -outdir=dashboard-example examples/*
Created the 'dashboard-example' directory
Writing dashboard markdown files to 'dashboard-example' and overwriting existing files
Successfully wrote to 'dashboard-example/tm1-toweroflondon.md'
Successfully wrote to 'dashboard-example/tm1-fortknox.md'
Successfully wrote to 'dashboard-example/tm2-modellymodel.png'
Successfully wrote to 'dashboard-example/tm2-modellymodel.md'
Successfully wrote to 'dashboard-example/dashboard.md'
The threatcl dashboard
command can also take optional flags to specify custom templates (as per Golang's text/template).
To specify a dashboard template file, use the -dashboard-template
flag. For an example, see dashboard-template.tpl.
To specify a threatmodel template file, use the -threatmodel-template
flag. For an example, see threatmodel-template.tpl.
The threatcl dashboard
command can also take an optional flag to specify a filename for the "index" generated dashboard file. By default this file is dashboard.md
. Use the -dashboard-filename
flag without an extension to change this filename.
As per the spec, a threatmodel
may include data_flow_diagram_v2
blocks. An example of a simple DFD is available here. The old, single-use-block data_flow_diagram
will be deprecated at some point, so it's better to use data_flow_diagram_v2
named blocks, that way you can have multiple associated DFDs.
The threatcl dfd
command takes threatcl
spec HCL files, and generates a number of png files, dropping them into a selected folder.
If the HCL file doesn't include a threatmodel
block with a data_flow_diagram
or data_flow_diagram_v2
block, then nothing is output.
The command itself is very similar to the Dashboard command.
$ threatcl dfd -overwrite -outdir testout examples/*
Successfully created 'testout/tm2-modellymodel.png'
If your threatmodel
doesn't include a diagram_link
, but does include a data_flow_diagram
, then this will also be rendered when running threatcl dashboard
.
The threatcl terraform
command is able to extract data resources from the terraform show -json
docs here output of plan files, or active state files, and convert these into drafted information_asset
blocks for inclusion in threatcl
files.
If you're in a folder with existing state, you can execute the following:
terraform show -json | threatcl terraform -stdin
This will output something similar to this:
information_asset "aws_rds_cluster default" {
description = "cluster_identifier: aurora-cluster-demo, database_name: mydb"
information_classification = ""
source = "terraform state"
}
information_asset "aws_s3_bucket example" {
description = "bucket: terraform-20211107232017071500000001"
information_classification = ""
source = "terraform state"
}
You can also see similar output from a plan file that hasn't yet been applied with Terraform by running:
terraform show -json <plan-file> | threatcl terraform -stdin
If you want to update an existing threatcl
threat model file ("threatmodel.hcl") you can with:
terraform show -json <plan> | threatcl terraform -stdin -add-to-existing=threatmodel.hcl > new-threatmodel.hcl
With the -add-to-existing
flag, you can also specify -tm-name=<string>
if you need to specify a particular threat model from the source file, if there are multiple. And you can also apply a default classification, with the -default-classification=Confidential
flag.
These commands can also take a file as input too, in which case, omit the -stdin
flag.
The terraform resources that threatcl
is aware of are hard coded in pkg/terraform/terraform.go. If you want the threatcl terraform
command to output other information_asset
resources that aren't in there, you can supply your own version of this json via the -tf-collection=<json file>
flag.