How to automate DAST for OPC UA with Jenkins
Jenkins is a popular open-source automation server. Commonly used as an integration and continuous delivery (CI/CD) tool, Jenkins helps to automate the testing and deployment of code.
Security testing is an essential process of ensuring the security of products. However, it is time-consuming and error-prone if done manually. Security testing is divided into two main categories: Static Application Security Testing (SAST) and Dynamic Application Security Testing (DAST).
This tutorial shows how you can automate the DAST for an OPC UA server using Jenkins and OpalOPC. The result is continuous security testing of the server, which allows you to catch any issues as early as possible.
With minor changes, you can adapt this pipeline to test your own OPC UA server.
Overview
We will be creating a pipeline that clones the Git repository with OPC UA server code, builds and runs the server, scans it with OpalOPC, and finally archives the scanning report for us to download.
The server we will be testing is the Console Reference Server.
We avoid installing any additional software on the Jenkins server by using Docker containers for the build and scanning processes.
You can install OpalOPC directly on the Jenkins runner, as well as all the requirements for building the server. However, this is not recommended as it makes the Jenkins server hard to maintain.
Prerequisites
- Jenkins installed and running
- The following plugins installed in Jenkins:
- Jenkins user can run docker without sudo
- Git installed
Fork the server repository
- Fork the Console Reference Server repository
- Clone the forked repository to your local machine
git clone <your fork uri>
You can refer to our fork of the repository at any time to see the exact changes we made.
Create a pipeline
- Login to Jenkins
- Create a new pipeline in Jenkins, and configure it to fetch the Jenkinsfile from your forked repository.
You can also use the Pipeline script
setting to write the pipeline directly in Jenkins. However, this is not recommended as it makes it difficult to version control the pipeline.
- Select
Build Now
to run the pipeline. Verify you get the errorERROR: Unable to find Jenkinsfile from git
- Create a new file called
Jenkinsfile
in the root of your forked repository with the following content (also available here):
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Create Docker Network') {
steps {
sh 'docker network create $BUILD_NUMBER-opalopc-network'
}
}
stage('Build & Start ReferenceServer') {
steps {
sh '''
cd Applications/ConsoleReferenceServer/
docker build -f Dockerfile -t consolerefserver ./../..
docker run --rm -d --name $BUILD_NUMBER-refserver --network $BUILD_NUMBER-opalopc-network consolerefserver:latest
'''
}
}
stage('Run OpalOPC') {
agent {
dockerfile {
filename 'Dockerfile.opalopc'
args '--network=$BUILD_NUMBER-opalopc-network'
}
}
steps {
sh '''
export HOME=`pwd`
opalopc -vv opc.tcp://$BUILD_NUMBER-refserver:62541 -o opalopc-report
'''
// Archive results
archiveArtifacts artifacts: 'opalopc-report.*'
}
}
}
post {
always {
// Kill ReferenceServer if its running
sh 'docker kill $BUILD_NUMBER-refserver || true'
// Remove Docker Network if it exists
sh 'docker network rm $BUILD_NUMBER-opalopc-network || true'
}
}
}
- Create a new file called
Dockerfile.opalopc
, also in the root, with the following content (also available here):
FROM ubuntu:jammy
# Install dependencies
RUN apt-get update && apt-get install -y \
curl \
libicu70
# Install opalopc http://opalopc.com/docs/get-started/install
RUN curl -LO "https://dl.opalopc.com/release/$(curl -L -s https://dl.opalopc.com/release/stable.txt)/bin/linux/amd64/opalopc" \
&& install -o root -g root -m 0755 opalopc /usr/local/bin/opalopc
- Commit & Push the changes to the repository
git add .
git commit -m "Add pipeline files"
git push
Get results
After the pipeline is configured, we can run it to get a testing report.
- Select
Build Now
to run the pipeline. The first run will take a while as Jenkins needs to download and build docker images. - Verify the pipeline finishes successfully
- Select the reports below
Last Successful Artifacts
to download them.
The HTML report does not display correctly on Jenkins. Therefore you should download it on your machine for viewing.
Configure continuous testing
Now that we have a working pipeline, we will configure it to run automatically when new code is pushed to the Git repository.
- Add the following snippet to the Jenkinsfile, under agent:
triggers {
pollSCM('*/5 * * * *')
}
- Commit & Push the changes to the repository
git add Jenkinsfile
git commit -m "Add trigger"
git push
- Run the pipeline
Configured this way, Jenkins will check your repository every 5 minutes for new changes and run the pipeline if any are found. You simply need to check the pipeline results to see if there are any security issues.
The best practice is to configure webhooks in your Git repository to trigger the pipeline instead of the polling configured here. This reduces the load on your Git server and ensures that the pipeline is triggered as soon as possible.
Conclusion
Automating the security testing of OPC UA servers being developed with Jenkins and OpalOPC is a great way to ensure you always have the latest security assessment results at hand. By tracking the results, you will be the first to learn when a change in the codebase makes your server vulnerable.
Usually, the next step after automation is to configure centralized vulnerability management, which allows you to track the security of your servers over time. This is especially important in large organizations with many servers. We cover this in How to import OPC UA vulnerabilities into DefectDojo.