Ldap-authorized keys » Historique » Version 1
Pierre-Arnaud Poudret, 05/06/2013 15:54
1 | 1 | Pierre-Arnaud Poudret | h1. Centralisation et distribution des clés RSA publiques |
---|---|---|---|
2 | |||
3 | {{>toc}} |
||
4 | |||
5 | L'intégration [[ldap-pam-nss]] permet de provisionner les comptes d'utilisateurs sur les serveurs, et de contrôler quel utilisateur peut ouvrir une session sur quelle machine. |
||
6 | Si les clés RSA publiques des utilisateurs étaient également centralisées sur le LDAP, on disposerait d'un système complet de contrôle d'accès aux machines. |
||
7 | |||
8 | Il existe un patch pour openssh qui répond exactement à ce besoin: OpenSSH LDAP Public Key patch (http://code.google.com/p/openssh-lpk). Le serveur openssh patché interroge un annuaire ldap pour connaître les clés autorisées. |
||
9 | |||
10 | Je ne suis pas très chaud pour sortir openssh de la gestion automatique des paquets. En attendant que cette fonctionnalité soit éventuellement intégrée au code mainstream, on va donc faire autrement. Un simple script shell exécuté en cron devrait pouvoir faire l'affaire. |
||
11 | |||
12 | Le script devra parcourir le ldap et installer ou mettre à jour les clés des utilisateurs autorisés à se connecter. |
||
13 | |||
14 | Le script ne devra pas supprimer les clés des comptes locaux destinés à se connecter en cas de défaillance du ldap. |
||
15 | |||
16 | Note: j'ai cru voir quelque part qu'on peut installer les clés des users hors de leur home. Cela permettrait d'installer la clé d'un user qui ne s'est pas encore loggé et n'a donc pas encore eu son /home créé par pam. |
||
17 | Edit: oui, utiliser AuthorizedKeysFile dans /etc/ssh/sshd_config (http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5 - exemple: AuthorizedKeysFile %h/.ssh/authorized_keys /var/ldap_authorized_keys/%u) |
||
18 | Edit2: FIXME WHEEZY - dans squeeze, AuthorizedKeysFile ne permet de spécifier qu'un seul emplacement => on utilise à la place le paramètre AuthorizedKeysFile2, qui disparaît avec l'arrivée de Wheezy => penser à faire la modification lors du passage de Squeeze à Wheezy. |
||
19 | |||
20 | h1. Stockage des clés dans l'annuaire |
||
21 | |||
22 | Le schéma d'openssh-lpk fournit une classe et un attribut servant à stocker des clés RSA. |
||
23 | |||
24 | +openssh-lpk.schema+ |
||
25 | <pre> |
||
26 | # |
||
27 | # LDAP Public Key Patch schema for use with openssh-ldappubkey |
||
28 | # Author: Eric AUGE <eau@phear.org> |
||
29 | # |
||
30 | # Based on the proposal of : Mark Ruijter |
||
31 | # |
||
32 | |||
33 | |||
34 | # octetString SYNTAX |
||
35 | attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' |
||
36 | DESC 'MANDATORY: OpenSSH Public key' |
||
37 | EQUALITY octetStringMatch |
||
38 | SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
||
39 | |||
40 | # printableString SYNTAX yes|no |
||
41 | objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY |
||
42 | DESC 'MANDATORY: OpenSSH LPK objectclass' |
||
43 | MAY ( sshPublicKey $ uid ) |
||
44 | ) |
||
45 | </pre> |
||
46 | |||
47 | +openssh-lpk.ldif+ |
||
48 | <pre> |
||
49 | dn: cn=openssh-lpk,cn=schema,cn=config |
||
50 | objectClass: olcSchemaConfig |
||
51 | cn: openssh-lpk |
||
52 | olcAttributeTypes: {0}( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DES |
||
53 | C 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4. |
||
54 | 1.1466.115.121.1.40 ) |
||
55 | olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DESC |
||
56 | 'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MAY ( sshPublicKey $ |
||
57 | uid ) ) |
||
58 | |||
59 | </pre> |
||
60 | |||
61 | |||
62 | h1. Stockage local des fichiers authorized_keys |
||
63 | |||
64 | Les fichiers sont stockés dans /var/ldap_authorized_keys/, sous le nom du user concerné, avec owner root, en 644. |
||
65 | |||
66 | Configurer AuthorizedKeysFile [ou AuthorizedKeysFile2 sous Squeeze] dans /etc/ssh/sshd_config pour que cet emplacement supplémentaire soit pris en compte: |
||
67 | +Version Wheezy+ |
||
68 | <pre> |
||
69 | #AuthorizedKeysFile %h/.ssh/authorized_keys |
||
70 | AuthorizedKeysFile %h/.ssh/authorized_keys /var/ldap_authorized_keys/%u |
||
71 | </pre> |
||
72 | +Version Squeeze+ |
||
73 | <pre> |
||
74 | #AuthorizedKeysFile %h/.ssh/authorized_keys |
||
75 | AuthorizedKeysFile %h/.ssh/authorized_keys |
||
76 | AuthorizedKeysFile2 /var/ldap_authorized_keys/%u |
||
77 | </pre> |
||
78 | |||
79 | <pre> |
||
80 | service ssh restart |
||
81 | </pre> |
||
82 | |||
83 | |||
84 | h1. Script |
||
85 | |||
86 | Note: penser à modifier le paramètre _thishost_. |
||
87 | <pre> |
||
88 | #!/bin/bash |
||
89 | # ------------------------------------------------------------------------------ |
||
90 | # ldap_authorized_files |
||
91 | # ------------------------------------------------------------------------------ |
||
92 | # synchronisation des clés publiques avec le LDAP |
||
93 | # ------------------------------------------------------------------------------ |
||
94 | |||
95 | # ------------------------------------------------------------------------------ |
||
96 | # Paramètres |
||
97 | # ------------------------------------------------------------------------------ |
||
98 | # emplacement du fichier pid |
||
99 | pidfile=/var/run/ldap_authorized_files.pid |
||
100 | |||
101 | # uri de l'annuaire ldap |
||
102 | ldapuri=ldap://127.0.0.1 |
||
103 | # Note: c'est le "127.0.0.1" qu'on retrouve dans les ACL. Si on remplace par |
||
104 | # "localhost", ça ne fonctionne plus en IPv6, ou alors il faudrait |
||
105 | # ajouter ::1 dans les ACL |
||
106 | |||
107 | # base de recherche des données dns sur l'annuaire |
||
108 | ldapusersbase="ou=users,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" |
||
109 | ldapgroupsbase="ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" |
||
110 | |||
111 | # nom d'hôte |
||
112 | thishost=rigel |
||
113 | |||
114 | # chemin des fichiers allowed_keys |
||
115 | allowed_keys_path=/var/ldap_authorized_keys |
||
116 | |||
117 | # ------------------------------------------------------------------------------ |
||
118 | # Logs |
||
119 | # ------------------------------------------------------------------------------ |
||
120 | erreur=0 |
||
121 | |||
122 | date_log () { |
||
123 | echo -n "`date +\"%d/%m/%y-%X\"`: " |
||
124 | echo $1 |
||
125 | } |
||
126 | |||
127 | sortie_erreur () { |
||
128 | date_log "exécution terminée avec le code d'erreur $erreur" |
||
129 | exit $erreur |
||
130 | } |
||
131 | |||
132 | # ------------------------------------------------------------------------------ |
||
133 | # Vérification du pid |
||
134 | # ------------------------------------------------------------------------------ |
||
135 | if [ -f $pidfile ]; then |
||
136 | pid=`cat $pidfile` |
||
137 | if [ $? != 0 ]; then |
||
138 | date_log "lecture du fichier $pidfile impossible - pas d'exécution" |
||
139 | erreur=13 |
||
140 | sortie_erreur |
||
141 | fi |
||
142 | |||
143 | ps -p $pid 1>/dev/null 2>/dev/null |
||
144 | if [ $? == 0 ]; then |
||
145 | date_log "lancement impossible - script en cours d'exécution sous le pid $pid" |
||
146 | erreur=10 |
||
147 | sortie_erreur |
||
148 | fi |
||
149 | fi |
||
150 | |||
151 | echo $$ >$pidfile |
||
152 | |||
153 | # ------------------------------------------------------------------------------ |
||
154 | # Traitement |
||
155 | # ------------------------------------------------------------------------------ |
||
156 | |||
157 | for cn in $( ldapsearch -P 3 -H $ldapuri -x -b "ou=groups,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR" "(&(objectClass=posixGroup)(|(cn=login$thishost)(cn=loginall)(cn=sudo$thishost)(cn=sudoall)))" memberUid | grep "memberUid:" | sed 's/memberUid: \(.*\)/\1/' ) |
||
158 | do |
||
159 | date_log "cn $cn" |
||
160 | |||
161 | allowed_keys_file=$allowed_keys_path/$cn |
||
162 | |||
163 | if [ ! -f $allowed_keys_file.ok ]; then |
||
164 | tempfile=$( mktemp ) |
||
165 | |||
166 | touch $tempfile |
||
167 | chmod 644 $tempfile |
||
168 | |||
169 | IFS=$'\n' |
||
170 | for key in $(ldapsearch -P 3 -H $ldapuri -x -b "cn=$cn,$ldapusersbase" -LLL "(&(objectClass=posixAccount)(cn=$cn))" sshPublicKey | sed 's/^ //g' | tr -d '\n' | sed -e "s/sshPublicKey: /\n/g" | tail -n +2 ) |
||
171 | do |
||
172 | date_log "key $key" |
||
173 | echo $key >>$tempfile |
||
174 | done |
||
175 | unset $IFS |
||
176 | |||
177 | diff -q $tempfile $allowed_keys_file 1>/dev/null 2>&1 |
||
178 | if [ "$?" != "0" ]; then |
||
179 | mv $allowed_keys_file $allowed_keys_file.old 1>/dev/null 2>&1 |
||
180 | mv $tempfile $allowed_keys_file |
||
181 | else |
||
182 | rm $tempfile |
||
183 | fi |
||
184 | touch $allowed_keys_file.ok |
||
185 | fi |
||
186 | done |
||
187 | |||
188 | rm $allowed_keys_path/*.ok |
||
189 | |||
190 | exit 0 |
||
191 | </pre> |
||
192 | |||
193 | h1. Cron |
||
194 | |||
195 | <pre> |
||
196 | # m h dom mon dow command |
||
197 | |||
198 | # installation des clés publiques depuis le ldap |
||
199 | # (http://www.illyse.org/projects/illyseinfra/wiki/Ldap-authorized_keys) |
||
200 | 0 * * * * /usr/local/bin/ldap_authorized_keys 1>/dev/null 2>&1 |
||
201 | </pre> |