Complete Guide: Configuring a Local DevSecOps Environment

Complete Guide: Configuring a Local DevSecOps Environment

Introduction

In this article, we’ll explore how to set up a complete DevSecOps environment on a local machine. This environment will enable to test and experiment with various DevSecOps practices that are essential for the modern development of secure applications.

Why a local DevSecOps environment ?

A local environment offers a number of advantages :

  • Risk-free experimentation
  • Speed of development and testing
  • Configurations can be tested before being deployed in production
  • Practical learning of DevSecOps tools and practices

Prerequisites

Recommended hardware configuration

  • CPU : minimun 4 cores
  • RAM : minimum 16 GB
  • Disk space : minimum 50 GB free
  • Operating system : Linux (Ubuntu/Debian recommended)

Required software

  • Git
  • Docker
  • Docker Compose
  • Administrator access (sudo)

Step-by-step installation

  1. Preparating system

Let’s start by updating the system and installing the necessary prerequisites :

sudo apt update && sudo apt upgrade -y
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common git

2. Installing Docker and Docker Compose

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

sudo usermod -aG docker $USER

sudo systemctl enable docker
sudo systemctl start docker

3. Creating the project structure

mkdir -p devsecops-env/{jenkins,sonarqube,zap,monitoring,gitleaks,trivy}
cd devsecops-env

First, let’s create the network manually so that our containers (grafana, prometheus, sonarqube and jenkins) can be visible to each other on the same network.

docker network create monitoring

4. Service configuration

4.1. Jenkins (CI/CD)

Create a jenkins/docker-compose.yml file :

version: '3'
services:
  jenkins:
    image: jenkins/jenkins:lts
    container_name: jenkins
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - jenkins_home:/var/jenkins_home
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - JAVA_OPTS=-Djenkins.install.runSetupWizard=true
    networks:
      - monitoring
    restart: unless-stopped

volumes:
  jenkins_home:

networks:
  monitoring:
    external: true

4.2. SonarQube (Code analysis)

Create a sonarqube/docker-composer.yaml file :

version: '3'
services:
  sonarqube:
    image: sonarqube:latest
    container_name: sonarqube
    ports:
      - "9000:9000"
      - "8081:8081"
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - ./jmx_exporter:/opt/jmx_exporter
    environment:
      - SONAR_JDBC_URL=jdbc:postgresql://db:5432/sonar
      - SONAR_JDBC_USERNAME=sonar
      - SONAR_JDBC_PASSWORD=sonar
      - SONAR_WEB_JAVAADDITIONALOPTS=-javaagent:/opt/jmx_exporter/jmx_prometheus_javaagent.jar=8081:/opt/jmx_exporter/config.yaml
    depends_on:
      - db
    networks:
      - monitoring
    restart: unless-stopped
  db:
    image: postgres:12
    container_name: sonarqube_db
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
      - POSTGRES_DB=sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data
    networks:
      - monitoring
    restart: unless-stopped

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql:
  postgresql_data:

networks:
  monitoring:
    external: true

Before launching this configuration, you need to :

  1. Create the jmx_exporter folder and download the agent
mkdir jmx_exporter
wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.19.0/jmx_prometheus_javaagent-0.19.0.jar -O jmx_exporter/jmx_prometheus_javaagent.jar

2. Create the configuration file jmx_exporter/config.yaml

---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
  - pattern: ".*"

4.3. OWASP ZAP (Safety test)

Create a zap/docker-composer.yaml file :

version: '3'
services:
  zap:
    image: ghcr.io/zaproxy/zaproxy:stable
    container_name: owasp_zap
    command: zap.sh -daemon -host 0.0.0.0 -port 8090 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true -config api.key=changeme123
    ports:
      - "8090:8090"
    volumes:
      - zap_data:/zap/wrk/
    restart: unless-stopped

volumes:
  zap_data:

4.4. Trivy (Container vulnerability analysis)

Create a trivy/docker-composer.yaml file :

version: '3'
services:
  trivy:
    image: aquasec/trivy:latest
    container_name: trivy
    volumes:
      - trivy_cache:/root/.cache
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - TRIVY_CACHE_DIR=/root/.cache/
      - GITHUB_TOKEN=${GITHUB_TOKEN}  # Optional : To avoid the limitation of the GitHub API
    command: server --listen 0.0.0.0:4954
    ports:
      - "4954:4954"
    restart: unless-stopped

volumes:
  trivy_cache:

To use Trivy directly from the command line

# Trivy installation
sudo apt-get install wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy

# Examples of how Trivy is used
# Scan an image
trivy image nginx:latest

# Scanning an image with a JSON output format
trivy image -f json -o results.json nginx:latest

# Scanning an image with critical vulnerability filtering
trivy image --severity CRITICAL nginx:latest

# Scan a local project
trivy fs .

4.5. Monitoring (Prometheus + Grafana)

Create a monitoring/docker-composer.yaml file :

version: '3'
services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    networks:
      - monitoring
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    depends_on:
      - prometheus
    networks:
      - monitoring
    restart: unless-stopped

volumes:
  prometheus_data:
  grafana_data:

networks:
  monitoring:
    external: true

Create a monitoring/prometheus.yml file :

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['prometheus:9090']

  - job_name: 'jenkins'
    metrics_path: '/prometheus'
    static_configs:
      - targets: ['jenkins:8080']

  - job_name: 'sonarqube'
    static_configs:
      - targets: ['sonarqube:8081']
    basic_auth:
      username: 'admin'
      password: 'admin'

5. Service management script

#!/bin/bash

check_service() {
    if [ $? -eq 0 ]; then
        echo "$1 successfully launched"
    else
        echo "Error when starting $1"
        exit 1
    fi
}

start_services() {
    echo "Starting services..."
    
    cd jenkins
    docker-compose up -d
    check_service "Jenkins"
    
    cd ../sonarqube
    docker-compose up -d
    check_service "SonarQube"
    
    cd ../zap
    docker-compose up -d
    check_service "OWASP ZAP"
    
    cd ../monitoring
    docker-compose up -d
    check_service "Monitoring Stack"
    
    cd ..
    echo "All services are started"
    echo "
    Services available :
    - Jenkins: http://localhost:8080
    - SonarQube: http://localhost:9000
    - OWASP ZAP: http://localhost:8090
    - Grafana: http://localhost:3000
    - Prometheus: http://localhost:9090
    - Trivy Server: http://localhost:4954
    "
}

stop_services() {
    echo "Stopping services..."
    
    cd jenkins && docker-compose down
    cd ../sonarqube && docker-compose down
    cd ../zap && docker-compose down
    cd ../trivy && docker-compose down
    cd ../monitoring && docker-compose down
    
    cd ..
    echo "All services stopped"
}

case "$1" in
    start)
        start_services
        ;;
    stop)
        stop_services
        ;;
    *)
        echo "Usage: $0 {start|stop}"
        exit 1
        ;;
esac

Make the script executable :

chmod +x manage-services.sh

Post-installation configuration

Jenkins

  1. Recover the initial password
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword

Installing the prometheus plugin for Jenkins

  1. Go to http://127.0.0.1:8080 and follow the installation wizard

  2. Installing the plugin :

    • Go to ‘Manage Jenkins’ > ‘Plugins’ > ‘Available Plugins’.
    • Search for ‘Prometheus metrics
    • Install the plugin and restart Jenkins if necessary

3. Accès aux métriques : http://127.0.0.1:8080/prometheus/

image

SonarQube

  1. Go to http:127.0.0.1:9000(default login : admin/admin)
  2. Change the admin password
  3. Create a new and generate an authentication token

image

Grafana

  1. Go to http://127.0.0.1:3000(default login : admin/admin)
  2. Add prometheus as a datasource
  3. Import a preconfigured dashboards for jenkins and SonarQube

image

Prometheus

  1. Go to http://127.0.0.1:9090/target

image

OWAPS ZAP

  1. Go to http://127.0.0.1:8090

image

Partager cet article :