Una pregunta frecuente es ¿Cómo permito el acceso via scp/sftp a mi cuenta a otras personas sin que suponga compartir la clave?
Una forma sencilla es crear usar una clave con comando forzado. En SSH2 es muy simple:
# SSH2 [remote:~/.ssh2/authorization] key users_key.pub command /usr/local/bin/sftp-server
En SSH1 la cosa es mas complicada pues el cliente scp
modifica los argumentos pasados al lado remote scp
.
Observe lo que ocurre cuando se usa scp con el siguiente programa
rssh.pl
como programa forzado:
user@machine.domain.es:~/bin$ cat -n rssh.pl 1 #!/usr/bin/perl -w 2 use strict; 3 my $args = $ENV{SSH_ORIGINAL_COMMAND} || ''; 4 5 print "Usted escribió:<$args>\n";Al ejecutar
scp
en la máquina local vemos que los
argumentos se reciben modificados en el remoto:
someone@localhost:~$ scp prueba.txt user@machine.domain.es:trasladado.txt Usted escribió:<scp -t trasladado.txt> someone@localhost:~$ scp user@machine.domain.es:trasladado.txt local.txt Usted escribió:<scp -f trasladado.txt> someone@localhost:~$ scp * user@machine.domain.es:/home/user/bin/ Usted escribió:<scp -d -t /home/user/bin/>
El siguiente programa Perl
actúa como wrapper,
asegurando la presencia de los parámetros, que los ficheros implicados no casan
con las expresiones regulares en ~/.ssh/not_allowed
y modificando los argumentos
para que los ficheros seam tomados/llevados a un directorio shared
. Por
último se lanza el programa scp
:
casiano@millo:~$ cat -n reversecopy.pl 1 #!/usr/bin/perl -w 2 use strict; 3 use Backtick::AutoChomp; 4 use List::MoreUtils qw(firstidx any); 5 use File::Basename; 6 use Log::Log4perl qw{:easy}; 7 8 Log::Log4perl::init('/home/casiano/logconfig'); 9 my $log = Log::Log4perl->get_logger(); 10 11 my $name = shift || ''; 12 13 my $ip = $ENV{SSH_CONNECTION} || ''; 14 15 # location of the server-side scp we want to run 16 my $scp_server = `which scp`; 17 18 # File with regexps: If any target matches a regexp the transfer will be 19 # interrupted 20 my @not_allowed = `cat /home/casiano/.ssh/not_allowed`; 21 22 $log->warn("$ip:$name: Can't find not_allowed file. Status: $?. $!") if $?; 23 24 # Allow comments and empty lines 25 @not_allowed = grep { $_ !~ /^#|^\s*$/ } @not_allowed; 26 27 # Since this script is called as a forced command, need to get the 28 # original scp command given by the client. 29 30 my $command = $ENV{SSH_ORIGINAL_COMMAND} || $log->logdie("$ip:$name: Environment variable SSH_ORIGINAL_COMMAND not set\n"); 31 32 # Split the command string to make an argument list, and remove the first 33 # element (the command name; we'll supply our own); 34 35 my ($c, @args) = split /\s+/, $command; 36 37 # Complain if the command is not "scp". 38 39 $log->logdie("$ip:$name: Account restricted: only scp allowed ('$c')\n") unless $c eq 'scp'; 40 41 # Ensure that either -t or -f is on the command line, to enforce running 42 # scp in server mode. 43 44 # if we're OK, run our desired "scp" with arguments. No redirections allowed 45 46 my $i = firstidx { /^-[tf]$/ } @args; 47 $log->logdie("$ip:$name: Account Restricted; only server mode allowed.\n") unless defined($i); 48 $i++; 49 my $file = $args[$i]; 50 $log->logdie("$ip:$name: Can't make transference\n") unless defined($file); 51 52 # Don't allow relative paths 53 push @not_allowed, '\.\.'; 54 $log->logdie("$ip:$name: Not allowed transference\n") if any { $file =~ qr{$_} } @not_allowed; 55 56 $args[$i] = "$ENV{HOME}/shared/$args[$i]"; 57 58 $log->debug("$ip:$name: Copying with <$scp_server, @args>"); 59 exec($scp_server, @args);
En el fichero ~/.ssh/authorized_keys
ponemos opciones a la clave:
command="/home/casiano/reversecopy.pl fulanito",from="etsii.ull.es,tonga,192.168.100.242",no-port-forwarding,no-X11-forwarding,no-pty\ ssh-dss A...== key for scpSe trata de una sóla línea aún cuando por razones de legibilidad la hayamos partido en dos.
En el ejemplo restringimos las máquinas desde las que se permite la conexión.
Estos son los contenidos del fichero ~/.ssh/not_allowed
:
user@machine.domain.es:~/.ssh$ cat not_allowed \.\. # Comentario: La siguiente line es en blanco user@machine.domain.es:~/.ssh$Ahora al ejecutar la copia del fichero
casiano@tonga:~$ scp -i ~/.ssh/show_arguments machines.sample millo: machines.sampleQueda en el directorio
shared
:
casiano@millo:~$ ls -l shared/ total 4 -rw------- 1 casiano Profesor 198 2009-04-22 15:20 machines.sampleLa copia en dirección inversa funciona de forma similar:
casiano@tonga:~$ scp -i ~/.ssh/show_arguments millo:machines.sample chuchu machines.sample 100% 198 0.2KB/s 00:00 casiano@tonga:~$ ls -l chuchu -rw------- 1 casiano Profesor 198 2009-04-22 15:22 chuchuSi intento usar la clave desde una máquina no permitida la conexión es rechazada:
casiano@cc116:~$ scp -i ~/.ssh/show_arguments machines.sample millo: casiano@millo's password: Permission denied, please try again. casiano@millo's password:
Este fué el fichero de configuración usado para Log::Log4perl:
casiano@millo:~$ cat -n logconfig 1 # Separate configfile: customer.logconfig 2 log4perl.category = DEBUG, Logfile 3 #log4perl.category = DEBUG, Screen, Logfile 4 5 log4perl.appender.Screen = Log::Log4perl::Appender::Screen 6 log4perl.appender.Screen.layout = Log::Log4perl::Layout::PatternLayout 7 # %c Category of the logging event. 8 # %C Fully qualified package (or class) name of the caller 9 # %d Current date in yyyy/MM/dd hh:mm:ss format 10 # %F File where the logging event occurred 11 # %H Hostname (if Sys::Hostname is available) 12 # %l Fully qualified name of the calling method followed by the 13 # callers source the file name and line number between 14 # parentheses. 15 # %L Line number within the file where the log statement was issued 16 # %m The message to be logged 17 # %M Method or function where the logging request was issued 18 # %n Newline (OS-independent) 19 # %p Priority of the logging event 20 # %P pid of the current process 21 # %r Number of milliseconds elapsed from program start to logging 22 # event 23 # %T A stack trace of functions called 24 # %x The topmost NDC (see below) 25 # %X{key} The entry 'key' of the MDC (see below) 26 # %% A literal percent (%) sign 27 log4perl.appender.Screen.layout.ConversionPattern = %d %p %F{1}-%L-%M: %m%n 28 29 log4perl.appender.Logfile = Log::Log4perl::Appender::File 30 log4perl.appender.Logfile.filename = scp.log 31 log4perl.appender.Logfile.mode = append 32 log4perl.appender.Logfile.layout = Log::Log4perl::Layout::PatternLayout 33 log4perl.appender.Logfile.layout.ConversionPattern = %d %p> %m%n 34 35 log4perl.logger.main = DEBUG 36 log4perl.logger.customers.get = DEBUG
scp
con la máquina remota.
Restringa el conjunto de máquinas que pueden conectarse usando esa identidad.