Pixi-CRS goes to the Cloud - Part 3 : Microsoft Azure DevOps
Tags: waf, crs, pixi, azure
Published: 2020-10-06 08:40:40

---
series: Pixi-CRS goes to the Cloud
title: Pixi-CRS goes to the Cloud - Part 3 : Microsoft Azure DevOps
published: true
description:
tags: WAF, CRS, Pixi, Azure
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/3bf5mkp7oa9mzqz9cq2k.png
---

The second cloud provider to which I moved Pixi-CRS was Microsoft Azure DevOps: https://dev.azure.com/.

This is the third blog post in the "Pixi-CRS goes to the Cloud" series.

This is how Pixi-CRS looks on the Microsoft Azure DevOps Pipeline:

![Pixi-CRS on Azure DevOps](https://dev-to-uploads.s3.amazonaws.com/i/zid1enzmohw8jn5bd4go.png)

In the image above, we see that the Pixi-CRS CI Pipeline on Azure DevOps is configured as Azure DevOps > Pixi-CRS > Pipeline.


## Pixi-CRS Pipeline Code

The code behind the pipeline can be found [here](https://github.com/DevSlop/pixi-crs/blob/master/azure-pipelines.yml). 
Azure DevOps pipeline code is written in azure-pipeline.yml files in the root directory of the repository. It's quite easy to create a new pipeline project on Azure DevOps. 

Let's take a closer look at this azure-pipelines.yml file.

I will explain the different steps below. But I also give explanations in the comments in the provided yaml file.

```yaml
# Azure DevOps azure-pipelines.yml

trigger:
# Branch to trigger
- master

stages:

# Start the OWASP ModSecurity Core Rule Set and Pixi with its DB with docker-compose
# OWASP ModSecurity Core Rule Set Container (Apache Reverse Proxy)
# owasp/modsecurity-crs
# See https://coreruleset.org/
# ModSecurity Tuning:
# See https://www.netnea.com/cms/apache-tutorial-8_handling-false-positives-modsecurity-core-rule-set/
- stage: StartContainersAndTests
  jobs:
  - job: BuildJob
    steps:
      # Debugging
      # - script: pwd
      # - script: ls
      - task: DockerCompose@0
        displayName: Start Pixi and CRS
        inputs:
          containerregistrytype: 'Container Registry'
          dockerComposeFile: '**/docker-compose.yaml'
          action: 'Run a Docker Compose command'
          dockerComposeFileArgs: |
            CRSPORTHTTP=8080
            PROXYLOCATION=http://app:8000/
          dockerComposeCommand: 'up -d'

      # Application Tests with Testcafe
      # skip-js-errors because of: Uncaught Error: Bootstrap tooltips require Tether
      # Another way: https://devexpress.github.io/testcafe/documentation/continuous-integration/azure-devops.html
      # Debugging
      #- script: docker ps
      - script: docker run --volume /home/vsts/work/1/s/testcafe/tests_container_ip/:/tests testcafe/testcafe --skip-js-errors 'chromium:headless --no-sandbox'
        displayName: Run Testcafe Tests without and with CRS

      # Show Full error.log
      - script: docker exec crs cat /var/log/apache2/error.log
        displayName: Show ModSecurity logs

      # ModSecurity Log Analysis:
      # Fail if ModSecurity log is not empty
      # Show ModSecurity logs of Testcafe Tests
      # If not empty -> Repair your application OR
      #              -> ModSecurity Tuning:
      # See https://www.netnea.com/cms/apache-tutorial-8_handling-false-positives-modsecurity-core-rule-set/ OR
      #              -> GitHub issue: https://github.com/SpiderLabs/owasp-modsecurity-crs
      - script: if docker exec crs cat /var/log/apache2/error.log | grep ModSecurity | grep -vi MyEvilWAFTest | grep -v 949110 | grep -v 980130 | grep msg; then echo "False Positive Found! Aborting!" && exit 1 ; else echo "ModSecurity Logs empty. This is good!"; fi
        displayName: Fail if ModSecurity logs are not empty

      # Fail if ModSecurity log does not contain WAF Test String "MyEvilWAFTest"
      # That means CRS is not working properly or test was aborted.
      - script: if docker exec crs cat /var/log/apache2/error.log | grep ModSecurity | grep MyEvilWAFTest; then echo "WAF Test String Found. This is good!"; else echo "WAF Test String not Found! Aborting!" && exit 1; fi
        displayName: Fail if WAF Test String is missing in ModSecurity logs
```


## Pipeline Steps

### Start Pixi and the CRS

We start Pixi and the CRS with one docker-compose up command. We don't need to install Docker or docker-compose, it's already provided. But we need to configure a few things like the dockerComposeFileArgs, for example. 
Then we start Pixi and the CRS with the dockerComposeCommand "up -d".

### Testcafe tests

Now that the CRS and Pixi are running, we perform the Testcafe tests. This time we can run the tests with the testcafe/testcafe Docker container. The tests can be mounted easily into this container. 
Again, first, we test Pixi directly, then we test Pixi through the CRS. We also test the CRS itself with a malicious string. We want to ensure that the WAF blocks it.

For our tests, we call Pixi via http://172.17.0.1:8000 and the CRS via http://172.17.0.1:8080  because we call them from inside the Testcafe Docker container.

And this is how the Testcafe test output looks:

![Testcafe Output on Azure DevOps](https://dev-to-uploads.s3.amazonaws.com/i/i3tz5gbwwbu5bw2ifsu5.png)

### Check results

In the end, we check the results. We take a look at the ModSecurity log inside the CRS Docker container.
This is an important step that ensures that we did not have any false positives with our legitimate tests. In addition, we ensure that our malicious test was logged.

## Trigger

Because Pixi-CRS is a CI pipeline and we want to run our Azure DevOps pipeline project after every push into the repository, we need to configure a trigger on push events. 
I added this via the "trigger: -master" entry in the azure-pipeline.yml file. 

## Things to mention

Pixi-CRS is a CI Pipeline and I did not configure the CD part.
In this blog post, I only wanted to show the CI part. And I'm also aware that a lot more Azure DevOps options are available. But for this blog post, I wanted to keep it simple and concentrate on the Pixi-CRS CI part.

## Next blog post

In the next blog post, we will learn the Pixi-CRS pipeline on Google Cloud Platform.