Uwierzytelnianie klucza SSH przy użyciu LDAP

59

W skrócie:

Chciałby być sposobem na uwierzytelnienie klucza SSH przez LDAP.

Problem:

Używamy LDAP (slapd) do usług katalogowych, a ostatnio przeszliśmy na używanie własnego AMI do tworzenia instancji. Powodem, dla którego bit AMI jest ważny, jest to, że idealnie chcielibyśmy móc zalogować się za pomocą SSH za pomocą uwierzytelniania klucza, gdy tylko instancja się uruchomi i nie będziemy musieli czekać na nasze nieco powolne narzędzie do zarządzania konfiguracją, aby uruchomić skrypt, aby dodać poprawne klucze do instancji.

Idealny scenariusz polega na tym, że dodając użytkownika do LDAP, dodajemy również jego klucz i natychmiast mogliby się zalogować.

Uwierzytelnianie za pomocą klucza jest konieczne, ponieważ logowanie za pomocą hasła jest zarówno mniej bezpieczne, jak i uciążliwe.

Przeczytałem to pytanie, które sugeruje, że jest łatka dla OpenSSH o nazwie OpenSSH-lpk, aby to zrobić, ale nie jest to już potrzebne w przypadku serwera OpenSSH> = 6.2

Dodano opcję sshd_config (5) AuthorisedKeysCommand, aby obsługiwać pobieranie kluczy autoryzowanych z polecenia oprócz (lub zamiast) z systemu plików. Komenda jest uruchamiana na koncie określonym w opcji sshd_config (5) AuthorizedKeysCommandUser

Jak skonfigurować OpenSSH i LDAP, aby to zaimplementować?

c4urself
źródło

Odpowiedzi:

64

Zaktualizuj LDAP, aby uwzględnić schemat OpenSSH-LPK

Najpierw musimy zaktualizować LDAP za pomocą schematu, aby dodać sshPublicKeyatrybut dla użytkowników:

dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
    DESC 'MANDATORY: OpenSSH Public key'
    EQUALITY octetStringMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
    DESC 'MANDATORY: OpenSSH LPK objectclass'
    MAY ( sshPublicKey $ uid )
    )

Utwórz skrypt odpytujący LDAP o klucz publiczny użytkownika:

Skrypt powinien wypisywać klucze publiczne dla tego użytkownika, na przykład:

ldapsearch '(&(objectClass=posixAccount)(uid='"$1"'))' 'sshPublicKey' | sed -n '/^ /{H;d};/sshPublicKey:/x;$g;s/\n *//g;s/sshPublicKey: //gp'

Zaktualizuj, sshd_configaby wskazać skrypt z poprzedniego kroku

  • AuthorizedKeysCommand /path/to/script
  • AuthorizedKeysCommandUser nobody

Bonus : Zaktualizuj, sshd_configaby umożliwić uwierzytelnianie hasła z wewnętrznych sieci RFC1918, jak pokazano w tym pytaniu:

Zezwalaj tylko na uwierzytelnianie hasła do serwera SSH z sieci wewnętrznej

Przydatne linki:

EDYCJA: Dodano użytkownika nobodyzgodnie z sugestią TRS-80

c4urself
źródło
6
To fantastyczne, chociaż sugerowałbym AuthorizedKeysCommandUser nobodyzamiast rootowania.
TRS-80
Musi być coś innego w mojej ldapsearch lub sed, ponieważ przesyłanie danych wyjściowych do komendy sed czarnej magii, którą tam masz, nie daje mi żadnych wyników, nawet jeśli moje proste polecenie ldapsearch zwraca dane. Będę musiał napisać skrypt do czyszczenia danych wyjściowych zamiast używania sed.
Chris L,
1
Zignoruj ​​mój poprzedni komentarz. Mój problem został spowodowany tym, że końcowy znak nowej linii we właściwości sshPublicKey spowodował, że ldapsearch w base64 zakoduje całość. Uprościłem polecenie sed:ldapsearch -u -LLL -o ldif-wrap=no '(&(objectClass=posixAccount)(uid='"$1"'))' 'sshPublicKey' | sed -n 's/^[ \t]*sshPublicKey:[ \t]*\(.*\)/\1/p'
Chris L
1
@Chris rzeczywiście mniej czarnej magii, ale sed wciąż jest jednokierunkową funkcją haszującą
zapis
1
W mojej wersji OpenSSH (5.3p1-122.el6) jest AuthorizedKeysCommandRunAsi nie maAuthorizedKeysCommandUser
mveroone
5

Dla każdego, kto otrzyma błąd podczas uruchamiania ldapsearch:

sed: 1: "/^ /{H;d};": extra characters at the end of d command

tak jak ja (na FreeBSD), poprawka polega na zmianie pierwszego polecenia sed na:

/^ /{H;d;};

(dodanie średnika po „d”).

Scott
źródło
4

Chciałem tylko udostępnić moją „metodę”, moja strona klienta jest specyficzna dla Debiana / Ubuntu, ale moja strona serwera jest zasadniczo taka sama jak powyżej, ale z nieco więcej „HowTo:”

Serwer :

Włącz atrybut klucza publicznego:

Kredyt:

https://blog.shichao.io/2015/04/17/setup_openldap_server_with_openssh_lpk_on_ubuntu.html

cat << EOL >~/openssh-lpk.ldif
dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
  DESC 'MANDATORY: OpenSSH Public key'
  EQUALITY octetStringMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
  DESC 'MANDATORY: OpenSSH LPK objectclass'
  MAY ( sshPublicKey $ uid )
  )
EOL

Teraz użyj tego, aby dodać ldif:

ldapadd -Y EXTERNAL -H ldapi:/// -f ~/openssh-lpk.ldif

Dodanie użytkownika z kluczem publicznym SSH w phpLDAPadmin

Najpierw utwórz użytkownika za pomocą szablonu „Ogólne: Konto użytkownika”. Następnie przejdź do sekcji atrybutu „objectClass”, kliknij „dodaj wartość” i wybierz atrybut „ldapPublicKey”. Po przesłaniu wróć do strony edycji użytkownika, kliknij „Dodaj nowy atrybut” w górnej części i wybierz „sshPublicKey”, wklej klucz publiczny do pola tekstowego i na koniec kliknij „Aktualizuj obiekt”.

sshPublicKey Atrybut nie jest wyświetlany - klucz autoryzacji OpenLDAP PHPLDAP SSH

Klient Ubuntu:

apt-get -y install python-pip python-ldap
pip install ssh-ldap-pubkey
sh -c 'echo "AuthorizedKeysCommand /usr/local/bin/ssh-ldap-pubkey-wrapper\nAuthorizedKeysCommandUser nobody" >> /etc/ssh/sshd_config' && service ssh restart

Utwórz klucze testowe:

ssh-keygen -t rsa
FreeSoftwareServers
źródło
3

To nie jest pełna odpowiedź, tylko dodatek do odpowiedzi c4urself . Dodałbym to jako komentarz, ale nie mam wystarczającej reputacji, aby komentować, więc proszę nie głosować!

To jest skrypt, którego używam AuthorizedKeysCommand(na podstawie wersji c4urself). Działa niezależnie od tego, czy wartość jest zwracana w kodowaniu base64, czy nie. Może to być szczególnie przydatne, jeśli chcesz przechowywać wiele autoryzowanych kluczy w LDAP - po prostu oddziel klucze znakami nowej linii, podobnie jak w pliku autoryzowanych kluczy.

#!/bin/bash
set -eou pipefail
IFS=$'\n\t'

result=$(ldapsearch '(&(objectClass=posixAccount)(uid='"$1"'))' 'sshPublicKey')
attrLine=$(echo "$result" | sed -n '/^ /{H;d};/sshPublicKey:/x;$g;s/\n *//g;/sshPublicKey:/p')

if [[ "$attrLine" == sshPublicKey::* ]]; then
  echo "$attrLine" | sed 's/sshPublicKey:: //' | base64 -d
elif [[ "$attrLine" == sshPublicKey:* ]]; then
  echo "$attrLine" | sed 's/sshPublicKey: //'
else
  exit 1
fi
mbrgm
źródło