Forum: PC-Programmierung Linux: Skript bei erstem Login starten


von Taucher (Gast)


Lesenswert?

Ich habe einen Server unter Ubuntu 20.04 laufen, auf den per git eine 
Website deployt werden soll. Aus den mit git push ins Repo übertragenen 
Daten soll automatisch ein Docker-Image erzeugt werden.

Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob 
eine vom git-hook post-receive geschriebene Datei existiert und ggf. die 
darin enthaltenen Kommandos ausführt und die Datei löscht.

Das funktioniert so weit.

Jetzt würde ich gerne dieses Skript automatisch starten, wenn das 
home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das 
Skript soll aber nur genau einmal laufen und sich verabschieden, wenn 
niemand mehr eingeloggt ist.

Wie stellt man das am besten an?

von sys (Gast)


Lesenswert?

> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird


man sshd, script nach:   ~/.ssh/rc

von Sheeva P. (sheevaplug)


Lesenswert?

Taucher schrieb:
> Wie stellt man das am besten an?

Vielleicht indem Du uns Deinen Anwendungsfall genauer erklärst?! ;-)

von Eric (Gast)


Lesenswert?

Taucher schrieb:
> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das
> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird.

Du könntest zum Beispiel mit entr die atime überprüfen. Bei 
Verzeichnissen geht das aber nur in einer Loop.
Zum Beispiel:
while true; do ls home/* | entr -pd <was auch immer du damit vorhast>; 
done

von MaWin (Gast)


Lesenswert?

Ich mache das deploy direkt aus dem post-update hook heraus.

von Imonbln (Gast)


Lesenswert?

Taucher schrieb:
> Ich habe einen Server unter Ubuntu 20.04 laufen, auf den per git eine
> Website deployt werden soll. Aus den mit git push ins Repo übertragenen
> Daten soll automatisch ein Docker-Image erzeugt werden.

Soweit so Normal, die meisten verwenden für sowas eine CI/CD Pipeline, 
Jenkins und Gitlab oder nur Gitlab sind da weit verbreitet.

Taucher schrieb:
> Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob
> eine vom git-hook post-receive geschriebene Datei existiert und ggf. die
> darin enthaltenen Kommandos ausführt und die Datei löscht.
>
> Das funktioniert so weit.

Die Erfahrung sagt, das klingt aus mehreren Gründen falsch. Die 
Wichtigsten sind:

1.) Du machst Busy Waiting, Dein Bash script wird die meiste Zeit nichts 
zu tun haben, aber um das zu Prüfen muss es immer mal wieder den 
Prozessor bemühen. Warum lässt Du den post-receive hook nicht gleich das 
Script starten oder arbeitest notfalls mit iNotify.

2.) unter Umständen kommt es hier zu einer Privilege escalation wenn der 
Prozess mehr rechte hat als der Benutzer, welche die Befehle in die 
Datei tut. Mit genügend krimineller Energie, kann der Benutzer das 
System benutzen, um dauerhaft die gleichen rechte zu bekommen wie der 
Prozess.

3.) das Umgehen Löschen nach dem Ausführen, klingt auch aus 
unterschiedlichen Gründen fehleranfällig. Was passiert, wenn das Löschen 
nicht klappt, weil das Script abbricht? Nach 10 Sekunden kommt dann der 
nächste Bash lauf und so weiter...
Was wenn das Scipt durchläuft aber einen Fehler macht, kann ich das 
Script irgendwo zu debug zwecken sehen?

Taucher schrieb:
> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das
> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das
> Skript soll aber nur genau einmal laufen und sich verabschieden, wenn
> niemand mehr eingeloggt ist.

Denn Teil verstehe ich nicht, meinst Du das Bash Script das alle 10 
Sekunden pollt, oder das Script mit den Befehlen welches Dir, der 
post-receive hook erzeugt oder was ganz anderes.
Was meinst Du mit das Script soll genau einmal laufen und sich 
verabschieden, ich denke das post-receive Skript löscht sich, wenn des 
erfolgreich war. Und so ein wenig widerspricht sich das einmal laufen 
auch mit den" und sich verabschieden, wenn niemand mehr eingeloggt ist." 
ist Dein ominöse Skript vielleicht ein Dämon der die ganze Zeit läuft?

Taucher schrieb:
> Wie stellt man das am besten an?

systemd/User https://wiki.archlinux.org/title/systemd/User) vielleicht, 
dort ein oneshot bauen der wird genau einmal gestartet, wenn sich der 
Benutzer einloggt.

Ich bin mir aber nicht sicher, ob Deine Architektur, so eine gute Idee 
ist. Vielleicht gehst Du vorher nochmal zurück ans Zeichenbrett und 
siehst Dir an wie andere eine ähnliche Architektur gebaut haben. Ich 
vermute mit einer gut geplanten CI/CD Pipeline, wird sich Deine aktuelle 
Fragestellung wahrscheinlich nicht ergeben.

von Taucher (Gast)


Lesenswert?

MaWin schrieb:
> Ich mache das deploy direkt aus dem post-update hook heraus.

Das hat nur den Nachteil, dass dann die git-Verbindung so lange gesperrt 
ist, bis das Generierungsskript fertig ist. Das dauert in meinem Fall.

Ich hatte auch schon versucht, aus dem git-Hook heraus das Skript 
einfach in den Hintergrund zu schieben, das hat aber aus unklaren 
Gründen nicht funktioniert.

von Taucher (Gast)


Lesenswert?

Imonbln schrieb:
> Soweit so Normal, die meisten verwenden für sowas eine CI/CD Pipeline,
> Jenkins und Gitlab oder nur Gitlab sind da weit verbreitet.

Ich mache es ohne Github & Co. mit einem einfachen git push.

> Die Erfahrung sagt, das klingt aus mehreren Gründen falsch. Die
> Wichtigsten sind:

Ist es aber nicht…

> 1.) Du machst Busy Waiting, Dein Bash script wird die meiste Zeit nichts
> zu tun haben, aber um das zu Prüfen muss es immer mal wieder den
> Prozessor bemühen.

Na ja, alle 10 sec nachsehen und dann wieder sleep würde ich nicht als 
Busy Waiting bezeichnen… Innerhalb der 10 sec kommt genug Rauschen von 
außen rein, dass die CPU immer wieder aktiv werden muss.

> Warum lässt Du den post-receive hook nicht gleich das
> Script starten oder arbeitest notfalls mit iNotify.

S.o.

> 2.) unter Umständen kommt es hier zu einer Privilege escalation wenn der
> Prozess mehr rechte hat als der Benutzer, welche die Befehle in die
> Datei tut. Mit genügend krimineller Energie, kann der Benutzer das
> System benutzen, um dauerhaft die gleichen rechte zu bekommen wie der
> Prozess.

Das ist eine ziemlich theoretische Gefahr: in diesem Fall müsste sich 
der Hacker auf dem Server einloggen, was voraus setzt, dass er die 
Zugangsdaten kennt. Damit könnte er aber auf dem Server sowieso tun und 
lassen, was er will…

> 3.) das Umgehen Löschen nach dem Ausführen, klingt auch aus
> unterschiedlichen Gründen fehleranfällig. Was passiert, wenn das Löschen
> nicht klappt, weil das Script abbricht? Nach 10 Sekunden kommt dann der
> nächste Bash lauf und so weiter...

Schon mal was von Fehlerbehandlung gehört? Die soll es angeblich auch in 
der bash geben ;-)

> Was wenn das Scipt durchläuft aber einen Fehler macht, kann ich das
> Script irgendwo zu debug zwecken sehen?

Weißt du, was man unter "logging" versteht?

> Denn Teil verstehe ich nicht, meinst Du das Bash Script das alle 10
> Sekunden pollt, oder das Script mit den Befehlen welches Dir, der
> post-receive hook erzeugt oder was ganz anderes.

Nochmal zum mitmeißeln:

- Das Skript, um das es hier geht, läuft in einer unendlichen Schleife 
und
  guckt alle 10 sec nach, ob was zu tun ist
- Dieses Skript soll automatisch starten, wenn eine sftp- oder
  ssh-Verbindung aufgebaut wird und terminieren, wenn die letzte 
Verbindung
  abgebrochen wurde.
- Das Signal, dass was zu tun ist, ist die Datei mit den auszuführenden
  Kommandos, die der git-Hook schreibt.

Damit habe ich das ssh-/sftp-Login als Authentifizierungsprozess vor die 
ganze Sache gestellt. Damit sollten keine über das übliche Maß hinaus 
gehenden Sicherheitsprobleme entstehen.

von Taucher (Gast)


Lesenswert?

Imonbln schrieb:
> systemd/User https://wiki.archlinux.org/title/systemd/User) vielleicht,
> dort ein oneshot bauen der wird genau einmal gestartet, wenn sich der
> Benutzer einloggt.

Das ist ein guter Tipp. Jetzt muss ich nur noch herausbekommen, wie man 
das 10-sec-Skript dort verdrahten muss.

von Taucher (Gast)


Lesenswert?

Hm, mir scheint, systemd/User ist für dieses Problemchen etwas 
überdimensioniert.

ps kann den User-Namen ausgeben – damit kann das 10-sec-Skript 
feststellen, wieviele Prozesse unter diesem Namen noch laufen. Wenn es 
nur noch einer – er selbst – ist, dann verabschiedet es sich und das 
Terminierungsproblem ist gelöst.

Starten kann man das Skript aus ~/.bash_profile heraus. Die wird bei 
jedem Login über ssh abgearbeitet. Das Skript stellt fest, ob schon eine 
Instanz läuft. Wenn nein, schickt es sich selbst in den Hintergrund und 
wenn ja, terminiert es stillschweigend.

Die Hintergrund-Instanz schreibt ihre PID in eine Datei in /tmp – dort 
können weitere Instanzen nachsehen (und mit ps prüfen, ob ein Prozess 
mit der dort vermerkten PID existiert).

Jetzt weiß ich nur noch nicht, ob der automatische Start auch mit sftp 
funktioniert.

von JE (Gast)


Lesenswert?

Taucher schrieb:
> MaWin schrieb:
>> Ich mache das deploy direkt aus dem post-update hook heraus.
>
> Das hat nur den Nachteil, dass dann die git-Verbindung so lange gesperrt
> ist, bis das Generierungsskript fertig ist. Das dauert in meinem Fall.
>
> Ich hatte auch schon versucht, aus dem git-Hook heraus das Skript
> einfach in den Hintergrund zu schieben, das hat aber aus unklaren
> Gründen nicht funktioniert.

Das solltest du dir weiter anschauen. Hast du schonmal versucht das 
Skript mit nohup in den Hintergrund zu schicken?

von Taucher (Gast)


Lesenswert?

JE schrieb:
> Das solltest du dir weiter anschauen. Hast du schonmal versucht das
> Skript mit nohup in den Hintergrund zu schicken?

Das habe ich eben probiert – funktioniert leider nicht, egal ob per
1
nohub skript </dev/null &>/dev/null &
oder mit
1
nohub bash -c skript </dev/null &>/dev/null &

von 🐧 DPA 🐧 (Gast)


Lesenswert?


von JE (Gast)


Lesenswert?

Taucher schrieb:
> Das habe ich eben probiert – funktioniert leider nicht, egal ob per

Hast du mehr Infos was nicht geht?
Du könntest die Ausgabe der Scripte auch mal auffangen.
Statt bash -c macht bash -lic oft viel besser.

von Taucher (Gast)


Lesenswert?

JE schrieb:
> Hast du mehr Infos was nicht geht?

Ich sehe nur mit ps, dass das Skript nach dem git push nicht läuft.

> Statt bash -c macht bash -lic oft viel besser.

Die -i-Option macht die Shell interaktiv – das ist das Skript aber 
definitiv nicht.

von Taucher (Gast)


Lesenswert?

🐧 DPA 🐧 schrieb:
> Ist es vielleicht mal wieder Systemd?
>
> 
https://www.freedesktop.org/software/systemd/man/logind.conf.html#KillUserProcesses=

Das ist ein guter Tipp, danke.

von JE (Gast)


Lesenswert?

Taucher schrieb:
>> Statt bash -c macht bash -lic oft viel besser.
>
> Die -i-Option macht die Shell interaktiv – das ist das Skript aber
> definitiv nicht.

Das -i stellt der Shell auch einen STDIN zur Verfügung und führt andere 
Login Scripte aus, eventuell benötigt dein Script das. Das -l führt die 
Login Scripte aus - vielleicht wird dort ein Pfad gesetzt der benötigt 
wird.

Solange wir nicht sehen was die Scripte ausgeben ist das aber alles 
rumraterei. Ersetze doch mal die ganzen /dev/null Umleitungen durch

>> /tmp/logfile.txt 2>&1

und schau nach was angemeckert wird.

Ich bin mir bei den Git-Hooks jetzt nicht ganz sicher - aber sind die 
Scripte ausführbar?

von Taucher (Gast)


Lesenswert?

JE schrieb:
> Ich bin mir bei den Git-Hooks jetzt nicht ganz sicher - aber sind die
> Scripte ausführbar?

Die Skripte sind alle ausführbar. Wenn ich nach einem git push das 
Generierungsskript zu Fuß anwerfe, läuft alles durch und die Änderungen 
greifen.

von Jemand (Gast)


Lesenswert?

Taucher schrieb:
> ps kann den User-Namen ausgeben – damit kann das 10-sec-Skript
> feststellen, wieviele Prozesse unter diesem Namen noch laufen. Wenn es
> nur noch einer – er selbst – ist, dann verabschiedet es sich und das
> Terminierungsproblem ist gelöst.

Ich gebe Zehn von Zehn Frickelpunkten

von PittyJ (Gast)


Lesenswert?

Etwas OT, aber ich mußte sofort an einen alten Comic denken.
In etwa so:
 http://ronald-wagner.de/tauchwi.gif

von Harry (Gast)


Lesenswert?

Oh sorry, oben ist mir die Formatierung kaputt gegangen

```
/Pfad/zum/Script >> /tmp/logfile.txt 2>&1
```

schreibt die die Ausgabe des Scipts in eine Datei.

von JE (Gast)


Lesenswert?

Und wieso heiße ich hier Harry?

von quotendepp (Gast)


Lesenswert?

in meinem früheren leben habe ich das deployment über gitlab-ci in zwei 
branches (dev, prod) durchgeführt.
bei einem push in den jeweiligen branch wurde ein deploy script 
(normales shell script) ausgeführt. die anzahl der auszuführenden 
scripts ist dabei variabel.

von 900ss (900ss)


Lesenswert?

Jemand schrieb:
> Ich gebe Zehn von Zehn Frickelpunkten

LOL..... der gefällt mir :)

von Nop (Gast)


Lesenswert?

Taucher schrieb:
> JE schrieb:
>> Das solltest du dir weiter anschauen. Hast du schonmal versucht das
>> Skript mit nohup in den Hintergrund zu schicken?
>
> Das habe ich eben probiert – funktioniert leider nicht, egal ob per
> nohub skript </dev/null &>/dev/null &
> oder mit nohub bash -c skript </dev/null &>/dev/null &

Es heißt ja auch "nohup" mit P und nicht mit B. Wie in "no hangup".

von Taucher (Gast)


Lesenswert?

Nop schrieb:
> Es heißt ja auch "nohup" mit P und nicht mit B. Wie in "no hangup".

Oh, das war die Gurke… Jetzt läuft das Generierungsskrip aus dem 
git-hook heraus, danke für den Hinweis.

Damit ist mein 10-sec-Skript überflüssig. Dank an alle, die Tipps 
geliefert haben.

von Rolf M. (rmagnus)


Lesenswert?

Taucher schrieb:
> Jetzt würde ich gerne dieses Skript automatisch starten, wenn das
> home-Verzeichnis auf dem Server per sftp oder per ssh geöffnet wird. Das
> Skript soll aber nur genau einmal laufen und sich verabschieden, wenn
> niemand mehr eingeloggt ist.

Ich hab nicht so richtig verstanden, was du willst. Wenn sich jemand 
einlogt, soll ein Skript ausgeführt werden, das einen Docker-Image 
erstellt? Und wenn sich der letzte auslogt, soll das Skript gekillt 
werden? Oder was meinst du mit "sich verabschieden"?

> Ich habe dazu ein bash-Skript geschrieben, das alle 10 sec prüft, ob
> eine vom git-hook post-receive geschriebene Datei existiert und ggf. die
> darin enthaltenen Kommandos ausführt und die Datei löscht.

Das könnte man vermutlich mit inotifywait geschickter machen. Damit 
kannst du auf Änderungen warten, ohne sie explizit abfragen zu müssen.

: Bearbeitet durch User
von Karl II. (Gast)


Lesenswert?

Ich heb einen Server, der schickt mir eine eMail beim Login per ssh, das 
mache ich über die Datei /etc/profile, da habe ich folgendes angehängt:
1
if [ -n "$SSH_CLIENT" ]; then
2
  ip=`echo $SSH_CONNECTION | cut -d " " -f 1`
3
  name=`nslookup $ip | grep "name =" | cut -d " " -f 3`
4
  echo -e "subject: LOGIN auf BLABLA\n\nLOGIN auf BLABLA - von $USER @ $ip - $name - am $(date -d today +\%d.\%m\.%Y) $(date -d today +\%H:\%M:\%S)" | sendmail email@domain.domain
5
fi

Müsste auch für sftp gehen und dann kein sendmail sondern das script 
starten

von Sheeva P. (sheevaplug)


Lesenswert?

Rolf M. schrieb:
> Das könnte man vermutlich mit inotifywait geschickter machen.

Oder incrond... ;-)

Aber, sorry, für mich hört sich der ganze Anwendungsfall ein bisschen... 
komisch an, wie dreimal um die Ecke gedacht und sich am Ende dann doch 
sehenden Auges in beide Füße, ein Knie und ein Ohr geschossen. Wird aber 
wohl an mir liegen...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.