4

How can I pass environment variables from sshd's environment to new SSH sessions?

I'm running sshd in Kubernetes pods. Kubernetes sets various variables in the containers environment, including the API server: KUBERNETES_PORT=tcp://100.64.0.1:443

Now, my problem is that this environment variable is not passed to new SSH sessions, and they need it in order to configure kubectl.

Shuzheng
  • 4,023
  • 1
  • 31
  • 71

1 Answers1

9

There may be better ways to do that, but a quick way is to use the SetEnv directive from the command line of sshd:

export FOO=bar
sshd ... -o "SetEnv=FOO=$FOO" ...

export FOO=foo BAR='baz   quux'
sshd ... -o "SetEnv=FOO=$FOO BAR=\"$BAR\"" ...

The SetEnv directive is supported since OpenSSH 7.8 (check with sshd -V). As with all -o key=val options, only the first will be used.

With older versions, you may source an automatically generated file from the users' ~/.ssh/rc (PermitUserRC) or from the initialization files of the login shell: When started via ssh, bash sources ~/.bashrc (and before it, on Debian-like distros, /etc/bash.bashrc) even when run in non-interactive mode [1].

Do not use PermitUserEnvironment because that allows a user to bypass their login shell and any ForceCommand via LD_PRELOAD.


Test example with sshd running as an ordinary user:

t=$(mktemp -d)
ssh-keygen -qN '' -f "$t/key"
export FOO=foo BAR='baz  quux'
/usr/sbin/sshd -h "$t/key" -p 2222 -o "PidFile=$t/pid" \
    -o "SetEnv=FOO=\"$FOO\" BAR=\"$BAR\""

connect to it

$ ssh -p 2222 localhost 'echo "$FOO" "$BAR"'
foo baz  quux

You may use

alias ssh0='ssh -o UserKnownHostsFile=/dev/null \
    -o StrictHostKeyChecking=no -o LogLevel=ERROR'
ssh0 ...

if you want to prevent ssh from prompting for and adding the throwaway key to the known hosts file.


[1] Bash determines if it's started by ssh by checking the SSH_CLIENT and SHLVL envvars. That's another way PermitUserEnvironment may be "useful" -- to bypass the /etc/bash.bashrc which is sourced before anything else on Debian-like distros:

$ bash -xc ''
<nothing>
$ SHLVL= SSH_CLIENT=foo bash -xc ''
+ case $- in
+ return
<stuff from /etb/bash.bashrc and ~/.bashrc>
  • Why is `bar` showing up after “The authenticity of...”? – Shuzheng Mar 20 '20 at 15:21
  • The value of the FOO environment variable –  Mar 20 '20 at 15:22
  • 1
    using `openssh-server` I get `command-line: line 0: Bad configuration option: SetEnv` - any ideas? – Shuzheng Mar 20 '20 at 18:49
  • 2
    Yes, that's not supported in older versions of openssh (< 7.8). You generally don't want to run older versions of sshd ;-) –  Mar 20 '20 at 18:57
  • Thanks for all your kindness, but how can I install a newer version of `openssh-server`? The one I just installed using `apt-get install -y openssh-server` reports `OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n 7 Dec 2017`. Also, why are there no `man` pages, when I installed `man-db` and `openssh-server`? – Shuzheng Mar 20 '20 at 19:00
  • I don't have any Ubuntu, but on Debian 10 (released ~1 year ago), the OpenSSH version is 7.9something, and the `dpkg -L openssh-server` shows the `sshd_config.5.gz`, `sshd.8.gz`, `authorized_keys.5.gz`, `moduli.5.gz`. If you don't want to compile from source and don't find any other workaround, look for "backports". –  Mar 20 '20 at 19:07
  • A possible workaround would be to set `PermitUserEnvironment` and create a `~/.ssh/environment` (eg. as a symlink to a dynamically generated file). But I cannot test it now, and I don't know if this could allow the users to bypass their login shell via a `LD_PRELOAD` envvar. –  Mar 20 '20 at 19:14
  • What do you mean by “backports”? – Shuzheng Mar 20 '20 at 20:06
  • https://www.google.com/search?q=ubuntu+backports. But you could probably just have an automatically generated file sourced from `/etc/bash.bashrc` (on Ubuntu, Debian, etc) or from the user's `~/.bashrc` (on Fedora, etc). Assuming that bash is the login shell of the user(s). Bash is also sourcing those files when run NON-interactively via ssh. –  Mar 20 '20 at 20:56
  • Thanks. But aren't `~/.bashrc` sourced in the user's session without the environment variables that I want to copy from the session running `sshd`? Also, how can I specify multiple environment variables using `-o`? If I specify that option multiple times, only the first occurrence gets copied. – Shuzheng Mar 21 '20 at 06:46
  • 1
    Added an example of how to use SetEnv with multiple variables. The fact that sshd only considers the first config directive and silently ignores the rest (while still cheking them!) is a well-know braindamage, documented in the ssh*_config(5) manpages. –  Mar 21 '20 at 09:32
  • Add at the beginning of `~/.bashrc` a line like `. /path/to/kubenv` where `/path/to/kubenv` is a file you're generating automatically containing `export FOO=bar` lines. Maybe Kubernetes already creates such a file. –  Mar 21 '20 at 09:34
  • Figured out myself that `SetEnv` needed environment variables to be separated by spaces, but couldn’t find that anywhere in the man page. Tried first with commas etc. Doesn’t your `~/.bashrc` example suffer from the `LD_PRELOAD` trick, like your earlier example? I thought about this, and I don’t think it’s an issue if `LD_PRELOAD` gets set - after all, it’s only set in the user’s session and so the shared libraries run under the user’s privileges? – Shuzheng Mar 21 '20 at 11:50
  • No, it doesn't. As soon as ssh has started the user's login shell, she's free to run any command (and of course, she could override those environment variables). What she's NOT supposed to do is to directly run another program instead of her login shell, the `ForceCommand` or some subsystem. I suspect (though I have NOT tested it yet) that turning `PermitUserEnvironment` on (which is OFF by default) may allow her to do that via a `LD_PRELOAD` environment variable. –  Mar 21 '20 at 15:54
  • Thank you @mosvy, your help and guidance has been excellent. But what's the problem of running a command directly rather than the login shell? Both things would run under the user's credentials after `sshd` has called e.g. `seteuid`? – Shuzheng Mar 22 '20 at 11:26
  • 1. "excellent, etc" please keep it to the facts, thanks. 2. You may ask another Q about that, maybe on security.se (if it's not already answered). For the `ForceCommand` (which is also run by the user's login shell), it's quite obvious that it's not forced anymode if you can bypass it ;-) –  Mar 22 '20 at 14:12