Projet

Général

Profil

Wiki » Historique » Version 19

sacha, 10/12/2023 05:10

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