Azure Fortify Integration and Breaking Pipelines

Batuhan Sancak
8 min readJan 4, 2024

--

Introduction

Hello everyone, we will talk about “Azure Devops Fortify integration process and secure pipeline configuration” this article. First we will perform the installation. azure agent, ssc connection etc. Afterwards, we will scan a project in the Azure Devops environment with Fortify SCA and upload the result to SSC. This is a pipeline diagram in normal flow. To spice up the work, we will break the pipeline if the number of vulnerabilities at a certain level is high in the project.

Stage 1: Azure Devops Agent Installation and Setup Proccess

Stage 2: Service Connection (SSC) and Fortify Addon Install

Stage 3: Create first pipeline

Stage 4: How to break pipeline from the number of vulnerabilities in the project.

Requirements

Fortify SSC/SCA

Azure Devops Account

Lab Information

Windows Server 2019, Fortify SSC/SCA 23.2.* version.

Azure Devops Configuration and Agent Installation

In the first stage, we create an account by going to dev.azure.com and create a project by clicking “new project” as seen in figure 1.0. My project name is “Test”

Figure 1.0

With this video you can see how the agent can be created and downloaded.

Figure 1.1

Project Settings > Agent Pools > Agent Pool Name > New Agent

If you downloaded agent, you continue next step.

mkdir agent ; cd agent
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$HOME\Downloads\vsts-agent-win-x64-3.232.1.zip", "$PWD")

You can then configure the agent and start the service by following the steps in the image using PowerShell. Even though it is not the same as in the example image, it is recommended that you set the startup type of the agent to automatic from the services.

Figure 1.2

Stage 1 completed. Let’s we do now configuration service connection.

Service Connection and Fortify Addon Installation

In this section, we will connect the ssc service to the azure devops environment. Finally, we will add the Fortify plugin to our Azure environment.

Step by Step

Projects Settings > Service Connections > New Service Connection > Generic

Figure 1.3

What you need to pay attention to when creating the service is the token you specify. You can create the token via fortify ssc. You can review the official Fortify document for the token you should use at the minimum level.

This section finally, You must download Fortify Addon on Microsoft marketplace.

Figure 1.4

Create First Pipeline

In this section, we will create firs pipeline. We will pull a project that we forked from the Github repo. We will create a simple azure.yml file and start a sca scan and upload the result to ssc.

Step by Step

Projects > Pipelines > New Pipelines

Figure 1.5

At this stage we will select the github option. It will ask us to connect our own github account. (Your company may also have a joint enterprise github account. When you make this connection, it will ask us to select a repository. At this stage, you can fork a public github project you want to scan and add it to your own repository.

I used the https://github.com/ferhatcil/hackigniter repository. Thanks to the person who shared the project publicly.

You can select the startup pipeline on the configuration screen. Afterwards, you can delete all the default lines in the azure-yml file.

Figure 1.6

You can then search for the “fortify” plugin we added before from the “show assistant” panel. There will be more than one result. The “Fortify Static Code Analyzer Assessment” option you need to select. When you click Add, it will give you a sample scanning option. The information you need to fill in before adding is indicated with photographs. Additionally, you need to create an application via ssc.

Figure 1.7
Figure 1.8
Figure 1.9

Footnote: The application name and application version information shown in Figure 1.9 must be entered.

Finally, all that remains is to edit our file in .yml format. You may need to edit the draft a bit. You can take the code blog as an example.

trigger:
- master

pool: Medium-Article

steps:

- task: FortifySCA@7
inputs:
applicationType: 'other'
fortifyBuildId: 'php'
fortifyScanType: 'LocalScan'
runFortifyUpload: true
fortifyServerName: 'ssc test'
fortifyApplicationName: 'hackigniter'
fortifyApplicationVersion: '1'

pool: change.

fortifyserverName: change

fortifyApplicationName: change

FortifyApplicationVersion: change

run pipeline! 🚀

Figure 2.1

Congratulations. You have successfully created your first pipeline. When you check the SSC, you will see that the project has been scanned successfully and its report has been uploaded.

How to Break Pipeline by Potential Security Issues

In the final stage of the work, we will organize the pipeline we created from a security perspective. The pipeline structure we use here and our goal is, at the end of the day, as follows:

1- Create a pipeline where integrations are carried out in the Azure Devops environment.
2- Pull the project from Github, scan it with SCA, upload it to SSC.
3- Finish Pipeline.

In addition to this, we will add an extra step in the last stage.

4- If you see a vulnerability in x (variable) number and y (variable) level during the scanning, break the pipeline.

If we need to interpret this code script;

I adapt the curl request to the powershell script for the Fortify API connection. Python vs. you can use It’s completely habit. Then, I print the json file with the get request I send. Here you can use azure variables for file path and similar structures. In this article, I specified the file path directly to make it more visible.

- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
$fortify_ssc_api_url = "$(url)"
$token = "FortifyToken $(FortiToken)"

$headers = @{
"Authorization" = $token
"Content-Type" = "application/json"
"Accept" = "application/json"
}

try {
# Api request get
$response = Invoke-WebRequest -Uri $fortify_ssc_api_url -Method Get -Headers $headers

# Reponse status
if ($response.StatusCode -eq 200) {
# JSON data parse
$project_versions_data = $response.Content | ConvertFrom-Json

# Json data write
$file_path = "C:\Users\Administrator\Desktop\test.json"
$project_versions_data | ConvertTo-Json -Depth 4 | Out-File -FilePath $file_path
$jsonData = Get-Content "C:\Users\Administrator\Desktop\test.json"
$priorityLines = $jsonData | Where-Object { $_ -like "*friority*" }
$txtFile = "C:\Users\Administrator\Desktop\output.txt"
$priorityLines | Out-File -FilePath "C:\Users\Administrator\Desktop\output.txt"


Write-Host "Project vulnerability info export succes."
} else {
throw "HTTP Error: $($response.StatusCode) $($response.StatusDescription)"
}
} catch [System.Net.WebException] {
Write-Host "HTTP Error: $($_.Exception.Message)"
} catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}

I used this endpoint.

Figure 2.2

Azure Define Variables

Now we parse the json file with the where-object structure and extract the lines containing the expression “friority”. To make this more understandable, I shared the sample json output visually. It gives multiple outputs as api response. Our goal, as I explained in the pipeline process structure, is to actually obtain the number of vulnerabilities at the end of the day and terminate the pipeline accordingly.

Figure 2.3
$jsonData = Get-Content "C:\Users\Administrator\Desktop\test.json"
$priorityLines = $jsonData | Where-Object { $_ -like "*friority*" }
$txtFile = "C:\Users\Administrator\Desktop\output.txt"
$priorityLines | Out-File -FilePath "C:\Users\Administrator\Desktop\output.txt"

As the last stage, we will read our txt file and if the “*friority*” statement is used more than x variable (exit1), we will throw an error code and break the pipeline.

Why Exit 1

A pipeline is a command-line structure in which a series of commands are executed sequentially. The output of each command is used as the input for the next command. Breaking a pipeline means stopping the execution of one or more commands.

The exit 1 expression indicates that the execution of a command has failed. Therefore, using the exit 1 expression to break a pipeline will stop the execution of the rest of the pipeline.

Final

trigger:
- master

pool: Default

steps:

- task: FortifySCA@7
inputs:
applicationType: 'other'
fortifyBuildId: 'php'
fortifyScanType: 'LocalScan'
runFortifyUpload: true
fortifyServerName: 'ssc test'
fortifyApplicationName: 'hackigniter'
fortifyApplicationVersion: '1'
- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
$fortify_ssc_api_url = "$(url)"
$token = "FortifyToken $(FortiToken)"

$headers = @{
"Authorization" = $token
"Content-Type" = "application/json"
"Accept" = "application/json"
}

try {
# Api request get
$response = Invoke-WebRequest -Uri $fortify_ssc_api_url -Method Get -Headers $headers

# Reponse status
if ($response.StatusCode -eq 200) {
# JSON data parse
$project_versions_data = $response.Content | ConvertFrom-Json

# Json data write
$file_path = "C:\Users\Administrator\Desktop\test.json"
$project_versions_data | ConvertTo-Json -Depth 4 | Out-File -FilePath $file_path
$jsonData = Get-Content "C:\Users\Administrator\Desktop\test.json"
$priorityLines = $jsonData | Where-Object { $_ -like "*friority*" }
$txtFile = "C:\Users\Administrator\Desktop\output.txt"
$priorityLines | Out-File -FilePath "C:\Users\Administrator\Desktop\output.txt"


Write-Host "Project vulnerability info export succes."
} else {
throw "HTTP Error: $($response.StatusCode) $($response.StatusDescription)"
}
} catch [System.Net.WebException] {
Write-Host "HTTP Error: $($_.Exception.Message)"
} catch {
Write-Host "An error occurred: $($_.Exception.Message)"
}

- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
$content = Get-Content -Path "C:\Users\Administrator\Desktop\output.txt"
$x = 2

$lines = $content | Where-Object { $_ -like "*friority*" }

if ($lines.Length -ge $x) {
Write-Host "Pipeline Broken. Error Status: Exit Code 1"
Exit 1

}

Broke Pipeline ❌

Figure 2.4
Figure 2.5

Conclusion

Sometimes a pipeline’s failure to work may be as important as its operation. In today’s DevSecops concept, this is just one of the processes that can be improved. There are many processes like this.

https://www.linkedin.com/in/0x3d/

https://twitter.com/nullx3d

References

--

--