# LDAP

Le Crans dispose d'une base de donnée avec laquelle on peut communiquer via le
protocole LDAP (que nous appellerons par la suite base LDAP ou simplement LDAP)
stockant l'ensemble de ses administrateurs, groupes, serveurs, réseaux et
services.

La serveur LDAP se trouve sur tealc et est répliqué sur les virtualiseurs
ainsi que sur sputnik et gulp.

## Connexion

Le LDAP écoute uniquement sur son interface `adm` en LDAPS et en local sur
`flirt`. Pour s'y connecter, le plus simple est de se connecter en ssh sur
`flirt`, puis d'utiliser `shelldap` (voir ci-dessous).

## Schéma

Voici la hiérarchie actuelle du LDAP (mars 2023) :

```txt
dc=crans,dc=org
+-ou=dns
| +-dc=eu (dNSDomain, domain)
| +-dc=fr (dNSDomain, domain)
| +-dc=org (dNSDomain, domain)
|
+-ou=group
| +-cn=_nounou (posixGroup)
| +-cn=_user (posixGroup)
|
+-ou=hosts
| +-cn=machine (device)
|   +-cn=machine.adm.crans.org (device, ipHost, ieee802Device)
|
+-ou=networks
| +-cn=adm (ipNetwork)
|
+-ou=passwd
| +-uid=_nom (inetOrgPerson, posixAccount)
|
+-ou=services
  +-cn=ssh (ipService)
```

### DNS

Les enregistrements DNS sont ajoutés dans `ou=dns`, il y a actuellement trois
groupes : `eu`, `fr` et `org` contenant chacun le groupe `crans`, correspondant
respectivement à `crans.eu`, `crans.fr` et `crans.org`. L'enregistrement DNS
de `subdomain.crans.org` sera modifiable dans un attribut `description` de
l'entrée `dc=crans,dc=org,ou=dns,dc=crans,dc=org` ou dans une entrée
`dc=subdomain,dc=crans,dc=org,ou=dns,dc=crans,dc=org` selon le besoin.

### Groupes

Les groupes sont ajoutés dans `ou=group`, il y a actuellement deux groupes :

* `_user`: qui contient tout le monde ;

* `_nounou`: qui contient les nounous et permet de `sudo` sur les serveurs.

### Machines

Les machines sont ajoutées dans `ou=hosts` et sont de classe `device`. Les
interfaces sont regroupées sous les machines et sont de classes `device`,
`ipHost` (ce qui permet de leur ajouter une IP) et `ieee802Device` (qui permet
de leur ajouter un attribut `macAddress`).

### Réseaux

Les réseaux sont ajoutés dans `ou=networks` et sont de classe `ipNetwork`.

### Utilisateurs

Les utilisateurs sont ajoutés dans `ou=passwd` et sont de classes
`inetOrgPerson` et `posixAccount`.

### Services

Les services (noms des protocoles TCP/UDP utilisés au Crans) sont ajoutés
dans `ou=services` et sont de classe `ipService`.

Voici un exemple de service :

```txt
dn: cn=ssh,ou=services,dc=crans,dc=org
objectClass: ipService
cn: ssh
ipServicePort: 22
ipServiceProtocol: tcp
```

## Conventions

La base LDAP suit un certain nombre de conventions qu'il faut respecter quand
on ajoute une entrée.

### Machines

La description des machines indique le rôle de la machine.

La description des interfaces sert à spécifier l'ouverture de ports sur
celles-ci, par exemple :

```txt
description: in:service1,in:service2,out:service3
```

Pour autoriser les `service1` et `service2` en entrée et le `service3` en
sortie. Il ne faut pas mettre d'espace et bien préciser `in:` ou `out:` avant
le nom du service qui doit exister dans `ou=services`.

### Réseaux

La description du réseau est le numéro du VLAN sur lequel ce réseau est
présent.

### Utilisateurs

Le nom d'utilisateur (`uid`) doit nécessairement commencer par un `_`
(underscore), cette contrainte est forcée dans la configuration du serveur.

### Services

Le champ description du service sert à spécifier une range de ports : on met
alors le port de fin dans la description.

## Configuration

Par défaut, la configuration de l'annuaire LDAP est dans la base LDAP
elle-même. Mais on trouve ça peu pratique, et il est possible de la déplacer
dans un fichier texte : `/etc/ldap/slapd.conf`. Pour cela, il suffit de
supprimer `/etc/ldap/slapd.d` et de restart `sladp`.

Pour faire écouter uniquement en LDAPS sur adm, on a ajouté dans
`/etc/default/slapd` :

```txt
SLAPD_SERVICES="ldaps://172.16.10.1/ ldapi:///"
```

Pour que les nounous puissent modifier les mots de passe des utilisateurs et
que chacun puisse modifier son mot de passe, on ajoute la configuration
suivante :

```txt
access to attrs=userPassword,shadowLastChange
        by anonymous auth
        by self write
        by set="[cn=nounou,ou=group,dc=crans,dc=org]/memberUid & user/uid" write
        by * none
```

Pour que tout le monde puisse modifier son shell, mail et numéro de
téléphone et que les nounous puissent modifier ceux des autres :

```txt
access to attrs=loginShell,mail,telephoneNumber
        by self write
        by set="[cn=nounou,ou=group,dc=crans,dc=org]/memberUid & user/uid" write
        by * read
```

Pour que les nounous puissent modifier tout le reste :

```txt
access to *
        by set="[cn=nounou,ou=group,dc=crans,dc=org]/memberUid & user/uid" write
        by * read
```

Le LDAPS a été configuré avec un certificat autosigné valable 1000 ans :

```txt
TLSCertificateFile /etc/ldap/ldap.pem
TLSCertificateKeyFile /etc/ldap/ldap.key
```

### Réplication

Le LDAP est répliqué notamment sur les virtualiseurs et sur `sputnik` grâce
à la configuration suivante :

```txt
syncrepl
        rid=1
        provider=ldaps://172.16.10.1:636
        bindmethod=simple
        binddn="cn=replicator,dc=crans,dc=org"
        credentials=coucoupollion
        searchbase="dc=crans,dc=org"
        scope=sub
        schemachecking=on
        type=refreshAndPersist
        timeout=0
        network-timeout=0
        retry="30 20 300 +"
        tls_reqcert=allow
```

(les valeurs `rid`, et `credentials` sont à remplacer : `rid` doit être
unique pour chaque serveur répliqué et `credentials` doit correspondre au mot
de passe du `binddn`).

Si jamais le LDAP ne se synchronise pas il faut lancer les commandes suivantes
(en remplaçant la valeur de `rid` par celle du serveur répliqué) :

```bash
systemctl stop slapd
slapd -c rid=1,csn=0
systemctl start slapd
```

### Overlays

Les overlays sont des modules pour slapd (le serveur LDAP) on utilise plusieurs
overlays dans la base de données des membres actifs. Tout est spécifié dans
`/etc/ldap/slapd.conf`.

#### auditlog

Auditlog permet de logguer les modifications faites à la base LDAP dans un
fichier LDIF.

#### constraint

Constraint permet de restreindre certains atttributs à certaines valeurs, par
exemple on force l'`uid` d'un membre actif à commencer par `_`.

```txt
constraint_attribute uid regex ^_
  restrict=ldap:///ou=passwd,dc=crans,dc=org??one?(objectClass=posixAccount)
```

## Outils

### Curl

C'est l'outil sans doute le plus basique pour faire des requêtes, et il
supporte LDAP(S). Avec la redirection de ports définie plus haut :

```bash
curl -k "ldaps://localhost:1636/ou=hosts,dc=crans,dc=org?cn?one?description=pve"
```

me renvoie tous les virtus, ie pve1, pve2 et pve3. Et

```bash
curl -k "ldaps://localhost:1636/ou=hosts,dc=crans,dc=org?cn?one?description=radius"
```

me renvoie tous les serveurs radius.

### Apache Directory Studio

Plus d'info [ici](https://directory.apache.org/studio/).

C'est un outil graphique pour naviguer dans un annuaire LDAP. Bien pratique !

Pour le configurer il faut créer une nouvelle connexion (dans le menu en bas
à gauche). Par exemple, pour utiliser le LDAP membres actifs du crans on peut
utiliser :

Dans le menu Network Parameter

* Connection name : LDAP nounous

* Hostname : localhost

* Port : 1636 (ou n'importe quel autre port).

* Encryption method : Use SSL encryption (ldap://)

et dans le menu Authentication

* Authentication Method : Simple Authentication

* Bind DN or user : votre DN, par exemple pour moi c'est
  `uid=_pollion,ou=passwd,dc=crans,dc=org`

Et renseignez votre mot de passe sur le LDAP Membres actifs.

Avec cette configuration, il suffit de faire une redirection du port 636
distant vers localhost 1636 et à vous la navigation sur le LDAP !

### Shelldap

Pour naviguer dans la base, on peut aussi utiliser un utilitaire en ligne de
commande : shelldap qui permet de se déplacer à coup de `ls`, `cd` et `cat`.
shelldap est installé sur `tealc`, mais non configuré. En ajoutant la
configuration dans le fichier `.shelldap.rc` :

```txt
server: ldaps://172.16.10.1:636
binddn: uid=<_pseudo>,ou=passwd,dc=crans,dc=org
basedn: dc=crans,dc=org
promptpass: yes
tls: yes
tls_cacert: /etc/ldap/ldap.pem
```

Et on peut ensuite se connecter au LDAP :

```txt
_shirenn@tealc $ shelldap
Bind password: coucoupollion // Ce mot de passe est le mot de passe du compte
<_pseudo>, et non l'un de ceux dans le pass crans.
~ > ls
cn=admin
cn=replicator
ou=dns/
ou=group/
ou=hosts/
ou=networks/
ou=passwd/
ou=services/
~ >
```