# Passing credentials to SSH and is the read command in a bash script secure?



## tay9000 (Jul 5, 2012)

Two questions:
1. Is *expect* the best way to pass credentials to SSH in a bash script? I was hoping for something simpler but it seems like this is the way to do it (without using a passwordless SSH key which is not an option for what I would like to do).
2. Is using the *read* command a secure way to store credentials while a script is executing? As in, is there any way the credentials could be intercepted or somehow pulled out of the machine's memory or something? All users on the machine are trusted and the firewall rules are pretty strict so I don't need this to be super secure. I am moreso worried if it is a majorly flawed way of collecting credentials security-wise. The credentials would only be stored in a variable within the script and forgotten once it's done.

Thanks in advance.


----------



## fluca1978 (Jul 5, 2012)

Uhm...I believe that once a password is loaded into memory it can be extracted, even if this will be not so simple. Key exchange is usually the right way to go, and please note that passing a username is not a problem or a limitation. Knowing what you are trying to achieve could help suggesting a solution or evaluating the security risk of your implementation.


----------



## SirDice (Jul 5, 2012)

Depending on your needs using Perl and net/p5-Net-SSH or net/p5-Net-SSH-Perl might be a better option.


----------



## anomie (Jul 5, 2012)

I too prefer the perl approach. For an example of the latter (that SirDice pointed to) module's usage: 


```
#!/usr/bin/perl

# AUTHOR:	anomie

# LICENSE:	Simplified BSD License 

# DESCRIPTION:  Connects to ssh servers that support password 
#               authentication. Examples of executing a command
#               and copying a file included here. 

use warnings ;
use strict ;
use Net::SSH::Perl ;
use File::Slurp ;

# --------------------------------------------------------------------- #
# FUNCTIONS
# --------------------------------------------------------------------- #

sub connect_to_sshd { 

	my ($host, $user, $pass) = @_ ;

	my %parms = (
		"protocol" => "2",
		"port"     => "22",
		"options"  => ["BatchMode yes", "ConnectionAttempts 1",
			"NumberOfPasswordPrompts 1", "ConnectTimeout 5"] 
	) ;

	my $session = Net::SSH::Perl->new($host, %parms) ;

	$session->login($user, $pass) ;

	return $session ;

}

sub run_ssh_command {

	# Third argument can optionally be provided. Normally one would 
	# do so to feed a file name for copying to the remote host. 
	#
	my ($session, $cmd, $stdin) = @_ ;

	my ($stdout, $stderr, $exit_code) ;

	if($stdin) {

		($stdout, $stderr, $exit_code) 
			= $session->cmd($cmd, $stdin) ;

	} else {

		($stdout, $stderr, $exit_code) 
			= $session->cmd($cmd) ;

	}

	print $stdout if ($stdout) ;
	print $stderr if ($stderr) ;
	print $exit_code if ($exit_code) ;

}

# --------------------------------------------------------------------- #
# MAIN LOGIC
# --------------------------------------------------------------------- #

my @creds = qw!your-host.local someguy good-password! ;

my $ssh_session = &connect_to_sshd(@creds) ;

# Run a simple command
#
&run_ssh_command($ssh_session, "hostname") ;

my $indata = read_file('/etc/aliases') ;

# Copy a file to the remote host
#
&run_ssh_command($ssh_session, "cat > ~/boo", $indata) ;
```

Keep in mind that net/p5-Net-SSH-Perl requires that PasswordAuthentication is enabled on the sshd(8) server side. For perl modules that wrap the ssh(1) client, you may have more flexibility on authentication methods.


----------



## _martin (Jul 5, 2012)

Depending on what you're trying to achieve SSH passwordless key might not be a bad idea. You can chop user's permissions to minimum (remote user) so he can execute only few commands and/or lock him even to execute one script upon login. 

Security is very subjective here - what do you want to secure it from?


----------



## tay9000 (Jul 6, 2012)

I have about 30 boxes that have a table of IPs in PF. These IPs get access to more ports. I want to write a script that can be executed from a central box that will run a script on the chosen remote machines which will grab a file containing the most up to date privileged IPs and then replace the table with this file.

The requirement is that the update must be manually executed by an Administrator, not a crontab, which is what makes this is bit annoying. Using the *pfctl* command requires root privileges which I do not want to give to a passwordless RSA key user. I also do not want a passwordless RSA key that can login to every machine in the network. So I was thinking about writing a script that will ask which hosts you want to update, then asks for your password (this assumes users have the same SSH password for all machines which kind of sucks), and then runs a loop through all of the hosts with a command like *ssh host.domain.com 'bash /path/to/script'*. All users on this box are trusted administrators with sudo rights and the box will be locked down pretty well with an eye on logins and PF Firewall logs so I am not worried about somebody untrusted being on this machine.

I am not completely happy with my solution so I am definitely open to suggestions. Thank you!

EDIT: A lightbulb just went off in my head. Matoatlantis said I can chop the permissions of this user. This may or may not work because I am developing a box full of utilities/scripts/tools to help manage our other machines so it may end up needing basically every command unless I can restrict it to only being able to execute certain scripts because basically all it will be doing is executing scripts. What documentation should I look at for this?


----------



## fluca1978 (Jul 6, 2012)

tay9000 said:
			
		

> I have about 30 boxes that have a table of IPs in PF. These IPs get access to more ports. I want to write a script that can be executed from a central box that will run a script on the chosen remote machines which will grab a file containing the most up to date privileged IPs and then replace the table with this file.
> 
> The requirement is that the update must be manually executed by an Administrator, not a crontab, which is what makes this is bit annoying. Using the *pfctl* command requires root privileges which I do not want to give to a passwordless RSA key user. I also do not want a passwordless RSA key that can login to every machine in the network. So I was thinking about writing a script that will ask which hosts you want to update, then asks for your password (this assumes users have the same SSH password for all machines which kind of sucks), and then runs a loop through all of the hosts with a command like *ssh host.domain.com 'bash /path/to/script'*. All users on this box are trusted administrators with sudo rights and the box will be locked down pretty well with an eye on logins and PF Firewall logs so I am not worried about somebody untrusted being on this machine.



Well, the first things that come into my head is that each machine should run a cron job that downloads the update script/table from a central repository. Therefore your admins need to push the updates to a repository, and if the update is found it is executed automatically. Doing this you don't have to give out any credentials but the central repository.
The second choice would be to configure a set of ssh keys and sudo on each host to execute the script and give the keys to any admin, so that it he can perform the update. You can use an installation script to distribute keys, so that on each machine keys are automatically placed along with the looping script. And this is in my opinion better than having a script asking for a password, or at least it is not worst.
If none of the above match, than developing a specific program using, for instance, the perl module will do the trick.


----------

