Jak ograniczyć użytkowników SSH do predefiniowanego zestawu poleceń po zalogowaniu?

85

To pomysł na zabezpieczenie. Nasi pracownicy będą mieli dostęp do niektórych poleceń na serwerze Linux, ale nie do wszystkich. Powinni mieć np. Możliwość dostępu do pliku dziennika ( less logfile) lub uruchamiania różnych poleceń ( shutdown.sh/ run.sh).

Informacje podstawowe:

Wszyscy pracownicy uzyskują dostęp do serwera z tą samą nazwą użytkownika: nasz produkt działa na „normalnych” uprawnieniach użytkownika, nie jest wymagana żadna „instalacja”. Po prostu rozpakuj go w katalogu użytkownika i uruchom. Zarządzamy kilkoma serwerami, na których „zainstalowana” jest nasza aplikacja. Na każdej maszynie jest użytkownik johndoe. Nasi pracownicy czasami potrzebują dostępu do aplikacji z wiersza poleceń, aby uzyskać dostęp i sprawdzić pliki dziennika lub ręcznie ponownie uruchomić aplikację. Tylko niektóre osoby będą miały pełny dostęp do wiersza poleceń.

Używamy uwierzytelniania ppk na serwerze.

Byłoby wspaniale, gdyby pracownik1 miał dostęp tylko do pliku dziennika, a pracownik2 mógł również wykonywać X itd.

Rozwiązanie: Jako rozwiązanie użyję commandopcji podanej w zaakceptowanej odpowiedzi. Zrobię swój własny mały skrypt powłoki, który będzie jedynym plikiem, który będzie można uruchomić dla niektórych pracowników. Skrypt będzie oferował kilka poleceń, które można wykonać, ale żadnych innych. Użyję następujących parametrów w authorized_keysod, jak podano tutaj :

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host

To nam wystarczy. Dzięki społeczności!

Marcel
źródło
Czy standardowe zabezpieczenia list ACL systemu Linux nie są wystarczające? Jakich dodatkowych funkcji potrzebujesz?
James Brady
22
To okropny pomysł, Marcel.
Vinko Vrsalovic
13
@Vinko, @PEZ: Dodałem kilka podstawowych informacji. Zamiast mówić „głupi pomysł”, możesz dodać wartościowe komentarze. Jaki jest Twoim zdaniem lepszy pomysł?
Marcel
8
Nadal nie widzę żadnego usprawiedliwienia dla wielu użytkowników o tej samej nazwie użytkownika.
Eldelshell
3
„Mój własny mały skrypt powłoki”? Brzmi dość niebezpiecznie. Jeśli nie jesteś ekspertem, prawdopodobnie istnieje wiele sposobów na ucieczkę od tego do pełnej skorupy. Wolałbym raczej zaufać dobrze napisanemu, debugowanemu i utrzymywanemu programowi (kilka zostało wspomnianych).
bortzmeyer,

Odpowiedzi:

68

Możesz także ograniczyć klucze do dozwolonych poleceń (w pliku authorised_keys).

To znaczy, że użytkownik nie logowałby się przez ssh, a następnie miałby ograniczony zestaw poleceń, ale raczej mógłby wykonywać te polecenia tylko przez ssh (np. „Ssh somehost bin / showlogfile”)

HD.
źródło
To wygląda interesująco. Czy można zdefiniować wiele poleceń?
Marcel
12
W tym artykule przedstawiono kilka opcji dla wielu poleceń korzystających z pliku busy_keys
Bash
@ rd834 ...: Wielkie dzięki. Myślę, że to dało mi „dobre” rozwiązanie ... (dodane do pytania). Przyjmę tę odpowiedź jako „poprawną”.
Marcel
11
Książka O'Reilly SSH zawiera doskonałe wyjaśnienie, jak to zrobić, w tym zezwolenie na wiele poleceń poprzez skonfigurowanie skryptu, który sprawdza zmienną środowiskową SSH_ORIGINAL_COMMAND. oreilly.com/catalog/sshtdg/chapter/ch08.html
Alex Dupuy
5
ta odpowiedź na błąd serwera zawiera fajną wskazówkę, jak zezwolić na wiele poleceń za pomocą wyeksportowanej zmiennej SSH_ORIGINAL_COMMAND.
MattBianco
32

sshpostępuje zgodnie z rshtradycją, używając programu powłoki użytkownika z pliku haseł do wykonywania poleceń.

Oznacza to, że możemy rozwiązać ten problem bez angażowania sshw jakikolwiek sposób konfiguracji.

Jeśli nie chcesz, aby użytkownik miał dostęp do powłoki, po prostu zastąp powłokę tego użytkownika skryptem. Jeśli /etc/passwdzajrzysz do środka, zobaczysz, że istnieje pole, które przypisuje każdemu użytkownikowi interpreter poleceń powłoki. Skrypt jest używany jako powłoka zarówno do ich interaktywnego logowania, ssh user@host jak i do poleceń ssh user@host command arg ....

Oto przykład. Stworzyłem użytkownika, fooktórego powłoką jest skrypt. Skrypt wypisuje komunikat, my arguments are:po którym następują jego argumenty (każdy w osobnym wierszu i w nawiasach ostrych) i kończy. W przypadku dziennika nie ma argumentów. Oto, co się dzieje:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.

Jeśli użytkownik spróbuje uruchomić polecenie, wygląda to tak:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>

Nasza „powłoka” otrzymuje -cwywołanie stylu, z całym poleceniem jako jednym argumentem, dokładnie w taki sam sposób, w /bin/shjaki je otrzyma.

Jak widać, możemy teraz dalej rozwijać skrypt, tak aby rozpoznawał przypadek, gdy został wywołany z -cargumentem, a następnie analizuje ciąg (powiedzmy przez dopasowanie do wzorca). Te ciągi, które są dozwolone, mogą być przekazane do prawdziwej powłoki przez rekurencyjne wywołanie /bin/bash -c <string>. Przypadek odrzucenia może wydrukować komunikat o błędzie i zakończyć (w tym przypadek, gdy go -cbrakuje).

Musisz uważać, jak to piszesz. Polecam pisać tylko pozytywne dopasowania, które pozwalają tylko na bardzo konkretne rzeczy i nie pozwalają na wszystko inne.

Uwaga: jeśli tak root, nadal możesz zalogować się na to konto, zastępując powłokę w supoleceniu, w ten sposób su -s /bin/bash foo. (Wybrana powłoka zastępcza). Nie-root nie może tego zrobić.

Oto przykładowy skrypt: ogranicz użytkownika do korzystania tylko sshz gitdostępu do repozytoriów w ramach /git.

#!/bin/sh

if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
  printf "interactive login not permitted\n"
  exit 1
fi

set -- $2

if [ $# != 2 ] ; then
  printf "wrong number of arguments\n"
  exit 1
fi

case "$1" in
  ( git-upload-pack | git-receive-pack )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    printf "access denied outside of /git\n"
    exit 1
    ;;
esac

if ! [ -e "$gitpath" ] ; then
   printf "that git repo doesn't exist\n"
   exit 1
fi

"$1" "$gitpath"

Oczywiście ufamy, że te programy Git git-upload-packi git-receive-packnie mają dziur ani włazów, które umożliwią użytkownikom dostęp do systemu.

Jest to nieodłączne w tego rodzaju schemacie ograniczeń. Użytkownik jest uwierzytelniany w celu wykonania kodu w określonej domenie bezpieczeństwa, a my wzywamy do ograniczenia tej domeny do subdomeny. Na przykład, jeśli pozwolisz użytkownikowi uruchomić vimpolecenie na określonym pliku w celu jego edycji, użytkownik może po prostu uzyskać powłokę za pomocą :!sh[Enter].

Kaz
źródło
6
Poważnie, to BARDZO NIEBEZPIECZNE. Co powstrzyma mnie przed wykonaniem git-receive-pack '/git/';dd if=/dev/urandom of=/dev/sda?
Yeti
@Yeti Czy mamy tutaj otwór do wstrzykiwania poleceń? Należy się tym zająć. Poza tym nadużywanie wzorców plików, które popełniłem w programie case, nie wygląda na poprawne.
Kaz
1
Tak, /bin/bash -c "$2"jest niebezpieczny (podobnie jak działa wstrzyknięcie SQL). Możesz filtrować ciąg za pomocą „magicznych cudzysłowów”, takich jak PHP. Jednak najłatwiejszym sposobem zapewnienia całkowitego bezpieczeństwa jest ręczne wywołanie polecenia, a następnie przekazanie parametrów w cudzysłowie. Ponieważ bezpieczeństwo całości zależy wtedy od tego, czy polecenie jest najsłabszym ogniwem (trudniejszym do zweryfikowania). Najciekawsze, jak twoja odpowiedź ma 22 głosy za, ale nikt tego nie zauważył;) Czy zaktualizujesz własną odpowiedź?
Yeti
1
@Yeti Yes; Właśnie zrobiłem. Zastąpiłem skrypt takim, który łamie argument -c seti pobiera z niego tylko pierwsze dwa słowa. Pierwsza musi być dozwolonym git-poleceniem, a druga musi być ścieżką, która jest kanonizowana, sprawdzana pod kątem dozwolonego przedrostka i sprawdzana pod kątem istnienia. Czy możesz wymyślić jakiś sposób, aby to przerwać?
Kaz
1
O ile ktoś nie utworzy aliasu (lub nie zastąpi polecenia) dla któregokolwiek z podanych poleceń, to nie, podwójne cudzysłowy Bash powinny być bezpieczne (a jeśli nie, to jest to błąd w Bash).
Yeti
15

To, czego szukasz, nazywa się Restricted Shell . Bash zapewnia taki tryb, w którym użytkownicy mogą wykonywać tylko polecenia obecne w ich katalogach domowych (i nie mogą przenosić się do innych katalogów), co może być dla Ciebie wystarczająco dobre.

Uważam, że ten wątek jest bardzo ilustracyjny, choć trochę przestarzały.

Vinko Vrsalovic
źródło
1
Co się stanie, jeśli użytkownik wykona "! / Bin / sh" lub coś takiego z polecenia less?
PEZ
3
@Ubersoldat: Dorośnij i stonuj agresję we wszystkich swoich postach. Pytał, czy ograniczenie dotyczy tylko procesów bash czy potomnych (i odpowiadając na jego pytanie, okazuje się, że nie).
Głównym problemem związanym z powłoką ograniczoną jest to, że aby ją zabezpieczyć, musisz użyć .profile lub .bashrc, aby ograniczyć PATH, wyłączyć wbudowane itp., Ale te pliki są wywoływane tylko dla powłok interaktywnych. Jeśli użytkownik używa ssh do wykonania zdalnego polecenia, nie jest wywoływany. Pozwala to użytkownikowi z dostępem ssh do konta z SHELL = / bin / rbash na wykonanie czegoś w rodzaju „ssh remotehost bash”, aby uzyskać nieinteraktywną, ale nieograniczoną powłokę. Potrzebujesz wymuszonych poleceń SSH, zgodnie z sugestią HD, ale może to chronić przed ucieczką powłoki, o co prosił PEZ (po zablokowaniu PATH - domyślnie zawiera / bin: / usr / bin).
Alex Dupuy
2
Wracam do tego, bash wywoła .bashrc (nie .profile), gdy działa nieinteraktywnie pod sshd; jednakże musisz się upewnić, że ustawiłeś PATH jawnie i wyłączyłeś wbudowane i aliasy w .bashrc - zmiana na podkatalog nie w / powyżej PATH lub .ssh / lub .bashrc jest również dobrym pomysłem. Posiadanie dowolnego polecenia, które może zapisywać w dowolnych plikach, spowoduje problem - nie zawsze są one oczywiste, np. Polecenie sed 'w' może zostać użyte do nadpisania .bashrc i przerwania. Więzienie chroot zawsze będzie bezpieczniejsze, jeśli możesz go użyć, a wymuszone polecenia ssh będą bardziej ograniczone.
Alex Dupuy
4

Powinieneś kupić `rssh ', powłokę z ograniczeniami

Możesz postępować zgodnie ze wskazówkami dotyczącymi ograniczeń, o których mowa powyżej, wszystkie są raczej oczywiste i łatwe do naśladowania. Zapoznaj się z terminami `` jail chroot '' i jak skutecznie wdrażać konfiguracje sshd / terminala i tak dalej.

Ponieważ większość użytkowników uzyskuje dostęp do terminali przez sshd, prawdopodobnie powinieneś również zajrzeć do sshd_conifg, pliku konfiguracyjnego demona SSH, aby zastosować pewne ograniczenia przez SSH. Uważaj jednak. Zrozum dobrze, co próbujesz zaimplementować, ponieważ konsekwencje nieprawidłowych konfiguracji są prawdopodobnie dość tragiczne.

Chuah
źródło
1
Zauważ, że pizzashack.org/rssh jest doskonałym (prawdopodobnie najlepszym) rozwiązaniem dla specjalnego przypadku, w którym chcesz zezwolić na scp / sftp / rdist / rsync / cvs (i nie potrzebujesz dostępu do niczego poza więzieniem chroot) - jednak , nie rozwiązuje ogólnego problemu oryginalnego plakatu, który chciał, aby użytkownicy mogli przeglądać pliki dziennika i uruchamiać określone skrypty uruchamiania / zamykania.
Alex Dupuy
2
rsshzostał usunięty z Debian Buster. Myślę, że nowa gorączka to pośpiech GNU .
Thomas
1
@Thomas Uważam, że rssh nie jest teraz konserwowany i ma znany problem z bezpieczeństwem: sourceforge.net/p/rssh/mailman/message/36519118
Max Barraclough
4

Dlaczego nie napiszesz własnej powłoki logowania? Byłoby całkiem proste użycie do tego Bash, ale możesz użyć dowolnego języka.

Przykład w Bash

Użyj swojego ulubionego edytora, aby utworzyć plik /root/rbash.sh(może to być dowolna nazwa lub ścieżka, ale powinno być chown root:rooti chmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit
        
    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'
    
    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection
        
        # For example, optionally you can log this command
        log COMMAND "echo $ln"
    
    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi

Wszystko, co musisz zrobić, to ustawić ten plik wykonywalny jako swoją powłokę logowania. Na przykład, edytować swój /etc/passwdplik i zastąpić bieżącą powłokę logowania tego użytkownika /bin/bashz /root/rbash.sh.

To tylko prosty przykład, ale możesz zrobić to tak zaawansowanym, jak chcesz, pomysł istnieje. Uważaj, aby nie zablokować się, zmieniając powłokę logowania swojego i jedynego użytkownika. I zawsze testuj dziwne symbole i polecenia, aby sprawdzić, czy jest to rzeczywiście bezpieczne.

Można przetestować go z: su -s /root/rbash.sh.

Uważaj , pamiętaj, aby dopasować całe polecenie i uważaj na symbole wieloznaczne! Lepiej wykluczyć bash symboli, takich jak ;, &, &&, ||, $, i backticks aby się upewnić.

W zależności od swobody, jaką dajesz użytkownikowi, nie będzie to dużo bezpieczniejsze niż to. Zauważyłem, że często potrzebowałem tylko użytkownika, który ma dostęp tylko do kilku odpowiednich poleceń i w takim przypadku jest to naprawdę lepsze rozwiązanie. Czy jednak chcesz dać więcej wolności, więzienie i pozwolenia mogą być bardziej odpowiednie. Błędy są łatwe do zrobienia i zauważone dopiero, gdy jest już za późno.

Yeti
źródło
Bardzo podobało mi się to podejście. Czy masz pojęcie, jak możemy obsłużyć polecenia złożone z wielu słów, takie jak „usługa httpd restart”?
Farzan
2
@Farzan Można wykonywać polecenia w zmiennej, na przykład ln="service httpd restart", z: ${ln[@]}. Pamiętaj jednak, aby pomyśleć o kwestiach bezpieczeństwa, w takim przypadku przydatna byłaby biała lista zawierająca tylko znaki alfanumeryczne i białe spacje. Ale możesz też po prostu zrobić: if [[ "$ln" == "restart-httpd"];then service httpd restart;fii pracować z takimi prostymi poleceniami.
Yeti
/root/rbash.sh: Permission denied Próbowałem też chmod 777
Christian
@Christian, czy dodałeś /root/rbash.shdo /etc/shells? To zależy od dystrybucji. Możesz także spróbować tymczasowo wyłączyć selinuxi sprawdzić komunikaty dziennika pod kątem wskazówek (spójrz na sygnaturę czasową) w plikach w formacie /var/log.
Yeti
@yeti no, zostało wyjaśnione, aby dodać do / root :) Spróbuję teraz.
Christian
1

Możesz spojrzeć na ustawienie więzienia .

tmeisenh
źródło
Pytanie jest oznaczone jako „linux”. Czy więzienia nie są specyficzne dla FreeBSD?
Max Barraclough
1

GNU Rush może być najbardziej elastycznym i bezpiecznym sposobem na osiągnięcie tego:

GNU Rush to Restricted User Shell, zaprojektowana dla witryn, które zapewniają ograniczony zdalny dostęp do swoich zasobów, takich jak repozytoria svn lub git, scp i tym podobne. Używając wyrafinowanego pliku konfiguracyjnego, GNU Rush daje ci pełną kontrolę nad wierszami poleceń wykonywanymi przez użytkowników, a także nad wykorzystaniem zasobów systemowych, takich jak pamięć wirtualna, czas procesora itp.

Tomasz
źródło
0

Innym sposobem spojrzenia na to jest użycie list ACL POSIX, musi być obsługiwane przez twój system plików, jednakże możesz precyzyjnie dostroić wszystkie polecenia w Linuksie tak samo, jak masz taką samą kontrolę w Windows (tylko bez ładniejszego interfejsu użytkownika ). połączyć

Inną rzeczą, na którą należy zwrócić uwagę, jest PolicyKit .

Będziesz musiał trochę googlować, aby wszystko działało, ponieważ zdecydowanie nie jest to w tej chwili mocna strona Linuksa.

Bryan Rehbein
źródło
0

[Ujawnienie: napisałem sshdo, które opisano poniżej]

Jeśli chcesz, aby logowanie było interaktywne, ustawienie powłoki z ograniczeniami jest prawdopodobnie właściwą odpowiedzią. Ale jeśli istnieje rzeczywisty zestaw poleceń, na które chcesz zezwolić (i nic więcej) i jest w porządku, aby te polecenia były wykonywane indywidualnie przez ssh (np. Ssh user @ host cmd arg blah blah), to ogólne polecenie umieszczania białej listy na ssh może być tym, czego potrzebujesz. Jest to przydatne, gdy polecenia są w jakiś sposób skryptowane po stronie klienta i nie wymagają od użytkownika rzeczywistego wpisywania polecenia ssh.

Do tego służy program o nazwie sshdo. Kontroluje, które polecenia mogą być wykonywane przez przychodzące połączenia ssh. Można go pobrać pod adresem:

http://raf.org/sshdo/ (przeczytaj strony podręcznika tutaj) https://github.com/raforg/sshdo/

Posiada tryb uczenia, który pozwala na wykonywanie wszystkich poleceń, a także opcję --learn do tworzenia konfiguracji potrzebnej do trwałego zezwalania na wyuczone polecenia. Wtedy tryb treningu można wyłączyć, a inne polecenia nie będą wykonywane.

Posiada również opcję --unlearn, która zatrzymuje zezwalanie na polecenia, które nie są już używane, aby zachować jak najmniejsze uprawnienia, gdy wymagania zmieniają się w czasie.

Jest bardzo wybredny, jeśli chodzi o to, na co pozwala. Nie pozwoli na polecenie z żadnymi argumentami. Dozwolone są tylko pełne polecenia powłoki.

Ale obsługuje proste wzorce do reprezentowania podobnych poleceń, które różnią się tylko cyframi pojawiającymi się w linii poleceń (np. Numery sekwencji lub znaczniki daty / czasu).

To jest jak zapora ogniowa lub kontrola białej listy dla poleceń ssh.

I obsługuje różne polecenia, które są dozwolone dla różnych użytkowników.

raf
źródło