Kein Shell im Container. Und nun?

Kein Shell im Container. Und nun?

Probleme von minimalen Container Images

Jeder der sich mit sicheren Containern beschäftigt ist vermutlich schon über den einen oder anderen Artikel gestolpert der berechtigterweise empfiehlt eine der folgenden minimalen Baseimages zu verwenden

Nach einigen Versuchen hast Du es sicher geschafft Deine Anwendung mit einem der Baseimages zum Laufen zu bringen und die neue Anwendung in Produktion zu deployen.

Irgendwann geht aber was schief. Deine Anwendung funktioniert nicht mehr und Du befindest Dich im Blindflug. Die Story die Anwendung mit OpenTelementry zu instrumentieren hast Du noch nicht begonnen. Um die Anwendung zu debuggen oder weitere Informationen zu entlocken benötigst Du eine Shell in den Container. Jedoch grüßt dich eine Fehlermeldung und keine Shell.

docker exec -it proxy /bin/sh OCI runtime exec failed: exec failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown

Was können wir tun?

Als Beispiel starten wir einen nginx basierend auf einem minimalen Image das keine Shell enthält

docker run --rm --name secure-web -d abdennour/nginx-distroless-unprivileged

Wenn wir nun versuchen eine Shell in diesen Conainer zu erhalten bekommen wir eine Fehlermeldung

docker exec -it secure-web /bin/sh OCI runtime exec failed: exec failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown

Bestens. Jetzt können wir eine Lösung dafür bauen

Debuggen mit einem Sidecar-Container

Auch wenn wir keine Shell in den Container bekommen können wir diesen mit einem Sidecar Container debuggen. Eine Sidecar Container ist nichts anderes als ein Container der seine Resourcen mit einem anderen Container teilt. Du frägst dich jetzt bestimmt welche Resourcen das sind? Prozess-ID (PID) und Netzwerk hautptsächlich.

In Kubernetes läuft ein Sidecar Container im gleichen Pod wie ein anderer Container. In diesem Beispiel verwenden wir keine Kubernetes aber wir können trotzdem einen Sidecar Container erstellen und diesen an die Resourcen des Applikaktionscontainer binden.

Dafür nehmen wir eine Ubuntu Container und binden diesen an die gleiche Prozess-ID und das gleiche Netzwerk wie unser Nginx Container.

docker run --rm -it --pid container:secure-web \ --network container:secure-web \ --cap-add=SYS_PTRACE \ --security-opt seccomp=unconfined ubuntu:latest

Die Option --pid gibt den PID Namespace an der benutzt werden soll. Die Optionen --cap-add und --security-opt sind notwendig damit das Kommando strace funktioniert. Dieses Kommando gibt alle Systemcalls aus. Das kann bei der Fehlersuche hilfreich sein.

Danach installieren wir noch ein paar Debuggingtools

apt update && apt install -y iproute2 file strace

Diese können wir nun benutzen.

Wir können uns die Liste aller Prozesse anzeigen

root@49a834bc2851:/# ps -ef UID PID PPID C STIME TTY TIME CMD 1001 1 0 0 19:59 ? 00:00:00 nginx: master process nginx -g daemon off; 1001 6 1 0 19:59 ? 00:00:00 nginx: worker process root 13 0 0 20:08 pts/0 00:00:00 /bin/bash root 388 13 0 20:10 pts/0 00:00:00 ps -ef

Mit strace können wir uns nun auch auf einen der laufenden Prozesse aus dem anderen Container connecten

root@49a834bc2851:/# strace -p 6 strace: Process 6 attached epoll_pwait(8,

Auch das Dateisystem des anderen Container können wir untersuchen

root@49a834bc2851:/# cat /proc/1/root/usr/share/nginx/html/index.html <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>

Fazit

Dies ist eine elegante Möglichkeit um mit einer Shell auf einen bestehenden Container zuzugreifen, bei dem das eigentlich nicht vorgesehen wurde. Das Beste an dieser Vorgehensweise ist das wir keine Änderungen an dem bestehenden Image vornehmen müssen. Sobald wir mit der Fehlersuche fertig sind, können wir den Sidecar Container entfernen und hinterlassen keine Spuren oder Nebeneffekte.

← Zurück