Gitlab in Docker mit SSH Standardport
Im Docker basierten Setup von Gitlab wird ein SSH Daemon mitgeliefert, der im Normalfall aber auf einem anderen Port laufen muss wie der native SSH-Daemon vom Betriebssystem. Möchte man den SSH Daemon von Gitlab öffentlich betreiben und hat nur eine öffentliche IP-Adresse zur Verfügung gibt es verschiedene Möglichkeiten (die letzte wird hier beschrieben):
- Gitlab-SSH auf anderem Port als den des Betriebssystem lauschen lassen
- System-SSH auf anderen Port binden um 22 für Gitlab frei zu räumen
- System-SSH mit Gitlab-SSH verknüpfen (wird hier beschrieben)
Erklärung
Gitlab stellt für den eigenen SSH-Daemon ein Script bereit, das alle registrierten SSH-Keys zurückmeldet. Diese werden vom SSH-Daemon genutzt um zu prüfen, ob ein zu verbindener Klient generell zugelassen werden kann. Dieses vorgehen ist generell beim OpenSSH-Server möglich, nur weiß der des Betriebssystems nichts von Dingen die im Docker Container passieren. Der nötige Befehl wird mittels Wrapper-Script und docker exec
zur Verfügung gestellt, damit der Betriebssystem-SSH-Daemon die Keys abfragen kann. Der Gitlab-Befehl erhält alle nötigen Informationen über die SSH Verbindung um diese für weitere Verarbeitungen heranziehen zu können.
Script und Konfiguration
SSH-Daemon Konfiguration
Zunächst benötigen wir einen System-Benutzer git der im Regelfall in der Distribution bereits angelegt ist. Der Pfad zum Script kann angepasst werden, falls man docker-volumes nutzt und das Script lieber wo anders liegen haben möchte (z.B. /usr/local/bin/). Im SSH-Daemon wird folgendes konfiguriert:
# File: /etc/ssh/sshd_config
Match User git
AuthorizedKeysCommand /srv/docker/containers/gitlab/scripts/gitlab_authorized_keys
# muss root sein, weil das gitlab_authorized_keys root:root gehoert!
AuthorizedKeysCommandUser root
Es bietet sich an die bestehende Verbindung nicht zu trennen, bevor nach dem Restart ein erfolgreicher Verbindungsaufbau durchgeführt wurde! Falsche Konfigurationen in der sshd_config können zum Aussperren führen…
systemctl restart sshd.service
Gitlab Authorized-Keys
Dieses Script wird vom SSH-Daemon initial abgerufen um die Keys zu lesen. Es ist wichtig, dass der Pfad angepasst wird, je nachdem wo euer Gitlab seine Daten speichert. Dies kann z.B. auch ein Docker Volume sein (/var/lib/docker/volumes/ghitlab/data/.ssh/authorized_keys).
Das verwendete Script enthält folgendes:
# File /srv/docker/containers/gitlab/scripts/gitlab_authorized_keys
#!/bin/bash
# docker exec -u git gitlab cat /var/opt/gitlab/.ssh/authorized_keys
f="/srv/docker/containers/gitlab/data/.ssh/authorized_keys"
if [[ -f "${f}" ]];then
cat /srv/docker/containers/gitlab/data/.ssh/authorized_keys
fi
In dem authorized_keys File von Gitlab stehen alle gültigen SSH Keys, allerdings wird beim Verbinden das Ausführen eines Scripts erzwungen (siehe command=…):
# File: /srv/docker/containers/gitlab/data/.ssh/authorized_keys
command="/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3Nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
Gitlab-Shell Wrapper-Script
Somit wird unser SSH-Daemon dieses Script ausführen wollen. Deshalb legen wir unser Wrapper-Script an den gewünschten Ort (/opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell):
# File: /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell
#!/bin/bash
docker exec -u git -i -e SSH_CONNECTION="$SSH_CONNECTION" -e SSH_ORIGINAL_COMMAND="$SSH_ORIGINAL_COMMAND" gitlab /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell $*
Wichtig sind noch die Berechtigungen. Diese sollten noch korrigiert werden um sicherzustellen, dass nur git das Skript ausführen kann.
chown git:git /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell
chmod 0750 /opt/gitlab/embedded/service/gitlab-shell/bin/gitlab-shell
Außerdem muss der git-Benutzer noch in die Gruppe docker, damit er auf den Docker-Socket zugreifen kann (docker exec …):
usermod -a -G docker git
Test der Funktion
Mit funktionierendem Agent / SSH-Key:
git clone git@my.gitlab.server.com:repo/something.git
Sollte etwas nicht funktionieren kann im Journal nachgesehen werden:
journalctl -u sshd.service -f