QScanner Backend

The QScanner backend provides on-demand security scanning for Jenkins pipelines. It downloads the scanner binary at runtime, making it ideal for ephemeral agents, cloud builds, and environments without pre-installed sensors.

Overview

Feature Description
Authentication API Token (recommended for automation)
Scanner Delivery Downloaded on-demand at runtime
Scan Types Container, Code (SCA), Rootfs
Best For Ephemeral agents, cloud builds, Kubernetes pods

Supported Scan Types

Scan Type Description Use Case
container Scan Docker/OCI container images Container image vulnerability scanning
code Scan source code for vulnerable dependencies Software Composition Analysis (SCA)
rootfs Scan filesystem directories VM images, extracted archives, mounted volumes

Setting Up Credentials

Create a Jenkins credential for your Qualys API token:

  1. Navigate to Manage Jenkins > Manage Credentials
  2. Select the appropriate domain (or global)
  3. Click Add Credentials
  4. Select Secret text
  5. Enter your Qualys API access token
  6. Set ID to qualys-api-token
  7. Save the credential

Pipeline Examples

Container Scanning

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }
        stage('Security Scan') {
            steps {
                qualysScan(
                    credentialsId: 'qualys-api-token',
                    scannerBackend: 'qscanner',
                    scanType: 'container',
                    imageId: "myapp:${BUILD_NUMBER}",
                    platform: 'linux/amd64',
                    scanSecrets: true,
                    scanMalware: true,
                    maxCritical: 0,
                    maxHigh: 5,
                    publishSarif: true
                )
            }
        }
    }
}

Code Scanning (SCA)

pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Security Scan') {
            steps {
                qualysScan(
                    credentialsId: 'qualys-api-token',
                    scannerBackend: 'qscanner',
                    scanType: 'code',
                    scanPath: '.',
                    excludeDirs: 'node_modules,vendor,test',
                    scanSecrets: true,
                    generateSbom: true,
                    sbomFormat: 'spdx',
                    maxCritical: 0,
                    maxHigh: 10
                )
            }
        }
    }
}

Rootfs Scanning

pipeline {
    agent any
    stages {
        stage('Extract Image') {
            steps {
                sh '''
                    docker save myapp:latest -o image.tar
                    mkdir -p rootfs
                    tar -xf image.tar -C rootfs
                '''
            }
        }
        stage('Security Scan') {
            steps {
                qualysScan(
                    credentialsId: 'qualys-api-token',
                    scannerBackend: 'qscanner',
                    scanType: 'rootfs',
                    rootfsPath: 'rootfs',
                    scanSecrets: true,
                    maxCritical: 0
                )
            }
        }
    }
}

QScanner Backend Parameters

Authentication

Parameter Required Default Description
credentialsId Yes - Jenkins credential ID for Qualys API token
qualysPod No US1 Qualys platform POD

Scanner Configuration

Parameter Required Default Description
scannerBackend Yes - Set to 'qscanner'
scanType Yes - Scan type: container, code, or rootfs

Container Scan Parameters

Parameter Required Default Description
imageId Yes* - Container image to scan (name:tag or digest)
imageTar No - Path to image tar archive
platform No linux/amd64 Target platform for multi-arch images

Code Scan Parameters

Parameter Required Default Description
scanPath No . Path to directory to scan
excludeDirs No - Comma-separated directories to exclude
includeDev No false Include development dependencies
generateSbom No false Generate Software Bill of Materials
sbomFormat No spdx SBOM format: spdx or cyclonedx

Rootfs Scan Parameters

Parameter Required Default Description
rootfsPath Yes - Path to root filesystem directory

Scan Options

Parameter Required Default Description
scanSecrets No false Enable secrets detection
scanMalware No false Enable malware detection (container only)
offlineMode No false Scan without uploading to Qualys platform

Accessing Scan Results

Access scan results programmatically in your pipeline:

pipeline {
    agent any
    stages {
        stage('Security Scan') {
            steps {
                script {
                    def result = qualysScan(
                        credentialsId: 'qualys-api-token',
                        scannerBackend: 'qscanner',
                        scanType: 'container',
                        imageId: 'myapp:latest'
                    )

                    echo "Total vulnerabilities: ${result.totalVulnerabilities}"
                    echo "Critical: ${result.criticalCount}"
                    echo "High: ${result.highCount}"
                    echo "Medium: ${result.mediumCount}"
                    echo "Low: ${result.lowCount}"
                    echo "Policy result: ${result.policyResult}"
                    echo "Thresholds passed: ${result.thresholdsPassed}"

                    if (!result.thresholdsPassed) {
                        error "Security scan failed thresholds"
                    }
                }
            }
        }
    }
}

Jira Integration

Create Jira issues for vulnerabilities found:

qualysScan(
    credentialsId: 'qualys-api-token',
    scannerBackend: 'qscanner',
    scanType: 'container',
    imageId: 'myapp:latest',
    createJiraIssues: true,
    jiraCredentialsId: 'jira-credentials',
    jiraProject: 'SEC',
    jiraIssueType: 'Bug',
    jiraSeverities: '4,5'
)

Offline Scanning

Scan without uploading results to Qualys platform:

qualysScan(
    credentialsId: 'qualys-api-token',
    scannerBackend: 'qscanner',
    scanType: 'container',
    imageId: 'myapp:latest',
    offlineMode: true,
    publishSarif: true
)

Next Steps