Ansible Lint Integration with DefectDojo
Ansible Lint Integration with DefectDojo
Ansible Lint (ansible-lint) is an open source linter for Ansible playbooks, roles, and collections, maintained within the Ansible project on GitHub. It checks content against a rule set that covers correctness and idiom as well as security-relevant patterns, such as world-writable file permissions, shell use where a module exists, and certificate validation being turned off. It can write its results as Code Climate formatted JSON, which DefectDojo imports.
Ansible Lint Integration with DefectDojo
Our infrastructure is mostly Ansible, and ansible-lint already runs in the pull request checks for those repositories. The problem was that its output vanished with each build log, and nobody could tell whether the risky permission settings flagged last quarter had ever been fixed. Importing ansible-lint JSON into DefectDojo gives every violation a Finding with its rule, file, and line, keeps the rule categories so we can separate security issues from style, and lets reimports close what the team fixes.
Why Ansible Lint Matters
Ansible playbooks run with real privileges against real servers, so a sloppy task can become a security problem on every host it touches.
- Rules like
risky-file-permissionsandcommand-instead-of-shellcatch patterns that weaken hosts or make tasks harder to reason about. - It runs on the source, before anything is applied, which is the cheapest place to fix configuration mistakes.
- Each rule carries categories, which lets security teams focus on the subset that matters to them.
- Linters are noisy by nature. Without a place to triage, suppress, and track results, teams tend to ignore the output entirely.
Advantages of This Integration
- Rule-level tracking. The rule name (
check_name) is stored as the vuln ID from tool and is part of the dedupe hash, so each rule violation in each file and line is tracked on its own. - Security versus style. Every finding's description lists the rule's categories, so security-relevant findings can be filtered from idiom and formatting ones.
- Reimport lifecycle. Reimporting a new report into the same Test mitigates violations that were fixed and adds new ones.
- Direct links to rule docs. Each finding's references point to the ansible-lint documentation page for that rule.
- Same workflow as code findings. IaC issues get SLAs, assignment, Jira pushes, and false positive handling next to the application's SAST and SCA results.
How This Integration Works
1. Generate a JSON report. Run ansible-lint with JSON output against a playbook or your project:
ansible-lint -f json playbook.yml > ansible-lint.json
ansible-lint returns a non-zero exit code when it finds violations, so make sure your pipeline step still uploads the report in that case.
Keep in mind what you are importing. ansible-lint is a general linter, not only a security scanner, and a typical first report on an older codebase is dominated by naming and idiom rules such as name[play]. That is fine, because DefectDojo keeps each rule's categories on the Finding, but it is worth deciding up front whether the security team or the platform team owns the non-security results. Many teams import everything into one Test and then build a saved filter for the security-relevant rules.
The report is a JSON array of issues. Each issue carries a rule name, categories, a severity, a description, a link to the rule's documentation, a location, and a fingerprint. An empty array (a clean run) imports zero findings.
2. Import it. In the UI, open the Engagement, choose Import Scan Results, select Ansible Lint Scan, and upload the file. For automation, use the API (Community Edition or DefectDojo Pro):
curl "https://YOUR_INSTANCE/api/v2/import-scan/"
-H "Authorization: Token $DD_API_TOKEN"
-F "scan_type=Ansible Lint Scan"
-F "file=@ansible-lint.json"
-F "product_name=infra-playbooks"
-F "engagement_name=CI"
-F "auto_create_context=true"
DefectDojo Pro users can call Universal Importer from the pipeline instead:
universal-importer import
--defectdojo-url "https://YOUR_INSTANCE.cloud.defectdojo.com/"
--scan-type "Ansible Lint Scan"
--report-path "./ansible-lint.json"
--product-name "infra-playbooks"
--engagement-name "CI"
--auto-create-context
3. Reimport on each run. For the main branch, send later reports to /api/v2/reimport-scan/ against the same Test so the open list always reflects the current code.
Data Granularity: What Gets Imported
| DefectDojo Field | Source in ansible-lint Report | Notes |
|---|---|---|
| Title | check_name and description |
Formatted as rule: description; rule name alone if no description |
| Severity | severity |
blocker: Critical, critical: High, major: Medium, minor: Low, info: Info; anything else Low |
| Description | Description, rule, categories, location | Categories listed for filtering |
| File Path | location.path |
Relative path in the project |
| Line | location.positions.begin.line or location.lines.begin |
Both location formats handled |
| Vuln ID from Tool | check_name |
The rule identifier |
| Unique ID from Tool | fingerprint |
Stable per rule violation per file |
| References | url |
Link to the rule's documentation |
| Finding type | Static | Source analysis |
| Deduplication | Hashcode | vuln_id_from_tool, file_path, line |
Use Cases
In pull request checks: Each merge to main runs ansible-lint and reimports the report. The platform team sees new violations introduced by the change, and fixed ones close on their own.
Security-focused triage: A security engineer filters findings whose description lists security-relevant rules, such as risky file permissions or shell use, and assigns those to role owners while leaving style rules to the team's own backlog.
Shared roles across teams: An organization with a central role library imports each repository into its own Asset. When a shared role has a risky task, reporting shows every Asset that carries it.
Hardening programs: During a push to clean up legacy playbooks, the team sets an SLA for High and above and tracks burn-down in DefectDojo metrics instead of rerunning the linter and counting lines.
Operational Tips
- ansible-lint uses the Code Climate severity scale, so
criticalin its output becomes High in DefectDojo, and onlyblockerbecomes Critical. - Line number is part of the dedupe hash. Inserting lines above a violation can shift it and make it look new on reimport, so expect some churn after large edits.
- Use
minimum_severityto keepinfoandminorresults out until the team has worked through the rest. - Use tags such as the repository or role name on import to make cross-repository filtering easy.
- Mark style rules your team has decided not to enforce as false positives, or better, disable them in the ansible-lint configuration so they never reach DefectDojo.
- Run ansible-lint against the same paths every time. Changing the scope between runs makes reimport mitigate findings that simply weren't scanned.