2. Gitlab CI/CD¶
2.1. CI / CD Pipeline¶
2.1.1. Docker¶
Für die CI/CD Pipeline wird ein Runner benötigt, der gemäß der .gitlab-ci.yml Datei die entsprechenden Befehle und Stages ausführt. Da die Hochschule selber keine Runner
hat, mussten wir uns selber einen anlegen. Dazu haben wir ein Docker Image über Docker-Compose verwendet, welches auf einer VM läuft, die sich wiederum über ein VPN
im Hochschulnetz befindet, da das Hochschulgitlab nicht öffentlich erreichbar ist.
version: "3.9"
services:
gitlab-runner:
image: gitlab/gitlab-runner:latest
container_name: gitlab-runner
restart: unless-stopped
volumes:
- data:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
volumes:
data:
Nachdem der Gitlab Runner erstellt und gestartet wurde muss anschließend noch bei einem Gitlab Host registriert werden:
docker exec -it gitlab-runner gitlab-runner register
Daraufhin müssen folgende Informationen angegeben werden:
Gitlab Host (https://gitlab.informatik.hs-augsburg.de)
Authentikation-Token (Token Generieren.)
Runner Name (z.B.: Gitlab-Runner)
Executor angeben (z.B.: docker)
Docker Image angeben (z.B: alpine)
2.1.2. Gitlab-Runner Token generieren:¶
Im folgenden Bildern wird ein Token für den Gitlab-Runner generiert: -> Settings - CI/CD - Runners - New project runner
2.1.3. Stages¶
Ein wichtiger Aspekt von CI/CD sind die sogenannten Stages. Mit ihnen lässt sich die Software, die man entwickelt, bauen, testen und sogar deployen. Wenn eine Stage
fehlschlägt, wird man in Form von einer E-Mail benachrichtigt. Definiert wird in der .gitlab-ci.yml alles im yaml-Format.
image: "alpine:latest"
stages:
- build
- deploy
variables:
SERVER_ADDRESS: "login.rz.hs-augsburg.de"
SERVER_USER: "arwe2002"
SERVER_DEST_PATH: "/www/arwe2002/sphinxbericht/"
build_job:
stage: build
script:
- apk add make py3-sphinx
- cd Bericht/
- make html
artifacts:
when: on_success
expire_in: 30 days
paths:
- "./Bericht/_build/*"
only:
- main
- web
- pipelines
deploy_job:
stage: deploy
script:
- apk update
- apk add curl rsync openssh-client
- curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | ash
- chmod 600 .secure_files/HSA_CICD_ONLY
- rsync -e 'ssh -i .secure_files/HSA_CICD_ONLY -o StrictHostKeyChecking=no' -zav --delete Bericht/_build/html/ $SERVER_USER@$SERVER_ADDRESS:$SERVER_DEST_PATH
needs:
- build_job
only:
- main
- web
- pipelines
Im Unterpunkt stages: werden die Stages und die Reihenfolge, in der sie ablaufen, definiert. Wie man hier sieht gibt es 2 Stages: build und deploy. Zu jeder
Stage gibt es mindestens einen Job und die Stage wird unter stage: beim Job festgelegt.
Zunächst pullt sich jeder Job ein Docker Image, das bei Image: definiert ist und klont das Repository in den Docker Container. In unserem Fall haben wir uns für Alpine entschieden,
da Alpine sehr leichtgewichtig ist.
Beim script: Unterpunkt kann man dann einen Shell-Skript festlegen, was im Job gemacht werden soll. Hier werden die Pakete make und py3-sphinx installiert.
Anschließend wird in den Bericht/ Ordner gewechselt und der make html Befehl aufgerufen, was den html-Bericht baut.
Mithilfe der artifacts: kann man Ordner definieren, die über mehrere Jobs persistieren, was sehr nützlich ist,
da z.B. der Output der Build Stage in der Deploy Stage benötigt wird. Außerdem kann man die Artifacts auch als Archiv herunterladen.
Unter only: kann definiert werden, wann die Pipeline bzw. der Job triggert.
Im variables: Unterpunkt kann man Variablen festlegen.
Beim deploy_job: gibt es eine Besonderheit: Dort wurde mit Secure Files gearbeitet. Das sind Dateien auf die nur die Projekt Developer und Maintainer Zugriff
haben und sensitive Inhalte beinhalten. Hochgeladen werden diese über folgendes Web-Interface:
In diesem Fall wurde ein SSH PrivateKey hochgeladen mit dem dann der Output des Build-Jobs via rsync auf den Hochschulserver übertragen wird. Über folgende Zeile werden die Secure Files heruntergeladen:
curl --silent "https://gitlab.com/gitlab-org/incubation-engineering/mobile-devops/download-secure-files/-/raw/main/installer" | bash
und in den Ordner .secure_files abgespeichert.
2.2. Gitlab Security Features¶
2.2.1. Secret Detection¶
Secret Detection ist eine Schlüsselfunktion von GitLab, die darauf ausgerichtet ist, unbeabsichtigt in den Quellcode eingecheckte sensible Informationen wie Passwörter, API-Schlüssel oder Tokens frühzeitig zu erkennen. Dieses Sicherheitsfeature spielt eine wesentliche Rolle dabei, die Sicherheit und Integrität von Softwareprojekten während des gesamten Entwicklungsprozesses zu gewährleisten.
Die Funktionalität von Secret Detection basiert auf einer Vielzahl von vordefinierten Mustern, die bekannte Formate für sensible Daten erkennen. Diese Muster werden auf jeden Commit angewendet, der in das Repository gepusht wird. Sollte ein potentielles Geheimnis gefunden werden, wird dies in der Merge Request-Ansicht markiert und kann im Detail im CI/CD-Pipeline-Bericht nachvollzogen werden.
include:
- template: Security/Secret-Detection.gitlab-ci.yml
Benutzer können die Erkennungsregeln anpassen oder erweitern, um spezifische Bedürfnisse ihres Projekts oder ihrer Organisation zu berücksichtigen. Zusätzlich zu den standardmäßigen Erkennungsregeln bietet GitLab die Möglichkeit, eigene Regeln zu definieren, die dann in die CI/CD-Pipeline integriert werden können.
Die Implementierung der Secret Detection ist ein Schritt zur Vermeidung von Datenlecks und zur Förderung einer Sicherheitskultur innerhalb von Entwicklungsteams. Dieses Tool ermöglicht es Teams, proaktiv auf Sicherheitsrisiken zu reagieren, bevor diese zu ernsthaften Bedrohungen werden.
Zusammenfassend ist Secret Detection nicht nur eine Sicherheitsmaßnahme, sondern auch ein wichtiges Werkzeug für die Compliance, indem es hilft, die Einhaltung von Datenschutzbestimmungen sicherzustellen.
2.2.2. Dependency Scanning¶
Dependency Scanning ist ein Tool, um eventuelle Schwächen im Programmcode zu identifizieren. Das beinhaltet auch die Analyse von transitiven Abhängigkeiten, sowie verwendete 3rd-party Bibliotheken.
Neben Python werden noch viele weitere Pakete unterstützt, u.a. C/C++, C#, Java, und JavaScript/Typescript.
Die verwendeten Programmiersprachen werden vom Dependency Scanner automatisch erkannt und daraufhin angewendet.
Für u.a. Python wird versucht das Programm zu bauen oder eine Liste aller Abhängigkeiten zu finden, also z.B. wird die requirements.txt Datei gesucht.
Um den Analyzer einzuschalten, wird eine .gitlab-ci.yml File vorausgesetzt, die eine test stage hat.
Folgende Zeilen müssen in die .gitlab-ci.yml Datei eingefügt werden:
include:
- template: Jobs/Dependency-Scanning.gitlab-ci.yml
Um zu prüfen, ob der Analyzer richtig konfiguriert wurde, kann man im Repository unter dem Tab Build / Pipelinte editor eine Simulation laufen lassen,
die den Inhalt der .gitlab-ci.yml validiert.
(Abbildung 1)
Es gibt noch andere Methoden um den Dependency Scanner einzubinden, unter anderem gibt es vorkonfigurierte Merge-Requests. Auf diesem Weg könnte die manuelel Bearbeitung des .gitlab-ci.yml File
weggelassen werden.
Der Output des Scanners ist ein Report, der u.a. bereits bei Merge Merge-Requests angezeigt wird. Außerdem werden bei entdeckten potentiellen Vulnerabilities direkt Lösungen angeboten.
Unglücklicherweise ist uns erst nach dem Setup des Dependency-Scanning Jobs in unserem Projekt aufgefallen, dass es sich hierbei um ein exlusives Advanced Security Feature handelt, dass nur mit Gitlab Ultimate zugänglich ist. Das Gitlab der Hochschule enthält dieses Feature leider nicht. Ein Beispiel Bericht sieht aus wie folgt:
(Abbildung 2)
2.2.3. SAST¶
Static Application Security Testing (SAST) überprüft den Code während der Entwicklung nach Sicheheitsschwachstellen. Zusammengefasst wird diese Schwachstelle in der gl-sast-report.json und ist im Merge Request sichtbar.
SAST kann für die Sprachen Python, React, TypeScript, Go und viele mehr verwendet werden und erkennt dabei automatisch die verwendete Programmiersprache
Auch hierfür wird eine .gitlab-ci.yml File vorausgesetzt, die eine test stage besitzt.
Folgende Zeilen müssen eingefügt werden:
include:
- template: Security/SAST.gitlab-ci.yml
Das Verhalten der Analysatoren kann angepasst werden indem eine sast-ruleset.toml in das .gitlab Verzeichnis eingefügt wird. Dort können vordefinierte Regeln deaktiviert beziehungsweise überschrieben werden. Es wird jedoch empfholen die Default Ruleset zu verwenden.
Es werden mehrere Analysatoren verwendet, die jeweils den Code durchgehen. Diese sind ein Wrapper um einen Scanner eines Drittanbieters. Beispielsweise wird für die meisten Sprachen der Semgrep-based analyzer verwendet, der unter anderem aus dem Sempreg open-source code besteht.
2.3. Fazit¶
Mithilfe von Gitlab CI/CD kann vor allem bei größeren Projekten sehr viel Zeit eingespart werden, da die Software vollautomatisiert gebaut, getestet, deployed und auch realeased werden kann. Es gibt eine Reihe von Security Features, bei denen aber beachtet werden muss, welches Gitlab Abonnement man besitzt, da einige Features nur in der Ultimate Variante verfügbar sind.
2.4. Literatur¶
Gitlab Pipeline Documentation https://docs.gitlab.com/ee/topics/build_your_application.html (10.04.2024)
Gitlab Runner Installation https://docs.gitlab.com/runner/install/ (10.04.2024)
GitLab Secret Detection https://docs.gitlab.com/ee/user/application_security/secret_detection/ (17.04.2024)
GitLab dependency Scanning: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#dependency-scanning-report (12.04.2024)
GitLab SAST https://docs.gitlab.com/ee/user/application_security/sast/ (17.04.2024)
Abbildung 2: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/img/dependency_scanning_v13_2.png (12.04.2024)