Premier jet pour un serveur de noms

This commit is contained in:
southerntofu 2020-04-14 00:13:43 +00:00
parent fb60c76dfc
commit 06409485c9
12 changed files with 381 additions and 5 deletions

258
README.md
View File

@ -1,17 +1,265 @@
# infra
Bienvenue sur le dépôt de la configuration système de ~fr !
Configuration système de fr.tild3.org
On écrit des playbooks [Ansible](https://fr.wikipedia.org/wiki/Ansible_(logiciel)) pour décrire les étapes à suivre pour configurer notre serveur basé sur Debian 10 Buster (stable). Pour l'instant, on gère:
# Ajouter unE utilisateurice
- des comptes shell avec authentification par clé SSH
- des sites web (avec nginx) et des pages perso pour nos utilisateurices
- des [.onion](https://fr.wikipedia.org/wiki/.onion) pour les pages perso
- des serveurs de noms primaires/secondaires
- des comptes mail utilisables @localhost
Pour créer un compte, il suffit de le déclarer dans host_vars/fr.yml:
# Guide utilisateurice
Bienvenue sur le serveur ~fr ! Ici, tu trouveras peut-être des réponses à tes questions.
## Configurer ton client SSH
Si tu n'es pas encore connectéE au serveur, tu as peut-être besoin d'un petit coup de pouce !
### Générer une paire de clés
Pour se connecter, on utilise des clés SSH. Ces clés vont par paire, une clé publique et une clé privée. La clé privée, tu la garde sur ta machine: elle te permet grâce à un mot de passe, de t'authentifier auprès de n'importe qui connaît ta clé publique. Du coup, pour créer un compte, faut nous envoyer ta clé publique.
Quand tu génères une paire de clés avec la commande ssh-keygen, cela génère dans ton dossier ~/.ssh un fichier sans extension (la clé privée), et un fichier du même nom avec une extension .pub. Pour avoir une connexion sécurisée sans pomper trop de ressources, on utilise des clés de type ed25519 en passant le paramètre `-t ed25519` à la commande :
```
$ ssh-keygen -t ed25519
Generating public/private rsa key pair.
Enter file in which to save the key (/home/tonutilisateurice/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/tonutilisateurice/.ssh/id_rsa.
Your public key has been saved in /home/tonutilisateurice/.ssh/id_rsa.pub.
The key fingerprint is:
f6:61:38:25:25:df:4d:4b:13:11:70:cf:4c:c8:a0:22 tonutilisateurice@tamachine
```
La commande te demande où stocker la clé (le paramètre par défaut est très bien pour commencer), puis te demande de renseigner une phrase de passe qui protègera l'utilisation de ta clé privée si jamais tu te la fais dérober. Après avoir reconfirmé ta phrase de passe, hop ta clé est crée ! On peut maintenant la lire, par exemple avec la commande cat :
```
$ cat .ssh/id_ed25519.pub
ssh-ed25519 BLABLABLA tonutilisateurice@tamachine
```
Pour qu'on puisse te créer un compte, c'est cette clé publique qu'il faut nous transmettre. Le dernier bout, par contre n'est pas obligatoire et peut t'empêcher de te connecter depuis une autre machine en copiant simplement ta clé ailleurs, parce que le nom de ta machine ou ton nom d'utilisateurice aura changé.
### Se connecter
Une fois que ton compte aura été activé, tu peux maintenant te connecter au serveur avec SSH :
```
$ ssh utilisateurice@fr.tild3.org
Enter passphrase for key '/home/tonutilisateurice/.ssh/id_ed25519':
```
### Configurer SSH pour raccourcir la commande
C'est long à taper. Vite, comment configurer des Hosts!
TODO
### Gérer plusieurs clés SSH
Ton client SSH peut gérer plusieurs paires de clés à la fois. Si tu as besoin d'en créer d'autres, tu peux leur donner des petits noms avec le paramètre `-f ~/.ssh/taclé` de ssh-keygen, ou bien en renseignant un autre emplacement pour stocker la clé quand le programme te le demande. Ces clés peuvent être stockées plus ou moins n'importe où sur ta machine, mais en général on trouve ça plutôt pratique de les garder dans le dossier ~/.ssh.
Pour te connecter à un serveur en utilisant une clé spécifique, on utilise `ssh -i ~/.ssh/taclé utilisateurice@fr.tild3.org`. Si ça devient un peu long à tout taper, le fichier de configuration de ton client SSH a une option `IdentityFile` dans le Host qui te permet de spécifier la clé à utiliser pour ce serveur :
```
Host fr
IdentityFile ~/.ssh/taclé
...
```
Comme tu sais maintenant configurer ton client SSH, il y a une option pratique pour gérer plusieurs clés. Un Host dans le fichier de configuration SSH
### Se connecter en passant par Tor
Pour se connecter au serveur en passant pas le réseau Tor, il suffit d'ajouter les paramètres suivants à la configuration du Host correspondant :
```
...
ProxyCommand connect -4 -S localhost:9050 $(tor-resolve %h localhost:9050) %p
CheckHostIP no
...
```
Bien sûr cela ne fonctionne que si tor est installé et fonctionnelle sur ta machine. Sur Debian GNU/Linux, il te suffit d'installer le paquet tor (apt install tor) et tout marche.
## Configurer tes pages perso
Nous proposons de l'hébergement de pages/fichiers statiques sur le web. Si ton nom d'utilisateurice est `username`, alors tu contrôles les addresses username.fr.tild3.org et fr.tild3.org/~username. En plus de cela, une adresse en .onion est générée pour toi à la création de ton compte, et te permet de fournir un accès sécurisé et anonymes à tes pages perso.
Par défaut, ces trois adresses servent le même contenu, que tu trouveras dans ~/public_html/ c'est à dire le dossier public_html dans ton dossier personnel. Si tu veux rajouter du contenu sur ton site, il suffit de le verser dans ce dossier.
TODO: Si tu souhaites avoir des sites différents sur ces trois adresses, pas de problème! En réalité, chaque site est servi par un dossier différents dans le dossier public/ de ton compte. Mais pour te simplifier la vie, à la création de ton compte, ces trois dossiers sont par défaut reliés à ton dossier ~/public_html avec des liens symboliques, pour éviter de perdre la tête.
Maintenant, si tu supprimes un de ces liens symboliques, tu peux le remplacer par un dossier qui sert du contenu spécifique à cette adresse :
```
$ rm ~/public/utilisateurice
$ mkdir ~/public/utilisateurice
$ echo "Bienvenue sur mon sous-domaine perso!" > ~/public/utilisateurice/index.html
# Et ce fichier est désormais accessible sur le web
$ curl https://utilisateurice.fr.tild3.org/
Bienvenue sur mon sous-domaine perso!
```
Ces trois dossiers sont disponibles:
- ~/public/tilde: le contenu servi à l'adresse fr.tild3.org/~utilisateurice
- ~/public/utilisateurice: le contenu servi à l'adresse utilisateurice.fr.tild3.org
- ~/public/onion: le contenu servi à l'adresse en .onion (à trouver dans ~/onion)
## Envoyer des fichiers sur le serveur
Si tu as fait un petit site web en local que tu veux publier sur le serveur, ou que tu veux stocker des trucs sur ton compte, cela se passe directement avec tes identifiants SSH! Pas besoin de configurer un client FTP ou Dropbox, tu peux simplement taper dans ta console (sur ta machine, pas sur le serveur) :
```
# Envoie un fichier au serveur dans le dossier personnel
$ scp monfichier username@fr.tild3.org:~
# Envoie mon dossier dans le fichier personnel
$ scp -r Documents username@fr.tild3.org:~
# La partie derrière les : indique dans quel dossier envoyer
$ scp -r mon_site/* username@fr.tild3.org:~/public_html
```
Si cela te ferait plaisir, on peut activer rsync aussi.
# Administration du serveur
Les principaux paramètres du serveur sont configurés dans le fichier `host_vars/127.0.0.1.yml`. Ensuite, le dossier roles abrite des recettes pour le système de base (common), pour le serveur web et les utilitaires associés (webserver) et pour le DNS (nameserver). Ces recettes sont appelées dans `site.yml` qui définit leurs paramètres spécifiques.
## Gestion des utilisateurices
Pour créer un nouveau compte utilisateurice, il faut le déclarer dans la configuration du serveur:
```
- name: username
(- sudo: true)
(- sudo: true)
- key: "clé publique SSH (format ~/.ssh/authorized_keys)"
```
## Configuration
Les principales directives de configuration du serveur sont expliquées dans cette section.
### hostname
Définit le nom de domaine principal associé au serveur.
```
hostname: fr.tild3.org
```
### users
Définit une liste d'utilisateurices configuréEs sur la machine. Chaque utilisateurice est un dictionnaire comprenant une clé 'name' portant son pseudonyme, une clé 'key' portant sa clé publique, et une clé optionnelle sudo contenant un booléen (true/false) pour définir si l'utilisateurice doit pouvoir exécuter des commandes admin.
```
users:
- name: user1
key: "-- REMPLACEZ MOI PAR UNE CLÉ SSH --"
- name: new_admin
sudo: true
key: "-- REPLACEZ MOI PAR UNE CLÉ SSH --"
```
### peers
Définit les serveurs amis, et nous permet de stocker des informations à leur propos et notamment des clés publiques. Chaque peer est un dictionnaire contenant les clés suivantes :
```
peers:
- name: ns1.tildeverse.org
key: "-- REMPLACEZ MOI PAR UNE CLÉ SSH --"
fingerprint: "-- REMPLACEZ MOI PAR UNE FINGERPRINT SSH --"
```
La clé SSH définie ici ouvre automatiquement un accès SSH chrooté aux serveurs pairs, pour leur permettre de mettre à jour leurs secrets sur notre serveur. Ce processus est notamment utilisé par le rôle nameserver pour échanger de façon sécurisée les clés (symmétriques) TSIG afin de sécuriser les mises à jour des zones DNS.
L'empreinte de clé définie dans la clé fingerprint correspond à la clé publique du serveur SSH du serveur pair. Cela nous permet de vérifier qu'une tierce personne n'est pas en train d'extirper nos secrets.
# Rôles
Le playbook sur ce dépôt contient un certain nombre de rôles. Ils sont expliqué plus en détail dans cette section.
## common
TODO
## webserver
variables: une liste de sites avec leur utilisateurice correspondantE et un template de vhost associé
TODO
## nameserver
Le rôle nameserver est une recette pour une configuration opinionée et moderne de bind9. Tout est fait pour faciliter la maintenance de serveurs de noms primaires et secondaires, et encourager la coopération entre serveurs. À ce propos :
- les serveurs secondaires vers lesquels sont propagées les mises à jour des zones sont déclarés pour le serveur entier (c'est à dire toutes les zones)
- les serveurs primaires correspondant à une zone secondaire sont déclarés par zone
Cette approche permet à chaque serveur de choisir en qui placer sa confiance pour agir comme serveur de noms secondaire, tout en lui permettant de lui-même agir pour n'importe qui en tant que serveur de noms secondaire.
Certaines zones sont stockées directement dans ce dépot, tandis que d'autres sont chargées dynamiquement directement sur le serveur. En effet, s'il est pratique de garder ici la zone du serveur, il peut être utile de permettre à certainEs utilisateurices de modifier certaines zones dynamiquement. Il faut alors faire attention à inclure ces zones dans les backups.
Cela permet notamment à unE utilisateurice de gérer sa propre zone au-sein de celle du serveur, car utilisateurice.fr.tild3.org lui est délégué, et la zone correspondante stockée dans son dossier ~/.dns/zones/. Additionnellement, une clé TSIG est générée pour chaque utilisateurice dans ~/.dns/tsig.key afin de lui permettre de recharger sa zone dynamiquement à l'aide de la commande `rndc reload`.
### Déclarer des zones
Les zones administrées par le serveur sont déclarées dans la variables primary. Chaque entrée prend une clé name contenant un nom de domaine, et une optionnelle clé template indiquant à partir de quel fichier de configuration générer la zone. Si aucun template n'est proposé, le fichier /etc/bind/zones/ZONE.db sera chargé.
```
- role: nameserver
variables:
primary:
- name: fr.tild3.org
file: ../files/fr.tild3.org.db
```
### Redondance sociale
Le but principal de ce role est de rendre la coopération entre opérateurices de serveurs de noms particulièrement simple. Chaque serveur de noms avec lequel on entretient des relations doit être déclaré dans les [peers](#peers) de notre serveurs.
Ainsi, pour déclarer des serveurs pairs pour lesquels on se porte serveur de noms secondaire, on utilise la variable secondary :
```
...
secondary:
- ns1.tildeverse.org
```
Pour définir les serveurs pairs qui nous servent de serveurs secondaires, on utilise la variable send_to_secondary :
```
...
send_to_secondary:
- emmagoldman.example.com
```
Pour chacun des serveurs pairs, un compte SSH est créé sur notre machine lui autorisant l'accès avec sa clé publique. Son accès est toutefois restreint à un chroot, et idéalement on aimerait bien que seul SFTP soit autorisé. Cela permet aux serveurs de s'échanger des secrets, et notamment les clés TSIG qui servent à sécuriser les échanges entre serveurs DNS.
Si le serveur ne trouve pas une clé TSIG qui lui aurait déjà été communiquée, alors il en génère une et l'envoie au serveur pair selon le processus décrit [plus loin](#scripter-des-trucs).
### Zone catalogue
Si tu as déjà administré un serveur de noms par le passé, tu dois te dire que tout n'est pas si simple. En effet, comment puis-je découvrir qu'une personne pour qui je suis serveur secondaire vient de créer une nouvelle zone ? En fait, on utilise pour cela une zone spéciale qu'on appelle zone catalogue. Cette zone contient la liste de tous les noms de domaine pour lesquels on est serveur primaire.
Cette zone a un nom fixé à l'avance (fr.tild3.org.catalog) qui nous permet de découvrir toutes les zones hébergées par un serveur, et de les ajouter automatiquement en tant que serveur secondaires.
### Scripter des trucs
Par défaut, pour un serveur pair.example.com le rôle crée un lien symbolique de /etc/bind9/keys/pair.example.com vers /home/peers/pair.example.com/.dns/tsig.key. Le système de serveurs pairs de ce playbook a déjà créé l'utilisateurice sur la machine, avec la clé SSH correspondante. Si la clé TSIG pour le pair n'existe pas encore, elle sera crée et on va tenter d'envoyer la clé sur le serveur distant.
Par exemple, si fr.tild3.org est serveur secondaire pour ns1.tildeverse.org, peer@fr.tild3.org va essayer de se connecter à fr.tild3.org@ns1.tildeverse.org avec sa clé SSH, générer une clé TSIG, et la placer dans ~/.dns/tsig.key.
Ainsi, même si tu n'utilises pas ce rôle pour gérer tes zones, tu peux scripter un système compatible avec le nôtre !
### DNSSEC
TODO
# TODO
- Services

View File

@ -0,0 +1,17 @@
$TTL 3600
$ORIGIN {{ hostname }}.
@ SOA {{ hostname }}. root.{{ hostname }}. (
2020041200 ; serial
86400 ; refresh (1 day)
7200 ; retry (2 hours)
3600000 ; expire (5 weeks 6 days 16 hours)
172800 ; minimum (2 days)
)
NS {{ hostname }}.
NS myimaginaryfriend.example.com
A 192.95.3.24
AAAA 2607:5300:203:5fd5::24
MX 1 {{ hostname }}.
TXT "v=spf1 mx -all"
* A 192.95.3.24
AAAA 2607:5300:203:5fd5::24

View File

@ -0,0 +1,5 @@
zone "{{ item.domain }}" {
type master;
update-policy local;
file "zones/primary/{{ item.domain }}.db";
}

View File

@ -0,0 +1,19 @@
# TODO update-policy for primary zones
{% for zone in primary %}
zone {{ zone.name }} {
type master;
file "/etc/bind/zones/{{ zone.name }}.db";
};
{% endfor %}
{% if secondary is defined %}{% for ns in secondary %}
zone {{ ns }}.catalog {
type slave;
file "/etc/bind/zones/.{{ ns }}.catalog.db";
};
{% endfor %}{% endif %}

View File

@ -0,0 +1,27 @@
# TODO TSIG keys
# TODO DNSSEC
# TODO also-notify our secondary servers
options {
directory "/var/cache/bind";
//========================================================================
// If BIND logs error messages about the root key being expired,
// you will need to update your keys. See https://www.isc.org/bind-keys
//========================================================================
dnssec-validation auto;
listen-on-v6 { any; };
recursion no;
{% if secondary is defined %}
catalog-zones {
in-memory no;
zone-directory /etc/bind/peers;
{% for ns in secondary %}
zone "{{ ns }}.catalog";
{% endfor %}
}
{% endif %}
};

View File

@ -0,0 +1,5 @@
zone "{{ item.domain }}" {
type master;
update-policy local;
file "zones/primary/{{ item.domain }}.db";
}

View File

@ -0,0 +1,4 @@
- name: reload bind
service:
name: bind9
state: restarted

View File

@ -0,0 +1,13 @@
options {
recursion no;
;also-notify { } OUR SECONDARY SERVERS
{% if secondary %}
catalog-zones {
in-memory no;
zone-directory /etc/bind/peers;
{% for ns in secondary %}
zone "{{ ns }}.catalog";
{% endfor %}
}
{% endif %}
}

View File

@ -0,0 +1,7 @@
{% for ns in secondary %}
zone {{ ns }}.catalog {
type slave;
file /etc/bind/zones/.{{ ns }}.catalog.db;
}
{% endfor %}

View File

@ -0,0 +1,4 @@
zone "{{ item }}" {
type master;
file "/etc/bind/zones/{{ item }}";
}

View File

@ -0,0 +1,4 @@
zone {{ item }} {
type slave;
file /etc/bind/zones/{{ item }}.db;

View File

@ -0,0 +1,23 @@
- name: Installer bind9
apt:
name: bind9
state: present
- name: Créer les dossiers /etc/bind/{zones,catalog}
file:
path: "/etc/bind/{{ item }}"
owner: bind
group: bind
state: directory
loop: [ "zones", "catalog" ]
- name: Générer la config du serveur
template:
src: ../files/named.conf.local.j2
dest: /etc/bind/named.conf.local
notify: reload bind
- name: Configuration de la zone principale
template:
src: ../files/main.zone.j2
dest: "/etc/bind/zones/{{ hostname }}.db"