Projet

Général

Profil

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>