mbogning.com - Building is my Passion
Post
Cancel

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 :

1
2
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

1
2
3
4
5
6
7
8
9
10
11
12
13
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

1
2
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.

1
docker network create monitoring

4. Service configuration

4.1. Jenkins (CI/CD)

Create a jenkins/docker-compose.yml file :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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
1
2
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

1
2
3
4
5
---
lowercaseOutputName: true
lowercaseOutputLabelNames: true
rules:
  - pattern: ".*"

4.3. OWASP ZAP (Safety test)

Create a zap/docker-composer.yaml file :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/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 :

1
chmod +x manage-services.sh

Post-installation configuration

Jenkins

  1. Recover the initial password
1
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

Featured Blog Posts
    Quote
    "When faith and will unite in a person, he realises all that is in his mind and it shapes itself." Merlin Lagowo
    Contents