Configure CI security scanning

6 minute read

Configure security scanning in your CloudBees CI or Jenkins® Pipeline to maintain the security and integrity of your software assets. Set up your Jenkinsfile to run security scans with various tools including SAST, SCA, container, and secret scanning, then publish results to CloudBees Unify for enhanced analytics and vulnerability tracking.

Before you begin, ensure you have completed the CI or Jenkins integration. For setup instructions, refer to Connect CI and Jenkins controllers.

Set up security scanning on your Multibranch Pipeline

Set up your Jenkinsfile to install scanning tools, run scans, and publish security scan reports for ingestion to CloudBees Unify, to leverage its enhanced analytics.

To enable security scan reports from your CI build to CloudBees Unify:

  1. Complete the steps in Connect CI and Jenkins controllers.

  2. Configure your Jenkinsfile to install, run, and publish scans as described below.

Supported scanning tools

CloudBees Unify supports the following security scanning tools:

Table 1. Available scanning tools in CloudBees Unify
Scanning tool Type

Black Duck

SCA

Checkov

SAST

CodeQL

SAST

findsecbugs

SAST

Gitleaks

Secrets

Gosec

SAST

Grype

SAST

njsscanner

SAST

Snyk

SAST

Trivy

Container

SonarQube

SAST

JFrog

SCA, Container

Configure your Jenkinsfile to install, run, and publish scans

Use the registerSecurityScan step to indicate which Security Scan Result must be sent to CloudBees Unify. For the full parameter specification, refer to registerSecurityScan reference.

Input name Data type Required? Description

artifacts

String

Yes

Security scan to include. Wildcards are supported.

format

String

No

sarif and json are the supported values. sarif is the default value.

scanner

String

No

If the format is not sarif, a parameter value must be specified. If a parameter value is not specified, CloudBees Unify ignores this security scan and the build is marked Unstable. CloudBees Unify uses this to determine which scanner produces the security scan. The default value is empty.

archive

String

No

Describes if the reports must also be archived in the Jenkins build. The default value is true.

Example of a Pipeline stage including the step:

pipeline { stages { stage('Security Scan') { steps { registerSecurityScan( // Security Scan to include artifacts: "scan*", format: "sarif", scanner: "the-scanner", archive: true ) } } } }

Examples for scanners that support SARIF format

SARIF is a widely accepted standard used for sharing results from static analysis tools, especially in CI/CD environments.

The following examples illustrate how to use scanners that support SARIF format.

Black Duck sample Pipeline

Add the following steps to your Jenkinsfile to install, run, and publish the results of a Black Duck scan to CloudBees Unify.

pipeline { agent any environment { BRIDGE_CLI_DIR = "${WORKSPACE}/bridge-cli" BD_PROJECT_NAME = "my-blackduck-project" BD_VERSION_NAME = "1.0.0" GO_VERSION="1.21.2" BD_URL = credentials('BLACKDUCK_URL') BD_TOKEN = credentials('BLACKDUCK_API_TOKEN') } stages { stage('Download and Extract Bridge CLI') { (1) steps { sh ''' mkdir -p "$BRIDGE_CLI_DIR" # Download with error check curl -f -L "https://repo.blackduck.com/bds-integrations-release/com/blackduck/integration/bridge/binaries/bridge-cli-bundle/latest/bridge-cli-bundle-linux64.zip" \ -o bridge.zip # Extract with jar (no unzip needed) (cd "$BRIDGE_CLI_DIR" && jar -xf ../bridge.zip) # check if the binary exists ls -lrt ${BRIDGE_CLI_DIR} chmod +x "$BRIDGE_CLI_DIR"/bridge-cli-bundle-linux64/bridge-cli # Verify "$BRIDGE_CLI_DIR/bridge-cli-bundle-linux64/bridge-cli" --version ''' } } stage('Prepare Bridge CLI') { steps { sh ''' chmod -R +x bridge-cli/bridge-cli-bundle-linux64/adapters ''' } } stage('Run Black Duck Bridge CLI with SARIF Output') { (2) steps { sh """ curl -LO https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz rm -rf /tmp/go tar -C /tmp -xzf go${GO_VERSION}.linux-amd64.tar.gz export PATH=/tmp/go/bin:$PATH "${BRIDGE_CLI_DIR}/bridge-cli-bundle-linux64/bridge-cli" \ --stage blackducksca \ blackducksca.url="https://blackduck.example.com/" \ blackducksca.scan.full=true \ blackducksca.token="${BD_TOKEN}" \ blackducksca_reports_sarif_create=true \ blackducksca_reports_sarif_file_path="output/blackduck-sarif-report.sarif" \ blackducksca_reports_sarif_groupSCAIssues=false """ } } stage('Check the SARIF Report') { (3) steps { sh ''' echo "Checking SARIF report..." ls -l output/*.sarif cat output/*.sarif ''' } } stage('Archive SARIF Report') { steps { registerSecurityScan( artifacts: "output/*.sarif", format: "sarif", // can be omitted scanner: "BlackDuck", // can be omitted archive: true ) } } } }
1 Download and extract Bridge CLI. Use Black Duck Bridge, not Black Duck Detect, for scanning.
2 Run the scan with SARIF output. The shell command should be formed as above. You must include blackducksca_reports_sarif_groupSCAIssues=false.
3 Check the SARIF report.

Checkov sample Pipeline

Add the following steps to your Jenkinsfile to install, run, and publish the results of a Checkov scan to CloudBees Unify.

pipeline { agent any environment { PYTHON_URL = "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" PYTHON_DIR = "${env.WORKSPACE}/python" VENV_DIR = "${env.WORKSPACE}/venv" CHECKOV_REPORT = "checkov-report.sarif" CHECKOV_TARGET_DIR = "${env.WORKSPACE}/terragoat" CHECKOV_TARGET_FILE = "${env.WORKSPACE}/minimain.tf" CHECKOV_DISABLE_GUIDE = "true" BC_API_KEY = "" PRISMA_API_URL = "" } stages { // Step 1: Download and set up prebuilt Python binary stage('Download Prebuilt Python') { steps { echo ":arrow_down: Downloading prebuilt Python binary..." sh ''' mkdir -p $PYTHON_DIR cd $PYTHON_DIR curl -L -o python.tar.gz $PYTHON_URL tar -xzf python.tar.gz --strip-components=1 echo ":white_check_mark: Python extracted to: $PYTHON_DIR" ''' } } // Step 2: Verify Python & Pip installation stage('Verify Python & Pip') { steps { sh ''' $PYTHON_DIR/bin/python3.11 --version $PYTHON_DIR/bin/pip3.11 --version ''' } } // Step 3: Create Virtual Environment for Pipenv stage('Create Virtual Environment') { steps { echo "Creating virtual environment if missing..." sh ''' if [ ! -d "$VENV_DIR" ]; then $PYTHON_DIR/bin/python3.11 -m venv "$VENV_DIR" else echo "Virtualenv already exists." fi ''' } } // Step 4: Install Pipenv if missing stage('Install Pipenv if Missing') { steps { echo "Installing Pipenv if missing..." sh ''' source "$VENV_DIR/bin/activate" if ! pip show pipenv > /dev/null 2>&1; then pip install pipenv else echo "Pipenv already installed." fi ''' } } // Step 5: Install Checkov via Pipenv stage('Install Checkov via Pipenv') { (1) steps { echo "Installing Checkov using Pipenv..." sh ''' source "$VENV_DIR/bin/activate" pip install certifi pipenv install checkov echo "Checkov and certifi installed." ''' } } stage('Run Checkov Scan') { (2) steps { echo "Running Checkov scan on a specific file (main.tf)..." sh ''' source "$VENV_DIR/bin/activate" export SSL_CERT_FILE=$(python -m certifi) CHECKOV_DISABLE_GUIDE=true pipenv run checkov -f "$CHECKOV_TARGET_FILE" -o sarif > "$CHECKOV_REPORT" || true ''' } } stage('Display SARIF Report') { (3) steps { echo "Displaying SARIF report:" sh ''' echo "=== Checkov SARIF Report (First 20 lines) ===" head -n 20 "$CHECKOV_REPORT" ''' } } } stage('Archive Checkov Report') { steps { registerSecurityScan( artifacts: "${env.CHECKOV_REPORT}", format: "sarif", // can be omitted scanner: "Checkov", // can be omitted archive: true ) } } }
1 Install the scanner.
2 Run the scan.
3 Format the report in SARIF.

Examples for scanners that do not support SARIF format

The following examples illustrate how to use scanners that do not support SARIF format.

Anchore sample Pipeline

Add the following steps to your Jenkinsfile to install, run, and publish the results of an Anchore scan to CloudBees Unify.

pipeline { agent any stages { stage('Registering build artifact') { steps { echo 'Registering the metadata' registerBuildArtifactMetadata( name: "test-artifact-demo", version: "1.0.1", type: "docker", url: "http://non:1111", digest: "6f637064707039346163663237383938", label: "prod" ) } } stage('Register Security Scan') { steps { script { if (fileExists("anchore-findings.json")) { echo "File exists, registering scan..." registerSecurityScan( artifacts: "anchore-findings.json", format: "JSON", scanner: "Anchore", archive: false ) } else { error "anchore-findings.json not found!" } } } } } post { always { echo 'Pipeline completed.' } failure { echo 'Build or tests failed!' } } }

SonarQube sample Pipeline

If you are using SonarQube and want to send results to your CloudBees Unify instance, you must use the exportSonarQubeScan step to generate and download the scanning results from SonarQube in a single step, as SonarQube does not provide an easy way to do this.

Add the following steps to your Jenkinsfile to install, run, and publish the results of a SonarQube scan to CloudBees Unify.

pipeline { agent any environment { SONAR_HOST = "https://sonarqube.yourdomain.com" PROJECT_KEY = "sarif__bash_test_${env.BUILD_NUMBER}" SCANNER_VERSION = "5.0.1.3006" SCANNER_HOME = "${WORKSPACE}/sonar-scanner-5.0.1.3006" JAVA_HOME = "${WORKSPACE}/jdk17" PATH = "${WORKSPACE}/jdk17/bin:${PATH}" jq = "${WORKSPACE}/bin/jq" } stages { stage('Install JDK') { steps { sh ''' echo "Downloading JDK..." curl -sLo openjdk.tar.gz https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14%2B7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.14_7.tar.gz tar -xzf openjdk.tar.gz rm -rf jdk17 && mv jdk-17* jdk17 mkdir -p ${WORKSPACE}/bin if [ ! -f ${WORKSPACE}/bin/jq ]; then echo "Downloading jq..." curl -sLo ${WORKSPACE}/bin/jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 chmod +x ${WORKSPACE}/bin/jq fi ''' } } stage('Install SonarScanner CLI') { steps { sh """ if [ ! -d "sonar-scanner-${SCANNER_VERSION}-linux" ]; then echo "Downloading Sonar Scanner CLI..." curl -sLo scanner-sq.zip https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}.zip jar -xf scanner-sq.zip rm scanner-sq.zip else echo "SonarScanner already installed." fi """ } } stage('SonarQube Analysis') { steps { withCredentials([string(credentialsId: 'sonarqube-preprod-token', variable: 'SONAR_TOKEN')]) { sh """ chmod +x ${SCANNER_HOME}/bin/sonar-scanner ${SCANNER_HOME}/bin/sonar-scanner \ -Dsonar.projectKey=$PROJECT_KEY \ -Dsonar.sources=. \ -Dsonar.host.url=$SONAR_HOST \ -Dsonar.login=$SONAR_TOKEN """ } } } stage('Wait for Analysis') { steps { withCredentials([string(credentialsId: 'sonarqube-preprod-token', variable: 'SONAR_TOKEN')]) { script { def reportTask = readFile '.scannerwork/report-task.txt' def ceTaskUrl = reportTask.readLines() .find { it.startsWith("ceTaskUrl=") } .replace("ceTaskUrl=", "") echo "Waiting for SonarQube CE task to complete: ${ceTaskUrl}" timeout(time: 5, unit: 'MINUTES') { waitUntil { def result = sh( script: "curl -s -u ${SONAR_TOKEN}: ${ceTaskUrl} | $jq -r '.task.status'", returnStdout: true ).trim() echo "SonarQube CE task status: ${result}" return (result == "SUCCESS") } } } } } } stage('Export Sonar Findings') { steps{ exportSonarQubeScan( component: "", project: "$PROJECT_KEY", host: "$SONAR_HOST", credentialId: "sonarqube-preprod-token" ) } } } }

Run an automatically triggered implicit scan of your source code

Implicit scanning in CloudBees Unify refers to the automatic security analysis of source code without requiring explicit user intervention. This process ensures continuous security checks by automatically triggering scans whenever certain events occur, such as:

  • The creation of a new component.

  • Committing changes in a connected repository.

  • Generating an artifact from a CI build.

Enable implicit security scanning to provide ongoing security monitoring.