Qualys was the tool I first encountered on the infrastructure side of security — used mostly by ops teams to keep tabs on server patch levels and network-level vulnerabilities. It took me a while to realize how well it fits into a CI/CD pipeline too, especially for scanning container images and cloud infrastructure before they ever reach production. Once I hooked Qualys into Jenkins, vulnerability management stopped being a quarterly compliance checkbox and became part of the everyday build process.
This guide walks through integrating Qualys with Jenkins for both infrastructure/network scanning and container image scanning use cases.
Why Qualys in CI/CD
Qualys Cloud Platform offers several modules relevant to DevSecOps pipelines, most notably:
- Vulnerability Management (VM) — scans hosts, networks, and cloud assets for known CVEs.
- Web Application Scanning (WAS) — DAST scanning similar to Acunetix/Burp Suite.
- Container Security (CS) — scans Docker images for vulnerabilities before deployment.
Integrating Qualys into Jenkins means every build can trigger a scan of the relevant asset type — whether that’s a freshly built container image, a newly provisioned VM, or a deployed web application — before it’s promoted further down the pipeline.
Jenkins Architecture Context
Qualys operates primarily through its Cloud Platform API, authenticated using a Qualys username/password or API token depending on the module. Jenkins calls these APIs to launch scans, poll status, and retrieve results, very similar in pattern to how Acunetix and Burp Suite integrations work, but Qualys’s API structure (XML-based for VM/WAS, REST/JSON for Container Security) differs enough to be worth walking through separately.
Prerequisites
- A Qualys Cloud Platform subscription with the relevant module enabled (VM, WAS, or Container Security).
- Qualys API credentials (stored securely in Jenkins).
- Network connectivity from Jenkins agents (or Qualys Scanner Appliances) to target assets.
- Jenkins with HTTP Request Plugin, Pipeline Utility Steps, and Credentials Binding Plugin installed.
Step 1: Store Qualys Credentials in Jenkins
Under Manage Jenkins > Credentials, add a Username with password credential (ID: qualys-api-creds) containing your Qualys API username and password.
Step 2: Qualys Container Security Scanning in a Jenkinsfile
This is one of the most common Qualys + Jenkins integrations — scanning a Docker image immediately after it’s built, before it’s pushed to a registry.
pipeline {
agent any
environment {
IMAGE_NAME = 'myapp'
IMAGE_TAG = "${env.BUILD_NUMBER}"
QUALYS_CS_URL = 'https://qualysapi.qualys.com/csapi/v1.3'
}
stages {
stage('Build Docker Image') {
steps {
sh "docker build -t ${IMAGE_NAME}:${IMAGE_TAG} ."
}
}
stage('Qualys Container Scan') {
steps {
withCredentials([usernamePassword(credentialsId: 'qualys-api-creds', usernameVariable: 'QUALYS_USER', passwordVariable: 'QUALYS_PASS')]) {
sh """
# Save image as tarball for sensor-based scanning
docker save -o image.tar ${IMAGE_NAME}:${IMAGE_TAG}
# Trigger scan via Qualys Container Sensor (assumes sensor is deployed as a container on the build host)
docker run --rm \
-e QUALYS_USER=${QUALYS_USER} \
-e QUALYS_PASS=${QUALYS_PASS} \
-v \$(pwd)/image.tar:/scan/image.tar \
qualys/cs-sensor:latest scan --file /scan/image.tar --output /scan/results.json
"""
}
}
}
stage('Evaluate Scan Results') {
steps {
script {
def results = readJSON file: 'results.json'
def critical = results.vulnerabilities.findAll { it.severity == '5' || it.severity == '4' }
if (critical.size() > 0) {
error "Found ${critical.size()} critical/high vulnerabilities in image ${IMAGE_NAME}:${IMAGE_TAG}"
} else {
echo "No critical vulnerabilities found. Proceeding to push image."
}
}
}
}
stage('Push Image to Registry') {
steps {
sh "docker push ${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
post {
always {
archiveArtifacts artifacts: 'results.json', allowEmptyArchive: true
}
failure {
mail to: 'security-team@example.com',
subject: "Qualys Scan Failed for ${IMAGE_NAME}:${IMAGE_TAG}",
body: "Critical vulnerabilities detected. See archived results.json for details."
}
}
}
Step 3: Qualys Web Application Scanning (WAS) Integration
For DAST-style scanning of a deployed staging application:
pipeline {
agent any
environment {
QUALYS_API = 'https://qualysapi.qualys.com/qps/rest/3.0'
WEBAPP_ID = '123456'
}
stages {
stage('Deploy to Staging') {
steps {
sh './deploy.sh staging'
}
}
stage('Trigger Qualys WAS Scan') {
steps {
withCredentials([usernamePassword(credentialsId: 'qualys-api-creds', usernameVariable: 'QUALYS_USER', passwordVariable: 'QUALYS_PASS')]) {
script {
def response = httpRequest(
url: "${QUALYS_API}/launch/was/wasscan/",
httpMode: 'POST',
authentication: 'qualys-api-creds',
customHeaders: [[name: 'Content-Type', value: 'application/xml']],
requestBody: """<ServiceRequest>
<data>
<WasScan>
<name>Jenkins-Triggered-Scan-${env.BUILD_NUMBER}</name>
<webApp><id>${WEBAPP_ID}</id></webApp>
<profile><id>111</id></profile>
</WasScan>
</data>
</ServiceRequest>"""
)
echo "Scan launched: ${response.content}"
}
}
}
}
}
}
Qualys WAS uses XML-based requests, which is a notable difference from the JSON-first APIs of Acunetix and Burp Suite — worth remembering when you’re debugging request formatting issues.
Step 4: Qualys Vulnerability Management (Infrastructure Scanning)
If you’re provisioning infrastructure with Terraform and want to scan newly created VMs before they join production traffic:
stage('Provision Infrastructure') {
steps {
sh 'terraform apply -auto-approve'
}
}
stage('Qualys VM Scan') {
steps {
withCredentials([usernamePassword(credentialsId: 'qualys-api-creds', usernameVariable: 'QUALYS_USER', passwordVariable: 'QUALYS_PASS')]) {
sh """
curl -u "\$QUALYS_USER:\$QUALYS_PASS" \
-X POST "https://qualysapi.qualys.com/api/2.0/fo/scan/" \
-d "action=launch&scan_title=Jenkins-${env.BUILD_NUMBER}&ip=10.0.1.0/24&option_title=Initial+Options"
"""
}
}
}
Integrating with Terraform and Ansible
Qualys pairs naturally with infrastructure-as-code workflows:
- Terraform: Trigger a Qualys VM scan against newly provisioned subnets right after
terraform applyand before traffic is routed to new instances (e.g., before updating a load balancer target group). - Ansible: Use an Ansible playbook post-provisioning step to register new hosts as Qualys scan targets automatically via the Qualys Asset Management API.
Integrating with Docker and Kubernetes
For Kubernetes environments, Qualys Container Security also supports scanning images already stored in a registry or running in a cluster via the Qualys Kubernetes sensor, which can be deployed as a DaemonSet, giving continuous vulnerability visibility beyond just the CI build step.
Monitoring and Reporting
Qualys Cloud Platform maintains a centralized dashboard across VM, WAS, and Container Security modules. I recommend archiving raw JSON/XML scan results as Jenkins build artifacts in addition to relying on the Qualys dashboard, since build-linked artifacts make it much easier to trace “which commit introduced this vulnerability” during retrospectives.
Troubleshooting Common Issues
- Authentication failures — Qualys accounts are region-specific (US, EU, India platforms use different API endpoints); double-check you’re hitting the correct
qualysapi.qualysXX.comregion host. - Scans stuck in “Queued” status — often due to Scanner Appliance availability; verify appliance health in the Qualys UI if using internal network scanning.
- Container sensor fails to connect — ensure the Jenkins agent’s Docker daemon allows the sensor container to reach Qualys Cloud Platform endpoints (check firewall/proxy rules).
Best Practices
- Scan container images before pushing to a registry, not after — catch issues before they’re even distributable.
- Use Qualys Container Security continuously in Kubernetes (via DaemonSet sensor) in addition to CI-time scanning, since new CVEs are discovered daily even for unchanged images.
- Separate your gating threshold by asset type — a “critical” host vulnerability is a different risk profile than a “critical” web app finding.
- Store scan artifacts against build numbers for compliance audits (SOC 2, PCI-DSS, HIPAA scans often require this level of traceability).
- Rotate Qualys API credentials regularly and store them exclusively via Jenkins Credentials.
FAQs
Can Qualys scan private container registries? Yes, Qualys Container Security supports scanning images directly in registries like Docker Hub, ECR, GCR, and Harbor via configured registry connectors, in addition to CI-time tarball scanning.
Is Qualys VM scanning safe to run against production without causing outages? Qualys offers non-intrusive scan options, but any active vulnerability scan carries some risk of triggering sensitive systems (like IDS/IPS). Best practice is to schedule production scans during low-traffic windows and coordinate with your infrastructure team.
What’s the difference between Qualys WAS and Container Security modules? WAS is a DAST tool testing running web applications for vulnerabilities like SQLi/XSS; Container Security is more like SCA (Software Composition Analysis) for container images, focused on known CVEs in OS packages and application dependencies within the image layers.
How do I avoid false positives blocking every build? Use Qualys’s vulnerability exception/acceptance workflow to formally document accepted risks, rather than loosening your Jenkins severity gate broadly.
Summary
Qualys brings enterprise-grade vulnerability management into your Jenkins pipeline, whether you’re scanning container images before they’re pushed, testing live web applications, or validating freshly provisioned infrastructure. By wiring Qualys’s APIs into your Jenkinsfile and gating deployments on severity thresholds, you shift vulnerability detection left — catching issues during the build instead of during a security audit months later.
References
- Qualys API Documentation Portal: https://www.qualys.com/docs/
- Qualys Container Security Documentation: https://www.qualys.com/apps/container-security/
- Qualys WAS API Guide: https://www.qualys.com/docs/qualys-was-api-user-guide.pdf
- Jenkins HTTP Request Plugin: https://plugins.jenkins.io/http_request/