Projet

Général

Profil

Wiki » Historique » Version 24

sacha, 10/12/2023 17:04

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 21 sacha
* /etc/letsencrypt/renewal/dns.aquilenet.fr.conf
306 1 sacha
307 21 sacha
~~~
308
+ post_hook = /root/certificats.sh
309
~~~
310 20 sacha
311 22 sacha
* /root/certificats.sh
312
313
~~~
314
#!/bin/sh
315
cp -RL /etc/letsencrypt/live/dns.aquilenet.fr/ /etc/unbound/ssl/
316
systemctl restart unbound
317
scp -qrP 55555 /etc/unbound/ssl/dns.aquilenet.fr pan2.aquilenet.fr:/etc/unbound/ssl/
318
ssh -p 55555 pan2.aquilenet.fr systemctl restart unbound
319 16 sacha
~~~
320
321
### Clée sdns (auth par épinglage de la clé / key pining)
322
323
* A partir de la clé
324 23 sacha
325 16 sacha
~~~
326 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
327
writing RSA key
328
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
329
~~~
330 23 sacha
331 3 sacha
* ou à partir du certificat
332 23 sacha
333 3 sacha
~~~
334
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
335
writing RSA key
336
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
337
~~~
338
339
### Keepalived
340
341
#### Hades Master
342
343
* /etc/keepalived/keepalived.conf
344
345
~~~
346
global_defs {
347
  notification_email {
348
    sysop@aquilenet.fr
349
  }
350 24 sacha
  notification_email_from vrrp-dns@aquilenet.fr
351
  smtp_server localhost 
352 3 sacha
  smtp_connect_timeout 30
353
}
354
355
vrrp_instance DNS {
356
  state MASTER 
357 24 sacha
  interface enX0
358
  virtual_router_id 101
359
  priority 100 
360
  advert_int 5 
361 1 sacha
  smtp_alert
362 24 sacha
  unicast_src_ip 45.67.81.21 
363 1 sacha
  unicast_peer {
364 24 sacha
    45.67.81.22
365 1 sacha
  }
366 3 sacha
  virtual_ipaddress {
367 24 sacha
    45.67.81.23/32 dev enX0 scope global # VIP
368 3 sacha
  }
369 24 sacha
  virtual_ipaddress_excluded {
370
    2a0c:e300::1337/128 dev enX1
371
    }
372
373 3 sacha
}
374 24 sacha
375 3 sacha
~~~
376
377
#### Gaia Slave
378
379
* /etc/keepalived/keepalived.conf
380
381
~~~
382
global_defs {
383
  notification_email {
384
    sysop@aquilenet.fr
385
  }
386
  notification_email_from vrrp-dns@aquilenet.fr.fr
387
  smtp_server localhost
388
  smtp_connect_timeout 30
389
}
390
391
vrrp_instance DNS {
392
  state BACKUP
393
  interface eth0
394
  virtual_router_id 101
395
  priority 50
396 1 sacha
  advert_int 2
397 4 sacha
  smtp_alert
398
  unicast_src_ip 185.233.100.2
399
  unicast_peer {
400
    185.233.100.16
401
  }
402 1 sacha
  virtual_ipaddress {
403 13 sacha
    45.67.81.23/32 dev eth1 scope global # VIP
404
  }
405
}
406
407 8 sacha
~~~
408 4 sacha
409
## Validation
410
411 8 sacha
* test du service
412
~~~
413 1 sacha
dig +short dns.aquilenet.fr @45.67.81.23 
414 12 sacha
45.67.81.23
415 9 sacha
dig +https +short dns.aquilenet.fr @45.67.81.23      
416
45.67.81.23
417
dig +tls +short dns.aquilenet.fr @45.67.81.23      
418
45.67.81.23
419 10 sacha
~~~
420
421 9 sacha
* bascule keepalived
422 16 sacha
423 17 sacha
sur hades: `systemctl stop keepalived`
424 16 sacha
sur gaia: `ip a |grep /32`doit donner "inet 45.67.81.23/32 scope global eth1"
425
http://dns.aquilenet.fr/host permet de savoir quel est le serveur qui porte l'IP virtuelle
426
427
## Indexes de serveurs DNS ouverts:
428 1 sacha
429
https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers <= fait
430
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
431
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
432
https://dnsprivacy.org/public_resolvers/
433
434
## Ressources
435
436
https://www.bortzmeyer.org/doh-bortzmeyer-fr-policy.html
437
https://www.bortzmeyer.org/7858.html
438
https://kb.isc.org/docs/aa-01386