Demo Overview
This demo shows how Magalix Kubeguard integrates well with other GitLab features to create a DevSecOps end-2-end pipeline.
In this demo, we will build a pipeline that's triggered on every commit. The pipeline has 3 stages:
1- Build: In this stage, we build an example docker image in our repo which has a vulnerability to be tested using GitLab's container scanning feature.
2- Test: In this stage, we have 3 tests:
1- Container Image Scanning Test (GitLab feature).
2- Static Application Security Testing SAST (GitLab feature).
3- IaC Scanning (Magalix Kubeguard feature).
Note: GitLab features require ultimate plan
3- Deploy: In this stage, we deploy an example pod file in our repo on a GKE cluster after it's scanned by Magalix Kubeguard.
Let's Start
1- Log into GitLab and create a new blank project.
2- Add example files that our tests will scan:
- Dockerfile: This is an example Dockerfile that contains a vulnerability so that we can see the container scanning test results.
# Example Dockerfile
FROM node:12-alpine
RUN apk add --no-cache python g++ make
RUN echo "HELLO DEVSECOPS"
- example.py: This is just a simple yaml_to_json parser file. It has a vulnerability that's detected by SAST. You can use any file to be scanned by SAST.
import os
import yaml
import json
rootdir = '/yamls'
# Loop over dirs and convert each yaml file to json
def convert_yamls_to_json(rootdir):
for d in os.listdir(rootdir):
dir_path = os.path.join(rootdir, d)
for yaml_file in os.listdir(dir_path):
file_ext = os.path.splitext(yaml_file)[1]
if file_ext in [".yml", ".yaml"]:
# Read YAML
with open(os.path.join(dir_path, yaml_file)) as infile:
data_obj = yaml.load(infile, Loader=yaml.FullLoader)
json_filename = yaml_file.replace(".yaml", ".json")
json_filename = yaml_file.replace(".yml", ".json")
# Write JSON file
with open(os.path.join(dir_path, json_filename), 'w') as outfile:
json.dump(data_obj, outfile, indent=2)
convert_yamls_to_json(rootdir)
- k8s/nginx.yaml: (This is a simple K8s nginx pod file that will be scanned by Magalix Kubeguard)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
owner: test
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
- Your repo structure should now look like this:
__
|____ Dockerfile
|____ example.py
|____ k8s
|____ nginx.yaml
3- Create a Magalix Kubeguard and attach your desired policies.
Guard URL: https://console.magalix.com/api/v1/kubeguard/<kubguard_id>
Attached policies: Test Missing Owner Key - Missing Kubernetes App Label
4- In GitLab: From the left sidebar, go to settings then CI/CD then add these masked environment variables to be used in our pipeline
- GUARD_WEBHOOK: Kubeguard webhook url
- KUBECONFIG: base64 encrypted string of your cluster kubeconfig file Or GCLOUD_SERVICE_KEY: base64 encrypted string of your gcloud service account key file (Here I've used kubeconfig file)
5- Let's add our .gitlab-ci.yaml file to define our pipeline
stages:
- build
- test
- deploy
# variables:
# specify $DOCKER_IMAGE var if you want container scanning to use a specific image instead of the one built in the build step
# if the image is in another registry you need to provide $DOCKER_USER and $DOCKER_PASSWORD
# DOCKER_IMAGE: registry.gitlab.com/test4927/test-kubeguard/main:bb4edb61e2787e4f23a00ccc5ef3ba45b353d53e
include:
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/SAST.gitlab-ci.yml
build:
image: docker:19.03.8
stage: build
services:
- docker:19.03.8-dind
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
magalix sast:
image:
name: ahsayde/mglx-test:latest
entrypoint: [""]
stage: test
script:
- cd ${CI_PROJECT_DIR}
- mglx-scanner -w ${GUARD_WEBHOOK} -d . --no-exit-error --sast mglx-sast-result.json
allow_failure: true
artifacts:
reports:
sast: mglx-sast-result.json
paths:
- mglx-sast-result.json
sast:
stage: test
artifacts:
reports:
sast: gl-sast-report.json
paths:
- gl-sast-report.json
gke deploy:
stage: deploy
image: google/cloud-sdk
script:
# deploy using kubeconfig file with user access token
- echo $KUBECONFIG | base64 -d > ~/kubeconfig.yaml
- export KUBECONFIG=~/kubeconfig.yaml
- kubectl get pods
- kubectl apply -f k8s/nginx.yaml
- kubectl get pods
# alternative way to deploy is using service account key file generated from GCP console
# - echo $GCLOUD_SERVICE_KEY | base64 -d > ~/gcloud-service-key.json
# - gcloud auth activate-service-account --key-file ~/gcloud-service-key.json
# - gcloud config set project $GCP_PROJECT_ID
# - gcloud container clusters get-credentials $CLUSTER_NAME --zone $CLUSTER_ZONE --project $GCP_PROJECT_ID
# - kubectl apply -f k8s/nginx.yaml
Notes:
- GitLab container scanning and SAST features require GitLab’s paid ultimate plan.
- If you want the container scanning test to scan another image you should provide the DOCKER_IMAGE, DOCKER_USER, DOCKER_PASSWORD variables in the .gitlab-ci.yaml.
- In the magalix sast job, you can use the --no-exit-error option if you want the job to succeed even if there're violations. I used it just to run the pipeline to the end but it should not be used in order to stop the pipeline if the magalix_sast test discovered violations in your k8s files.
- In the gke deploy job, you have 2 options:
1- Kubeconfig file.
2- GCloud service account key file, You can find the code for each one in the .gitlab-ci.yaml file.
I used the kubeconfig code and commented on the other one.
6- Once you commit your .gitlab-ci.yaml, go to the Pipelines page in GitLab and you'll find our pipeline triggered.
Click on the pipeline and you'll find the 3 stages and their jobs. The bandit sast and semgrep sast jobs are GitLab SAST tests.
7- After some time, the jobs will finish successfully
8- You can then see the violations and vulnerabilities of each job by viewing the job artifacts.
- Bandit (Python - SAST) artifacts:
- Container scanning artifacts:
- Magalix Kubeguard violations:
9- You can configure SAST analyzers to be applied in order to cover languages across your project, by default all analyzers are applied. Go to Security & Compliance then Configuration and click Configure SAST. You'll find the list of SAST analyzers.
10- And the pod is spinned up successfully in the GKE cluster 😎
kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment2-5d59d67564-f9rx7 1/1 Running 0 41s
nginx-deployment2-5d59d67564-pllcv 1/1 Running 0 41s