DEV Community

Cover image for Pixi-CRS goes to the Cloud - Part 4 : Google Cloud Platform
Franziska Bühler for OWASP DevSlop

Posted on

Pixi-CRS goes to the Cloud - Part 4 : Google Cloud Platform

The third cloud provider I moved Pixi-CRS to was Google Cloud Platform (GCP): https://console.cloud.google.com/

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

This is how Pixi-CRS looks on Google Cloud Platform:

Pixi-CRS on Google Cloud Platform

In the image above, we see that the Pixi-CRS CI Pipeline on GCP is configured as a GCP Cloud Build.

Pixi-CRS Pipeline Code

The code behind the pipeline can be found here.
GCP Cloud Build code is written in a cloudbuild.yaml file in the root directory of the repository. It's pretty easy to create a new Cloud Build on GCP. First, I had to create a project and "Enable Cloud Build".

Let's take a closer look at this cloudbuild.yaml file.

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

# Google Cloud cloudbuild.yaml
#
steps:
# 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/
- id: 'Starting Pixi and CRS with docker-compose up'
  name: 'docker/compose:1.26.2'
  args: ['--env-file', '/workspace/compose-gcp.env', 'up', '-d']

# Debugging possibilities
#- name: 'ubuntu'
#  args: [ "touch", "foo" ]
#- name: 'ubuntu'
#  args: [ "ls", "-l", "/workspace/testcafe/tests_container_ip" ]
#- name: 'ubuntu'
#  args: [ "pwd" ]
# Debugging with curl
#- name: 'curlimages/curl:7.69.0'
#  args: [ "-v", "http://172.17.0.1:8000/register"]
#- name: 'curlimages/curl:7.69.0'
#  args: [ "-v", "http://172.17.0.1:8080/register"]

# Application Tests with Testcafe
# skip-js-errors because of: Uncaught Error: Bootstrap tooltips require Tether
- id: 'Run Testcafe Tests: Pixi without and with CRS'
  name: 'gcr.io/cloud-builders/docker'
  args: [ "run", "--volume", "/workspace/testcafe/tests_container_ip:/tests", "--rm", "testcafe/testcafe", "chromium:headless --no-sandbox", "--skip-js-errors" ]

# Copy ModSecurity Logs:
- id: 'Copy ModSecurity logs'
  name: 'gcr.io/cloud-builders/docker'
 # args: [ "exec", "crs", "cat /var/log/apache2/error.log | grep ModSecurity" ]
  args: [ "cp", "crs:/var/log/apache2/error.log", "/workspace/error.log" ]

# Show ModSecurity Logs
- id: 'Show ModSecurity logs'
  name: 'ubuntu'
  args: [ "cat", "/workspace/error.log" ]

# ModSecurity Log Analysis:
# Fail if ModSecurity log does not contain WAF Test String "MyEvilWAFTest"
# That means CRS is not working properly or test was aborted.

- id: 'Fail if ModSecurity log does not contain WAF Test String'
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: "bash"
  args:
    - "-c"
    - |
        cat /workspace/error.log | grep -q MyEvilWAFTest
# 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
- id: 'Fail if ModSecurity log is not empty'
  name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: "bash"
  args:
    - "-c"
    - |
        "cat /workspace/error.log grep ModSecurity | grep error | grep -vi MyEvilWAFTest | grep -v 949110 | grep -v 980130 && exit 1 || exit 0"
#- id: 'Fail if ModSecurity log is not empty'
#  name: 'gcr.io/cloud-builders/docker'
#  args: [ 'exec', 'crs', 'cat /var/log/apache2/error.log | grep ModSecurity | grep error | grep -vi "MyEvilWAFTest" | grep -v "949110" | grep -vi "980130" && exit 1 || exit 0' ]


# Debugging docker
#- id: 'Docker'
#  name: 'gcr.io/cloud-builders/docker'
#  args: [ "ps" ]

Pipeline Steps

Start Pixi and the CRS

We start Pixi and the CRS with one docker-compose up command and provide an --env-file. We don't need to install Docker or docker-compose, since we use the docker/compose image.

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 GCP

Check results

In the end, we check the results. We have a look at the ModSecurity log inside the CRS Docker container.
This 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 GCP Cloud Build after every push into the repository, we need to configure a trigger on push events.
I added this via the option Cloud Build > Triggers > Create Trigger.

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 Google Cloud Platform 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 in this series, I will implement the Pixi-CRS CI Pipeline in GitHub Actions.

Discussion (0)