Rustmaninoff: IaC Security Scanner
Attribute scanner for Terraform, CloudFormation, Kubernetes, and Dockerfiles. Policies are Checkov-compatible YAML and reuse published CKV ids. The engine is not a port of the Checkov Python runtime.
Built-in policies are rewritten YAML, attributed to Checkov (Bridgecrew / Palo Alto Networks, Apache-2.0).
Build
Requires Rust 1.95 or newer.
Scan
Exit codes: 0 when nothing fails the threshold, 1 when a finding is at or above --fail-on (default HIGH) or a file fails to parse, 2 on usage errors. --soft-fail always exits 0.
Interpolations (${...}, Fn::*, !Ref, !GetAtt) are unknown. Unknown results do not fail the process. Pass --show-unknown to print them.
Inline skip: # checkov:skip=CKV_AWS_3:reason. Kubernetes annotation value: checkov.io/skip: CKV_K8S_16=reason.
Optional .rustmaninoff.yaml:
frameworks:
skip_checks:
fail_on: HIGH
excluded_paths:
external_checks_dirs:
show_unknown: false
compact: false
Directories named .git, .terraform, .terragrunt-cache, node_modules, vendor, and target are skipped. Symbolic links are not followed. Files larger than 10 MB, and files past the nesting or YAML-alias limits, are reported as diagnostics and are not parsed.
v0.2 scope
- Terraform
.tfand.tf.jsonmanagedresourceblocks anddatasources. Data sources are emitted as IR resources with kinddataand typedata.TYPEso policies can target them. No module download and no full HCL evaluation. - CloudFormation YAML and JSON
Resources. Attribute paths are relative toProperties. - Kubernetes multi-document YAML, including
List. - Dockerfiles (
Dockerfile,Containerfile,*.dockerfile): FROM, USER, ADD vs COPY, HEALTHCHECK, and privileged-ish RUN patterns. - 181 built-in checks (94 Terraform, 51 CloudFormation, 32 Kubernetes, 4 Docker). Each check has a pass fixture and a fail fixture.
- Text, JSON, SARIF 2.1.0, and JUnit reports.
S3 encryption, versioning, and logging on current Terraform target aws_s3_bucket_server_side_encryption_configuration, aws_s3_bucket_versioning, and aws_s3_bucket_logging. CKV_AWS_286 matches a static action subset, including * and *:*. CKV_K8S_14 accepts a digest or a tag other than latest; an image whose last colon is a registry port and which has no tag is treated as pinned.
Not in v0.2: graph checks (CKV2_*), Terraform plan JSON, remote modules, Helm, Kustomize, secrets scanning, full variable evaluation, and cfn-lint resource-spec validation.
Policy dialect
A check definition is the pass condition. Operators: equals, not_equals, exists, not_exists, contains, not_contains, within, regex_match, starting_with, ending_with, numeric comparisons, is_true, is_false, is_empty, length_greater_than, length_less_than, and their negated forms. Combinators: and, or, not.
Extensions: no_element, forbid_resource, equals_any, intersects, image_tag_pinned, and missing: pass|fail|unknown. scope is ignored. Severity defaults to MEDIUM when omitted.
Benchmark
Against Checkov and Trivy
Wall-clock time of each CLI on one synthetic corpus, Apple M2, macOS 14.8. Median of three runs after a warmup. Stdout was discarded. The corpus is 40 Terraform files (1,080 resources), 20 CloudFormation files (300 resources), and 20 Kubernetes files (160 resources).
| Scanner | Full corpus | Terraform | CloudFormation | Kubernetes |
|---|---|---|---|---|
| Rustmaninoff 0.2.0 | 20 ms | 11 ms | 9 ms | 11 ms |
| Checkov 3.3.21 | 4.51 s | 3.72 s | 2.71 s | 2.92 s |
| Trivy 0.74.0 | 5.71 s | 2.67 s | 1.29 s | 2.59 s |
On the full corpus that is about 225 times the Rustmaninoff time for Checkov, and about 285 times for Trivy. The catalogs are not the same: Rustmaninoff runs 181 attribute checks, Checkov runs its built-in checks for the selected frameworks, and Trivy runs its misconfiguration policies.
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#E07A3D, #2A9D8F, #3D5A80", "titleColor": "#C44536", "xAxisLineColor": "#E07A3D", "yAxisLineColor": "#2A9D8F", "xAxisTickColor": "#E9C46A", "yAxisTickColor": "#7B6CF6"}}}}%%
xychart-beta
title "CLI wall time on the full corpus"
x-axis [Rustmaninoff, Checkov, Trivy]
y-axis "seconds" 0 --> 6
bar "Rustmaninoff" [0.02, 0, 0]
bar "Checkov" [0, 4.51, 0]
bar "Trivy" [0, 0, 5.71]
Copper is Rustmaninoff, teal is Checkov, and steel blue is Trivy.
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#E07A3D, #2A9D8F, #E9C46A, #3D5A80, #C44536, #7B6CF6", "titleColor": "#C44536", "xAxisLineColor": "#E07A3D", "yAxisLineColor": "#2A9D8F", "xAxisTickColor": "#E9C46A", "yAxisTickColor": "#7B6CF6"}}}}%%
xychart-beta
title "Times slower than Rustmaninoff"
x-axis [Terraform, CloudFormation, Kubernetes]
y-axis "times slower" 0 --> 360
bar "Checkov" [345, 288, 263]
bar "Trivy" [247, 137, 234]
Copper is Checkov. Teal is Trivy.
Commands, release binary versus the other CLIs:
Engine stages
Release build, same synthetic corpus, Apple M2. Findings were 9,476. These times are in-process. They do not include CLI startup or report formatting, which is why they are lower than the CLI rows above.
| Stage | Time |
|---|---|
| Terraform, 40 files, 1,080 resources | 13.3 ms |
| Terraform, those files in parallel | 2.7 ms |
| One Terraform file, 400 resources | 3.2 ms |
| CloudFormation, 20 files, 300 resources | 2.8 ms |
| Kubernetes, 20 files, 160 resources | 4.3 ms |
| Full builtin pack on 1,540 resources | 7.9 ms |
CKV_AWS_3 on 2,000 volumes |
2.06 ms |
| Attribute lookup, 200,000 single keys | 5.9 ms |
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#E07A3D, #2A9D8F, #3D5A80, #E9C46A, #7B6CF6", "titleColor": "#C44536", "xAxisLineColor": "#E07A3D", "yAxisLineColor": "#2A9D8F", "xAxisTickColor": "#E9C46A", "yAxisTickColor": "#7B6CF6"}}}}%%
xychart-beta
title "In-process stage time"
x-axis ["TF", "TF parallel", "TF 400", "CFN", "K8s"]
y-axis "milliseconds" 0 --> 16
bar "TF" [13.3, 0, 0, 0, 0]
bar "TF parallel" [0, 2.7, 0, 0, 0]
bar "TF 400" [0, 0, 3.2, 0, 0]
bar "CFN" [0, 0, 0, 2.8, 0]
bar "K8s" [0, 0, 0, 0, 4.3]
Builtin YAML is parsed once per process (about 6 ms) and reused. Repeat the stage measurement with cargo run --release -p rustmaninoff --example stages.
Install
Release
Pushing the tag v0.2.0 runs .github/workflows/release.yml. It publishes Linux and macOS binaries for amd64 and arm64, each with a SHA-256 checksum.
- uses: actions/checkout@v4
- run: cargo install --path crates/cli --locked
- run: rustmaninoff scan . --fail-on HIGH --output sarif --sarif-file rustmaninoff.sarif
License
Apache-2.0. See LICENSE.