My first client-server application. It's a simple Python script that gets a list of running processes from Server_1 and writes it to a datetime-named file on Server_2, every 5 seconds.
I am planning on refactoring this code into one or two functions, maybe one for securing the connection and one for implementing the logic.
I also know nothing about security best-practices, and I'm looking for some pointers. Any feedback on any aspect of the code is welcome.
import os
import paramiko
from time import sleep
from datetime import datetime
SERVER_1 = os.getenv('HOST_1') or ""
SERVER_1_PASS = os.getenv('PASS_1') or ""
SERVER_2 = os.getenv('HOST_2') or ""
SERVER_2_PASS = os.getenv('PASS_2') or ""
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(SERVER_1, username='root', password=SERVER_1_PASS)
ssh2 = paramiko.SSHClient()
ssh2.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh2.connect(SERVER_2, username='root', password=SERVER_2_PASS)
while True:
now = datetime.now()
dt_string = now.strftime("%d-%m-%YT%H:%M:%S")
stdin, stdout, stderr = ssh.exec_command("ps -aux")
processes = stdout.readlines()
output = [line.strip() for line in processes]
ftp = ssh2.open_sftp()
try:
file = ftp.file(dt_string, "a", -1)
file.write('\n'.join(output))
file.flush()
ftp.close()
except IOError as e:
print("Could not write to file")
print(e)
sleep(5)
```
-
\$\begingroup\$ Don't use root. Create another account that just has permissions to do these commands. Also, the loop will be 5 seconds plus the time to execute all the code. Maybe it doesn't matter. \$\endgroup\$RootTwo– RootTwo2021年02月25日 08:05:57 +00:00Commented Feb 25, 2021 at 8:05
-
\$\begingroup\$ @RootTwo does that mean create a new user and put them in a specific group, then modify the group privileges of the directory they operate in? Or what do you mean? Thanks \$\endgroup\$Bn.F76– Bn.F762021年02月27日 23:51:33 +00:00Commented Feb 27, 2021 at 23:51
1 Answer 1
SERVER_1_PASS = os.getenv('PASS_1') or "" SERVER_2_PASS = os.getenv('PASS_2') or ""
I don't think it's a good idea to pass secrets in the environment - that's too easily read by other processes. Instead, prefer to hold them in a file that's accessible only by the user. Since we're using SSH, we even already have such a file ($HOME/.ssh/config), though a better choice would be to use public-key authentication.
ssh.connect(SERVER_1, username='root', password=SERVER_1_PASS)
Ouch - why to we need to connect as root? We should have a dedicated user for this, with the minimum level of capability to perform the task.
What does connect() do when SERVER_1 is the empty string (our default if not passed in environment)? Is that what we want, or should we error out in that case?
-
\$\begingroup\$ can you expand on having a "dedicated user"? I'm confused: do I create a new user and put them in a group and then modify the group's priviledges? Or do I modify group privildges on the directory I want the new user to work in? \$\endgroup\$Bn.F76– Bn.F762021年02月27日 22:39:16 +00:00Commented Feb 27, 2021 at 22:39
-
\$\begingroup\$ That's quite a broad topic to expand on (and maybe worth looking over on Information Security (and perhaps Unix & Linux) for ideas on how best to set up a user to run a particular task). Something you could do with SSH is permit only a particular command to be run, thus denying a login shell even to someone with the correct private key. \$\endgroup\$Toby Speight– Toby Speight2021年02月28日 11:18:16 +00:00Commented Feb 28, 2021 at 11:18