Locking down root privileges on a cloud instance

Photo by Alice on Unsplash

Locking down root privileges on a cloud instance

Following best practices to minimize vulnerability

When I was writing my last blog post, I ended up having to enable root access to my Vultr instance so that I could reset my SSH configuration and document it properly for the blog post.

But now I'm done with that blog post, and root is still available for login with a password (I didn't use my real domain name in that blog post, calm down).

Naturally, I'd like to lock it back down to the status it was in before I wrote that blog post. I figured I'd document the process and share my findings along the way.

Prework

Before disabling root login on the Vultr instance, I need to make sure that I'm able to ssh in as a non-root user.

This is because some ssh configuration has to be done as the root user on the Vultr instance. Once that configuration is done, then we can be done with root.

Vultr documentation

Referencing Vultr's documentation for this use case, they present three options:

  • create a new SSH key

    • not a fan of this because getting the key from the server to my local machine is more involved than the other way around
  • move the root SSH key to the non-root user

    • this immediately jumped out as the approach I wanted to use
  • startup scripts

    • seems too involved

    • docs say it's best suited for deploying many instances

So I proceed with option #2: move the root SSH key to the non-root user

Check existing keys

The Vultr instructions say to

  • make a ~/.ssh folder for the non-root user

  • move the authorized_keys file from /root/.ssh/ to /home/<nonRootUser>/.ssh/

  • make the non-root user the owner of the /home/<nonRootUser/.ssh directory

...but I think I may have already done some of these steps.

So I log into the Vultr instance as root, and start poking around:

# root@vultr

ls -la ~/.ssh # press enter

# output
drwx------  2 root  wheel  512 May 14 16:15 .
drwx------  3 root  wheel  512 May 14 15:54 ..
-rw-------  1 root  wheel  185 May 14 19:34 authorized_keys

I can see that /root/authorized_keys exists, so I see what's in it:

# root@vultr

cat /root/.ssh/authorized_keys # press enter

# output
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbll4kwbvR/um3/zzMxEZs7+Jmj8NpAPkqQj8SC6cia idev@MSI
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaQ9obHa6yYVZPqjQSaeG5OadwxxYguPJVNA7zJpuEm jester@devbox

I see that there are two public keys, one from each of my laptops. I believe these are the keys that I generated and copied over in the last blog post.

To confirm these are the correct keys, I go to each client machine:

# idev@MSI

ls -la ~/.ssh # press enter

# output
drwx------  2 idev idev 4096 May 14 12:15 .
drwxr-x--- 34 idev idev 4096 May 15 18:18 ..
-rw-------  1 idev idev 1342 May 14 11:30 known_hosts
-rw-------  1 idev idev 1120 May 14 11:30 known_hosts.old
-rw-------  1 idev idev  399 May 14 12:11 vultr_ed25519
-rw-r--r--  1 idev idev   90 May 14 12:11 vultr_ed25519.pub

I see what looks like a Vultr public key, so I check its contents:

# idev@MSI

cat ~/.ssh/vultr_ed25519.pub # press enter

# output
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbll4kwbvR/um3/zzMxEZs7+Jmj8NpAPkqQj8SC6cia idev@MSI

I can see that the public key on the client machine matches what is in the /root/authorized_keys file on the Vultr instance. So far so good.

Now I do the same thing on my other laptop:

# jester@devbox

ls -la ~/.ssh # press enter

# output
drwx------  2 jester jester 4096 May 14 19:37 .
drwxr-x--- 21 jester jester 4096 May 15 18:26 ..
-rw-------  1 jester jester  201 May 14 19:37 config
-rw-------  1 jester jester 1484 May  2 17:22 known_hosts
-rw-------  1 jester jester  506 Apr 29 12:41 known_hosts.old
-rw-------  1 jester jester  399 May 14 19:29 rpi_ed25519
-rw-r--r--  1 jester jester   95 May 14 19:29 rpi_ed25519.pub
-rw-------  1 jester jester  399 May 14 15:33 vultr_ed25519
-rw-r--r--  1 jester jester   95 May 14 15:33 vultr_ed25519.pub

I see an additional key pair and a config file, but right now I'm just concerned with the Vultr key, so I view the contents of the file to see if it matches what's on the server:

# jester@devbox

cat ~/.ssh/vultr_ed25519.pub # press enter

# output
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaQ9obHa6yYVZPqjQSaeG5OadwxxYguPJVNA7zJpuEm jester@devbox

It does indeed match, so I'm ready to move on to the next step.

Check the non-root user

Recall that the instructions said to make a .ssh folder for the non-root user, but I think I already created it, so I go ahead and check:

# root@vultr

ls -la /home/sharif/.ssh # press enter

# output
drwx------  2 sharif  sharif  512 May 14 15:01 .
drwxr-xr-x  4 sharif  sharif  512 May 14 14:55 ..
-rw-------  1 sharif  sharif  747 May 14 15:04 authorized_keys

Yep, there it is. I suspect the authorized_keys file is not up-to-date because of the configuration changes I made during my last blog post, so I view the contents:

# root@vultr

cat /home/sharif/.ssh/authorized_keys

Sure enough, I've got some old keys that don't match what's on the client machines, so I remove the file:

# root@vultr

rm /home/sharif/.ssh/authorized_keys

Now I can follow Vultr's instructions and move the root user's authorized_keys file over to my non-root user:

# root@vultr

mv /root/.ssh/authorized_keys /home/sharif/.ssh/ # press enter

# make sure it worked

ls -la /home/sharif/.ssh/ # press enter

# output 
drwx------  2 sharif  sharif  512 May 15 22:43 .
drwxr-xr-x  4 sharif  sharif  512 May 14 14:55 ..
-rw-------  1 root    wheel   185 May 14 19:34 authorized_keys
# end output

cat /home/sharif/.ssh/authorized_keys # press enter

# output -- correct keys confirmed
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbll4kwbvR/um3/zzMxEZs7+Jmj8NpAPkqQj8SC6cia idev@MSI
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaQ9obHa6yYVZPqjQSaeG5OadwxxYguPJVNA7zJpuEm jester@devbox

Now to adjust the permissions so that the non-root user can properly access the authorized_keys file:

# root@vultr

chown -R sharif:sharif /home/sharif/.ssh # press enter

# make sure it worked
ls -la /home/sharif/.ssh # press enter

# output -- non-root ownership confirmed
drwx------  2 sharif  sharif  512 May 15 22:43 .
drwxr-xr-x  4 sharif  sharif  512 May 14 14:55 ..
-rw-------  1 sharif  sharif  185 May 14 19:34 authorized_keys

The non-root user's configuration looks good; now to test it from both clients.

Test SSH as the non-root user

This part should (hopefully) be pretty painless since I set up SSH configuration files in the last blog post.

Theoretically, I should just be able to change the user from root to sharif in the config, use that config for both laptops, and all should be well.

Let's try it:

# idev@MSI

# /home/idev/.ssh/config
Host myvultrserver.com
    HostName myvultrserver.com
    User sharif
    IdentityFile ~/.ssh/vultr_ed25519

Moment of truth:

# idev@MSI
ssh myvultrserver.com

Success!

The process should be the same on my other laptop:

# jester@devbox

# /home/jester/.ssh/config
Host myvultrserver.com
    HostName myvultrserver.com
    User sharif
    IdentityFile ~/.ssh/vultr_ed25519

# save the config file

# test ssh
ssh myvultrserver.com

Now that I've confirmed I can SSH into the server with both my client machines (laptops), I can finally move on to removing the ability to:

  • log in as root

  • log in with a password

Disable root and password login

I'll need to log in to my Vultr as root one last time:

ssh root@myvultrserver.com

Now I need to edit the /etc/ssh/sshd_config file to disable root and password login:

# root@vultr

# /etc/ssh/sshd_config

# change 'PermitRootLogin' from 'yes' to 'no'
PermitRootLogin no
# add 'PasswordAuthentication no' to bottom of file
PasswordAuthentication no

Once the file is saved, I need to restart the sshd service on the server:

# root@vultr

rcctl restart sshd # press enter

# output
sshd(ok)
sshd(ok)

Now I can log out of the instance and see if the changes took effect:

# root@vultr
exit # press enter

# idev@MSI
ssh root@myvultrserver.com # press enter

# output
root@sharif.gg: Permission denied (publickey,keyboard-interactive).

This is what I wanted to see -- an error message when trying to log in as root via ssh.

As a final test, I want to see if I can run an elevated command as my non-root user:

# idev@MSI

ssh myvultrserver.com # press enter

# login successful -- sharif@vultr

# attempt to edit a readonly file with sudo
sudo vim /etc/ssh/sshd_config # press enter

# prompted for password
Password: # enter password

sharif is not in the sudoers file. # error
This incident has been reported to the administrator.

I'm feeling pretty good about this, but there is a looming question...

What if I need root?

There is a good chance I'll want to change something else on my server that requires root privileges.

But how do I do that if I just disabled root login and password login?

Thankfully, cloud services like Vultr offer a backdoor through their web console, where you can access a special web terminal with root access.

The web console is usually located in the dashboard/account management area for your cloud provider and is only available once you've logged into your account.