Security Scanning Pipelines
KubeRocketCI provides automated security scanning at three levels of the software delivery lifecycle: source code, dependencies, and container images. Scanners are embedded into Tekton pipelines and report findings to DefectDojo, Dependency-Track, and SonarQube.
| Tool | Category | Report Destination | DefectDojo Scan Type |
|---|---|---|---|
| Semgrep | SAST | DefectDojo | Semgrep JSON Report |
| Gitleaks | Secret Detection | DefectDojo | Gitleaks Scan |
| CycloneDX cdxgen | SCA / SBOM | Dependency-Track | N/A (direct API upload) |
| SonarQube | SAST + Code Quality | SonarQube server | N/A |
| Trivy | Container Vulnerability Scan | DefectDojo | Trivy Scan |
| Anchore Grype | Container Vulnerability Scan | DefectDojo | Anchore Grype |
| Hadolint | Dockerfile Linting | Pipeline log | N/A |
| Helm chart-testing | Helm Chart Linting | Pipeline log | N/A |
Pipeline Typesβ
Security scanning is distributed across three pipeline types. Each serves a different stage of the development workflow.
Build and Review Pipelinesβ
Build and review pipelines are language-specific and run for every codebase. They include SonarQube for code quality and security analysis, Hadolint for Dockerfile validation, and Helm chart-testing for chart linting.
Build pipeline β triggered on merge to a tracked branch:
Review pipeline β triggered on PR/MR creation or update:
For details on SonarQube configuration and Quality Gate behavior, refer to the SonarQube Integration page.
Security-Scan Pipelineβ
A dedicated pipeline that runs comprehensive security analysis independently from build/review. Available for all supported VCS providers (GitHub, GitLab, Gerrit, Bitbucket). Triggered via webhook or manually through the KubeRocketCI portal.
After cloning the repository, two tasks execute in parallel:
The pipeline returns two result URLs visible in the portal:
SCAN_REPORT_URLβ DefectDojo link to code security findings (Semgrep + Gitleaks)IMAGE_SCAN_REPORT_URLβ DefectDojo link to container image findings (Trivy + Grype)
Image-Scan-Remote Pipelineβ
An on-demand pipeline for scanning pre-built container images from remote registries without source code. Accepts an array of fully-qualified image references:
params:
- name: IMAGE_NAMES
value:
- "registry.example.com/myapp/backend:1.2.3"
- "registry.example.com/myapp/frontend:1.2.3"
- name: CODEBASE_NAME
value: "myapp"
Uses Trivy only (no Grype) and uploads results to DefectDojo with per-image engagements.
Scanner-to-Pipeline Matrixβ
| Scanner | Build Pipeline | Review Pipeline | Security-Scan Pipeline | Image-Scan-Remote |
|---|---|---|---|---|
| SonarQube | Yes | Yes (PR mode) | - | - |
| Semgrep | - | - | Yes | - |
| Gitleaks | - | - | Yes | - |
| cdxgen (SBOM) | - | - | Yes | - |
| Trivy | - | - | Yes | Yes |
| Grype | - | - | Yes | - |
| Hadolint | - | Yes | - | - |
| Helm Lint | - | Yes | - | - |
Scanner Referenceβ
This section describes each integrated scanner: what it detects, the command it runs, and where results are reported.
Source Code Scannersβ
Semgrep (SAST)β
Semgrep performs Static Application Security Testing across the entire source tree. It runs as the first step of the security task in the security-scan pipeline.
Command:
semgrep --jobs 1 --config=auto . --json \
--output semgrep-report.json --disable-version-check
Key behaviors:
- Uses
--config=autowhich downloads community and recommended rules from the Semgrep registry, selecting rules based on detected languages and frameworks. - Runs single-threaded (
--jobs 1) for stability in container environments. - Excludes
.docker/config.jsonvia a.semgrepignorefile created at scan time. - Produces a JSON report consumed by the DefectDojo upload step.
- Does not fail the pipeline on findings β results go to DefectDojo for triage.
DefectDojo mapping: scan type = Semgrep JSON Report, engagement = code-security-{branch}.
Gitleaks (Secret Detection)β
Gitleaks detects hardcoded secrets, API keys, passwords, and tokens in the source code. It runs as the second step of the security task.
Command:
gitleaks detect --source . --report-format=json \
--report-path=gitleaks-report.json \
--no-git --verbose --exit-code=0 --config=gitleaks.toml
Key behaviors:
--no-gitscans file content only (not git history), which is faster and avoids needing a full git clone.--exit-code=0ensures the pipeline does not fail on findings β all results are sent to DefectDojo.- Uses a custom
gitleaks.tomlconfig that excludes the.docker/directory.
DefectDojo mapping: scan type = Gitleaks Scan, engagement = code-security-{branch}.
CycloneDX cdxgen (SCA / SBOM)β
CycloneDX cdxgen generates a Software Bill of Materials (SBOM) from the project source and uploads it directly to Dependency-Track. It runs as the third step of the security task and is also available as a standalone cdxgen Tekton task.
Command:
/opt/cdxgen/bin/cdxgen.js \
--api-key=$API_TOKEN \
--server-url=$DEPTRACK_URL \
--project-name=$PROJECT_NAME \
--project-version=$PROJECT_BRANCH \
--print
Key behaviors:
- Automatically detects the project type (Maven, npm, pip, Go, etc.) and generates an appropriate SBOM.
- Uploads the SBOM directly to Dependency-Track via its API (not through DefectDojo).
--project-namemaps to the KubeRocketCI Codebase name (e.g.,my-java-app).--project-versionmaps to the git branch being scanned (e.g.,main,release/1.0).- If the
ci-dependency-tracksecret is missing or empty, the step is skipped gracefully.
After upload, Dependency-Track provides:
- Full dependency tree visualization
- Known vulnerability (CVE) matching against NVD and other feeds
- License risk analysis (GPL, Apache, MIT compliance)
- Policy evaluation (banned components, outdated versions)
- Audit workflow for triaging findings
- Project-level risk scoring
SonarQube (Code Quality and Security)β
SonarQube scanning is embedded in every build and review pipeline. It serves a dual purpose: code quality enforcement and security vulnerability detection. SonarQube is the only scanner that acts as a hard gate β if the Quality Gate fails, the pipeline fails.
SonarQube provides language-specific task variants:
| Task Name | Language | Build Tool |
|---|---|---|
sonarqube-maven | Java (Maven) | Maven plugin (sonar:sonar) |
sonarqube-gradle | Java (Gradle) | Gradle plugin (sonarqube) |
sonarqube-general | Go, Python, JS/TS | Standalone sonar-scanner-cli |
sonarqube-dotnet | C# / .NET | dotnet sonarscanner |
Each task performs three phases:
- Project setup β verifies SonarQube availability, auto-creates the project if missing (using the Codebase's default branch).
- Analysis β runs the scanner with branch-mode parameters (build pipeline) or pull-request-mode parameters (review pipeline).
- Quality Gate β with
sonar.qualitygate.wait=true, the scanner polls SonarQube until evaluation completes. A failed Quality Gate blocks artifact publishing (build) or sets a failing PR status (review).
SonarQube detects bugs, security vulnerabilities, security hotspots, code smells, coverage gaps, and code duplications.
For installation, configuration, and integration instructions, refer to the SonarQube Integration page.
Container Image Scannersβ
Container image scanning discovers and reports vulnerabilities in OS packages and application libraries baked into container images. KubeRocketCI provides multiple scanning approaches depending on the context.
Helm-Based Image Discovery (image-scan-chart)β
This is the primary approach, used in all security-scan pipelines. It renders the application's Helm chart to discover which container images are deployed, then scans each one.
Execution flow:
| Step | Description |
|---|---|
| discover-image-repository | Queries Kubernetes for the CodebaseImageStream CR to extract the image repository and latest tag |
| helm-template-and-extract | Runs helm template with image overrides from the previous step, then parses rendered manifests for all image: references |
| trivy | Scans each discovered image using Trivy in client/server mode, producing a JSON report per image |
| grype | Scans each discovered image using Anchore Grype, producing a JSON report per image |
| upload-report | Uploads all Trivy and Grype reports to DefectDojo with per-image engagements |
Key details:
- CodebaseImageStream lookup normalizes the branch name (lowercase, non-alphanumeric characters replaced with
-) to locate the correct resource. - Helm template uses
--set image.repositoryand--set image.tagoverrides so rendered manifests contain real production image references. - If no Helm chart exists at
deploy-templates/, the scan is skipped gracefully. - Trivy runs in client/server mode by default (server at
http://trivy-service.trivy-system:4954) for performance. It falls back to standalone mode if no server is configured. - Grype always runs standalone (no server mode).
- Both scanners use soft failure β a scan error on one image does not block other images from being scanned. Upload errors do fail the task.
Remote Registry Scanning (image-scan-remote)β
For scanning images that already exist in a remote registry, without needing source code or Helm charts. This approach uses Trivy only (no Grype) and creates per-image engagements in DefectDojo.
Build-Time TAR Scanning (image-scan)β
For scanning container images saved as TAR archives (e.g., output of kaniko --tarPath). Runs both Trivy and Grype. Uses a fixed DefectDojo engagement name container-security.
Standalone Trivy Check (trivy-scan)β
A lightweight task that scans a single image for HIGH and CRITICAL vulnerabilities only:
trivy image --scanners vuln --severity HIGH,CRITICAL "${TARGET_IMAGE}"
Results are printed to the pipeline log. No DefectDojo integration.
Infrastructure-as-Code Lintingβ
These tools run during review pipelines to catch issues before merge:
- Hadolint β validates Dockerfile best practices: pinned base images, proper instruction ordering, and shell best practices.
- Helm chart-testing β validates Helm chart structure, values schema, and template rendering using
ct lint.
Both tools block the review pipeline on failure.
DefectDojo Reporting Modelβ
Understanding how KubeRocketCI organizes findings in DefectDojo is essential for navigating scan results and configuring alerts.
Data Hierarchyβ
Product Type: "KubeRocketCI"
ββ Product: "{CODEBASE_NAME}"
ββ Engagement: "code-security-{branch}"
β ββ Test: "Semgrep JSON Report"
β β ββ Findings: [...]
β ββ Test: "Gitleaks Scan"
β ββ Findings: [...]
β
ββ Engagement: "image:registry.example.com/myapp:1.0.0"
β ββ Test: "Trivy Scan"
β β ββ Findings: [...]
β ββ Test: "Anchore Grype"
β ββ Findings: [...]
β
ββ Engagement: "image:nginx:1.25"
ββ Test: "Trivy Scan"
ββ Test: "Anchore Grype"
- Product Type β
KubeRocketCI(configurable viaDD_PRODUCT_TYPE_NAME). Groups all platform codebases. - Product β one per KubeRocketCI Codebase. Named after the Codebase (e.g.,
my-java-app). - Engagement β groups related scans. Naming depends on the scan source (see table below).
- Test β one per scanner execution. Holds the actual findings.
Engagement Naming Strategyβ
| Scan Source | Engagement Name | Rationale |
|---|---|---|
| Code security scans | code-security or code-security-{branch} | One engagement per branch for SAST and secret findings |
| Container image scans | image:{full-image-reference} | One engagement per image to prevent close_old_findings from cross-contaminating findings between different images |
| TAR image scans | container-security | Fixed engagement for build-time scanning |
Upload Mechanismβ
All uploads use the DefectDojo reimport-scan API:
POST {DD_HOST_URL}/api/v2/reimport-scan/
Authorization: Token {DD_TOKEN}
Content-Type: multipart/form-data
Standard parameters sent with every upload:
| Parameter | Value | Purpose |
|---|---|---|
scan_date | Current date (YYYY-MM-DD) | When the scan was performed |
minimum_severity | Info | Import all severity levels |
active | true | Mark findings as active |
verified | false | Findings require human verification |
auto_create_context | true | Auto-create product, engagement, and test if missing |
close_old_findings | true | Close findings from previous scans that are no longer present |
push_to_jira | false | No automatic Jira integration |
environment | Development | Environment classification |
product_type_name | KubeRocketCI | Product type grouping |
product_name | {CODEBASE_NAME} | Maps to the KubeRocketCI Codebase |
Result URLsβ
After upload, pipeline tasks return clickable DefectDojo URLs as results:
- Single image scanned:
{DD_HOST_URL}/engagement/{ENGAGEMENT_ID} - Multiple images scanned:
{DD_HOST_URL}/product/{PRODUCT_ID}(shows all engagements)
These URLs appear in the KubeRocketCI portal pipeline run details.
Configurationβ
Required Secretsβ
| Secret Name | Keys | Used By | Purpose |
|---|---|---|---|
ci-defectdojo | token, url | security, image-scan-chart, image-scan-remote, image-scan tasks | DefectDojo report upload |
ci-dependency-track | token, url | security task (cdxgen step), standalone cdxgen task | SBOM upload to Dependency-Track |
ci-sonarqube | token, url | All sonarqube-* tasks | SonarQube analysis |
ci-nexus | username, password | sonarqube-maven, sonarqube-gradle tasks | Maven/Gradle artifact resolution during Sonar analysis |
All security-related secrets are optional at the task level. If a secret is missing, the corresponding step is skipped gracefully. This means you can incrementally adopt tools: start with SonarQube only, then add DefectDojo, then Dependency-Track.
For secret provisioning instructions, refer to:
Helm Chart Settingsβ
Security scanning pipelines are controlled by the following values.yaml settings in the pipelines-library Helm chart:
global:
gitProviders:
- github # Determines which security-scan pipeline variants are deployed
- gitlab
pipelines:
deployableResources:
security: true # Enable/disable all security-scan pipelines and tasks
java:
java25SkipSonar: true # Skip SonarQube for Java 25
tekton:
workspaceSize: 7Gi # PVC size for pipeline workspaces
| Setting | Effect |
|---|---|
pipelines.deployableResources.security | When true, deploys all security-scan pipelines, tasks, and triggers |
global.gitProviders | Controls which VCS-specific pipeline variants are deployed (e.g., github-security-scan) |
java25SkipSonar | When true, omits SonarQube from Java 25 pipelines (SonarQube does not yet support Java 25) |
External Servicesβ
| Service | Default Endpoint | Purpose |
|---|---|---|
| Trivy Server | http://trivy-service.trivy-system:4954 | Centralized vulnerability database for faster container scans |
| SonarQube | From ci-sonarqube secret | Static analysis and Quality Gate evaluation |
| DefectDojo | From ci-defectdojo secret | Vulnerability management and reporting |
| Dependency-Track | From ci-dependency-track secret | SBOM storage, dependency vulnerability tracking, license analysis |
End-to-End Example: Java Maven Applicationβ
This section walks through the complete security scanning lifecycle of a Java Maven application called payment-service on KubeRocketCI.
Setup:
- Codebase:
payment-service(registered in KubeRocketCI) - Git provider: GitHub
- Branch:
main - Container image:
registry.example.com/payment-service:0.1.0-SNAPSHOT.42 - Helm chart:
deploy-templates/withimage.repositoryandimage.tagvalues
Phase 1: Developer Opens a Pull Requestβ
A developer pushes a feature branch and opens a PR against main. GitHub fires a webhook, and the review pipeline starts.
Pipeline: github-maven-java17-app-review
| Step | Task | What Happens |
|---|---|---|
| 1 | fetch-repository | Clones the PR branch |
| 2 | init-values | Reads Codebase/CodebaseBranch CRs for pipeline config |
| 3 | get-cache | Restores Maven .m2/repository cache |
| 4 | compile | Runs mvn compile |
| 5 | test | Runs mvn verify with JaCoCo coverage |
| 6 | sonar | SonarQube PR analysis (see below) |
| 7 | build | Runs mvn package -DskipTests |
| 8 | save-cache | Saves Maven cache for next run |
| 9 | dockerfile-lint | Hadolint validates Dockerfile |
| 10 | dockerbuild-verify | Dry-run container build (no push) |
| 11 | helm-lint | chart-testing validates deploy-templates/ |
| finally | set-status | Reports pass/fail back to GitHub PR |
SonarQube during review β the sonarqube-maven task runs:
mvn -s /var/configmap/settings.xml -B \
-Dsonar.projectKey=payment-service \
-Dsonar.projectName=payment-service \
-Dsonar.pullrequest.key=42 \
-Dsonar.pullrequest.branch=feature/add-refunds \
-Dsonar.pullrequest.base=main \
-Dsonar.qualitygate.wait=true \
-DskipTests verify sonar:sonar
Result in SonarQube: PR #42 appears as a decoration on the payment-service project. The Quality Gate evaluates new code coverage, bugs, vulnerabilities, and security hotspots. If the Quality Gate fails, the pipeline fails at step 6 and the GitHub PR status shows a red check.
Phase 2: PR Is Merged β Build Pipeline Runsβ
After the PR is approved and merged, the build pipeline triggers.
Pipeline: github-maven-java17-app-build-default
| Step | Task | What Happens |
|---|---|---|
| 1 | fetch-repository | Clones main branch |
| 2 | init-values | Reads Codebase CR metadata |
| 3 | get-version | Generates version: 0.1.0-SNAPSHOT.42 |
| 4 | get-cache | Restores Maven cache |
| 5 | update-build-number | Stamps version into the project |
| 6 | compile | Runs mvn compile |
| 7 | test | Runs mvn verify with JaCoCo |
| 8 | sonar | SonarQube branch analysis |
| 9 | build | Runs mvn package -DskipTests |
| 10 | push | Publishes JAR/WAR to Nexus |
| 11 | container-build | Kaniko builds and pushes container image |
| 12 | save-cache | Saves Maven cache |
| 13 | git-tag | Tags commit with 0.1.0-SNAPSHOT.42 |
| 14 | update-cbis | Updates CodebaseImageStream with new image tag and digest |
| finally | report-status | Reports to JIRA and GitHub |
SonarQube during build β branch analysis updates the main branch in SonarQube with the latest merged code, enabling long-lived branch trend tracking.
Phase 3: Security-Scan Pipeline Runsβ
The security-scan pipeline is triggered via webhook or manually from the portal.
Pipeline: github-security-scan
Two tasks run in parallel after fetch-repository:
Task A: security (SAST + Secrets + SCA)β
| Step | Tool | What Happens |
|---|---|---|
| A.1 | Semgrep | Scans all source files for vulnerabilities. Writes semgrep-report.json. |
| A.2 | Gitleaks | Scans file content for hardcoded secrets. Writes gitleaks-report.json. |
| A.3 | cdxgen | Analyzes pom.xml and transitive dependencies. Generates CycloneDX SBOM. Uploads to Dependency-Track as project payment-service, version main. |
| A.4 | Upload | Uploads Semgrep and Gitleaks reports to DefectDojo. |
What appears in DefectDojo after Task A:
Product: payment-service
ββ Engagement: "code-security-main"
ββ Test: "Semgrep JSON Report"
β ββ Finding: SQL Injection in PaymentDao.java:45 [HIGH]
β ββ Finding: Insecure Deserialization in WebConfig.java:112 [CRITICAL]
ββ Test: "Gitleaks Scan"
ββ Finding: AWS Access Key in application-dev.properties:7 [HIGH]
What appears in Dependency-Track after Task A:
Project: payment-service (version: main)
Components: 247
Vulnerabilities:
ββ CVE-2024-22262 β spring-web 6.1.4 [HIGH]
ββ CVE-2024-22243 β spring-web 6.1.4 [MEDIUM]
ββ CVE-2023-44487 β netty-codec-http2 4.1.97 [HIGH]
License Risk:
ββ 198 components: Apache-2.0
ββ 41 components: MIT
ββ 8 components: LGPL-2.1 (review required)
Task B: image-scan-chart (Container Scanning)β
| Step | What Happens |
|---|---|
B.1 discover-image-repository | Queries CodebaseImageStream for payment-service-main. Finds image: registry.example.com/payment-service, tag: 0.1.0-SNAPSHOT.42. |
B.2 helm-template-and-extract | Renders the Helm chart with image overrides. Discovers 2 images: registry.example.com/payment-service:0.1.0-SNAPSHOT.42 and nginx:1.25-alpine (sidecar). |
B.3 trivy | Scans both images against Trivy server. |
B.4 grype | Scans both images with Grype. |
B.5 upload-report | Uploads all 4 reports (2 images x 2 scanners) to DefectDojo. |
What appears in DefectDojo after Task B:
Product: payment-service
ββ Engagement: "code-security-main"
β ββ (Semgrep + Gitleaks findings from Task A)
β
ββ Engagement: "image:registry.example.com/payment-service:0.1.0-SNAPSHOT.42"
β ββ Test: "Trivy Scan" (version: 0.1.0-SNAPSHOT.42, branch: main)
β β ββ Finding: CVE-2024-32002 β git 2.43.0 [HIGH]
β β ββ Finding: CVE-2024-6345 β setuptools 69.0.3 [HIGH]
β ββ Test: "Anchore Grype" (version: 0.1.0-SNAPSHOT.42, branch: main)
β ββ Finding: CVE-2024-32002 β git 2.43.0 [High]
β
ββ Engagement: "image:nginx:1.25-alpine"
ββ Test: "Trivy Scan"
β ββ Finding: CVE-2024-24790 β Go standard library [CRITICAL]
ββ Test: "Anchore Grype"
ββ Finding: CVE-2024-24790 β Go standard library [Critical]
Phase 4: On-Demand Remote Image Scanβ
If the security team needs to re-scan specific images without source code (e.g., after a Trivy DB update), they trigger the image-scan-remote pipeline:
params:
IMAGE_NAMES:
- "registry.example.com/payment-service:0.1.0-SNAPSHOT.42"
CODEBASE_NAME: "payment-service"
This runs Trivy against the remote registry and uploads results to the existing payment-service product in DefectDojo, updating the per-image engagement.
Security Coverage Summaryβ
| Scanner | What It Detects | Where Results Live | Blocks Pipeline? |
|---|---|---|---|
| SonarQube | Code quality, bugs, security vulnerabilities, coverage | SonarQube server | Yes (Quality Gate) |
| Semgrep | SAST findings (injection, deserialization, etc.) | DefectDojo | No |
| Gitleaks | Hardcoded secrets and credentials | DefectDojo | No |
| cdxgen + Dependency-Track | Vulnerable dependencies, license risks | Dependency-Track | No |
| Trivy | OS-level and library CVEs in container images | DefectDojo | No |
| Grype | OS-level and library CVEs in container images | DefectDojo | No |
| Hadolint | Dockerfile best practices | Pipeline log | Yes (review only) |
| Helm Lint | Chart structure and template errors | Pipeline log | Yes (review only) |
SonarQube is the only scanner that acts as a hard gate. All other security scanners operate in a "report and continue" mode β findings are sent to DefectDojo and Dependency-Track for triage by the security team.