IaC Scanning & SecOps
Onam's SecOps engine scans Infrastructure-as-Code templates, application code, and open-source dependencies before they reach production — at pull-request time, in CI, and on demand. The goal is to catch security issues at the earliest, cheapest point in the SDLC: in the editor, before merge, before the pipeline deploys, before a real cloud resource exists.
This page covers the shift-left cost model, the five scan categories (SAST, IaC, SCA, DAST, secrets), language and template coverage, CI/CD integration with working configs, and the finding catalog.
The Shift-Left Model
The further left you catch an issue, the cheaper the fix. These are industry averages from IBM's Cost of a Data Breach report and NIST's software cost estimation studies:
| Stage | Where the issue is found | Average cost to fix | Why the cost grows |
|---|---|---|---|
| Development | Developer's IDE / pre-commit hook | ~$80 | One person, one file, one edit |
| Code review | Pull-request review | ~$240 | Reviewer plus author context-switch |
| CI pipeline | Build / test / scan job | ~$960 | Pipeline minutes, re-runs, branch coordination |
| Staging | Deployed to staging | ~$7,600 | Test-data state and downstream system impact |
| Production | Live customer-impacting deployment | ~$7,600+ | Incident response, rollback, post-mortems |
| Post-breach | After a security incident | $4M+ | IBM 2024 average — detection, response, notification, fines |
Onam runs at every stage — IDE plugin, GitHub PR / GitLab MR comments, CI integration, and the unified posture dashboard. One rule catalog evaluates the same misconfiguration consistently across all stages, so a rule that fires in production CSPM also fires on the Terraform that would create it.
Capabilities
Five scan categories ship out of the box. Enable them individually per repository or run them together in one integrated scan.
| Category | Acronym | Scope | Notes |
|---|---|---|---|
| Static Application Security Testing | SAST | Source code in 7 languages plus Kubernetes manifests | semgrep-based analysis plus dedicated per-language scanners · OWASP Top 10 · CWE-mapped |
| Infrastructure-as-Code scanning | IaC | Terraform · CloudFormation · ARM · Bicep · Helm · Kustomize · raw K8s YAML · Pulumi · Ansible · Dockerfile | 340+ Terraform rules plus per-format coverage |
| Software Composition Analysis | SCA | Open-source dependency CVEs · license compliance · transitive analysis · SBOM generation | All major language ecosystems |
| Dynamic Application Security Testing | DAST | Runtime fuzzing of HTTP APIs and web apps | 479 attack payloads · OWASP API Top 10 · injection and auth-bypass |
| Secrets detection | Secrets | Hardcoded credentials in any file | 120+ patterns — see below |
A typical PR scan completes in 30–90 seconds for a ~50K LOC repo. Monorepos of 1M+ LOC take 5–10 minutes; PR-webhook scans are incremental and only analyze changed files.
SAST Language Coverage
SAST covers seven languages, each with a dedicated scanner plus shared semgrep rules, and additionally scans Kubernetes YAML manifests:
| Language | Frameworks and focus |
|---|---|
| Python | Django, Flask, FastAPI, SQLAlchemy |
| JavaScript / TypeScript | Node.js, React, Express, Next.js, NestJS |
| Java | Spring Boot, Spring MVC, Hibernate |
| Go | net/http, Gin, Echo, GORM |
| C# / .NET | ASP.NET Core, Entity Framework |
| C | Memory safety, buffer overflows |
| C++ | Memory safety, buffer overflows |
| Kubernetes YAML | Pod specs, RBAC, network policies |
IaC Framework Coverage
A rule like "S3 bucket public access not blocked" fires identically against Terraform, CloudFormation, Pulumi, and Helm — wherever the template surfaces the misconfiguration. The rule catalog is unified across template languages, so there are not four rule sets to maintain.
| Family | Variants supported | Notes |
|---|---|---|
| Terraform / OpenTofu | AWS (200+ resources), Azure (150+), GCP (130+), Kubernetes provider | Module recursion supported · .tf and .tf.json |
| AWS CloudFormation | SAM, native CFN (YAML / JSON), CDK synth output | CDK is scanned post-synth, not the TypeScript / Python source |
| Kubernetes | Helm charts (.tgz plus values.yaml plus rendered manifests), Kustomize overlays and bases, raw YAML, CRDs | Helm rendering is performed by the scanner — pass the chart, not the rendered output |
| Other | Azure ARM and Bicep, Pulumi (Python / TypeScript), Ansible playbooks and roles, Dockerfiles / Containerfiles | Pulumi requires the synthesized state for full coverage |
CI/CD Integration
First-class integrations ship for the most common CI systems. Each runs the same scanner with the same rule catalog — only the orchestration differs.
GitHub Actions
# .github/workflows/onam-scan.yml
name: Onam Security Scan
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Onam IaC + SAST Scan
uses: onam-io/secops-scan-action@v1
with:
api-key: ${{ secrets.ONAM_API_KEY }}
scan-types: iac,sast,sca,secrets
fail-on: CRITICAL,HIGH
paths: |
terraform/
k8s/
src/
- name: Upload SARIF Results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: onam-results.sarif
if: always()The action scans IaC templates and application code, checks dependencies (SCA), detects secrets, fails the job on Critical or High findings, and uploads SARIF to the GitHub Security tab.
GitLab CI
# .gitlab-ci.yml
onam-security-scan:
stage: test
image: onam/secops-scanner:latest
script:
- onam scan --type iac,sast,sca,secrets
--api-key $ONAM_API_KEY
--fail-on CRITICAL,HIGH
--output sarif
artifacts:
reports:
sast: onam-results.sarif
when: always
rules:
- if: $CI_MERGE_REQUEST_IID
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHJenkins
// Jenkinsfile
pipeline {
agent any
stages {
stage('Onam Security Scan') {
steps {
sh '''
onam scan \
--type iac,sast,sca,secrets \
--api-key ${ONAM_API_KEY} \
--fail-on CRITICAL,HIGH \
--output junit \
--output-file onam-results.xml
'''
}
post {
always {
junit 'onam-results.xml'
}
}
}
}
}Azure DevOps, CircleCI, Bitbucket Pipelines, and Buildkite use the same onam CLI.
Finding Categories
Findings come in two main dimensions — SAST findings (application code) and IaC findings (infrastructure templates). Each carries severity, CWE / CIS mappings, and a remediation suggestion.
SAST finding examples
| Finding | Severity | CWE | Language |
|---|---|---|---|
| SQL injection via f-string | Critical | CWE-89 | Python |
| Command injection via subprocess | Critical | CWE-78 | Python, Node.js |
| Hardcoded credentials | High | CWE-798 | All |
| Path traversal | High | CWE-22 | All |
| XSS via unescaped output | High | CWE-79 | JS/TS |
| Insecure deserialization | High | CWE-502 | Java, Python |
| SSRF via unvalidated URL | High | CWE-918 | All |
| JWT secret hardcoded | High | CWE-798 | All |
| Weak cryptography (MD5/SHA1) | Medium | CWE-327 | All |
| Missing CSRF protection | Medium | CWE-352 | Web frameworks |
IaC finding examples
| Finding | Severity | Resource type |
|---|---|---|
| S3 bucket with public ACL | Critical | aws_s3_bucket |
Security group: SSH open to 0.0.0.0/0 | Critical | aws_security_group |
| RDS instance not encrypted | High | aws_db_instance |
| EKS node group with public endpoint | High | aws_eks_cluster |
| Privileged container in pod spec | High | Kubernetes Pod |
cluster-admin binding in Helm chart | High | Kubernetes ClusterRoleBinding |
| Lambda function with admin role | High | aws_iam_role |
| Terraform state in unencrypted S3 | Medium | terraform_backend |
| Missing resource limits in K8s | Medium | Kubernetes Deployment |
Docker image using latest tag | Medium | Dockerfile |
Secrets Detection Patterns
120+ secret patterns across five categories. Each pattern combines a regex with an entropy or format check — high-entropy strings that match no known pattern are also flagged as "possible generic secret".
| Category | Patterns include | Why it's dangerous |
|---|---|---|
| Cloud credentials | AWS access keys, GCP service account JSON, Azure client secrets, OCI API keys | Full account compromise |
| API keys | GitHub PAT, GitLab PAT, Slack, Stripe, Twilio, SendGrid, OpenAI, Anthropic | Direct service abuse and billing fraud |
| Database credentials | PostgreSQL / MySQL / MongoDB connection strings, Redis URLs with auth | Direct data access |
| Certificates and keys | RSA / EC private key PEM, PKCS12, SSH private keys | TLS termination and client-cert bypass |
| Generic patterns | High-entropy strings, password= and secret= assignments, bearer tokens in code | Catch-all for unknown formats |
Pre-commit integration is available via pre-commit-onam-secrets — the same pattern set runs locally on every commit and blocks secrets before they ever reach the remote. Once a secret is pushed, rotating it is the only safe remediation; scrubbing git history is not enough.Output Formats
| Format | Use case |
|---|---|
| SARIF | GitHub Security tab, VS Code, any SARIF-compatible tool — recommended default |
| JUnit XML | Jenkins, Azure DevOps test reports |
| JSON | API consumption, custom dashboards, SIEM ingestion |
| HTML | Human-readable report for non-developer stakeholders |
| Audit and compliance evidence |
API
# List SecOps findings for a repository
GET /api/v1/secops/findings?repo=github.com/org/repo&severity=CRITICAL
# Trigger a scan on a repository
POST /api/v1/secops/scan
Content-Type: application/json
{"repo_url": "https://github.com/org/repo", "branch": "main", "scan_types": ["iac", "sast", "sca"]}
# Get scan results by scan ID
GET /api/v1/secops/scans/{scan_id}/findingsWebhook delivery on every completed scan can be configured under Settings → Notifications.
FAQ
How does SecOps integrate with branch protection? The PR / MR integration posts a status check you can require in branch protection. Critical or High findings fail the check, blocking merge until resolved or suppressed.
Can I suppress a finding I've reviewed and accepted? Yes. Suppressions are file-and-line-anchored, require a documented justification, follow the file if it moves, and expire after 90 days by default unless renewed.
Does SCA scan dependencies recursively? Yes — full transitive analysis. A vulnerability in a dependency-of-a-dependency surfaces with its full path, so you can decide whether to bump the direct dependency or wait upstream.
Can I run SecOps on monorepos? Yes. Path-based scoping scans only changed paths on PRs, with per-path rule profiles (stricter for production/ than playground/).
What about AI-generated code? SAST treats it identically to human-written code. AI-generated code shows a slightly higher rate of hardcoded credentials and incomplete input validation — the same catalog catches both.
Can I use SecOps in air-gapped environments? Yes — on-premises deployment on Enterprise plans. The scanner runs entirely in your network, with rule updates pulled via a one-way mirror.
Next steps
- Vulnerability Management — the runtime side of the same CVE data
- Container Security — what happens to Helm and pod-spec issues after deploy
- Integration catalog — every supported CI, ticketing, and notification integration
- CSPM — the production-side rule catalog that mirrors these IaC rules