Wykrywanie problemów związanych z bezpieczeństwem z Composer Audit i Gitlab CI

Bezpieczeństwo aplikacji to kluczowy priorytet, zwłaszcza w obliczu rosnących zagrożeń cybernetycznych. Aby skutecznie monitorować podatności w zależnościach PHP, zautomatyzowaliśmy proces audytu, łącząc Composer Audit z Mattermost i GitLab CI/CD. Dzięki temu nasz zespół może natychmiast reagować na zagrożenia w aplikacjach opartych na Drupal, Symfony, Grav i WordPress, zapewniając ich stabilność i bezpieczeństwo.
Motywacja
Do obowiązków naszego zespołu należy wsparcie, utrzymanie, monitorowanie podatności i zabezpieczenie aplikacji naszych klientów. Większość z nich to aplikacje oparte na platformie Drupal, choć od czasu do czasu pracujemy także z innymi aplikacjami napisanymi w PHP, takimi jak te oparte na Symfony, czy też prostymi stronami internetowymi, opartymi m.in na systemach jak Grav czy WordPress. Aby zapewnić stabilność i bezpieczeństwo tych aplikacji, kluczowe jest regularne ich aktualizowanie - szczególnie w kontekście uaktualnień związanych z bezpieczeństwem.
Biorąc pod uwagę różnorodność platform, z którymi mamy do czynienia, postanowiliśmy stworzyć prosty, a jednocześnie uniwersalny sposób identyfikacji kluczowych aktualizacji związanych z zagrożeniami bezpieczeństwa. Daje nam to możliwość szybkiego reagowania i zapewnienia najwyższego poziomu bezpieczeństwa dla aplikacji opartych na PHP, które są w naszym utrzymaniu.
Filozofia rozwiązania
Zanim przejdę do szczegółów, przedstawię filozoficzne ramy, które kierowały naszym procesem projektowania.
W książce “The Art of Unix Programming”, Eric S Raymond zwięźle podsumował kluczowe elementy filozofii Unix, która podkreśla zalety małych, komponowalnych programów.
Pierwszy opis filozofii powstał w 1978 roku, opisany przez Douga McIlroya (artykuł “Unix Time-Sharing System: Foreword”) na łamach “Bell System Technical Journal”. Filozofia Unix nadal pozostaje aktualna i znacząca, mimo że minęło 47 lat. W szczególności bliskie są dla nas następujące założenia:
- Twórzmy programy, które robią jedną rzecz i robią ją dobrze
- Twórzmy programy, które mogą pracować wspólnie
- Twórzmy programy, by przetwarzały strumień tekstu jako uniwersalny interfejs
Eric S Raymond podsumował tę filozofię jako “Keep it Simple, Stupid” (KISS). Przygotowując nasze rozwiązanie, staraliśmy się zachować ducha tych pryncypiów.
Elementy rozwiązania
- Composer Audit - Wykorzystujemy narzędzie composer audit do generowania tabeli raportów CVE. Pozwala to identyfikować znane podatności w pakietach zależności zarządzanych w naszym composer.json.
- Mattermost - Naszą platformą komunikacyjną jest Mattermost. Jest to otwartoźródłowa platforma do komunikacji w zespołach, będąc świetną alternatywą do usług takich jak Slack. Używamy mechanizmu incoming webhooks, aby wysyłać alerty o podatnościach.
- Skrypt bash - Napisaliśmy prosty skrypt, który integruje Mattermost i Composer Audit.
- Docker - Dystrybuujemy skrypt wraz ze środowiskiem uruchomieniowym w formie obrazu Dockera. Dzięki temu możemy łatwo przenosić nasze narzędzia między różnymi środowiskami i zapewnić ich poprawne działanie.
- Gitlab CI/CD - Aby wykonywać skanowanie okresowo oraz podczas rutynowych wdrożeń, wykorzystamy standardowe rozwiązanie CI/CD dla Ratioweb - Gitlab CI/CD. To pozwala nam na bieżąco monitorować stan bezpieczeństwa naszych projektów i szybko reagować na jakiekolwiek zagrożenia.
Implementacja
Skrypt Bash - entrypoint.sh
Poniżej znajduje się plik entrypoint.sh, który działa jako wrapper dla composer audit, umożliwiając automatyczną detekcję podatności i powiadamianie zespołu przez Mattermost.
#!/bin/sh
# Przejdźmy do katalogu budowania projektu (zmienna gitlab ci/cd)
cd $CI_PROJECT_DIR || exit 1
# Instalowanie zależności zdefiniowanych w composer.json.
composer install --ignore-platform-reqs
# Uruchomienie audytu bezpieczeństwa. Ignorujemy opuszczone pakiety
auditResult=$(composer audit --abandoned=report --format=plain 2>&1)
# Skrypt zwraca liczbę pakietów wymienionych w raporcie
auditStatus=$?
# Sprawdzenie, czy COMPOSER_SECURITY_MATTERMOST_WEBHOOK nie jest pusty i czy mamy przynajmniej jeden błąd
if [ -n "${COMPOSER_SECURITY_MATTERMOST_WEBHOOK}" ] && [ $auditStatus -ge 1 ]; then
# Wysyłanie wyniku audytu kompozytora do webhooka Mattermost.
jsonPayload=$(printf '{"text": "%s", "priority": { "priority": "important", "requested_ack": true }}' "### Raport bezpieczeństwa: $CI_PROJECT_PATH\n$auditResult")
echo "$jsonPayload" | http --verify=no POST "${COMPOSER_SECURITY_MATTERMOST_WEBHOOK}"
else
echo "$auditResult"
fi
exit $auditStatus
Podsumujmy kroki skryptu entrypoint.sh
- Przechodzi do katalogu projektu
cd $CI_PROJECT_DIR || exit 1
– jeśli katalog nie istnieje, skrypt kończy działanie.
- Instalacja zależności z composer.json
composer install --ignore-platform-reqs
– ignoruje wymagania platformy (np. rozszerzenia php). Nie będziemy tego kodu wykonywać, tylko poddamy go statycznej analizie.
- Wykonanie audytu bezpieczeństwa
auditResult=$(composer audit --abandoned=report --format=plain 2>&1)
sprawdza podatności. Informacje o porzuconych pakietach zostaną wyświetlone, ale nie wpłyną na efekt audytu.
- Analiza wyniku audytu
- Jeśli znaleziono podatności i webhook Mattermost jest ustawiony → wysyła alert i kończy się błędem.
- Jeśli znaleziono podatności, webhook nie jest ustawiony → kończy się błędem z raportem w konsoli
- Brak podatności - drukuje wynik w konsoli.
Plik Dockerfile
Aby nasz skrypt mógł działać w różnych środowiskach, pakujemy go w kontener Docker. Oto Dockerfile
:
ARG PHP_VER
FROM php:$PHP_VER-alpine
RUN apk update && apk add httpie git unzip patch
# Download and install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN chmod +x /usr/local/bin/composer
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENV COMPOSER_SECURITY_MATTERMOST_WEBHOOK ""
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Jak działa ten Dockerfile?
- Bazuje na oficjalnym obrazie PHP z hub.docker.com
FROM php:$PHP_VER-alpine
– używamy lekkiego obrazu Alpine dla różnych wersji PHP.
- Instaluje dodatkowe narzędzia
apk add httpie git unzip patch
– dodajemy niezbędne pakiety systemowe.
- Pobiera i instaluje najnowszą wersję composera
curl -sS https://getcomposer.org/installer | php
– pobieramy i instalujemy Composer.chmod +x /usr/local/bin/composer
– nadajemy uprawnienia do wykonania.
- Dodaje skrypt audytu napisany w bash
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
– kopiujemy skrypt do kontenera.
- Ustawia placeholder zmiennej środowiskowej
ENV COMPOSER_SECURITY_MATTERMOST_WEBHOOK ""
– placeholder na webhook Mattermost.
- Definiuje punkt wejścia
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
– skrypt uruchamiany przy starcie kontenera.
Jak budujemy nasz obraz docker?
Budujemy ten obraz dla każdej wersji PHP, którą obsługujemy (np. 8.1, 8.2, 8.3), używając następującego skryptu
docker build -t "$REPO":"$PHP_VER" --cache-from "$REPO":"$PHP_VER" --build-arg PHP_VER="$PHP_VER" .
- REPO to adres URL do obrazu docker w rejestrze (np. w naszym prywatnym repozytorium Docker zlokalizowanym na naszej prywatnej instancji Gitlab)
- PHP_VER to jedna z obsługiwanych wersji PHP (np. 8.1)
Integracja z GitLab CI/CD
Aby zapewnić automatyczną detekcję podatności w zależnościach PHP, wprowadziliśmy integrację z GitLab CI/CD. Korzystamy z dwóch typów zadań:
- test:composer-audit – sprawdza podatności w interaktywnych pipeline’ach (w kontekście pipelines merge request).
- security:composer – działa jako zadanie okresowe i monitoruje nowe podatności raz na dobę.
Konfiguracja Gitlab CI/CD
Poniżej fragment .gitlab-ci.yml
z konfiguracją naszego procesu CI/CD.
security:composer:
stage: tasks
image: {private-registry-url}/toolkit/composersecurity:$PHP_VERSION
needs: []
script:
entrypoint.sh
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
exists:
- '**/composer.json'
-
when: manual
exists:
- '**/composer.json'
test:composer-audit:
extends: security:composer
stage: test
variables:
COMPOSER_SECURITY_MATTERMOST_WEBHOOK: ""
allow_failure: true
rules:
- if: '$CI_PIPELINE_SOURCE != "merge_request_event"'
when: never
- exists:
- '**/composer.json'
Jak działają zadania w .gitlab-ci.yml:
- test:composer-audit
- Uruchamiane tylko w kontekście merge requestów
- Pozwala programistom sprawdzić podatności przed wdrożeniem.
- Webhook Mattermost jest wyłączony (COMPOSER_SECURITY_MATTERMOST_WEBHOOK=““), aby uniknąć zbędnych alertów.
- W przypadku wykrycia podatności skrypt informuje o błędzie, ale nie blokuje wdrożenia (
allow_failure: true
)
- security:composer
- Uruchamiane raz na dobę jako zadanie z harmonogramu gitlab (https://docs.gitlab.co.jp/ee/ci/pipelines/schedules.html)
- Jeśli wykryje nową podatność, wysyła powiadomienie do zespołu utrzymania.
Korzystając z tego mechanizmu, przygotowaliśmy wykonywanie skanera raz na dobę. Dzięki temu, gdy tylko pojawia się nowa podatność, narzędzie poinformuje zespół utrzymania o potrzebie aktualizacji w jednym z projektów, którym się zajmujemy.
Podsumowanie
Dlaczego to rozwiązanie?
Zautomatyzowana weryfikacja bezpieczeństwa, integracja z GitLab CI/CD i natychmiastowe powiadomienia w Mattermost tworzą kompleksowy mechanizm ochrony aplikacji PHP. Dzięki temu nasz zespół może szybko reagować na zagrożenia i minimalizować ryzyko ataków. Wykorzystanie Dockera zapewnia elastyczność i łatwość wdrożenia w różnych środowiskach, co dodatkowo zwiększa efektywność rozwiązania.
Co osiągnęliśmy?
- Automatyzacja audytu bezpieczeństwa – Composer Audit pozwala nam wykrywać podatności w zależnościach PHP.
- Integracja z GitLab CI/CD – Regularne skanowanie raz na dobę oraz analiza w trakcie merge requestów gwarantują ciągłą kontrolę nad bezpieczeństwem.
- Powiadomienia w Mattermost – Automatyczne alerty pozwalają zespołowi szybko reagować na wykryte zagrożenia.
- Przenośność i łatwa konfiguracja – Dzięki Dockerowi nasze narzędzie działa w różnych środowiskach bez potrzeby dodatkowej konfiguracji.
Korzyści dla zespołu utrzymania
- Proaktywne podejście do bezpieczeństwa – Monitorowanie nowych podatności pozwala na szybką reakcję i minimalizuje ryzyko ataków.
- Pełna integracja z cyklem życia aplikacji – Narzędzie wspiera zarówno bieżące utrzymanie, jak i rozwój aplikacji, nie zakłócając procesów wdrożeniowych.
- Jasna komunikacja – Automatyczne raporty eliminują ryzyko przeoczenia podatności i ułatwiają planowanie aktualizacji.
Korzyści dla klienta
- Bezpieczne aplikacje – Regularne audyty eliminują znane podatności, co zwiększa ochronę przed atakami.
- Minimalizacja ryzyka przestojów – Automatyczne wykrywanie i usuwanie podatności zmniejsza ryzyko awarii systemu.
- Zgodność z najlepszymi praktykami – Proces audytu wspiera zgodność z wymaganiami bezpieczeństwa, co może być istotne dla regulacji i standardów branżowych.
- Większa stabilność oprogramowania – Aktualizacje wprowadzane na bieżąco pozwalają utrzymać wysoką jakość i niezawodność aplikacji.
Dzięki tej architekturze zapewniamy najwyższy poziom bezpieczeństwa aplikacji opartych na Drupal, Symfony, Grav i WordPress, eliminując konieczność ręcznej analizy podatności.
Zautomatyzowane procesy weryfikacji bezpieczeństwa, integracja z GitLab CI/CD i natychmiastowe powiadomienia na platformie Mattermost tworzą kompleksowe rozwiązanie, które pozwala na szybkie reagowanie na zagrożenia i minimalizowanie ryzyka ataków. Dzięki Dockerowi, nasze narzędzie jest elastyczne i łatwe do wdrożenia w różnych środowiskach, co czyni je jeszcze bardziej efektywnym.
Zespół utrzymania aplikacji zyskuje narzędzie, które nie tylko zwiększa bezpieczeństwo, ale również usprawnia cały proces zarządzania aktualizacjami i wykrywaniem zagrożeń, umożliwiając jednocześnie błyskawiczne reakcje na pojawiające się problemy.
z ambitnymi ludźmi i projektami