Harden your Docker Containers using a Gitlab pipeline

 

Prerequisites

  1. RapidFort Server (SaaS or On-Premises)
  2. RapidFort Service Account
  3. GitLab Runner with RapidFort CLI tools installed on it.
  4. Deployment Environment (for example, Kubernetes, Docker, Docker-Compose, AWS Fargate) must:
    1. have HTTPS access to the RapidFort server
    2. provide support for adding the SYS_PTRACE Linux kernel capability
  5. Container Registry (for example, Amazon Elastic Container Registry, Docker Hub, Microsoft Azure Container Registry, and so forth)

Instrument (Stub), Test, and Harden the NGINX Docker Image

The following example documents how to stub, test, and harden a NGINX Docker image. It will entail deploying and testing/exercising the stub image on the GitLab runner. The images will not be pushed on to a container registry.

  1. Download the sample .gitlab-ci.yml file.
  2. Update the following variables in the yml file:
  • RF_ROOT_URL:
    • For SaaS users, specify https://frontrow.rapidfort.com.
    • For On-Premises users, specify the hostname or IP address of your RapidFort on-premises server (for example, https://rapidfort.example.com).
  • RF_ACCESS_ID: Specify the access id for your RapidFort service account.
  • RF_SECRET_ACCESS_KEY: Specify the secret access key for your RapidFort service account.
  • RF_CLI_UPDATE: Specify "no" to download and install the RapidFort CLI tools only if they are not already installed on the runner or "yes" to always download and install the tools (even if they are already installed).
  • RF_CLI_PATH: Specify the location where the RapidFort CLI tools will be installed on the GitLab runner.

.gitlab-ci.yml

variables:

  DOCKER_IMAGE_NAME: "nginx"

  TAG: latest

  RF_ROOT_URL: https://frontrow.rapidfort.com

  # generate service account & replace these

  RF_ACCESS_ID: RFabcdefghijkl123456

  RF_SECRET_ACCESS_KEY: 01234567891011abcdefghijklmnopqrstuvwxyz

  RF_CLI_UPDATE: "no"

  RF_CLI_PATH: /home/gitlab-runner/.local/bin


default:

  tags:

    - ubuntu

  before_script:

    - |

      if [ -z "$(command -v rflogin)" ] || [ "${RF_CLI_UPDATE}" == "yes" ]; then

        curl -ks "${RF_ROOT_URL}"/cli/ | bash

      fi

      export PATH="$RF_CLI_PATH:$PATH"


stages:

  - Build

  - Stub

  - Deploy

  - Test

  - Harden


build:

  stage: Build

  script:

    - |

      docker pull $DOCKER_IMAGE_NAME:$TAG

      docker tag $DOCKER_IMAGE_NAME:$TAG $DOCKER_IMAGE_NAME:$TAG-$CI_PIPELINE_ID


generate-stub:

  stage: Stub

  script:

    - |

      # ** GENERATE STUB **

      rfstub $DOCKER_IMAGE_NAME:$TAG-$CI_PIPELINE_ID

      docker images | grep $DOCKER_IMAGE_NAME | grep $CI_PIPELINE_ID


deploy:

  stage: Deploy

  script:

    - |

      # Run & test stub

      docker run --rm --name $DOCKER_IMAGE_NAME-$TAG-$CI_PIPELINE_ID -p9999:80 --cap-add=SYS_PTRACE -d $DOCKER_IMAGE_NAME:$TAG-$CI_PIPELINE_ID-rfstub


test:

  stage: Test

  script:

    - |

      STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:9999 || /bin/true)

      until [ "${STATUS_CODE}" == 200 ]; do

        sleep 1

        STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:9999 || /bin/true)

      done

      # Load test

      ab -n 10 -c 10 http://localhost:9999/

      # Remove running stub

      docker stop $DOCKER_IMAGE_NAME-$TAG-$CI_PIPELINE_ID


Harden:

  stage: Harden

  script:

    - |

      # ** GENERATE HARDENED IMAGE **

      rfharden $DOCKER_IMAGE_NAME:$TAG-$CI_PIPELINE_ID-rfstub && echo "Hardened Done" || echo "Hardened Failed"

      docker images | grep $DOCKER_IMAGE_NAME | grep $CI_PIPELINE_ID

  when: manual


In the above example, the Stub stage executes rfstub to generate a stub image - an instrumented image, but does not push the image to a container registry. If that is desired, add necessary steps to the .yaml file. During this stage RapidFort platform also scans the image to detect vulnerabilities and computes the estimated risk reduction opportunity by hardening. 

In the Deploy & Test stages RapidFort platform traces the runtime behavior of the application and builds the runtime profile.

The Harden stage is manual since it requires a runtime profile which is only generated after deploying and testing the stub image.