Enable Root Login Over SSH to Multipass Virtual Machines

E

I’ve recently forsaken VMware Fusion in favour of Canonical’s Multipass to create and manage Ubuntu Server VMs on macOS.

There are two things I want to be able to do with Ubuntu Server VMs: establish an SSH connection as root and navigate the file system using applications such as Forklift and FileZilla. Purists and more security-minded individuals may balk at this, but these VMs are local, non-production servers purely for testing.

NOTE: If you have both VMware Fusion and Multipass installed on the same machine, take a look at Possible Conflict between VMware Fusion and Multipass at the foot of this article.

Throughout this article the following terms are used:

Term Definition
host The machine or OS on which Multipass is installed.
guest instance The Multipass VM.
client The machine initiating a connection to another (virtual) machine.
server The (virtual) machine being connected to by a client.
identity file The file containing the private key necessary to authenticate a user on the guest instance or server. The identity file is stored on the host or client.
host key The public or private key used to authenticate the guest instance or server to the host or client. The public key is stored on the host or client and the private key is stored on the guest instance or server.

Glossary of terms

 

 

To demonstrate, I’ll be using macOS as the host OS and a Multipass guest instance named foo with an IP address of 172.16.170.4 running Ubuntu 20.04 LTS. A standard user with sudo privileges named ubuntu is created by default on every new guest instance:

Dummy Content
multipass list
Name                State             IPv4             Image
foo                 Running           172.16.170.4     Ubuntu 20.04 LTS

 

 

There are two built-in commands to connect with a guest instance. The first is the exec command which simply executes a command on the running guest instance. If it isn’t running, the exec command fails:

Dummy Content
multipass exec foo -- whoami
ubuntu
exec failed: instance "foo" is not running

 

 

The second is shell or sh which opens an interactive login shell on the running guest instance. If the guest instance isn’t running, an attempt is made to first start it:

Dummy Content
multipass shell foo

 

 

Neither of these methods can be used to configure connections in applications like Forklift or FileZilla. These and other file transfer applications typically use SFTP to transfer files to and from the client and server. Using SFTP, an encrypted SSH connection is first established by the client to the server. Files are then transferred using FTP over the SSH connection.

When establishing an SSH connection, we need to be mindful of the authentication method used by the server. Typically this is public key authentication and Multipass guest instances are no exception. Public key authentication requires both a public and private key. Multipass generates this key pair using the RSA algorithm with a 2048-bit key length and uses the same key pair for both the ubuntu and root users.

The private key is stored in an identity file on the host. For macOS, this identity file is /var/root/Library/Application Support/multipassd/ssh-keys/id_rsa1 and is created when Multipass is installed. The corresponding public key is included in the vendor-data that Multipass gives to cloud-init when the guest instance is initialised and is written to /home/ubuntu/.ssh/authorized_keys and /root/.ssh/authorized_keys on the guest instance.

1 On a Linux host with Multipass installed via Snap the identity file is /var/snap/multipass/common/data/multipassd/ssh-keys/id_rsa.

Because of its location on the host, superuser privileges are required to read the identity file. Using sudo on the command line is not an issue although by doing so the guest instance’s public host keys (ed25519, rsa and ecdsa) are added to /var/root/.ssh/known_hosts on the host not ~/.ssh/known_hosts. This is important to remember if attempting to remove public host keys for a given instance from the known_hosts file:

Dummy Content
sudo ssh-keygen -R 172.16.170.4 -f /var/root/.ssh/known_hosts

 

 

However, the requirement for using sudo is a problem when configuring SFTP connections in Forklift or FileZilla as it’s not possible to elevate an admin user’s privileges to those of the superuser. One way to overcome this is to copy the identity file to a new location accessible to the admin user:

Dummy Content
mkdir -p ~/.ssh/multipass && sudo cp /var/root/Library/Application\ Support/multipassd/ssh-keys/id_rsa $_

 

 

This first creates a sub-directory named multipass in the admin user’s .ssh directory, then copies the identity file to it. The $_ at the end of the cp command is a special parameter which expands to the last argument – ~/.ssh/multipass – passed to the previous command – mkdir.

The duplicate file has the same root:wheel ownership as the original. This needs to be changed to $USER:staff:

Dummy Content
sudo chown $USER:staff ~/.ssh/multipass/id_rsa

 

 

In addition, the duplicate identity file’s permissions are read-only (400), the same as the original. When using FileZilla, you may need to change the format of the private key. See FileZilla can’t Read the Private Key at the end of this article. To do so, the permissions must first be changed to read-write (600):

Dummy Content
chmod 600 ~/.ssh/multipass/id_rsa

 

 

Now the private key is in the correct location, let’s try to establish an SSH connection to the guest instance named foo using the standard user ubuntu. The location of the identity file is specified using the -i option. The instance must first be running or the connection will timeout:

Dummy Content
ssh -i ~/.ssh/multipass/id_rsa ubuntu@172.16.170.4

 

 

The credentials used to successfully establish an SSH connection to the guest instance can now be used to configure an SFTP connection in Forklift or FileZilla by specifying the location of the identity file, but what if we want to connect as the guest instance’s root user.

It’s possible to open a non-login shell with root access on a running guest instance using the built-in exec command:

Dummy Content
multipass exec foo -- sudo su

 

 

This is no different from executing sudo su having first logged-in using the standard user account ubuntu on the guest instance and as such doesn’t allow for the configuration of SFTP connections in file transfer applications.

Let’s see if it’s possible to establish an SSH connection to the guest instance using its root user. We use the same command syntax as before, but substitute root for ubuntu:

Dummy Content
ssh -i ~/.ssh/multipass/id_rsa root@172.16.170.4
Please login as the user "ubuntu" rather than the user "root".

Connection to 172.16.170.4 closed.

 

 

It’s pretty clear from the output that this isn’t possible. However, let’s take a look at the /root/.ssh/authorized_keys file on the guest instance:

Dummy Content
sudo cat /root/.ssh/authorized_keys
no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"ubuntu\" rather than the user \"root\".';echo;sleep 10;exit 142" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCz3PNy+AIaX4jTgvTw0VtrAxnH53kpOjiVnbjM27fMkXFUIZN1Fa16XynrVzg6pGaUrFYUJhK5OCXzZJ6DwcWQG1QYxI1TGytraJa3osTU72EZh71vsD+7EP6+M2MzxK7B7oQDh6GTt17f4dG5GPOHEdueG0qHhRM5A9WhiWvDCYUcFHm/eFfYAGQTEz103faMl7frl5Vq5VdJQBjVEVIKfnEtfP3vRGcuUfi+IRfzYS4L1dxX5blnj5Im39YMh31aBXxl/Fo4Atb6PKOAnoaR4wHBTDik+2q4vHhmfPDXPAcX3gUyWjQ9nyBLqpjptVF6rnPIMv228/WwwnVRB/ED ubuntu@localhost

 

 

As is evident from the output, the public key is prefixed with:

no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="echo 'Please login as the user \"ubuntu\" rather than the user \"root\".';echo;sleep 10;exit 142"

 

 

This string is the default value of the disable_root_opts configuration key used by cloud-init and the highlighted code is responsible for displaying an error message, waiting 10 seconds and then exiting, effectively denying root login.

To be able to establish an SSH connection as root, this code has to be removed either manually by opening the file with nano or similar editor or alternatively using sed:

;
Dummy Content
sudo sed -i.$(date +"%Y%m%d-%H%M%S") 's/,command.*exit 142"//' /root/.ssh/authorized_keys

 

 

Alternatively, if you pass user-data to cloud-init to bootstrap Multipass guest instances you could include either the disable_root or the disable_root_opts configuration keys in your cloud-init configuration file to control the root user’s access.

The default value for disable_root is true which causes the value of disable_root_opts to be pre-pended to the public key in the authorized_keys file. We’ve already seen what this default value is, so the first method is to provide a new value for the disable_root_opts configuration key in your cloud-init configuration file, omitting the offending code:

Dummy Content
#cloud-config
...
disable_root_opts: no-port-forwarding,no-agent-forwarding,no-X11-forwarding
...

 

 

In the second method, we change the disable_root configuration key to false which effectively ignores the the disable_root_opts configuration key and results in nothing being pre-pended to the public key:

Dummy Content
#cloud-config
...
disable_root: false
...

 

 

Multipass guest instances can now be created using:

Dummy Content
multipass launch --name foo --cloud-init config.yaml

 

 

It should now be possible to establish an SSH connection to the guest instance using its root user:

Dummy Content
ssh -i ~/.ssh/multipass/id_rsa root@172.16.170.4

 

 

These same credentials can be used to configure SFTP connections to the guest instance using its root user in Forklift and FileZilla.

NOTES

Possible Conflict between VMware Fusion and Multipass

If both Multipass and VMware Fusion are installed on your machine it’s worth noting that by default VMware Fusion VMs are configured to share the IP address of the Mac on the external network under Settings > Network Adapter > Share with my Mac. Before starting a VMware Fusion VM ensure that no Multipass guest instances are running by executing multipass stop --all. If any Multipass guest instances are running, VMware Fusion displays the error Could not connect 'Ethernet0' to virtual network '/dev/vmnet8'. The VMware Fusion VM will start, but will be unable to connect to the Internet.

A workaround to having both Multipass guest instances and VMware Fusion VMs running at the same time is to reconfigure the VMware Fusion VM’s network adapter to use Wi-Fi with Settings > Network Adapter > Wi-Fi before starting the VMware Fusion VM.

However, starting a VMware Fusion VM while a Multipass guest instance is running will most likely cause issues with Multipass as well. If this occurs, first stop and then start the Multipass daemon – multipassd – before restarting the guest instance:

Dummy Content
sudo launchctl unload /Library/LaunchDaemons/com.canonical.multipassd.plist && sudo launchctl load /Library/LaunchDaemons/com.canonical.multipassd.plist

 

 

FileZilla can’t Read the Private Key

FileZilla appears unable to read the private key in the identity file. It displays a Could not load key file error. The header of the private key is -----BEGIN PRIVATE KEY----- and the Base64-encoded text begins MII...IBADAN which identifies it as an unencrypted private key in Base64-encoded PKCS#8 format.

I couldn’t find any documentation to confirm if or explain why FileZilla doesn’t like this format, but FileZilla will accept the private key if it is first converted to the new OpenSSH format. This conversion appears to be as simple as setting a new empty passphrase – the original passphrase is also empty – using ssh-keygen:

Dummy Content
ssh-keygen -p -N '' -f ~/.ssh/multipass/id_rsa

 

 

The private key remains unencrypted, but its header is now -----BEGIN OPENSSH PRIVATE KEY-----.

About the author

A native Brit exiled in Japan, Steve spends too much of his time struggling with the Japanese language, dreaming of fish & chips and writing the occasional blog post he hopes others will find helpful.

1 response

1 Comment

Steve

Recent Comments

Recent Posts