Benutzer-Werkzeuge

Webseiten-Werkzeuge

doku:pamsshaccess

SSH-Login nur von bestimmten Hosts

Per SSH sollen sich Benutzer jeweils nur von bestimmten Hosts erlaubt werden.

Siehe auch pamdiensteerlauben

Beispiel Benutzer testuser darf nur von Host fc4.strukturpunkt.de.

  • /etc/pam.d/sshd (Debian: /etc/pam.d/ssh)
account    required     pam_access.so
  • /etc/security/access.conf
+ : testuser : fc4.strukturpunkt.de
- : testuser : ALL
  • DNS-Lookup wird jeweils on-the-fly gemacht, keine Neustart nötig.
  • Falls root reglementiert wird: access.conf wird auch für cron gelesen, daher für cron auch erlauben:
+ : root : cron
+ : root : 192.168.4.1
- : root : ALL

Getestet:

  • Zugriff via Passwort und/oder authorized_keys
  • Fedora 7
  • Debian 4.0 (Etch)

Umgang mit dynamischen IP-Nummern

  • /usr/local/bin/dynipget
# 
# (c) 2006 Klaus.Franken@StrukturPunkt.de
# 

#  creates $SYSTEMFILE from $TEMPLATE
#  change lines like "dynip(fc4.strukturpunkt.de)" with the actual ip-numer
#  store actual ip-numer in /var/run/dynipget/$HOSTNAME
#  print ip-number only if changed

#  Version: 6.12.1

use strict;
use Net::DNS;
use IO::File;

my $SYSTEMFILE="/etc/security/access.conf";
my $TEMPLATE="/etc/security/access.conf.TEMPLATE";

sub getSaveIp ($) {
        my $DYNDOMAIN=shift;

        my $VARRUN="/var/run/dynipget/$DYNDOMAIN";
        my $dynip;
        my $dynipLast;
        my $res   = Net::DNS::Resolver->new;
        my $query = $res->search($DYNDOMAIN);

        if ($query) {
                foreach my $rr ($query->answer) {
                         next unless $rr->type eq "A";
                         #print $rr->address, "\n";
                        $dynip=$rr->address;
                }
        } else {
                warn "query failed: ", $res->errorstring, "\n";
                # exit 1;
        }


        if (-r $VARRUN) {
                my $Fd = new IO::File;
                open ($Fd, $VARRUN) || die ("open $VARRUN: $!");
                $dynipLast = <$Fd>;
                chomp($dynipLast);
                close($Fd);
        }

        if ($dynipLast ne $dynip) {
                print "new dynip($DYNDOMAIN): $dynipLast -> $dynip\n";
                my $Fd = new IO::File;
                open ($Fd, "> $VARRUN") || die ("open $VARRUN: $!");
                print $Fd "$dynip\n";
                close($Fd);
        }
        return ($dynip);
}

my $FdTemplate = new IO::File;
open ($FdTemplate, $TEMPLATE) || die ("open $TEMPLATE: $!");

my $FdSystem = new IO::File;
open ($FdSystem, ">$SYSTEMFILE") || die ("open $SYSTEMFILE: $!");

while (my $line = <$FdTemplate>) {
        if ($line =~ /dynip\((.*)\)/i) {
                my $hostname=$1;
                #print "checking for '$hostname'\n";
                my $dynip=getSaveIp($hostname);
                if (! $dynip) {
                        warn "cannot determine ip-number for '$hostname' \n";
                }
                $line =~ s/dynip\((.*)\)/$dynip/i;
        }
        print $FdSystem $line;
}
close ($FdTemplate);
close ($FdSystem);

exit 0;
  • Perl-Modul Net::DNS
    • Test: perl -e "use Net::DNS;"
    • Debian: apt-get install libnet-dns-perl
  • mkdir /var/run/dynipget
  • /etc/pam.d/sshd (Debian: /etc/pam.d/ssh)
account    required     pam_exec.so log=/var/log/dynipget.log /usr/bin/perl /usr/local/bin/dynipget
account    required     pam_access.so
  • :!: Debian-Trouble: pam_exec.so ist nicht mehr dabei, früher wars im Paket libpam-modules
  • /etc/security/access.conf.TEMPLATE
+ : testuser : dynip(fc4.strukturpunkt.de)
- : testuser : ALL

Ausblick

  • pam_exec.so

Trouble gelöst

so richtig glücklich bin ich mit den Hausmitteln von PAM nicht geworden:

- in der Prüfung von pam_access.so wird dummerweise imm der erste
gefundene Hostname hergenommen (also: es wird eine Reverse-Lookup auf
die IP-Nummer gemacht und dieser Name wird für weitere Prüfungen
hergenommen; dass weitere Hostname für die IP-existieren könnten, wird
nicht überprüft)

- damit können wir nicht formulieren, dass z.B. "r2d2.selfip.net" auf
eine IP-Nummer aufgelöst wird und erlaubt/verboten wird.

- Es gibt zwar ein PAM-Modul pam_exec. Aber darin ist nicht vorgesehen
die aktuellen Login-Daten abzufragen. Man kann einfach nur ein Programm
starten.

Ich sehe folgende Lösungmöglichkeiten:

1. http://honk.sigxcpu.org/darcs/pam-exec/
Das pam-exec (nicht zu verwechseln mit pam_exec !) startet ein Programm
_und_ übermittelt die Login-Daten ähnlich wie das Modul pam_warn. Darin
könnten wir die gewünschte Prüfung machen.

Allerdings muss dafür selbst compiliert werden. Das halte schlecht
pflegbar und zu fehleranfällig auf Dauer (insbesondere bei vielen Systemen)

2. Wir schränken den Login auf Domains ein, z.B. .dsl.de.ignite.net
Das entspricht als Login-Regel dem was wir aktuell in der Logwatch per
Sichtprüfung machen. Allerdings bringt das nicht wirklich viel und Sie
haben damit kein Möglichkeit mal eben von einem anderen Provider die
Verbindung aufzubauen.

3. per "pam_exec" wird ein Programm gestartet, welchen die IP-Nummer von
r2d2.selfip.net aktuell ermittelt und dies die Regeldatei
/etc/security/access.conf einträgt. Erst danach wird dann mittels
pam_access.so bzw. /etc/security/access.conf geprüft, ob man von dieser
IP-Nummer darf.
Das ist zwar ein wenig von hinten durch die Brust ins Auge programmier,
aber der Aufwand hält sich in Grenzen und es ist IMHO übersichtlich genug.

Die Variante 3 ist mein Favorit! Soll ich's so machen?

Variante wurde umgesetzt, s. o.

Permalink doku/pamsshaccess.txt · Zuletzt geändert: 16.05.2009 09:00 von kfr

oeffentlich