How to capitalize on GitLab Security tools with external CI

Jul 10, 2020 · 4 min read · Leave a comment
Fernando Diaz GitLab profile

Recently, I have been working with users who are using GitLab for Source Code Management (SCM) that are still in the process of migrating to GitLab for CI/CD. In this case, the users are not ready to move everything from Jenkins directly to GitLab just yet, but want to take advantage of all the Security benefits of GitLab Ultimate/Gold .

In this blog, I will walk you through setting up external Jenkins jobs along with deterministic security scans. Deterministic security scans block the pipeline from proceeding if a vulnerability was detected. You can follow along with the video below to configure Jenkins and GitLab.

The sample project I am using contains code showing how to call Jenkins as well as how to setup deterministic security scans.

How to add external Jenkins jobs to GitLab

You can call jobs from external CI platforms such as Jenkins, from GitLab. You can use the Jenkins REST API to start a Jenkins job. In this demo, I show you how to do it in Python using python-jenkins, however there are many Jenkins Remote Access APIs available in different languages.

You can install python-jenkins by running:

pip3 install python-jenkins

Here's a simple script which a GitLab pipeline can run in order to call a Jenkins job:

import os
import sys
import jenkins
import time

server = jenkins.Jenkins(os.environ["JENKINS_URL"], username=os.environ["JENKINS_USER"], password=os.environ["JENKINS_PWRD"])
job_name = os.environ["JENKINS_JOB"]


# wait until last build is complete and then get the result
last_build_number = server.get_job_info(job_name)['lastCompletedBuild']['number']
next_build_number = server.get_job_info(job_name)['nextBuildNumber']
build_info = server.get_build_info(job_name, last_build_number)

# try max 2 mins before timing out
timeout = time.time() + 60 * 2
while last_build_number != next_build_number:
    if time.time() > timeout:
    last_build_number = server.get_job_info(job_name)['lastCompletedBuild']['number']
    build_info = server.get_build_info(job_name, last_build_number)

result = build_info["result"]

# return the status of the job
if result != "SUCCESS":
    print("Build Failed")


The required environment variables include:

Deterministic security scans

Oftentimes, static security scans run after the build stage. If any of these scans detect vulnerabilities, there are cases when we should not move on to the deployment stage, because of limited resources and time constraints. We're discussing a built-in way of doing this but for now there is a simple work around by editing the gitlab-ci.yaml.

Here is a gitlab-ci.yaml file that runs Static Application Security Testing (SAST), then generates a report, and finally blocks the pipeline from proceeding if any vulnerability was detected. It achieves this by parsing the SAST report JSON.

  - test
  - verify

  - template: SAST.gitlab-ci.yml

  stage: test
    CI_DEBUG_TRACE: "true"
  allow_failure: true
      - gl-sast-report.json
      sast: gl-sast-report.json

  stage: verify
    - job: sast
      artifacts: true
    - cat gl-sast-report.json
    - apk add jq
    - export VULNS=$(jq '.vulnerabilities | length' gl-sast-report.json)
    - if $VULNS -ne '0'; then exit 1; fi
  allow_failure: false

Note: Deterministic security scans can be setup for all of GitLab Security scans. The JSON reports may be different per scan.

I hope this blog can help you get started using GitLab's security features while using Jenkins for CI.

Learn more about GitLab Security

Cover image by Glenn Carstens-Peters on Unsplash

“Use @gitlab for security scanning with external-ci” – Fernando Diaz

Click to tweet

Open in Web IDE View source