Manchmal möchte man bei einem SSH-Server ein für bestimmte Benutzer ein festes …">

Intelligente Lösungen
in neuer Dimension

SSH: Auswertung von SSH_ORIGINAL_COMMAND

Manchmal möchte man bei einem SSH-Server ein für bestimmte Benutzer ein festes Kommando hinterlegen via “authorized_keys” und “command=xyz”. Wenn sich die Benutzer dann am SSH-Server anmelden, wird immer das Kommando xyz ausgeführt, also:

  • Benutzer: ssh ich@server –> xyz wird auf “server” ausgeführt

Nun kann man dem SSH-Kommando noch Argumente dranhängen und diese werden via SSH_ORIGINAL_COMMAND an xyz übergeben. Dadurch kann dann das Verhalten von xyz gesteuert werden.

Problem: “Gruppierung” von Argumenten in SSH_ORIGINAL_COMMAND geht leicht verloren. Wenn man also

  • ssh ich@server start "Uli Heller" now

aufruft, so erhält man bei naiver Auswertung von SSH_ORIGINAL_COMMAND diese Parameter

  • P1: start
  • P2: Uli
  • P3: Heller
  • P4: now

Wnsch wäre dies:

  • P1: start
  • P2: Uli Heller
  • P3: now

SSH-Setup

Ich verwende als Server den Rechner “uli-sshtest” und trage dort beim Benutzer “ubuntu” ies ein:

1
command="./my-command.sh" ssh-rsa AAAAB3Nza...p6Q+VFQ/eAnpCZDoITmw== TestKey von Uli

Erster Test – my-command.sh fehlt

1
2
3
4
5
6
7
uli:~$ ssh ubuntu@uli-sshtest
The authenticity of host 'uli-sshtest.lxd (<no hostip for proxy command>)' can't be established.
ECDSA key fingerprint is SHA256:1/HEqekk7wU+wFyHPyR4CwVIrAGanTyYXDU051t2J6Q.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'uli-sshtest.lxd' (ECDSA) to the list of known hosts.
bash: ./my-command.sh: No such file or directory
Connection to uli-sshtest closed.

Zweiter Test – Grundvariante von my-command.sh

Nun teste ich mit dieser Grundversion von “my-command.sh”:

1
2
3
#!/bin/sh
echo "Aufrufparameter: $@"
echo "SSH_ORIGINAL_COMMAND: ${SSH_ORIGINAL_COMMAND}"

Tests:

1
2
3
4
5
6
7
8
9
10
11
12
uli:~$ ssh ubuntu@uli-sshtest
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: 
Connection to uli-sshtest closed.

uli:~$ ssh ubuntu@uli-sshtest start "Uli Heller" now
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start Uli Heller now

uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now'
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now

Dritter Test – Auftrennen

Leicht erweiterte Version:

1
2
3
4
5
6
7
8
9
#!/bin/sh
echo "Aufrufparameter: $@"
echo "SSH_ORIGINAL_COMMAND: ${SSH_ORIGINAL_COMMAND}"

set --  ${SSH_ORIGINAL_COMMAND}
while [ $# -gt 0 ]; do
  echo "arg: $1"
  shift
done

Tests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
uli:~$ ssh ubuntu@uli-sshtest
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: 
Connection to uli-sshtest closed.

uli:~$ ssh ubuntu@uli-sshtest  start "Uli Heller" now
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start Uli Heller now
arg: start
arg: Uli
arg: Heller
arg: now

uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now'
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now
arg: start
arg: "Uli
arg: Heller"
arg: now

Vierter Test – Auftrennen mit “eval”

Noch eine Erweiterung:

1
2
3
4
5
6
7
8
9
#!/bin/sh
echo "Aufrufparameter: $@"
echo "SSH_ORIGINAL_COMMAND: ${SSH_ORIGINAL_COMMAND}"

eval "set --  ${SSH_ORIGINAL_COMMAND}"
while [ $# -gt 0 ]; do
  echo "arg: $1"
  shift
done

Test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
uli:~$ ssh ubuntu@uli-sshtest
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: 
Connection to uli-sshtest closed.

uli:~$ ssh ubuntu@uli-sshtest  start "Uli Heller" now
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start Uli Heller now
arg4: start
arg4: Uli
arg4: Heller
arg4: now

uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now'
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now
arg4: start
arg4: Uli Heller
arg4: now

Das entspricht schonmal ziemlich genau unserem Wunschzustand!

Problem: Damit kann man nun doch wieder eigene Kommandos ausführen!

1
2
3
4
5
6
7
8
uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now $(hostname)'
# ... führt "hostname" auf uli-sshtest aus
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now $(hostname)
arg4: start
arg4: Uli Heller
arg4: now
arg4: uli-sshtest

Fünfter Test – Auftrennen ohne “eval”

Anpassung gemäß StackOverflow:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
echo "Aufrufparameter: $@"
echo "SSH_ORIGINAL_COMMAND: ${SSH_ORIGINAL_COMMAND}"

COMMAND_ARRAY=()
while read line; do
  COMMAND_ARRAY+=("$line")
done < <(xargs -n 1 <<< "$SSH_ORIGINAL_COMMAND")

for arg in "${COMMAND_ARRAY[@]}"; do
  echo "arg5: ${arg}"
done

Test:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
uli:~$ ssh ubuntu@uli-sshtest
SSH_ORIGINAL_COMMAND: 
arg5: 
Connection to uli-sshtest.lxd closed.

uli:~$ ssh ubuntu@uli-sshtest start "Uli Heller" now
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start Uli Heller now
arg5: start
arg5: Uli
arg5: Heller
arg5: now

uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now'
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now
arg5: start
arg5: Uli Heller
arg5: now

uli:~$ ssh ubuntu@uli-sshtest 'start "Uli Heller" now $(hostname)'
Aufrufparameter: 
SSH_ORIGINAL_COMMAND: start "Uli Heller" now $(hostname)
arg5: start
arg5: Uli Heller
arg5: now
arg5: $(hostname)

Wunschzustand erreicht und Kommando-Ausführung unterbunden! Geht nur mit “#!/bin/bash” in der ersten Zeile!

Weitere Aufruf-Varianten mit gleichem Ergebnis:

1
2
3
4
uli:~$ ssh ubuntu@uli-sshtest start '"Uli Heller"' now
uli:~$ ssh ubuntu@uli-sshtest start "'Uli Heller'" now
uli:~$ ssh ubuntu@uli-sshtest start Uli\\ Heller now
uli:~$ ssh ubuntu@uli-sshtest start \"Uli Heller\" now

Links

Historie und Anmerkung

  • 2021-04-01: Erste Version