Acceso Sólo Via scp

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 scp
Se 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.sample
Queda en el directorio shared:
casiano@millo:~$ ls -l shared/
total 4
-rw------- 1 casiano Profesor 198 2009-04-22 15:20 machines.sample
La 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 chuchu
Si 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

Ejercicio 2.1.15   Establezca una identidad que tiene acceso sólo vía scp con la máquina remota. Restringa el conjunto de máquinas que pueden conectarse usando esa identidad.

Véase También



Subsecciones
Casiano Rodríguez León
Licencia de Creative Commons
Programación Distribuida y Mejora del Rendimiento
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=44.
2012-06-19