Hé Habr!
In de moderne realiteit is, vanwege de groeiende rol van containerisatie in ontwikkelingsprocessen, de kwestie van het waarborgen van de veiligheid van verschillende stadia en entiteiten die verband houden met containers niet de minst belangrijke kwestie. Het uitvoeren van handmatige controles is tijdrovend, dus het zou een goed idee zijn om in ieder geval de eerste stappen te zetten om dit proces te automatiseren.
In dit artikel deel ik kant-en-klare scripts voor het implementeren van verschillende Docker-beveiligingshulpprogramma's en instructies over hoe je een kleine demo-stand kunt inzetten om dit proces te testen. U kunt het materiaal gebruiken om te experimenteren met het organiseren van het proces van het testen van de beveiliging van Dockerfile-afbeeldingen en -instructies. Het is duidelijk dat de ontwikkel- en implementatie-infrastructuur voor iedereen anders is, dus hieronder zal ik verschillende mogelijke opties geven.
Hulpprogramma's voor beveiligingscontroles
Er is een groot aantal verschillende helperapplicaties en scripts die controles uitvoeren op verschillende aspecten van de Docker-infrastructuur. Sommigen van hen zijn al beschreven in het vorige artikel (
Hadolint
Een vrij eenvoudig consolehulpprogramma dat, als eerste benadering, helpt bij het evalueren van de juistheid en veiligheid van Dockerfile-instructies (bijvoorbeeld door alleen geautoriseerde afbeeldingsregisters te gebruiken of sudo te gebruiken).
dokken
Een consolehulpprogramma dat werkt met een afbeelding (of met een opgeslagen tar-archief van een afbeelding), dat de juistheid en veiligheid van een bepaalde afbeelding als zodanig controleert en de lagen en configuratie ervan analyseert - welke gebruikers worden gemaakt, welke instructies worden gebruikt, welke volumes zijn aangekoppeld, de aanwezigheid van een leeg wachtwoord, enz. d. Tot nu toe is het aantal controles niet erg groot en is het gebaseerd op verschillende van onze eigen controles en aanbevelingen
Trivia
Dit hulpprogramma is gericht op het vinden van twee soorten kwetsbaarheden: problemen met OS-builds (ondersteund door Alpine, RedHat (EL), CentOS, Debian GNU, Ubuntu) en problemen met afhankelijkheden (Gemfile.lock, Pipfile.lock, composer.lock, package -lock.json, garen.lock, cargo.lock). Trivy kan zowel een afbeelding in de repository als een lokale afbeelding scannen, en kan ook scannen op basis van het overgedragen .tar-bestand met de Docker-afbeelding.
Opties voor het implementeren van hulpprogramma's
Om de beschreven toepassingen in een geïsoleerde omgeving uit te proberen, zal ik instructies geven voor het installeren van alle hulpprogramma's in een enigszins vereenvoudigd proces.
Het belangrijkste idee is om te demonstreren hoe u automatische inhoudverificatie kunt implementeren van Dockerfiles en Docker-images die tijdens de ontwikkeling zijn gemaakt.
De controle zelf bestaat uit de volgende stappen:
- Controleren van de juistheid en veiligheid van Dockerfile-instructies met behulp van een linter-hulpprogramma Hadolint
- Controle van de juistheid en veiligheid van de eind- en tussenafbeeldingen met behulp van een hulpprogramma dokken
- Controleren op de aanwezigheid van publiekelijk bekende kwetsbaarheden (CVE) in de basisimage en een aantal afhankelijkheden - met behulp van het hulpprogramma Trivia
Verderop in het artikel zal ik drie opties geven om deze stappen uit te voeren:
De eerste is door de CI/CD-pijplijn te configureren met GitLab als voorbeeld (met een beschrijving van het proces voor het genereren van een testinstantie).
De tweede gebruikt een shellscript.
De derde omvat het bouwen van een Docker-image om Docker-images te scannen.
U kunt de optie kiezen die het beste bij u past, deze overbrengen naar uw infrastructuur en aanpassen aan uw behoeften.
Alle benodigde bestanden en aanvullende instructies bevinden zich ook in de repository:
Integratie in GitLab CI/CD
In de eerste optie zullen we bekijken hoe u beveiligingscontroles kunt implementeren met behulp van het GitLab-repositorysysteem als voorbeeld. Hier zullen we de stappen doorlopen en uitzoeken hoe we een testomgeving met GitLab helemaal opnieuw kunnen installeren, een scanproces kunnen maken en hulpprogramma's kunnen starten voor het controleren van het test-dockerbestand en een willekeurige afbeelding - de JuiceShop-applicatie.
GitLab installeren
1. Docker installeren:
sudo apt-get update && sudo apt-get install docker.io
2. Voeg de huidige gebruiker toe aan de dockergroep zodat u met docker kunt werken zonder sudo te gebruiken:
sudo addgroup <username> docker
3. Vind uw IP:
ip addr
4. Installeer en start GitLab in de container, waarbij u het IP-adres in de hostnaam vervangt door uw eigen adres:
docker run --detach
--hostname 192.168.1.112
--publish 443:443 --publish 80:80
--name gitlab
--restart always
--volume /srv/gitlab/config:/etc/gitlab
--volume /srv/gitlab/logs:/var/log/gitlab
--volume /srv/gitlab/data:/var/opt/gitlab
gitlab/gitlab-ce:latest
We wachten totdat GitLab alle noodzakelijke installatieprocedures heeft voltooid (je kunt het proces volgen via de uitvoer van het logbestand: docker logs -f gitlab).
5. Open uw lokale IP in de browser en zie een pagina waarin u wordt gevraagd het wachtwoord voor de rootgebruiker te wijzigen:
Stel een nieuw wachtwoord in en ga naar GitLab.
6. Maak een nieuw project, bijvoorbeeld cicd-test, en initialiseer dit met het startbestand README.md:
7. Nu moeten we GitLab Runner installeren: een agent die op verzoek alle noodzakelijke bewerkingen uitvoert.
Download de nieuwste versie (in dit geval voor Linux 64-bit):
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
8. Maak het uitvoerbaar:
sudo chmod +x /usr/local/bin/gitlab-runner
9. Voeg een OS-gebruiker toe voor Runner en start de service:
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start
Het zou er ongeveer zo uit moeten zien:
local@osboxes:~$ sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
Runtime platform arch=amd64 os=linux pid=8438 revision=0e5417a3 version=12.0.1
local@osboxes:~$ sudo gitlab-runner start
Runtime platform arch=amd64 os=linux pid=8518 revision=0e5417a3 version=12.0.1
10. Nu registreren we de Runner zodat deze kan communiceren met onze GitLab-instantie.
Open hiervoor de pagina Instellingen-CI/CD (http://OUR_IP_ADDRESS/root/cicd-test/-/settings/ci_cd) en zoek op het tabblad Runners de URL en het registratietoken:
11. Registreer Runner door de URL en het registratietoken te vervangen:
sudo gitlab-runner register
--non-interactive
--url "http://<URL>/"
--registration-token "<Registration Token>"
--executor "docker"
--docker-privileged
--docker-image alpine:latest
--description "docker-runner"
--tag-list "docker,privileged"
--run-untagged="true"
--locked="false"
--access-level="not_protected"
Als resultaat krijgen we een kant-en-klaar werkend GitLab, waarin we instructies moeten toevoegen om onze hulpprogramma's te starten. In deze demo hebben we niet de stappen om de applicatie te bouwen en in containers te plaatsen, maar in een echte omgeving zouden deze aan de scanstappen voorafgaan en afbeeldingen en een Dockerfile genereren voor analyse.
configuratie van pijpleidingen
1. Voeg bestanden toe aan de repository mijndockerbestand.df (dit is een test Dockerfile die we zullen controleren) en het GitLab CI/CD-procesconfiguratiebestand .gitlab-cicd.yml, waarin instructies voor scanners worden vermeld (let op de punt in de bestandsnaam).
Het YAML-configuratiebestand bevat instructies voor het uitvoeren van drie hulpprogramma's (Hadolint, Dockle en Trivy) die het geselecteerde Dockerfile en de afbeelding die is opgegeven in de DOCKERFILE-variabele analyseren. Alle benodigde bestanden kunnen uit de repository worden gehaald:
Uittreksel uit mijndockerbestand.df (dit is een abstract bestand met een reeks willekeurige instructies die alleen de werking van het hulpprogramma demonstreren). Directe link naar het bestand:
Inhoud van mijndockerfile.df
FROM amd64/node:10.16.0-alpine@sha256:f59303fb3248e5d992586c76cc83e1d3700f641cbcd7c0067bc7ad5bb2e5b489 AS tsbuild
COPY package.json .
COPY yarn.lock .
RUN yarn install
COPY lib lib
COPY tsconfig.json tsconfig.json
COPY tsconfig.app.json tsconfig.app.json
RUN yarn build
FROM amd64/ubuntu:18.04@sha256:eb70667a801686f914408558660da753cde27192cd036148e58258819b927395
LABEL maintainer="Rhys Arkins <[email protected]>"
LABEL name="renovate"
...
COPY php.ini /usr/local/etc/php/php.ini
RUN cp -a /tmp/piik/* /var/www/html/
RUN rm -rf /tmp/piwik
RUN chown -R www-data /var/www/html
ADD piwik-cli-setup /piwik-cli-setup
ADD reset.php /var/www/html/
## ENTRYPOINT ##
ADD entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
USER root
De configuratie YAML ziet er als volgt uit (het bestand zelf kun je vinden via de directe link hier:
Inhoud van .gitlab-ci.yml
variables:
DOCKER_HOST: "tcp://docker:2375/"
DOCKERFILE: "mydockerfile.df" # name of the Dockerfile to analyse
DOCKERIMAGE: "bkimminich/juice-shop" # name of the Docker image to analyse
# DOCKERIMAGE: "knqyf263/cve-2018-11235" # test Docker image with several CRITICAL CVE
SHOWSTOPPER_PRIORITY: "CRITICAL" # what level of criticality will fail Trivy job
TRIVYCACHE: "$CI_PROJECT_DIR/.cache" # where to cache Trivy database of vulnerabilities for faster reuse
ARTIFACT_FOLDER: "$CI_PROJECT_DIR"
services:
- docker:dind # to be able to build docker images inside the Runner
stages:
- scan
- report
- publish
HadoLint:
# Basic lint analysis of Dockerfile instructions
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/hadolint_results.json
script:
- export VERSION=$(wget -q -O - https://api.github.com/repos/hadolint/hadolint/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/1/')
- wget https://github.com/hadolint/hadolint/releases/download/v${VERSION}/hadolint-Linux-x86_64 && chmod +x hadolint-Linux-x86_64
# NB: hadolint will always exit with 0 exit code
- ./hadolint-Linux-x86_64 -f json $DOCKERFILE > $ARTIFACT_FOLDER/hadolint_results.json || exit 0
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/hadolint_results.json
Dockle:
# Analysing best practices about docker image (users permissions, instructions followed when image was built, etc.)
stage: scan
image: docker:git
after_script:
- cat $ARTIFACT_FOLDER/dockle_results.json
script:
- export VERSION=$(wget -q -O - https://api.github.com/repos/goodwithtech/dockle/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/1/')
- wget https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.tar.gz && tar zxf dockle_${VERSION}_Linux-64bit.tar.gz
- ./dockle --exit-code 1 -f json --output $ARTIFACT_FOLDER/dockle_results.json $DOCKERIMAGE
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/dockle_results.json
Trivy:
# Analysing docker image and package dependencies against several CVE bases
stage: scan
image: docker:git
script:
# getting the latest Trivy
- apk add rpm
- export VERSION=$(wget -q -O - https://api.github.com/repos/knqyf263/trivy/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/1/')
- wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz && tar zxf trivy_${VERSION}_Linux-64bit.tar.gz
# displaying all vulnerabilities w/o failing the build
- ./trivy -d --cache-dir $TRIVYCACHE -f json -o $ARTIFACT_FOLDER/trivy_results.json --exit-code 0 $DOCKERIMAGE
# write vulnerabilities info to stdout in human readable format (reading pure json is not fun, eh?). You can remove this if you don't need this.
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 0 $DOCKERIMAGE
# failing the build if the SHOWSTOPPER priority is found
- ./trivy -d --cache-dir $TRIVYCACHE --exit-code 1 --severity $SHOWSTOPPER_PRIORITY --quiet $DOCKERIMAGE
artifacts:
when: always # return artifacts even after job failure
paths:
- $ARTIFACT_FOLDER/trivy_results.json
cache:
paths:
- .cache
Report:
# combining tools outputs into one HTML
stage: report
when: always
image: python:3.5
script:
- mkdir json
- cp $ARTIFACT_FOLDER/*.json ./json/
- pip install json2html
- wget https://raw.githubusercontent.com/shad0wrunner/docker_cicd/master/convert_json_results.py
- python ./convert_json_results.py
artifacts:
paths:
- results.html
Indien nodig kunt u ook opgeslagen afbeeldingen scannen in de vorm van een .tar-archief (u moet echter wel de invoerparameters voor de hulpprogramma's in het YAML-bestand wijzigen)
NB: Trivy vereist installatie rpm и git. Anders genereert het fouten bij het scannen van op RedHat gebaseerde afbeeldingen en het ontvangen van updates voor de database met kwetsbaarheden.
2. Na het toevoegen van bestanden aan de repository, volgens de instructies in ons configuratiebestand, zal GitLab automatisch beginnen met het bouw- en scanproces. Op het tabblad CI/CD → Pipelines kunt u de voortgang van instructies zien.
Hierdoor hebben we vier taken. Drie ervan houden zich rechtstreeks bezig met scannen, en de laatste (Report) verzamelt een eenvoudig rapport van verspreide bestanden met scanresultaten.
Standaard stopt Trivy met werken als KRITISCHE kwetsbaarheden worden gedetecteerd in de afbeelding of afhankelijkheden. Tegelijkertijd retourneert Hadolint altijd een Succescode omdat deze altijd resulteert in opmerkingen, waardoor de build stopt.
Afhankelijk van uw specifieke vereisten kunt u een exitcode configureren, zodat wanneer deze hulpprogramma's problemen van een bepaald kritiek belang detecteren, ze ook het bouwproces stoppen. In ons geval stopt de build alleen als Trivy een kwetsbaarheid detecteert met de kriticiteit die we hebben opgegeven in de SHOWSTOPPER-variabele in .gitlab-ci.yml.
Het resultaat van elk hulpprogramma kan worden bekeken in het logboek van elke scantaak, rechtstreeks in de json-bestanden in de artefactensectie, of in een eenvoudig HTML-rapport (meer daarover hieronder):
3. Om hulpprogrammarapporten in een iets meer voor mensen leesbare vorm te presenteren, wordt een klein Python-script gebruikt om drie JSON-bestanden om te zetten in één HTML-bestand met een tabel met defecten.
Dit script wordt gestart door een afzonderlijke rapporttaak en het uiteindelijke artefact is een HTML-bestand met een rapport. De scriptbron bevindt zich ook in de repository en kan worden aangepast aan uw behoeften, kleuren, enz.
Shell-script
De tweede optie is geschikt voor gevallen waarin u Docker-images buiten het CI/CD-systeem moet controleren of als u alle instructies in een vorm wilt hebben die rechtstreeks op de host kan worden uitgevoerd. Deze optie wordt gedekt door een kant-en-klaar shellscript dat op een schone virtuele (of zelfs echte) machine kan worden uitgevoerd. Het script voert dezelfde instructies uit als de hierboven beschreven gitlab-runner.
Om het script succesvol uit te voeren, moet Docker op het systeem zijn geïnstalleerd en moet de huidige gebruiker zich in de dockergroep bevinden.
Het script zelf vind je hier:
Aan het begin van het bestand specificeren variabelen welke afbeelding moet worden gescand en welke kritieke defecten ervoor zorgen dat het Trivy-hulpprogramma wordt afgesloten met de opgegeven foutcode.
Tijdens de uitvoering van het script worden alle hulpprogramma's naar de map gedownload docker_tools, de resultaten van hun werk staan in de directory docker_tools/jsonen de HTML met het rapport staat in het bestand resultaten.html.
Voorbeeld van scriptuitvoer
~/docker_cicd$ ./docker_sec_check.sh
[+] Setting environment variables
[+] Installing required packages
[+] Preparing necessary directories
[+] Fetching sample Dockerfile
2020-10-20 10:40:00 (45.3 MB/s) - ‘Dockerfile’ saved [8071/8071]
[+] Pulling image to scan
latest: Pulling from bkimminich/juice-shop
[+] Running Hadolint
...
Dockerfile:205 DL3015 Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:248 DL3002 Last USER should not be root
...
[+] Running Dockle
...
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
...
[+] Running Trivy
juice-shop/frontend/package-lock.json
=====================================
Total: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 2, CRITICAL: 0)
+---------------------+------------------+----------+---------+-------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | VERSION | TITLE |
+---------------------+------------------+----------+---------+-------------------------+
| object-path | CVE-2020-15256 | HIGH | 0.11.4 | Prototype pollution in |
| | | | | object-path |
+---------------------+------------------+ +---------+-------------------------+
| tree-kill | CVE-2019-15599 | | 1.2.2 | Code Injection |
+---------------------+------------------+----------+---------+-------------------------+
| webpack-subresource | CVE-2020-15262 | LOW | 1.4.1 | Unprotected dynamically |
| | | | | loaded chunks |
+---------------------+------------------+----------+---------+-------------------------+
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
juice-shop/package-lock.json
============================
Total: 5 (CRITICAL: 5)
...
[+] Removing left-overs
[+] Making the output look pretty
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
Docker-image met alle hulpprogramma's
Als derde alternatief heb ik twee eenvoudige Dockerbestanden samengesteld om een image te maken met beveiligingshulpprogramma's. Eén Dockerfile helpt bij het bouwen van een set voor het scannen van een afbeelding uit een repository, de tweede (Dockerfile_tar) helpt bij het bouwen van een set voor het scannen van een tar-bestand met een afbeelding.
1. Haal het bijbehorende Docker-bestand en de scripts uit de repository
2. We lanceren het voor montage:
docker build -t dscan:image -f docker_security.df .
3. Nadat de montage is voltooid, maken we een container van de afbeelding. Tegelijkertijd geven we de omgevingsvariabele DOCKERIMAGE door met de naam van de afbeelding waarin we geïnteresseerd zijn en koppelen we het Dockerbestand dat we van onze machine willen analyseren naar het bestand / Dockerbestand (merk op dat het absolute pad naar dit bestand vereist is):
docker run --rm -v $(pwd)/results:/results -v $(pwd)/docker_security.df:/Dockerfile -e DOCKERIMAGE="bkimminich/juice-shop" dscan:image
[+] Setting environment variables
[+] Running Hadolint
/Dockerfile:3 DL3006 Always tag the version of an image explicitly
[+] Running Dockle
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
* not found HEALTHCHECK statement
INFO - DKL-LI-0003: Only put necessary files
* unnecessary file : juice-shop/node_modules/sqlite3/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm64/Dockerfile
* unnecessary file : juice-shop/node_modules/sqlite3/tools/docker/architecture/linux-arm/Dockerfile
[+] Running Trivy
...
juice-shop/package-lock.json
============================
Total: 20 (UNKNOWN: 0, LOW: 1, MEDIUM: 6, HIGH: 8, CRITICAL: 5)
...
[+] Making the output look pretty
[+] Starting the main module ============================================================
[+] Converting JSON results
[+] Writing results HTML
[+] Clean exit ============================================================
[+] Everything is done. Find the resulting HTML report in results.html
Bevindingen
We hebben slechts naar één basisset hulpprogramma's gekeken voor het scannen van Docker-artefacten, die naar mijn mening zeer effectief een behoorlijk deel van de beeldbeveiligingsvereisten dekken. Er zijn ook een groot aantal betaalde en gratis tools die dezelfde controles kunnen uitvoeren, mooie rapporten kunnen tekenen of puur in consolemodus kunnen werken, containerbeheersystemen kunnen dekken, enz. Een overzicht van deze tools en hoe ze te integreren verschijnen misschien iets later .
Het goede aan de set tools die in het artikel wordt beschreven, is dat ze allemaal op open source-code zijn gebouwd en dat je ermee en met andere soortgelijke tools kunt experimenteren om te ontdekken wat bij jouw vereisten en infrastructuurfuncties past. Uiteraard moeten alle gevonden kwetsbaarheden worden onderzocht op toepasbaarheid in specifieke omstandigheden, maar dit is een onderwerp voor een toekomstig groot artikel.
Ik hoop dat deze gids, scripts en hulpprogramma's je zullen helpen en een startpunt zullen worden voor het creëren van een veiligere infrastructuur op het gebied van containerisatie.
Bron: www.habr.com