Qual è il vantaggio di suddividere l'ambiente di esecuzione dei container in componenti strumentali separati? In particolare, che questi strumenti possono essere combinati per proteggersi a vicenda.

Molti sono attratti dall'idea di eseguire la build delle immagini OCI dei container all'interno di o un sistema simile. Supponiamo di avere un CI/CD che costruisce costantemente le immagini, allora qualcosa come /Kubernetes было бы весьма полезно с точки зрения распределения нагрузки при сборке. До недавних пор большинство людей просто давали контейнерам доступ к Docker-сокету и разрешали выполнять команду docker build. , che questo è molto insicuro, in effetti, è addirittura peggio che concedere accesso root o sudo senza password.
Pertanto, le persone cercano costantemente di eseguire Buildah in un container. In breve, abbiamo creato un modo, a nostro avviso, per eseguire al meglio Buildah all'interno di un container e abbiamo reso disponibili le relative immagini su . Cominciamo...
Impostazione
Queste immagini sono state compilate da Dockerfile, che possono essere trovati nel repository di Buildah nella cartella .
Qui esamineremo .
# stable/Dockerfile
#
# Build a Buildah container image from the latest
# stable version of Buildah on the Fedoras Updates System.
# https://bodhi.fedoraproject.org/updates/?search=buildah
# This image can be used to create a secured container
# that runs safely with privileges within the container.
#
FROM fedora:latest
# Don't include container-selinux and remove
# directories used by dnf that are just taking
# up space.
RUN yum -y install buildah fuse-overlayfs --exclude container-selinux; rm -rf /var/cache /var/log/dnf* /var/log/yum.*
# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
Invece di OverlayFS, implementato a livello del kernel Linux dell'host, utilizziamo all'interno del container il programma , poiché al momento OverlayFS può montare solo se gli vengono concesse le autorizzazioni SYS_ADMIN tramite le capacità di Linux. E vogliamo eseguire i nostri contenitori Buildah senza alcun privilegio di root. Fuse-overlay funziona abbastanza velocemente e offre migliori prestazioni rispetto al driver di storage VFS. Si noti che, quando si esegue un contenitore Buildah che utilizza Fuse, è necessario fornire il dispositivo /dev/fuse.
podman run --device /dev/fuse quay.io/buildahctr ...
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
Successivamente creiamo una directory per gli storage aggiuntivi. supporta il concetto di collegamento di storage immagine aggiuntivi in sola lettura. Ad esempio, è possibile configurare un'area di overlay di storage su una macchina e poi montare questa storage tramite NFS su un'altra macchina e utilizzare le immagini senza scaricarle tramite pull. Abbiamo bisogno di questo storage per poter collegare come volume uno storage immagine dall'host e usarlo all'interno del contenitore.
# Set up environment variables to note that this is
# not starting with user namespace and default to
# isolate the filesystem with chroot.
ENV _BUILDAH_STARTED_IN_USERNS="" BUILDAH_ISOLATION=chroot
Infine, utilizzando la variabile d'ambiente BUILDAH_ISOLATION, indichiamo che per impostazione predefinita il contenitore Buildah deve essere avviato con isolamento chroot. Ulteriore isolamento non è necessario, poiché stiamo già operando all'interno di un contenitore. Per consentire a Buildah di creare i propri contenitori con separazione dei namespace, è necessaria la privilegio SYS_ADMIN, e questo comporterebbe l'allentamento delle regole SELinux e SECCOMP per il contenitore, il che sarebbe in contraddizione con la nostra configurazione di eseguire costruzioni in un contenitore sicuro.
Avviamo Buildah all'interno del contenitore
Lo schema del contenitore Buildah discusso sopra consente di variare in modo flessibile i modi di avviare tali contenitori.
Velocità contro sicurezza
La sicurezza informatica è sempre un compromesso tra la velocità di esecuzione del processo e il livello di protezione che si è deciso di applicare. Questa affermazione è vera anche durante la costruzione dei contenitori, quindi di seguito esamineremo le opzioni per tale compromesso.
L'immagine del contenitore esaminata in precedenza manterrà i propri dati in /var/lib/containers. Pertanto, dobbiamo montare il contenuto in questa cartella, e il modo in cui lo faremo influenzerà notevolmente la velocità di costruzione delle immagini dei contenitori.
Esaminiamo tre opzioni.
Opzione 1. Se è necessaria la massima sicurezza, è possibile creare una propria cartella per containers/image per ogni contenitore e collegarla al contenitore tramite il volume-mount. Inoltre, si può posizionare la directory di contesto direttamente nel contenitore, nella cartella /build:
# mkdir /var/lib/containers1
# podman run -v ./build:/build:z -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable
buildah -t image1 bud /build
# podman run -v /var/lib/containers1:/var/lib/containers:Z quay.io/buildah/stable buildah push image1 registry.company.com/myuser
# rm -rf /var/lib/containers1
Sicurezza. Lavorando in un contenitore di questo tipo, Buildah ha la massima sicurezza: non gli vengono concessi privilegi di root attraverso le capacità, e si applicano tutte le restrizioni di SECOMP e SELinux. Questo contenitore può anche essere avviato con isolamento User Namespace, aggiungendo un'opzione come —uidmap 0:100000:10000.
Prestazioni. Tuttavia, le prestazioni qui sono minime, poiché ogni immagine dai registri dei container viene copiata ogni volta sull'host e la memorizzazione nella cache non funziona affatto. Una volta completato il suo lavoro, il container Buildah deve inviare l'immagine al registro e distruggere il contenuto sull'host. Quando l'immagine del container sarà ricostruita, dovrà essere scaricata di nuovo dal registro, poiché sull'host non rimarrà più nulla.
Opzione 2. Se hai bisogno di prestazioni a livello di Docker, puoi montare direttamente il container/storage dell'host all'interno del container.
# podman run -v ./build:/build:z -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah -t image2 bud /build
# podman run -v /var/lib/containers:/var/lib/containers --security-opt label:disabled quay.io/buildah/stable buildah push image2 registry.company.com/myuser
Sicurezza. Questo è il modo meno sicuro per costruire container, poiché qui al container è permesso modificare lo storage sull'host e potrebbe potenzialmente introdurre un'immagine dannosa a Podman o CRI-O. Inoltre, sarà necessario disattivare la separazione di SELinux affinché i processi all'interno del container Buildah possano interagire con lo storage sull'host. Tieni presente che questa opzione è comunque migliore del socket Docker, poiché il container è bloccato dalle rimanenti funzionalità di sicurezza e non può semplicemente avviare un qualsiasi container sull'host.
Prestazioni. Qui è massima, poiché viene utilizzata completamente la memorizzazione nella cache. Se Podman o CRI-O hanno già scaricato l'immagine necessaria sull'host, il processo di Buildah all'interno del contenitore non dovrà scaricarla nuovamente, e le successive compilazioni basate su quest'immagine potranno anche attingere quanto necessario dalla cache.
Opzione 3. L'idea di questo metodo è di unire più immagini in un unico progetto con una cartella condivisa per le immagini dei contenitori.
# mkdir /var/lib/project3
# podman run --security-opt label_level=s0:C100, C200 -v ./build:/build:z
-v /var/lib/project3:/var/lib/containers:Z quay.io/buildah/stable buildah -t image3 bud /build
# podman run --security-opt label_level=s0:C100, C200
-v /var/lib/project3:/var/lib/containers quay.io/buildah/stable buildah push image3 registry.company.com/myuser
In questo esempio non eliminiamo la cartella del progetto (/var/lib/project3) tra i lanci, quindi tutte le successive compilazioni all'interno del progetto traggono vantaggio dalla memorizzazione nella cache.
Sicurezza. Qualcosa a metà tra le opzioni 1 e 2. Da un lato, i contenitori non hanno accesso ai contenuti sull'host e, di conseguenza, non possono inserire nulla di dannoso nello storage delle immagini di Podman/CRI-O. Dall'altro lato, all'interno del proprio progetto, il contenitore può interferire nella compilazione di altri contenitori.
Prestazioni. Qui è peggiore rispetto all'utilizzo della cache condivisa a livello host, poiché non è possibile utilizzare immagini già scaricate con Podman/CRI-O. Tuttavia, una volta che Buildah scarica un'immagine, questa può essere utilizzata in tutte le compilazioni successive all'interno del progetto.
Archivi aggiuntivi
A C'è una funzione interessante chiamata archivi aggiuntivi (additional stores), grazie alla quale, durante l'avvio e la creazione di contenitori, i motori dei contenitori possono utilizzare archivi esterni delle immagini in modalità read-only overlay. In pratica, è possibile aggiungere uno o più archivi 'solo in lettura' al file storage.conf, in modo che durante l'avvio del contenitore il motore dei contenitori cerchi l'immagine necessaria in essi. Scaricherà l'immagine dal registro solo se non la trova in nessuno di questi archivi. Il motore dei contenitori potrà scrivere solo negli archivi accessibili in scrittura...
Se scorriamo verso l'alto e guardiamo il Dockerfile che utilizziamo per costruire l'immagine quay.io/buildah/stable, troveremo righe come queste:
# Adjust storage.conf to enable Fuse storage.
RUN sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' /etc/containers/storage.conf
RUN mkdir -p /var/lib/shared/overlay-images /var/lib/shared/overlay-layers; touch /var/lib/shared/overlay-images/images.lock; touch /var/lib/shared/overlay-layers/layers.lock
Nella prima riga modifichiamo /etc/containers/storage.conf all'interno dell'immagine del contenitore, dicendo al driver di archiviazione di utilizzare 'additionalimagestores' nella cartella /var/lib/shared. Nella riga successiva creiamo una cartella condivisa e aggiungiamo un paio di file lock, in modo da evitare conflitti da parte di containers/storage. Fondamentalmente, stiamo solo creando uno spazio di archiviazione vuoto per le immagini dei contenitori.
Se montiamo containers/storage a un livello superiore a questa cartella, Buildah sarà in grado di utilizzare le immagini.
Torniamo alla Variante 2 esaminata in precedenza, in cui il contenitore Buildah può leggere e scrivere in containers/store sugli host e, di conseguenza, ha la massima prestazione grazie alla memorizzazione nella cache delle immagini a livello di Podman/CRI-O, ma offre un minimo di sicurezza, poiché può scrivere direttamente negli archivi. Ora aggiungiamo archivi aggiuntivi e otteniamo il meglio di entrambi i mondi.
# mkdir /var/lib/containers4
# podman run -v ./build:/build:z -v /var/lib/containers/storage:/var/lib/shared:ro -v /var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable
buildah -t image4 bud /build
# podman run -v /var/lib/containers/storage:/var/lib/shared:ro
-v >/var/lib/containers4:/var/lib/containers:Z quay.io/buildah/stable buildah push image4 registry.company.com/myuser
# rm -rf /var/lib/continers4
Si prega di notare che /var/lib/containers/storage dell'host è montato in /var/lib/shared all'interno del contenitore in modalità di sola lettura. Pertanto, mentre si lavora nel contenitore, Buildah può utilizzare qualsiasi immagine che è stata già scaricata tramite Podman/CRI-O (saluti, velocità), ma può scrivere solo nel proprio storage (saluti, sicurezza). Si prega di notare che questo avviene senza disattivare la separazione SELinux per il contenitore.
Aspetto importante
In nessun caso si devono eliminare immagini dallo storage sottostante. Altrimenti, il contenitore Buildah potrebbe chiudersi inavvertitamente.
E questi non sono affatto tutti i vantaggi
Le possibilità di archiviazione aggiuntiva non si limitano solo allo scenario descritto sopra. Ad esempio, è possibile posizionare tutte le immagini dei container in uno storage di rete condiviso e concedere accesso a tutti i container Buildah. Supponiamo di avere centinaia di immagini che il nostro sistema CI/CD utilizza regolarmente per costruire immagini di container. Concentrando tutte queste immagini su un singolo host di archiviazione e poi utilizzando soluzioni di storage di rete preferite (NFS, Gluster, Ceph, ISCSI, S3…), rendiamo questo storage accessibile a tutte le nodi di Buildah o Kubernetes.
Ora è sufficiente montare questo storage di rete nel container Buildah in /var/lib/shared e il gioco è fatto: i container Buildah non dovranno più scaricare le immagini tramite pull. In questo modo eliminiamo la fase di pre-popolazione e siamo subito pronti a distribuire i container.
E naturalmente, questo può essere utilizzato all'interno di un sistema Kubernetes esistente o di un'infrastruttura basata su container, per eseguire e gestire container ovunque senza dover scaricare immagini tramite pull. Inoltre, il registro dei container, ricevendo una richiesta di push per caricare un'immagine aggiornata, può inviare automaticamente quell'immagine a un'archiviazione di rete condivisa, rendendola immediatamente disponibile a tutti i nodi.
Le dimensioni delle immagini dei container possono talvolta raggiungere diversi gigabyte. La funzionalità di archiviazione aggiuntiva consente di evitare il cloning di tali immagini tra i nodi, rendendo l'avvio dei container praticamente istantaneo.
Inoltre, stiamo attualmente lavorando su una nuova funzionalità di overlay volume mounts, che renderà la costruzione dei container ancora più veloce.
Conclusione
Eseguire Buildah all'interno di un container in un ambiente Kubernetes/CRI-O, Podman o anche in Docker è assolutamente realizzabile, ed è molto più semplice e sicuro rispetto all'uso di docker.socket. Abbiamo notevolmente aumentato la flessibilità nella gestione delle immagini, e ora puoi avviarle in vari modi per ottenere un equilibrio ottimale tra sicurezza e prestazioni.
La funzionalità dei repository aggiuntivi consente di accelerare o addirittura eliminare completamente il download delle immagini sui nodi.
Fonte: habr.com
