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 usermove 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.