-
Notifications
You must be signed in to change notification settings - Fork 14
OpenSSH server
Note
OpenSSH is a feature-packed and thus quite heavy SSH server. In the likely case that you just need shell access to the initramfs environment of your system TinySSH or Dropbear SSH server are probably a better choice. Those options are 21 times and 7 times (resp.) smaller than OpenSSH, keeping the initramfs image at a reasonable size and boot times low.
sd-openssh enables SSH access during the initramfs
phase of the
Linux boot process by means of OpenSSH. The
install hook sd-openssh takes care of providing the initramfs image with all
binaries and configuration files required by OpenSSH and enabling the listening
TCP port 22 (or some other). Every incoming connection request triggers a
separate OpenSSH process that handles one SSH session.
There are two vital prerequisites that must be met:
-
sd-network from package mkinitcpio-systemd-extras must also be activated and configured in
/etc/mkinitcpio.conf. -
Package openssh must have been installed so that OpenSSH's binaries can be copied into the initramfs.
Like every SSH server also OpenSSH in the initramfs must be able to present a
server key (aka host key). OpenSSH supports several key algorithms, the
corresponding key files are ssh_host_ed25519_key, ssh_host_rsa_key and
ssh_host_ecdsa_key. These files are copied from $SD_OPENSSH_KEYDIR
(default /etc/ssh).
It is highly recommended to provide the server keys in encrypted form (ending
in .enc), created with systemd-creds. (See section Server keys and
security considerations
below for details.)
If neither encrypted nor plaintext server keys are found the install hook
sd-openssh aborts with an error.
The hook sd-openssh also copies all public keys of root (from
$SD_OPENSSH_AUTHORIZED_KEYS, default /root/.ssh/authorized_keys) to the
initramfs image. This allows to log in with ssh as root.
The hook sd-openssh enlarges the initramfs image by approximately 3210KiB,
that's around 1321KiB for the zstd compressed archive.
Caution
Probably the most common use case for this hook is to remotely unlock an
encrypted partition (or device) before it can be mounted by systemd. Mind
that by default systemd only waits 90 seconds for the unlocked partition (or
device). After that systemd will give up and enter some emergency mode. You
are then effectively locked out! To avoid this painful situation define the
kernel parameter rootflags=x-systemd.device-timeout=0 in the configuration
of your boot loader. With this setting systemd will wait forever. See
systemd.mount
for details.
sd-openssh produces a warning when plaintext server keys are copied from the
default location /etc/ssh because SD_OPENSSH_KEYDIR has not been set:
Reusing the host keys from the regular operating environment poses a security risk. See https://github.com/wolegis/mkinitcpio-systemd-extras/wiki/OpenSSH-server for details.
This warning is issued under the assumption that you also use OpenSSH for the regular operating environment. It is trivially easy to extract the server key from the initramfs image located on the unencrypted boot partition. This may allow a man in the middle to impersonate your server and thus intercept the traffic between you and your SSH server. The attack will go unnoticed since from the client's perspective the server key was as expected.
The best you can do is to go with encrypted server keys. The second best option is to use a completely separate set of server keys (distinct from the 'regular' server keys).
The basic idea of this option is to store the server keys in encrypted form in
the initramfs image. systemd will decrypt these keys only when a new SSH
session is initiated and provide them to the sshd process on an ephemeral
filesystem. Thus the plaintext server keys will never touch persistent storage.
Important
This option requires that a TPM2 compliant module is present in your system to encrypt and later decrypt the secret server key. Nowadays, this is almost always true for Intel or AMD based desktop systems and also for many dedicated servers. However, this is not true for many virtual servers and ARM based systems.
sd-openssh expects the encrypted server keys as ssh_host_{keytype}_key.enc
in /etc/ssh. When at least one of these files is present they are copied into
the initramfs image instead of the plaintext server key files. The systemd
server unit for sshd is set up in a way that the encrypted server keys are
decrypted on-the-fly during startup of each sshd service. (See
Credentials
in systemd's documentation for details.)
-
Check if your system has a TPM2 chip:
systemd-analyze has-tpm2The tool needs to report yes. Otherwise encrypting and decrypting the server keys will not work.
-
Encrypt the server keys:
systemd-creds encrypt --with-key=tpm2 --name=ssh_host_{keytype}_key \ /etc/ssh/ssh_host_{keytype}_key \ /etc/ssh/ssh_host_{keytype}_key.encwith
{keytype}beinged25519,rsaandecdsa(or a subset thereof)[1].This encrypts the OpenSSH server keys with a key hidden in the TPM. The keys are thus bound to this very system. In other words: Always encrypt and decrypt on the same system!
As desired, you will end up with encrypted keys in your initramfs image. However, anyone who can boot ANY operating system on the machine (e.g. from a USB stick) will be able to decrypt the server keys. It is therefore recommended to additionally bind against at least PCR0 (firmware) and PCR7 (secure boot state). Just add option
--tpm2-pcrs=0+7to the list of options ofsystemd-creds:systemd-creds encrypt --with-key=tpm2 --tpm2-pcrs=0+7 --name=ssh_host_{keytype}_key \ /etc/ssh/ssh_host_{keytype}_key \ /etc/ssh/ssh_host_{keytype}_key.encMind that after a firmware update or a secure boot policy change the key must be encrypted again.
-
Recreate your initramfs image with
mkinitcpio -PThe hook
sd-opensshwill recognize the encrypted server keys by their namesssh_host_{keytype}_key.encand setup everything so that these encrypted keys will be used.
In case you cannot go with encrypted server keys, the second best option is to use a different set of server keys for your initramfs image. This way at least the server keys of your regular operating environment cannot leak.
Create the separate keys with:
ssh-keygen -t {keytype} -f /etc/ssh/initramfs_host_keys/ssh_host_{keytype}_key
with {keytype} being ed25519, rsa and ecdsa (or a subset
thereof)[1].
Additionally, you have to set
SD_OPENSSH_KEYDIR=/etc/ssh/initramfs_host_keys
somewhere in mkinitcpio.conf. Of course, you are free to choose any directory
you like.
As nearly always in IT the added security comes with a loss in usability. Depending on whether you connect to your server during initramfs phase (e.g. to unlock your encrypted root partition) or during regular operation the server will present different server keys - and your SSH client will complain.
One possible solution to deal with that is to configure separate Host
sections in $HOME/.ssh/config on the client side, e.g.:
Host myserver
Hostname myserver.mydoma.in
IdentityFile ....
IdentitiesOnly yes
CheckHostIP yes
User root
Host myserver-init
Hostname myserver.mydoma.in
IdentityFile ....
IdentitiesOnly yes
CheckHostIP no
User root
HostKeyAlias myserver-init
This way you have to use ssh myserver-init to connect to OpenSSH during
initramfs phase and ssh myserver to connect to the same machine while running
in regular operating environment.
There may be situations where you have good reasons not to go with any of the
two options mentioned above. To at least silence the security warning you
have to set configuration variable SD_OPENSSH_KEYDIR in mkminitcpio.conf.
SD_OPENSSH_KEYDIR=/etc/ssh
Add sd-openssh to the array HOOKS in /etc/mkinitcpio.conf. The entry must
be positioned somewhere after (right of) systemd. Apart from that the
concrete position is irrelevant.
There are five configuration variables affecting the behavior of the install
hook or the OpenSSH server. These can be specified somewhere in
/etc/mkinitcpio.conf (or in some file in /etc/mkinitcpio.conf.d):
-
SD_OPENSSH_COMMAND: With the hooksd-opensshyou can log into the Linux system during the initramfs phase as root. By default, you get a shell (busybox dash) and can perform interactive tasks. This variable defines a shell command that is used as argument ofsh -c(i.e. it may contain blanks, double quotes and all kinds of special characters that are interpreted by the shell , but see note below). The resulting command is executed instead ofshafter login. The SSH session terminates as soon as this command terminates.A good usage example is to set
SD_OPENSSH_COMMAND="systemd-tty-ask-password-agent --query"This allows to unlock LUKS encrypted devices - but nothing more.
Note
Due to the way how the command specified by SD_OPENSSH_COMMAND is passed to
the sshd executable usage of single quotes is highly problematic. It's best
to avoid single quotes all together - unless you know exactly what you are
doing. Refer to systemd's documentation regarding command
line
and
quoting
for all the details. After having run mkinitcpio check the resulting
command with
zstdcat /boot/initramfs-linux.img \
| cpio --extract --to-stdout usr/lib/systemd/system/sshd@.service-
SD_OPENSSH_AUTHORIZED_KEYS: Set this configuration variable to specify some other source of the keys fileauthorized_keysused for root in the initramfs (instead of/root/.ssh/authorized_keys):See the sshd man page for possible options regarding
authorized_keys.For example you may want to limit root to unlocking LUKS encrypted devices after having logged into the initramfs environment (instead of
shor any command provided by the SSH client). To achieve this make a copy of root'sauthorized_keysand putcommand="..."in front of the entry used for authentication, i.e.:command="systemd-tty-ask-password-agent --query" ssh-ed25519 AAAAC3Nza...Then set
SD_OPENSSH_AUTHORIZED_KEYSnaming the modified copy. -
SD_OPENSSH_CONFIG: By default,sd-opensshcopies a minimal configuration file to the initramfs image (ignoring any existing/etc/ssh/sshd_config). Set this configuration variable to override this behavior and reference some existing configuration file (e.g.etc/ssh/sshd_config). Files in${SD_OPENSSH_CONFIG}.dare automatically taken into account.
Important
All lines starting with UsePAM are automatically converted to UsePAM no
since there is no PAM in initramfs. This even applies for
/etc/ssh/sshd_config and /etc/ssh/sshd_config.d/*.
-
SD_OPENSSH_KEYDIR: Specifies a directory with server keysssh_host_{keytype}_keyor the encrypted formssh_host_{keytype}_key.encto be copied into the initramfs image. Default is/etc/ssh. -
SD_OPENSSH_PORT: With this configuration variable it is possible to change the port opened for OpenSSH. Default is 22.This may be used to circumvent simple firewall rules, e.g. by using port 443 instead of 22.
[1] Creating just one type of server key is usually sufficient as long as you know that all clients can deal with this type.