Linux: Skript bei erstem Login starten

Gast #6677519
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?
Gast #6677570
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
Gast #6677860
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.
Gast #6677964
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.
Gast #6678016
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.
Gast #6678252
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.
Gast #6678257
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?
Gast #6678302
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 &
Gast #6678350
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.
Gast #6678385
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?
Gast #6678406
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.
Gast #6678422
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
Gast #6678455
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.
Gast #6678663
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".
Gast #6678741
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.
#6678834
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.
Gast #6679757
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren