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.

Shift-left IaC scanning pipeline
Shift-left IaC scanning pipeline

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:

StageWhere the issue is foundAverage cost to fixWhy the cost grows
DevelopmentDeveloper's IDE / pre-commit hook~$80One person, one file, one edit
Code reviewPull-request review~$240Reviewer plus author context-switch
CI pipelineBuild / test / scan job~$960Pipeline minutes, re-runs, branch coordination
StagingDeployed to staging~$7,600Test-data state and downstream system impact
ProductionLive customer-impacting deployment~$7,600+Incident response, rollback, post-mortems
Post-breachAfter 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.

CategoryAcronymScopeNotes
Static Application Security TestingSASTSource code in 7 languages plus Kubernetes manifestssemgrep-based analysis plus dedicated per-language scanners · OWASP Top 10 · CWE-mapped
Infrastructure-as-Code scanningIaCTerraform · CloudFormation · ARM · Bicep · Helm · Kustomize · raw K8s YAML · Pulumi · Ansible · Dockerfile340+ Terraform rules plus per-format coverage
Software Composition AnalysisSCAOpen-source dependency CVEs · license compliance · transitive analysis · SBOM generationAll major language ecosystems
Dynamic Application Security TestingDASTRuntime fuzzing of HTTP APIs and web apps479 attack payloads · OWASP API Top 10 · injection and auth-bypass
Secrets detectionSecretsHardcoded credentials in any file120+ 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:

LanguageFrameworks and focus
PythonDjango, Flask, FastAPI, SQLAlchemy
JavaScript / TypeScriptNode.js, React, Express, Next.js, NestJS
JavaSpring Boot, Spring MVC, Hibernate
Gonet/http, Gin, Echo, GORM
C# / .NETASP.NET Core, Entity Framework
CMemory safety, buffer overflows
C++Memory safety, buffer overflows
Kubernetes YAMLPod 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.

IaC framework coverage — Terraform, CloudFormation, Kubernetes, and other template families converging on one engine
IaC framework coverage — Terraform, CloudFormation, Kubernetes, and other template families converging on one engine
FamilyVariants supportedNotes
Terraform / OpenTofuAWS (200+ resources), Azure (150+), GCP (130+), Kubernetes providerModule recursion supported · .tf and .tf.json
AWS CloudFormationSAM, native CFN (YAML / JSON), CDK synth outputCDK is scanned post-synth, not the TypeScript / Python source
KubernetesHelm charts (.tgz plus values.yaml plus rendered manifests), Kustomize overlays and bases, raw YAML, CRDsHelm rendering is performed by the scanner — pass the chart, not the rendered output
OtherAzure ARM and Bicep, Pulumi (Python / TypeScript), Ansible playbooks and roles, Dockerfiles / ContainerfilesPulumi 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_BRANCH

Jenkins

// 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

FindingSeverityCWELanguage
SQL injection via f-stringCriticalCWE-89Python
Command injection via subprocessCriticalCWE-78Python, Node.js
Hardcoded credentialsHighCWE-798All
Path traversalHighCWE-22All
XSS via unescaped outputHighCWE-79JS/TS
Insecure deserializationHighCWE-502Java, Python
SSRF via unvalidated URLHighCWE-918All
JWT secret hardcodedHighCWE-798All
Weak cryptography (MD5/SHA1)MediumCWE-327All
Missing CSRF protectionMediumCWE-352Web frameworks

IaC finding examples

FindingSeverityResource type
S3 bucket with public ACLCriticalaws_s3_bucket
Security group: SSH open to 0.0.0.0/0Criticalaws_security_group
RDS instance not encryptedHighaws_db_instance
EKS node group with public endpointHighaws_eks_cluster
Privileged container in pod specHighKubernetes Pod
cluster-admin binding in Helm chartHighKubernetes ClusterRoleBinding
Lambda function with admin roleHighaws_iam_role
Terraform state in unencrypted S3Mediumterraform_backend
Missing resource limits in K8sMediumKubernetes Deployment
Docker image using latest tagMediumDockerfile

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".

CategoryPatterns includeWhy it's dangerous
Cloud credentialsAWS access keys, GCP service account JSON, Azure client secrets, OCI API keysFull account compromise
API keysGitHub PAT, GitLab PAT, Slack, Stripe, Twilio, SendGrid, OpenAI, AnthropicDirect service abuse and billing fraud
Database credentialsPostgreSQL / MySQL / MongoDB connection strings, Redis URLs with authDirect data access
Certificates and keysRSA / EC private key PEM, PKCS12, SSH private keysTLS termination and client-cert bypass
Generic patternsHigh-entropy strings, password= and secret= assignments, bearer tokens in codeCatch-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

FormatUse case
SARIFGitHub Security tab, VS Code, any SARIF-compatible tool — recommended default
JUnit XMLJenkins, Azure DevOps test reports
JSONAPI consumption, custom dashboards, SIEM ingestion
HTMLHuman-readable report for non-developer stakeholders
PDFAudit 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}/findings

Webhook 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