evcc icon indicating copy to clipboard operation
evcc copied to clipboard

Docker: use non-root evcc user

Open sveba opened this issue 3 years ago • 39 comments

@andig fixes #4850 Was wurde getan:

  • ENV TZ removed (sollte mMn beim run übergeben werden)
  • Runtime user default auf evcc geändert (adduser ...)
  • /evcc Ordner als WORKDIR (kanm dann auch in der Doku als Mountpoint für persistierende Dateien übernommen werden)
  • Entrypoint in /bin
  • Auch docker-btmgmt in /bin (konnte aber nicht finden wofür das gut ist?)
  • entrypoint ein wenig aufgeräumt. Es sei denn, dass was ich gelöscht hab, macht noch Sinn. Konnte es mir aber nicht erklären und aus Git-Log bin ich auch nicht schlau geworden

Refs https://github.com/evcc-io/evcc/pull/4901

sveba avatar Oct 19 '22 18:10 sveba

Das macht einiges einfacher. thx

Hofyyy avatar Oct 19 '22 19:10 Hofyyy

Das mit dem if [ "$1" in dem entrypoint Script ist so ähnlich in dem dockerfile best practices für entrypoint:

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint

StefanSchoof avatar Oct 19 '22 20:10 StefanSchoof

Erstmal vielen Dank,. Ganz leicht über meinem üblichen shell-fu ;). Könntest du nochmal erklären, inwiefern das jetzt das uid/gid Problem löst? Ähnliches hätten wir ja auch mit dem guest user schnell und einfach (wenn auch nicht so schön) lösen können?

andig avatar Oct 19 '22 20:10 andig

Bzgl. ENV: was passiert bei alpine wenn nix übergeben wird? Sollten wir das für den typischen CET Anwender nicht auf einen sinnvollen Default setzen? Otto Normalo wird keine Timezone von aussen setzen?

andig avatar Oct 19 '22 20:10 andig

Das mit dem if [ "$1" in dem entrypoint Script ist so ähnlich in dem dockerfile best practices für entrypoint:

https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint

Seems that is only done because it passes just not the parameter but not the actual binary as CMD. Not sure what the advantage of that is but seems its not necessary here.

andig avatar Oct 19 '22 20:10 andig

Das mit dem if [ "$1" in dem entrypoint Script ist so ähnlich in dem dockerfile best practices für entrypoint: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint

Seems that is only done because it passes just not the parameter but not the actual binary as CMD. Not sure what the advantage of that is but seems its not necessary here.

Ich denke es geht darum, wie man Argumente an den cmd anhängen kann, also ob man docker run amdig\evcc evcc --help oder docker run andig\evcc --help machen muss.

StefanSchoof avatar Oct 19 '22 20:10 StefanSchoof

Erstmal vielen Dank,. Ganz leicht über meinem üblichen shell-fu ;). Könntest du nochmal erklären, inwiefern das jetzt das uid/gid Problem löst? Ähnliches hätten wir ja auch mit dem guest user schnell und einfach (wenn auch nicht so schön) lösen können?

Du meinst das hier https://github.com/evcc-io/evcc/pull/4859/commits/d134836d576c8a9d74ff8c296e3f11019b58cac2 oder? Da muss ich dir wohl Recht geben. Es ist tatsächlich ähnlich zu das, was du schon mal vorgeschlagen hattest. Zusätzlich setze ich nur 777 auf den /evcc-Ordner.

Ich habe etwas gegraben, wie Linuxserver das machen. Sie erzeugen den User im ENTRYPOINT-Script (sie benutzen allerdings s6) Das kann man auch hier tun. Allerdings bin ich deiner Meinung, dass das hier erstmals die "einfachere" Lösung ist. Hier Link zu der Linuxserver-Lösung https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/s6-overlay/s6-rc.d/init-adduser/run

sveba avatar Oct 19 '22 20:10 sveba

Das mit dem if [ "$1" in dem entrypoint Script ist so ähnlich in dem dockerfile best practices für entrypoint: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint

Seems that is only done because it passes just not the parameter but not the actual binary as CMD. Not sure what the advantage of that is but seems its not necessary here.

Ich denke es geht darum, wie man Argumente an den cmd anhängen kann, also ob man docker run amdig\evcc evcc --help oder docker run andig\evcc --help machen muss.

Ja, und? Spielt doch hier keine Rolle, oder?

andig avatar Oct 19 '22 20:10 andig

Bzgl. ENV: was passiert bei alpine wenn nix übergeben wird? Sollten wir das für den typischen CET Anwender nicht auf einen sinnvollen Default setzen? Otto Normalo wird keine Timezone von aussen setzen?

Auch hier richtig. Allerdings würde ich das eher in der Doku eintragen (docker run -e TZ=...)

sveba avatar Oct 19 '22 20:10 sveba

Erstmal vielen Dank,. Ganz leicht über meinem üblichen shell-fu ;). Könntest du nochmal erklären, inwiefern das jetzt das uid/gid Problem löst? Ähnliches hätten wir ja auch mit dem guest user schnell und einfach (wenn auch nicht so schön) lösen können?

Du meinst das hier d134836 oder? Da muss ich dir wohl Recht geben. Es ist tatsächlich ähnlich zu das, was du schon mal vorgeschlagen hattest. Zusätzlich setze ich nur 777 auf den /evcc-Ordner.

Ich habe etwas gegraben, wie Linuxserver das machen. Sie erzeugen den User im ENTRYPOINT-Script (sie benutzen allerdings s6) Das kann man auch hier tun. Allerdings bin ich deiner Meinung, dass das hier erstmals die "einfachere" Lösung ist. Hier Link zu der Linuxserver-Lösung https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/s6-overlay/s6-rc.d/init-adduser/run

Dann verstehe ich das, danke. Plus du nutzt nicht /home/evcc sondern generierst ein eigenes, weiteres. Gehupft wie gesprungen, oder bewirkt das noch mehr? Optisch ist /evcc vielleicht leichter zu mounten als /home/evcc?

andig avatar Oct 19 '22 20:10 andig

Bzgl. ENV: was passiert bei alpine wenn nix übergeben wird? Sollten wir das für den typischen CET Anwender nicht auf einen sinnvollen Default setzen? Otto Normalo wird keine Timezone von aussen setzen?

Auch hier richtig. Allerdings würde ich das eher in der Doku eintragen (docker run -e TZ=...)

Dann bitte Default. Es sind ja immer die gleichen Fragen im Support…

andig avatar Oct 19 '22 20:10 andig

Erstmal vielen Dank,. Ganz leicht über meinem üblichen shell-fu ;). Könntest du nochmal erklären, inwiefern das jetzt das uid/gid Problem löst? Ähnliches hätten wir ja auch mit dem guest user schnell und einfach (wenn auch nicht so schön) lösen können?

Du meinst das hier d134836 oder? Da muss ich dir wohl Recht geben. Es ist tatsächlich ähnlich zu das, was du schon mal vorgeschlagen hattest. Zusätzlich setze ich nur 777 auf den /evcc-Ordner. Ich habe etwas gegraben, wie Linuxserver das machen. Sie erzeugen den User im ENTRYPOINT-Script (sie benutzen allerdings s6) Das kann man auch hier tun. Allerdings bin ich deiner Meinung, dass das hier erstmals die "einfachere" Lösung ist. Hier Link zu der Linuxserver-Lösung https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/s6-overlay/s6-rc.d/init-adduser/run

Dann verstehe ich das, danke. Plus du nutzt nicht /home/evcc sondern generierst ein eigenes, weiteres. Gehupft wie gesprungen, oder bewirkt das noch mehr? Optisch ist /evcc vielleicht leichter zu mounten als /home/evcc?

jap, ich habe etwas Schönheitsreparatur miteingeschleust :) Keine böse Absicht gehabt. Ich kann den /evcc zurückbauen, falls gewünscht

sveba avatar Oct 19 '22 20:10 sveba

Das mit dem if [ "$1" in dem entrypoint Script ist so ähnlich in dem dockerfile best practices für entrypoint: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#entrypoint

Seems that is only done because it passes just not the parameter but not the actual binary as CMD. Not sure what the advantage of that is but seems its not necessary here.

Ich denke es geht darum, wie man Argumente an den cmd anhängen kann, also ob man docker run amdig\evcc evcc --help oder docker run andig\evcc --help machen muss.

Ja, und? Spielt doch hier keine Rolle, oder?

Ja, ist eine Geschmackssache, ob man die Verdoppelung von evcc in dem command vermeiden will. Habe gerade kurz auf die docs geschaut und dort nichts gesehen, wo das genutzt wird.

StefanSchoof avatar Oct 19 '22 20:10 StefanSchoof

Bzgl. ENV: was passiert bei alpine wenn nix übergeben wird? Sollten wir das für den typischen CET Anwender nicht auf einen sinnvollen Default setzen? Otto Normalo wird keine Timezone von aussen setzen?

Auch hier richtig. Allerdings würde ich das eher in der Doku eintragen (docker run -e TZ=...)

Dann bitte Default. Es sind ja immer die gleichen Fragen im Support…

ENV TZ ist wieder drin

sveba avatar Oct 19 '22 20:10 sveba

Leider wird gerade unter https://docs.evcc.io/docs/installation/docker#mit-docker-compose der entrypoint in der compose Datei auf /app/entrypoint.sh gesetzt. Wenn die Datei jetzt nicht mehr unter den Pfad zu finden ist, wird das bei einigen Nutzern beim Update zu einem Fehler führen:(

StefanSchoof avatar Oct 19 '22 20:10 StefanSchoof

Leider wird gerade unter https://docs.evcc.io/docs/installation/docker#mit-docker-compose der entrypoint in der compose Datei auf /app/entrypoint.sh gesetzt. Wenn die Datei jetzt nicht mehr unter den Pfad zu finden ist, wird das bei einigen Nutzern beim Update zu einem Fehler führen:(

Stimmt. 3 Möglichkeiten:

  • Doku anpassen
  • Change zurückbauen
  • Mit symlink probieren (und erst in einige Iterationen den Symlink löschen)

sveba avatar Oct 19 '22 20:10 sveba

Der Konflikt mit der Docker Doku besteht doch darin, dass die ganz viel vollkommen unnützen Kram spezifiziert der eh Default ist. In meinen Augen ist das ein Bug, den können wir- auch wenn breaking- korrigieren.

Bzgl. entrypoint: was wir mit dem Change verlieren (war aber auch vorher nicht funktioniert hat) ist, dass wir nicht mehr

Docker run andig/evcc charger

Machen können. Es wäre schön, dieses Verhalten (zurück) zu bekommen. Dynamisch ginge das nur, wenn alle evcc sub commands berücksichtigt würden. Keine Ahnung wie sich das anstellen liesse?

@sveba und ich würde immer noch super gerne die uid/gid Geschichte verstehen.

andig avatar Oct 20 '22 05:10 andig

Man muss zwischen HOST-User und Container-User unterscheiden. Der Container kennt die Benutzer vom Host nicht.

Der initiale Fehler bei mir war, dass ich den Docker-Container nicht mit einer anderen UID starten konnte, da die DB immer im HOME von root geschrieben wurde und der Ordner /root/.evcc nicht für alle RW gewesen war. Ich wollte das tun, da ich einen dedizierten HOST-Benutzer für Docker habe. Um dies zu beheben, konnte man den /root/.evcc einfach reinmounten und auf dem Host ihn RW für alle machen. Wäre schneller Fix.

Daraufhin habe ich die Lösung von Linuxserver vorgeschlagen. Die leider etwas mehr Aufwand bedeutet (und testing).

Dann war deine Idee, einen nonroot evcc-Benutzer im Container zu verwenden. Vollkommen richtig. Allerdings hätte das das Problem nicht gelöst, da der Ordner immernoch RW nur für den evcc-Container-Benutzer wäre. Deswegen habe ich in meinem PR einen /evcc-Ordner vorgestellt, der für alle RW ist und als Default-Storage für die DB genutzt wird. Egal mit welcher UID man den Container startet. Der Prozess wird aber mit einer UID gestartet, die nicht zu dem evcc-Container-Benutzer gehört! Der Container kennt diese UID nicht und kann sie zu keinem Container-Benutzer zuordnen. Deswegen sieht man bei einem ls innerhalb des Containers nur eine Zahl als File-Owner. Auch bei einem ps wäre der Owner unbekannt.

Die Linuxserver-Lösung bietet die Möglichkeit dem Container-User zur Laufzeit eine UID:GID zuzuweisen. Dafür wird im entrypoint der im Docker-Build angelegte Benutzer mit neuen UID:GID versehen. Dadurch kann man die UID:GID eines, auf dem HOST existierenden Nutzer beim run übergeben und alle Daten, die im Container geschrieben/erzeugt werden, kriegen die "richtige" GID:UID.

@andig Ich hoffe, das kann etwas helfen. Für weitere Fragen, oder falls der Wunsch besteht, dies Ähnlich wie bei Linuxserver zu tun, stehe ich zur Verfügung

sveba avatar Oct 20 '22 06:10 sveba

In meinen Augen ist das ein Bug, den können wir- auch wenn breaking- korrigieren.

So sollte das besser passen: https://github.com/evcc-io/docs/pull/239

andig avatar Oct 20 '22 06:10 andig

Die Linuxserver-Lösung bietet die Möglichkeit dem Container-User zur Laufzeit eine UID:GID zuzuweisen. Dafür wird im entrypoint der im Docker-Build angelegte Benutzer mit neuen UID:GID versehen. Dadurch kann man die UID:GID eines, auf dem HOST existierenden Nutzer beim run übergeben und alle Daten, die im Container geschrieben/erzeugt werden, kriegen die "richtige" GID:UID.

Genau, das muss ja zur Laufzeit sein. Hättest Du mal einen Link zu so einem entrypoint zum anschauen und vertehen wie das geht?

Ich hab bisher nur solche Dinge gefunden: https://nickjanetakis.com/blog/running-docker-containers-as-a-non-root-user-with-a-custom-uid-and-gid. Da passiert alles zur Buildzeit und das hat bei mir einfach nicht "klick" gemacht.

andig avatar Oct 20 '22 06:10 andig

Hier Link zu der Linuxserver-Lösung https://github.com/linuxserver/docker-baseimage-alpine/blob/master/root/etc/s6-overlay/s6-rc.d/init-adduser/run

@andig

sveba avatar Oct 20 '22 06:10 sveba

Damit bleibt der letzte offene Punkt: schaffen wir es, dieses Pattern zu ermöglichen:

docker run andig/evcc charger

evcc hat ein completions Kommando- kann man das evtl. nutzen um die Liste der gültigen Werte zu ermitteln und die im entrypoint zu verarbeiten? Der status quo schaute ja bisher auch nur auf - was tatsächlich nicht hilft. Falls niemand eine Idee hätte mergen wir as-is.

andig avatar Oct 20 '22 09:10 andig

@andig ist der letzte Commit was du meinst? Oder hab ich es falsch verstanden?

sveba avatar Oct 20 '22 10:10 sveba

Im Prinzip ja... es gibt aber mehrere Szenarien:

  • evcc (ohne Parameter)
  • evcc -foo
  • evcc charger|vehicle|...

aber auch

  • /bin/sh

Ich fände es gut, wenn gerade der letzte case auch für interaktive Shell ginge ohne dass man mit --entrypoint rumdaddeln muss. Deshalb wäre es in Deinem PR perfekt, wenn wir den evcc Case einschränken könnten auf

  • wenn erster Parameter eine Kommondozeilenoption ist (-) oder
  • wenn erster Parameter ein evcc Subkommando ist

... und zwar ohne die Liste der Subkommandos statisch in der entrypoint.sh anlegen zu müssen. Wär das machbar?

andig avatar Oct 20 '22 12:10 andig

Mit evcc __completeNoDesc "" bekommt man die liste der möglichen subcommands.

StefanSchoof avatar Oct 20 '22 12:10 StefanSchoof

Mit evcc __completeNoDesc "" bekommt man die liste der möglichen subcommands.

Top! Bekommen wir das (einschl. -) in eine Liste geparst und in der entrypoint.sh verarbeitet? Dann hätten wir die "Merzedes" Lösung :)

andig avatar Oct 20 '22 13:10 andig

Meine 2 Cents

  • evcc (ohne Parameter)
  • evcc -foo
  • evcc charger|vehicle|...

Alle 3 UseCases funktionieren. Wegen /bin/sh - jeder der -it kennt wird auch --entrypoint kennen Meine Meinung - macht es nicht komplizierter, als es sein soll :)

sveba avatar Oct 20 '22 13:10 sveba

Wegen /bin/sh - jeder der -it kennt wird auch --entrypoint kennen

Da hast du auch wieder recht. Ich bin trotzdem noch nicht so recht glücklich:

  • wir haben jetzt einen User mit /home/evcc als Directory
  • die Datenbank schieben wir aber nach /evcc
  • in https://github.com/evcc-io/evcc/pull/4901 wiederum landet die dann in /var/lib/evcc was auch als homedir genutzt wird

Wäre es nicht sinnvoll, die Strukturen gleich zu schneiden damits keine Verwirrung gibt?

andig avatar Oct 23 '22 11:10 andig

/cc @goebelmeier bzgl. https://github.com/evcc-io/evcc/pull/4878#issuecomment-1288092213

andig avatar Oct 30 '22 22:10 andig

Bekommen wir das hier irgendwie fertig? Brauchen wir wirklich unterschiedliche Hierarchien/User zwischen apt und Docker?

andig avatar Nov 01 '22 21:11 andig