Projet

Général

Profil

Wiki » Historique » Version 20

sacha, 10/12/2023 16:52

1 5 sacha
{{>toc}}
2
3 9 sacha
# DNS récursif Ouvert DoH DoT & haute disponibilité
4 15 sacha
**45.67.81.23 - dns.aquilenet.fr**
5 14 sacha
6 1 sacha
7 16 sacha
8 19 sacha
On propos un DNS récursif ouvert cf https://www.aquilenet.fr/services/dns/ https://dns.aquilenet.fr/
9 18 sacha
On a mis aussi un DNS ouvert sur l'IP 45.67.81.23 car facile à retenir, avec l'adresse de dns.aquilenet.fr (voir [http://dns.aquilenet.fr](http://dns.aquilenet.fr)) . Nous en avons profité pour ajouter [DoH](https://fr.wikipedia.org/wiki/DNS_over_HTTPS) et [DoT](https://fr.wikipedia.org/wiki/DNS_over_TLS) et d'avoir cette adresse en IP Virtuelle partagée entre pan1 et pan2.
10
Cette IP virtuelle est portée par Keepalived sur pan1 le primaire et pan2 le secondaire. Si le démon Keepalived est arrêté sur pan1, l'ip bascule sur pan2. Si on redémarre le démon sur pan1, ce dernier reprend l'IP: pratique pour les mises à jour, le service continue à fonctionner.
11 1 sacha
12 19 sacha
Pan[1|2] portent l'ip 45.67.81.23 gracieusement offerte par les copains de https://yaal.coop/fr un vlan est dédié sur ce réseau de l'hyperviseur.
13 6 sacha
14 18 sacha
## Configurations communes à pan1 et pan2
15 1 sacha
16 18 sacha
### Nginx
17 1 sacha
18 19 sacha
* /etc/nginx/sites-enabled/default
19 1 sacha
20
21
~~~
22
server {
23 19 sacha
    listen       45.67.81.23:80 ;
24
    listen       [::]:80 ;
25 1 sacha
26 19 sacha
    location ~ /.well-known/acme-challenge {
27
        allow all;
28
        root /var/www/letsencrypt;
29
    }
30
    location / {
31
        return 301 https://dns.aquilenet.fr;
32
        }
33 1 sacha
34 19 sacha
    server_name dns.aquilenet.fr; # managed by Certbot
35 1 sacha
36 19 sacha
    location ~ /.well-known/acme-challenge {
37
        allow all;
38
        root /var/www/letsencrypt;
39
    }
40
}
41
server {
42
    listen       45.67.81.23:443 ssl http2;
43
    listen       [::]:443 ssl http2;
44
    root /var/www/dns.aquilenet.fr;
45
    index index.htm;
46 1 sacha
47 19 sacha
    ssl_certificate     /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem;
48
    ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem;
49
location /dns-query {
50
    grpc_pass grpc://127.0.0.1:443;
51
        }
52
}
53 1 sacha
54 19 sacha
root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm 
55
root@pan1:/etc/unbound/ssl# ip a
56
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
57
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
58
    inet 127.0.0.1/8 scope host lo
59
       valid_lft forever preferred_lft forever
60
    inet6 ::1/128 scope host noprefixroute 
61
       valid_lft forever preferred_lft forever
62
2: enX0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
63
    link/ether 00:16:3e:01:01:21 brd ff:ff:ff:ff:ff:ff
64
    inet 45.67.81.21/24 brd 45.67.81.255 scope global enX0
65
       valid_lft forever preferred_lft forever
66
    inet 45.67.81.23/32 scope global enX0
67
       valid_lft forever preferred_lft forever
68
    inet6 fe80::216:3eff:fe01:121/64 scope link 
69
       valid_lft forever preferred_lft forever
70
root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm 
71
root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm 
72
root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm 
73
root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm 
74
root@pan1:/etc/unbound/ssl# cat /etc/nginx/sites-enabled/default 
75
server {
76
    listen       45.67.81.23:80 ;
77
    listen       [::]:80 ;
78
79
    location ~ /.well-known/acme-challenge {
80
        allow all;
81
        root /var/www/letsencrypt;
82
    }
83
    location / {
84
        return 301 https://dns.aquilenet.fr;
85
        }
86
87
    server_name dns.aquilenet.fr; # managed by Certbot
88
89
    location ~ /.well-known/acme-challenge {
90
        allow all;
91
        root /var/www/letsencrypt;
92
    }
93 1 sacha
}
94 19 sacha
server {
95
    listen       45.67.81.23:443 ssl http2;
96
    listen       [::]:443 ssl http2;
97
    root /var/www/dns.aquilenet.fr;
98
    index index.htm;
99 1 sacha
100 19 sacha
    ssl_certificate     /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem;
101
    ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem;
102
location /dns-query {
103
    grpc_pass grpc://127.0.0.1:443;
104
        }
105
}
106
107
108 1 sacha
~~~
109
110
### Unbound
111
112
~~~
113 19 sacha
server {
114
    listen       45.67.81.23:80 ;
115
    listen       [::]:80 ;
116 1 sacha
117 19 sacha
    location ~ /.well-known/acme-challenge {
118
        allow all;
119
        root /var/www/letsencrypt;
120
    }
121
    location / {
122
        return 301 https://dns.aquilenet.fr;
123
        }
124
125
    server_name dns.aquilenet.fr; # managed by Certbot
126
127
    location ~ /.well-known/acme-challenge {
128
        allow all;
129
        root /var/www/letsencrypt;
130
    }
131
}
132
server {
133
    listen       45.67.81.23:443 ssl http2;
134
    listen       [::]:443 ssl http2;
135
    root /var/www/dns.aquilenet.fr;
136
    index index.htm;
137
138
    ssl_certificate     /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem;
139
    ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem;
140
location /dns-query {
141
    grpc_pass grpc://127.0.0.1:443;
142
        }
143
}
144
145
root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound
146
cat: /etc/unbound/unbound: Aucun fichier ou dossier de ce type
147
root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound.conf
148
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
149
150
server:
151
    verbosity: 1 
152
153
    access-control: 0.0.0.0/0 allow 
154
    interface: 45.67.81.23
155
#    interface: 45.67.81.23@443
156
    interface: 45.67.81.23@853
157
158
http-notls-downstream: yes
159
    interface: 127.0.0.1@443
160
161
    port: 53
162
    tls-port: 853
163
    https-port: 443
164
    
165
    root-hints: "/usr/share/dns/root.hints"
166
 
167
    harden-glue: yes
168
    harden-large-queries: yes
169
    harden-dnssec-stripped: yes
170
    harden-below-nxdomain: yes
171
    harden-referral-path: yes
172
    harden-algo-downgrade: no # false positives with improperly configured zones
173
    use-caps-for-id: no # makes lots of queries fail
174
    edns-buffer-size: 1232
175
    rrset-roundrobin: yes
176
    cache-min-ttl: 300
177
    cache-max-ttl: 86400
178
    serve-expired: yes
179
    harden-algo-downgrade: yes
180
    harden-short-bufsize: yes
181
    hide-identity: yes
182
    identity: "dns.aquilenet.fr"
183
    hide-version: yes
184
    do-daemonize: no
185
    neg-cache-size: 4m
186
    qname-minimisation: yes
187
    deny-any: yes
188
    minimal-responses: yes
189
    prefetch: yes
190
    prefetch-key: yes
191
    num-threads: 2 
192
    msg-cache-size: 50m
193
    rrset-cache-size: 100m
194
    so-reuseport: yes
195
    so-rcvbuf: 4m
196
    so-sndbuf: 4m
197
    unwanted-reply-threshold: 100000
198
    log-queries: no
199
    log-replies: no
200
    log-servfail: no
201
    log-local-actions: no
202
    logfile: /dev/null
203
204
    # imposer la QNAME minimisation (RFC 7816)
205
    qname-minimisation: yes
206
    # même si le serveur faisant autorité ne le veut pas
207
    #   après discussion, il est possible que cette option ne soit
208
    #   pas recommandée dans le cadre d'un résolveur ouvert
209
    qname-minimisation-strict: yes
210
211
   # DoH
212
   tls-service-key: "/etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem"
213
   tls-service-pem: "/etc/letsencrypt/live/dns.aquilenet.fr/cert.pem"
214
215 1 sacha
~~~
216
217
### AppArmor
218
219
*  /etc/apparmor.d/usr.sbin.unbound
220
décomenter:
221
  include <local/usr.sbin.unbound>
222
223
* /etc/apparmor.d/local/usr.sbin.unbound
224
~~~
225
/etc/letsencrypt/archive/** r,
226
/etc/letsencrypt/live/** r,
227
~~~
228
appliquer avec: `apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound`
229
230
### Iptables
231
232
~~~
233 19 sacha
*filter
234
:INPUT DROP
235
:FORWARD DROP
236
:OUTPUT ACCEPT
237
238
-A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
239
-A INPUT -s 0.0.0.0 -i eth0 -j DROP
240
-A INPUT -d 0.0.0.0 -i eth0 -j DROP
241
-A INPUT -s 255.255.255.255 -i eth0 -j DROP
242
-A INPUT -d 255.255.255.255 -i eth0 -j DROP
243
-A INPUT -m conntrack --ctstate INVALID -j DROP
244
245
-A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
246
-A INPUT -p udp ! --dport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
247
-A INPUT -i lo -j ACCEPT
248
-A OUTPUT -o lo -j ACCEPT
249
250
# SSH no more 10 attempts in 3 min
251
-A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --update --hitcount 10 --seconds 180 -j DROP
252
-A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --set -j ACCEPT
253
254 1 sacha
# Web
255
-A INPUT -p tcp --dport 80 -j ACCEPT
256 19 sacha
257
# smtp
258
-A INPUT -i eth0 -p tcp --dport 25 -j ACCEPT
259
# smtps
260
-A INPUT -i eth0 -p tcp --dport 465 -j ACCEPT
261
# submission
262
-A INPUT -i eth0 -p tcp --dport 587 -j ACCEPT
263
264
# DNS
265
# récursif, lisible par nos abonnés seulement
266
-N dns_limit
267
-A dns_limit -s 185.233.100.0/22 -j ACCEPT
268 7 sacha
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 53 -j dns_limit
269
-A INPUT -d 45.67.81.23 -p udp -m udp --dport 53 -j dns_limit
270
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 443 -j dns_limit
271
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 853 -j dns_limit
272 19 sacha
273
# mais aussi par le reste d'Internet, mais en rate-limit
274
-A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 1/sec --hashlimit-burst 2 --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4 --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 1/s burst 2" -j DROP
275
-A dns_limit -m string --algo bm --hex-string "|00 00 ff 00 01|" --from 28 -m hashlimit --hashlimit-above 20/min --hashlimit-mode srcip --hashlimit-name RL-DNS-ANY-v4-LOG --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS ANY QTYPE 20/min" -j LOG --log-prefix "DNS-FLOOD "
276
-A dns_limit -m hashlimit --hashlimit-above 10/sec --hashlimit-burst 100 --hashlimit-mode srcip --hashlimit-name DNS --hashlimit-srcmask 28 -m comment --comment "RATE-LIMIT DNS 10/src burst 100" -j DROP
277
-A dns_limit -j ACCEPT
278
279
# ICMP
280
-A INPUT -p icmp -j ACCEPT
281
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
282
283
# NRPE
284
-A INPUT -s 185.233.100.230 -p tcp --dport 5666 -j ACCEPT
285
286
# Keepalived
287
-A INPUT -s 45.67.81.0/24 -p vrrp -j ACCEPT
288
289
COMMIT
290 20 sacha
~~~
291 3 sacha
292
## Configurations spécifiques
293
294
### Génération du certificat SSL sur Hades
295
296
~~~
297
certbot --apache --agree-tos --email sysop@aquilenet.fr -d dns.aquilenet.fr
298
chgrp bind /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem
299
chmod 0640 /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem
300 16 sacha
openssl dhparam -out /etc/bind/dhparam.pem 4096
301
~~~
302
303
Copie du certificat sur gaia
304
305 1 sacha
* /etc/letsencrypt/renewal-hooks/post/sync-cert.sh
306 20 sacha
307
308 16 sacha
#!/bin/bash
309
rsync -aPHSA /etc/letsencrypt/archive/dns.aquilenet.fr gaia:/etc/letsencrypt/archive/
310
~~~
311
312
### Clée sdns (auth par épinglage de la clé / key pining)
313
314
* A partir de la clé
315
~~~
316 3 sacha
hades|19:21:08|:~# openssl rsa -in /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
317
writing RSA key
318
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
319
~~~
320
* ou à partir du certificat
321
~~~
322
hades|19:22:21|:~# openssl x509 -in /etc/letsencrypt/live/dns.aquilenet.fr/cert.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
323
writing RSA key
324
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
325
~~~
326
327
### Keepalived
328
329
#### Hades Master
330
331
* /etc/keepalived/keepalived.conf
332
333
~~~
334
global_defs {
335
  notification_email {
336
    sysop@aquilenet.fr
337
  }
338
  notification_email_from vrrp-dns@aquilenet.fr.fr
339
  smtp_server localhost
340
  smtp_connect_timeout 30
341
}
342
343
vrrp_instance DNS {
344
  state MASTER 
345
  interface eth0
346
  virtual_router_id 101 
347
  priority 100
348
  advert_int 2
349
  smtp_alert
350
  unicast_src_ip 185.233.100.16 
351
  unicast_peer {
352
    185.233.100.2
353
  }
354
  virtual_ipaddress {
355
    45.67.81.23/32 dev eth1 scope global # VIP
356
  }
357
}
358
~~~
359
360
#### Gaia Slave
361
362
* /etc/keepalived/keepalived.conf
363
364
~~~
365
global_defs {
366
  notification_email {
367
    sysop@aquilenet.fr
368
  }
369
  notification_email_from vrrp-dns@aquilenet.fr.fr
370
  smtp_server localhost
371
  smtp_connect_timeout 30
372
}
373
374
vrrp_instance DNS {
375
  state BACKUP
376
  interface eth0
377
  virtual_router_id 101
378
  priority 50
379 1 sacha
  advert_int 2
380 4 sacha
  smtp_alert
381
  unicast_src_ip 185.233.100.2
382
  unicast_peer {
383
    185.233.100.16
384
  }
385 1 sacha
  virtual_ipaddress {
386 13 sacha
    45.67.81.23/32 dev eth1 scope global # VIP
387
  }
388
}
389
390 8 sacha
~~~
391 4 sacha
392
## Validation
393
394 8 sacha
* test du service
395
~~~
396 1 sacha
dig +short dns.aquilenet.fr @45.67.81.23 
397 12 sacha
45.67.81.23
398 9 sacha
dig +https +short dns.aquilenet.fr @45.67.81.23      
399
45.67.81.23
400
dig +tls +short dns.aquilenet.fr @45.67.81.23      
401
45.67.81.23
402 10 sacha
~~~
403
404 9 sacha
* bascule keepalived
405 16 sacha
406 17 sacha
sur hades: `systemctl stop keepalived`
407 16 sacha
sur gaia: `ip a |grep /32`doit donner "inet 45.67.81.23/32 scope global eth1"
408
http://dns.aquilenet.fr/host permet de savoir quel est le serveur qui porte l'IP virtuelle
409
410
## Indexes de serveurs DNS ouverts:
411 1 sacha
412
https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers <= fait
413
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
414
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
415
https://dnsprivacy.org/public_resolvers/
416
417
## Ressources
418
419
https://www.bortzmeyer.org/doh-bortzmeyer-fr-policy.html
420
https://www.bortzmeyer.org/7858.html
421
https://kb.isc.org/docs/aa-01386