296 lines
9.9 KiB
Markdown
296 lines
9.9 KiB
Markdown
# svc-proxy – Proxy für systemd-Dienste
|
||
|
||
`svc-proxy` legt fest, über welchen Proxy ein systemd-Dienst seine Verbindungen
|
||
aufbaut. Bedienen lässt es sich auf zwei Wegen:
|
||
|
||
- **ncurses-Menü**: listet alle Dienste auf. Man wählt einen aus und trägt die Daten bequem ein.
|
||
- **Kommandozeile**: für Skripte, Ansible, Provisionierung usw.
|
||
|
||
Es gibt einen **globalen Proxy**. Alle Felder, die man bei einem Dienst leer lässt,
|
||
übernehmen den globalen Wert. Explizit gesetzte Werte beim Dienst gelten vorrangig.
|
||
Benutzername und Kennwort sind optional; ohne sie wird der Proxy ohne Anmeldung genutzt.
|
||
|
||
Abhängigkeiten: nur `python3` (≥ 3.6) mit den Standardmodulen. `curses` ist bei
|
||
Debian/Ubuntu/RHEL im Python-Paket enthalten.
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
```bash
|
||
sudo install -m 0755 svc-proxy /usr/local/sbin/svc-proxy
|
||
```
|
||
|
||
Danach `sudo svc-proxy` (Menü) oder `svc-proxy --help` (Hilfe).
|
||
|
||
---
|
||
|
||
## Funktionsweise
|
||
|
||
Für jeden konfigurierten Dienst werden zwei Dateien erzeugt:
|
||
|
||
| Datei | Inhalt | Rechte |
|
||
|-------|--------|--------|
|
||
| `/etc/systemd/system/<dienst>.d/50-svc-proxy.conf` | Drop-in mit `EnvironmentFile=` | 0644 |
|
||
| `/etc/svc-proxy/env/<dienst>.env` | die eigentlichen Proxy-Variablen | 0600 |
|
||
|
||
Die Konfiguration selbst (global + alle Dienste) liegt in
|
||
`/etc/svc-proxy/config.json` (0600). Die Drop-ins und Env-Dateien werden daraus
|
||
generiert und sollten nicht von Hand bearbeitet werden.
|
||
|
||
Gesetzt werden die Variablen
|
||
|
||
```
|
||
http_proxy https_proxy ftp_proxy all_proxy no_proxy
|
||
HTTP_PROXY HTTPS_PROXY FTP_PROXY ALL_PROXY NO_PROXY
|
||
```
|
||
|
||
> **Warum `EnvironmentFile=` und nicht `Environment=`?**
|
||
> Werte aus `Environment=` kann jeder Benutzer mit `systemctl show <dienst>`
|
||
> auslesen, also auch ein Proxy-Kennwort. Die Env-Datei ist nur für root lesbar.
|
||
|
||
Sonderzeichen in Benutzername/Kennwort (z.B. `@`, `:`, `/`) werden automatisch
|
||
URL-kodiert.
|
||
|
||
### Wichtige Einschränkung
|
||
|
||
Der Proxy wirkt nur bei Programmen, die die Proxy-Umgebungsvariablen auswerten.
|
||
Das tun die meisten (curl, wget, apt, pip, Python `requests`/`urllib`, Go, Node
|
||
mit passenden Libs, Docker-Daemon, containerd, Git, ...). Programme, die die
|
||
Variablen ignorieren (z.B. viele Java-Anwendungen ohne `-Dhttp.proxyHost`),
|
||
müssen anders konfiguriert werden. Eine Netzwerk-Sperre ist das nicht: Ein
|
||
Programm *kann* den Proxy umgehen.
|
||
|
||
SOCKS-Proxys (`socks5://`, `socks5h://`) werden ebenfalls in alle Variablen
|
||
geschrieben. Das funktioniert z.B. mit curl und Go. Manche Programme verstehen in
|
||
`http_proxy` aber nur `http://`.
|
||
|
||
---
|
||
|
||
## Vererbung: Dienst ↔ global
|
||
|
||
Felder: **Typ, Host, Port, Benutzer, Kennwort, No-Proxy**
|
||
|
||
| Feld beim Dienst | Ergebnis |
|
||
|---|---|
|
||
| Typ / Host / Port / No-Proxy leer | globaler Wert |
|
||
| Typ / Host / Port / No-Proxy gesetzt | Wert des Dienstes |
|
||
| Benutzer leer **und** Host leer | globale Zugangsdaten |
|
||
| Benutzer leer, **eigener Host** | Proxy **ohne** Anmeldung |
|
||
| Benutzer gesetzt | Benutzer + Kennwort des Dienstes |
|
||
|
||
Die Sonderregel für Benutzer/Kennwort verhindert, dass globale Zugangsdaten an
|
||
einen fremden Proxy geschickt werden.
|
||
|
||
Ändert man den globalen Proxy, werden alle Dienste, die ihn ganz oder teilweise
|
||
erben, automatisch neu geschrieben. Wird der globale Proxy gelöscht, verlieren
|
||
Dienste ohne eigenen Host ihren Proxy. Ihre Konfiguration bleibt aber gespeichert
|
||
und wird wieder aktiv, sobald ein globaler Proxy gesetzt ist.
|
||
|
||
---
|
||
|
||
## ncurses-Menü
|
||
|
||
```bash
|
||
sudo svc-proxy
|
||
```
|
||
|
||
```
|
||
svc-proxy 1.0.0 – Proxy für systemd-Dienste
|
||
Global: http://max:****@proxy.firma.local:3128 No-Proxy: localhost,127.0.0.1,::1
|
||
220 Dienste
|
||
Dienst Status Proxy
|
||
G cron.service active global → http://max:****@proxy.firma.local:3128
|
||
E* docker.service active eigen → socks5h://10.1.1.1:1080
|
||
nginx.service inactive
|
||
...
|
||
↑↓ Wählen Enter Bearbeiten g Global Entf Proxy entfernen / Filter c Nur konfigurierte ...
|
||
```
|
||
|
||
Markierungen: **G** = nutzt globalen Proxy, **E** = eigene Werte,
|
||
**\*** = in dieser Sitzung geändert (Neustart noch offen).
|
||
|
||
### Tasten in der Liste
|
||
|
||
| Taste | Funktion |
|
||
|---|---|
|
||
| ↑ ↓ / Bild↑ Bild↓ / Pos1 Ende | Dienst wählen |
|
||
| Enter | Proxy des Dienstes bearbeiten |
|
||
| g | globalen Proxy bearbeiten |
|
||
| Entf / d | Proxy vom Dienst entfernen |
|
||
| / | Filter (Name oder Beschreibung), Esc löscht den Filter |
|
||
| c | nur konfigurierte Dienste anzeigen (an/aus) |
|
||
| r | gewählten Dienst sofort neu starten |
|
||
| F5 | Dienstliste neu einlesen |
|
||
| F1 / ? | Hilfe |
|
||
| q / F10 | Beenden |
|
||
|
||
### Tasten im Formular
|
||
|
||
| Taste | Funktion |
|
||
|---|---|
|
||
| Tab / ↑ ↓ | Feld wechseln |
|
||
| ← → / Leertaste | Proxy-Typ wählen (beim Dienst gibt es zusätzlich „global“) |
|
||
| Enter | nächstes Feld bzw. Schaltfläche auslösen |
|
||
| F2 | Speichern |
|
||
| Strg+U | Feld leeren |
|
||
| Esc | Abbrechen |
|
||
|
||
Leere Felder zeigen grau den globalen Wert an. Unter dem Formular steht live die
|
||
Proxy-URL, die sich ergibt. Ungültige Eingaben werden nicht gespeichert.
|
||
|
||
Nach jedem Speichern läuft `systemctl daemon-reload`. Beim Beenden erscheint eine
|
||
Liste der geänderten Dienste: Diese kann man an- und abwählen und neu starten lassen.
|
||
|
||
---
|
||
|
||
## Kommandozeile
|
||
|
||
```
|
||
svc-proxy [BEFEHL] [OPTIONEN]
|
||
```
|
||
|
||
| Befehl | Beschreibung |
|
||
|---|---|
|
||
| *(keiner)* / `tui` | Menü starten |
|
||
| `list [--all]` | konfigurierte Dienste (mit `--all`: alle Dienste) |
|
||
| `show [DIENST]` | effektive Werte eines Dienstes inkl. Herkunft; ohne DIENST: global |
|
||
| `global [FELDER]` | globalen Proxy setzen/ändern; ohne FELDER: anzeigen |
|
||
| `global --clear` | globalen Proxy löschen |
|
||
| `set DIENST... [FELDER] [--reset]` | Proxy für Dienst(e) setzen/ändern |
|
||
| `unset DIENST...` / `unset --all` | Proxy entfernen |
|
||
| `apply` | alle Drop-ins aus der Konfiguration neu erzeugen |
|
||
| `help`, `-h`, `--help` | Hilfe mit Beispielen |
|
||
|
||
### Felder
|
||
|
||
| Option | Bedeutung |
|
||
|---|---|
|
||
| `--proxy URL` | komplette URL, z.B. `http://user:pass@proxy:3128`; setzt Typ, Host, Port, Benutzer, Kennwort |
|
||
| `--type TYP` | `http`, `https`, `socks5`, `socks5h`, `socks4` |
|
||
| `--host HOST` | Hostname / IP |
|
||
| `--port PORT` | 1–65535 |
|
||
| `--user NAME` | Benutzername |
|
||
| `--password PW` | Kennwort (in `ps` sichtbar!) |
|
||
| `--password-stdin` | Kennwort aus der Standardeingabe lesen (empfohlen) |
|
||
| `--no-proxy LISTE` | Ausnahmen, kommagetrennt |
|
||
|
||
- Bei `set` und `global` werden **nur die angegebenen Felder** geändert, der Rest bleibt.
|
||
- Leerer Wert leert ein Feld: `--user ""`.
|
||
- `set DIENST --reset` leert vorher alle Felder, der Dienst nutzt danach komplett den globalen Proxy.
|
||
- Ein neuer Dienst ohne Felder (`set DIENST`) nutzt den globalen Proxy.
|
||
- Dienstnamen ohne Endung bekommen automatisch `.service` angehängt.
|
||
- Beim ersten Setzen des globalen Proxys ist No-Proxy standardmäßig `localhost,127.0.0.1,::1`.
|
||
|
||
### Neustart und Reload
|
||
|
||
| Option | Wirkung |
|
||
|---|---|
|
||
| *(nichts)* | im Terminal Nachfrage `[j/N]`; ohne Terminal (Cron, Skript) kein Neustart |
|
||
| `--restart` | geänderte Dienste ohne Nachfrage neu starten |
|
||
| `--no-restart` | nicht neu starten, nicht fragen |
|
||
| `--no-reload` | kein `systemctl daemon-reload` |
|
||
|
||
Neu gestartet wird mit `systemctl try-restart`, also nur Dienste, die gerade laufen.
|
||
Gestoppte Dienste werden nicht gestartet.
|
||
|
||
### Weitere Optionen
|
||
|
||
| Option | Bedeutung |
|
||
|---|---|
|
||
| `--config-dir DIR` | anderes Konfigurationsverzeichnis (Standard `/etc/svc-proxy`) |
|
||
| `--systemd-dir DIR` | anderes Ziel für Drop-ins (Standard `/etc/systemd/system`) |
|
||
| `-V`, `--version` | Version |
|
||
|
||
Mit `--config-dir`/`--systemd-dir` läuft das Skript auch ohne root. Das ist
|
||
praktisch zum Testen, z.B. zusammen mit `--no-reload`.
|
||
|
||
---
|
||
|
||
## Beispiele
|
||
|
||
```bash
|
||
# Menü
|
||
sudo svc-proxy
|
||
|
||
# Globaler Proxy ohne Anmeldung
|
||
sudo svc-proxy global --proxy http://proxy.firma.local:3128
|
||
|
||
# Globaler Proxy mit Anmeldung, Kennwort nicht in der Prozessliste
|
||
echo 'geheim' | sudo svc-proxy global --proxy http://proxy:3128 --user max --password-stdin
|
||
# oder aus einer Datei / einem Secret-Store
|
||
sudo svc-proxy global --user max --password-stdin < /root/proxy.pw
|
||
|
||
# Ausnahmen für den globalen Proxy
|
||
sudo svc-proxy global --no-proxy localhost,127.0.0.1,::1,.firma.local,10.0.0.0/8
|
||
|
||
# Mehrere Dienste nutzen den globalen Proxy, sofort neu starten
|
||
sudo svc-proxy set docker containerd nginx --restart
|
||
|
||
# Eigener SOCKS-Proxy ohne Anmeldung für einen Dienst
|
||
sudo svc-proxy set myapp --proxy socks5h://10.1.1.1:1080
|
||
|
||
# Nur anderer Host, Port/Typ/No-Proxy kommen vom globalen Proxy,
|
||
# keine Anmeldung (eigener Host ohne Benutzer)
|
||
sudo svc-proxy set backup --host proxy2.firma.local
|
||
|
||
# Nur den Port ändern
|
||
sudo svc-proxy set myapp --port 1081 --no-restart
|
||
|
||
# Zurück auf den globalen Proxy
|
||
sudo svc-proxy set myapp --reset
|
||
|
||
# Entfernen
|
||
sudo svc-proxy unset myapp --restart
|
||
sudo svc-proxy unset --all --no-restart
|
||
|
||
# Anzeigen
|
||
sudo svc-proxy list
|
||
sudo svc-proxy list --all
|
||
sudo svc-proxy show docker
|
||
sudo svc-proxy show # globaler Proxy
|
||
```
|
||
|
||
Beispielausgabe von `show`:
|
||
|
||
```
|
||
Dienst: ssh.service
|
||
Status: active
|
||
Modus: eigene Werte (leere Felder = global)
|
||
Proxy-Typ http (global)
|
||
Host other.proxy (dienst)
|
||
Port 3128 (global)
|
||
Benutzer - (dienst)
|
||
Kennwort - (dienst)
|
||
No-Proxy localhost,127.0.0.1,::1 (global)
|
||
Proxy-URL: http://other.proxy:3128
|
||
```
|
||
|
||
### Automatisierung (z.B. Ansible)
|
||
|
||
```yaml
|
||
- name: Proxy für Docker setzen
|
||
ansible.builtin.shell: >
|
||
svc-proxy global --proxy http://proxy.firma.local:3128 --no-restart &&
|
||
svc-proxy set docker.service --restart
|
||
```
|
||
|
||
Rückgabewert: `0` bei Erfolg, `1` bei Fehler (ungültige Eingabe, fehlende Rechte,
|
||
fehlgeschlagener Neustart).
|
||
|
||
---
|
||
|
||
## Prüfen, ob es wirkt
|
||
|
||
```bash
|
||
systemctl cat docker.service # zeigt das Drop-in
|
||
sudo cat /proc/$(systemctl show -p MainPID --value docker)/environ | tr '\0' '\n' | grep -i proxy
|
||
```
|
||
|
||
## Deinstallation
|
||
|
||
```bash
|
||
sudo svc-proxy unset --all --restart
|
||
sudo rm -rf /etc/svc-proxy /usr/local/sbin/svc-proxy
|
||
```
|