Aller au contenu

Installation et configuration

Prerequis

Composant Version minimale Objectif
Podman 4.0+ Runtime conteneurs
Podman Compose 1.0+ Orchestration multi-conteneurs
PostgreSQL 15+ Backend de persistance SonarQube
Certificat TLS Let's Encrypt ou PKI interne Chiffrement HTTPS
DNS Enregistrement sonar.example.com Accès au service
RAM 4 Go minimum (8 Go recommande) SonarQube + Elasticsearch + PG
Stockage SSD 50 Go minimum Elasticsearch performant

Déploiement SonarQube avec Podman Compose

Préparation du système

# Creer l'utilisateur dedie
sudo useradd -r -m -s /sbin/nologin sonarqube

# Creer les repertoires
sudo -u sonarqube mkdir -p /home/sonarqube/{certs,data,extensions,logs}

# Ajuster les limites systeme pour Elasticsearch
echo "vm.max_map_count=524288" | sudo tee -a /etc/sysctl.d/99-sonarqube.conf
echo "fs.file-max=131072" | sudo tee -a /etc/sysctl.d/99-sonarqube.conf
sudo sysctl --system

# Copier les certificats TLS
sudo cp /etc/pki/tls/certs/sonar.example.com.{crt,key} /home/sonarqube/certs/
sudo chown -R sonarqube:sonarqube /home/sonarqube/certs/
sudo chmod 600 /home/sonarqube/certs/*.key

vm.max_map_count obligatoire

Elasticsearch necessite vm.max_map_count >= 262144. Sans ce reglage, SonarQube refuse de démarrer. La valeur 524288 offre une marge confortable.

Initialisation des secrets

# Creer le repertoire de secrets
sudo -u sonarqube mkdir -p /home/sonarqube/.secrets
sudo chmod 700 /home/sonarqube/.secrets

# Generer les mots de passe
openssl rand -base64 32 | sudo -u sonarqube tee /home/sonarqube/.secrets/db_password > /dev/null
sudo chmod 600 /home/sonarqube/.secrets/*

Fichier Podman Compose

# /home/sonarqube/podman-compose.yml
version: "3.9"

services:
  postgres:
    image: docker.io/library/postgres:15-alpine
    container_name: sonarqube-db
    environment:
      POSTGRES_DB: sonarqube
      POSTGRES_USER: sonarqube
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - sonarqube-net
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sonarqube"]
      interval: 10s
      timeout: 5s
      retries: 5

  sonarqube:
    image: docker.io/library/sonarqube:10-community
    container_name: sonarqube
    environment:
      # Base de donnees
      SONAR_JDBC_URL: jdbc:postgresql://postgres:5432/sonarqube
      SONAR_JDBC_USERNAME: sonarqube
      SONAR_JDBC_PASSWORD_FILE: /run/secrets/db_password

      # JVM et Elasticsearch
      SONAR_WEB_JAVAOPTS: "-Xmx512m -Xms256m"
      SONAR_CE_JAVAOPTS: "-Xmx1024m -Xms512m"
      SONAR_SEARCH_JAVAOPTS: "-Xmx1024m -Xms512m"

      # Configuration web
      SONAR_WEB_PORT: "9000"
      SONAR_WEB_CONTEXT: "/"
    secrets:
      - db_password
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
    ports:
      - "9000:9000"
    networks:
      - sonarqube-net
    depends_on:
      postgres:
        condition: service_healthy
    ulimits:
      nofile:
        soft: 131072
        hard: 131072

  traefik:
    image: docker.io/library/traefik:v3.1
    container_name: sonarqube-proxy
    command:
      - "--entrypoints.websecure.address=:443"
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
    ports:
      - "443:443"
    volumes:
      - /run/user/1001/podman/podman.sock:/var/run/docker.sock:ro
      - /home/sonarqube/certs:/certs:ro
    networks:
      - sonarqube-net

volumes:
  pgdata:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:

networks:
  sonarqube-net:
    driver: bridge

secrets:
  db_password:
    file: /home/sonarqube/.secrets/db_password

Demarrage

# Demarrer la stack
sudo -u sonarqube podman-compose -f /home/sonarqube/podman-compose.yml up -d

# Verifier les logs (attendre "SonarQube is operational")
sudo -u sonarqube podman logs -f sonarqube

# Verifier l'acces
curl -s http://localhost:9000/api/system/status | jq .
# Attendu : {"id":"...","version":"10.x","status":"UP"}

Service systemd

# /etc/systemd/system/sonarqube.service
[Unit]
Description=SonarQube Quality Analysis Stack
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=sonarqube
WorkingDirectory=/home/sonarqube
ExecStartPre=/usr/bin/podman-compose pull
ExecStart=/usr/bin/podman-compose up
ExecStop=/usr/bin/podman-compose down
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now sonarqube.service

Configuration initiale de SonarQube

Premier accès et changement du mot de passe admin

# Le compte par defaut est admin/admin
# Changer immediatement le mot de passe
curl -u admin:admin -X POST \
  "http://localhost:9000/api/users/change_password" \
  -d "login=admin&previousPassword=admin&password=NEW_SECURE_PASSWORD"

Changer le mot de passe admin immédiatement

Le compte par defaut admin:admin est un vecteur d'attaque connu. Le changer des le premier demarrage, avant d'exposer le service sur le réseau.

Configurer le quality gate par defaut

# Creer un quality gate personnalise
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create" \
  -d "name=Organisation"

# Ajouter les conditions
# Couverture sur nouveau code >= 80%
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create_condition" \
  -d "gateName=Organisation&metric=new_coverage&op=LT&error=80"

# Pas de nouveau bug critique ou bloquant
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create_condition" \
  -d "gateName=Organisation&metric=new_reliability_rating&op=GT&error=1"

# Pas de nouvelle vulnerabilite critique ou bloquante
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create_condition" \
  -d "gateName=Organisation&metric=new_security_rating&op=GT&error=1"

# Duplication sur nouveau code < 3%
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create_condition" \
  -d "gateName=Organisation&metric=new_duplicated_lines_density&op=GT&error=3"

# Security hotspots revus
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/create_condition" \
  -d "gateName=Organisation&metric=new_security_hotspots_reviewed&op=LT&error=100"

# Definir comme quality gate par defaut
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualitygates/set_as_default" \
  -d "name=Organisation"

Recapitulatif du quality gate

Condition Metrique Opérateur Seuil
Couverture nouveau code new_coverage < (fail) 80%
Fiabilité nouveau code new_reliability_rating > (fail) A
Sécurité nouveau code new_security_rating > (fail) A
Duplication nouveau code new_duplicated_lines_density > (fail) 3%
Hotspots sécurité revus new_security_hotspots_reviewed < (fail) 100%

Activer les quality profiles

# Lister les profils disponibles pour Java
curl -u admin:TOKEN \
  "http://localhost:9000/api/qualityprofiles/search?language=java" | jq .

# Creer un profil enfant de Sonar way
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualityprofiles/create" \
  -d "name=Organisation-Java&language=java"

# Heriter de Sonar way
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualityprofiles/change_parent" \
  -d "qualityProfile=Organisation-Java&language=java&parentQualityProfile=Sonar way"

# Definir comme profil par defaut
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/qualityprofiles/set_default" \
  -d "qualityProfile=Organisation-Java&language=java"

Répéter pour chaque langage

Créer un profil Organisation-<langage> pour chaque langage utilise dans l'organisation. Cela permet d'ajouter des regles custom sans modifier le profil built-in.

Générer un token d'analyse

# Token pour le scanner CI
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/user_tokens/generate" \
  -d "name=ci-scanner&type=GLOBAL_ANALYSIS_TOKEN"

# Stocker le token dans le gestionnaire de secrets du CI
# Ne jamais le committer dans le code source

Configuration Semgrep CI

Installation du CLI

# Installation via pip (dans l'image CI ou en local)
pip install semgrep

# Verification
semgrep --version

Fichier de configuration Semgrep

# .semgrep.yml (a la racine du depot)
rules:
  # Utiliser les rulesets Semgrep officiels
  - id: semgrep-rules
    match:
      # Regles de securite generales
      - p/security-audit
      # Regles OWASP Top 10
      - p/owasp-top-ten
      # Regles specifiques au langage
      - p/python
      - p/java
      - p/javascript

Configuration avancee par dépôt

# .semgrep/settings.yml
# Configuration partagee pour l'organisation

# Rulesets a activer
rules:
  include:
    - p/security-audit
    - p/owasp-top-ten
    - p/secrets

  # Regles custom de l'organisation
  local:
    - .semgrep/rules/

# Fichiers a exclure
paths:
  exclude:
    - "vendor/"
    - "node_modules/"
    - "*.test.*"
    - "*.spec.*"
    - "dist/"
    - "build/"

Écrire une regle custom Semgrep

# .semgrep/rules/no-hardcoded-secrets.yml
rules:
  - id: no-hardcoded-password
    patterns:
      - pattern: |
          password = "..."
      - pattern-not: |
          password = ""
      - pattern-not: |
          password = "changeme"
    message: >
      Mot de passe en dur detecte. Utiliser un gestionnaire de secrets
      (Vault, variables d'environnement CI).
    severity: ERROR
    languages: [python, java, javascript, typescript, go]
    metadata:
      cwe:
        - CWE-798
      owasp:
        - A07:2021
      category: security

Execution locale

# Scan rapide du depot
semgrep scan --config auto

# Scan avec regles specifiques
semgrep scan --config p/security-audit --config .semgrep/rules/

# Export SARIF pour import dans SonarQube
semgrep scan --config auto --sarif --output semgrep-results.sarif

Vérification post-installation

Vérification Commande / URL Résultat attendu
Statut SonarQube curl -s http://localhost:9000/api/system/status {"status": "UP"}
Health check curl -s http://localhost:9000/api/system/health {"health": "GREEN"}
Dashboard https://sonar.example.com Page de login
Quality gate curl -s http://localhost:9000/api/qualitygates/list Quality gate "Organisation"
Semgrep version semgrep --version Version installee
Semgrep scan test semgrep scan --config auto --dry-run Liste des regles chargees
# Test d'analyse complet
# 1. Creer un projet de test
curl -u admin:TOKEN -X POST \
  "http://localhost:9000/api/projects/create" \
  -d "name=test-project&project=test-project"

# 2. Lancer un scan
cd /chemin/vers/un/projet
sonar-scanner \
  -Dsonar.projectKey=test-project \
  -Dsonar.host.url=http://localhost:9000 \
  -Dsonar.token=YOUR_TOKEN

# 3. Verifier le resultat
curl -u admin:TOKEN \
  "http://localhost:9000/api/qualitygates/project_status?projectKey=test-project"