Projet

Général

Profil

Wiki » Historique » Version 27

sacha, 10/12/2023 17:06

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 27 sacha
    listen       [2a0c:e300::1337]: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 27 sacha
    listen       [2a0c:e300::1337]:443 ssl http2;
44 19 sacha
    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
54 1 sacha
~~~
55
56
### Unbound
57
58
~~~
59 19 sacha
server {
60
    listen       45.67.81.23:80 ;
61
    listen       [::]:80 ;
62 1 sacha
63 19 sacha
    location ~ /.well-known/acme-challenge {
64
        allow all;
65
        root /var/www/letsencrypt;
66
    }
67
    location / {
68
        return 301 https://dns.aquilenet.fr;
69
        }
70
71
    server_name dns.aquilenet.fr; # managed by Certbot
72
73
    location ~ /.well-known/acme-challenge {
74
        allow all;
75
        root /var/www/letsencrypt;
76
    }
77
}
78
server {
79
    listen       45.67.81.23:443 ssl http2;
80
    listen       [::]:443 ssl http2;
81
    root /var/www/dns.aquilenet.fr;
82
    index index.htm;
83
84
    ssl_certificate     /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem;
85
    ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem;
86
location /dns-query {
87
    grpc_pass grpc://127.0.0.1:443;
88
        }
89
}
90
91
root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound
92
cat: /etc/unbound/unbound: Aucun fichier ou dossier de ce type
93
root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound.conf
94
include-toplevel: "/etc/unbound/unbound.conf.d/*.conf"
95
96
server:
97
    verbosity: 1 
98
99
    access-control: 0.0.0.0/0 allow 
100
    interface: 45.67.81.23
101
#    interface: 45.67.81.23@443
102
    interface: 45.67.81.23@853
103
104
http-notls-downstream: yes
105
    interface: 127.0.0.1@443
106
107
    port: 53
108
    tls-port: 853
109
    https-port: 443
110
    
111
    root-hints: "/usr/share/dns/root.hints"
112
 
113
    harden-glue: yes
114
    harden-large-queries: yes
115
    harden-dnssec-stripped: yes
116
    harden-below-nxdomain: yes
117
    harden-referral-path: yes
118
    harden-algo-downgrade: no # false positives with improperly configured zones
119
    use-caps-for-id: no # makes lots of queries fail
120
    edns-buffer-size: 1232
121
    rrset-roundrobin: yes
122
    cache-min-ttl: 300
123
    cache-max-ttl: 86400
124
    serve-expired: yes
125
    harden-algo-downgrade: yes
126
    harden-short-bufsize: yes
127
    hide-identity: yes
128
    identity: "dns.aquilenet.fr"
129
    hide-version: yes
130
    do-daemonize: no
131
    neg-cache-size: 4m
132
    qname-minimisation: yes
133
    deny-any: yes
134
    minimal-responses: yes
135
    prefetch: yes
136
    prefetch-key: yes
137
    num-threads: 2 
138
    msg-cache-size: 50m
139
    rrset-cache-size: 100m
140
    so-reuseport: yes
141
    so-rcvbuf: 4m
142
    so-sndbuf: 4m
143
    unwanted-reply-threshold: 100000
144
    log-queries: no
145
    log-replies: no
146
    log-servfail: no
147
    log-local-actions: no
148
    logfile: /dev/null
149
150
    # imposer la QNAME minimisation (RFC 7816)
151
    qname-minimisation: yes
152
    # même si le serveur faisant autorité ne le veut pas
153
    #   après discussion, il est possible que cette option ne soit
154
    #   pas recommandée dans le cadre d'un résolveur ouvert
155
    qname-minimisation-strict: yes
156
157
   # DoH
158
   tls-service-key: "/etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem"
159
   tls-service-pem: "/etc/letsencrypt/live/dns.aquilenet.fr/cert.pem"
160
161 1 sacha
~~~
162
163
### AppArmor
164
165
*  /etc/apparmor.d/usr.sbin.unbound
166
décomenter:
167
  include <local/usr.sbin.unbound>
168
169
* /etc/apparmor.d/local/usr.sbin.unbound
170
~~~
171
/etc/letsencrypt/archive/** r,
172
/etc/letsencrypt/live/** r,
173
~~~
174
appliquer avec: `apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound`
175
176
### Iptables
177
178
~~~
179 19 sacha
*filter
180
:INPUT DROP
181
:FORWARD DROP
182
:OUTPUT ACCEPT
183
184
-A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
185
-A INPUT -s 0.0.0.0 -i eth0 -j DROP
186
-A INPUT -d 0.0.0.0 -i eth0 -j DROP
187
-A INPUT -s 255.255.255.255 -i eth0 -j DROP
188
-A INPUT -d 255.255.255.255 -i eth0 -j DROP
189
-A INPUT -m conntrack --ctstate INVALID -j DROP
190
191
-A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
192
-A INPUT -p udp ! --dport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
193
-A INPUT -i lo -j ACCEPT
194
-A OUTPUT -o lo -j ACCEPT
195
196
# SSH no more 10 attempts in 3 min
197
-A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --update --hitcount 10 --seconds 180 -j DROP
198
-A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --set -j ACCEPT
199
200 1 sacha
# Web
201
-A INPUT -p tcp --dport 80 -j ACCEPT
202 19 sacha
203
# smtp
204
-A INPUT -i eth0 -p tcp --dport 25 -j ACCEPT
205
# smtps
206
-A INPUT -i eth0 -p tcp --dport 465 -j ACCEPT
207
# submission
208
-A INPUT -i eth0 -p tcp --dport 587 -j ACCEPT
209
210
# DNS
211
# récursif, lisible par nos abonnés seulement
212
-N dns_limit
213
-A dns_limit -s 185.233.100.0/22 -j ACCEPT
214 7 sacha
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 53 -j dns_limit
215
-A INPUT -d 45.67.81.23 -p udp -m udp --dport 53 -j dns_limit
216
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 443 -j dns_limit
217
-A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 853 -j dns_limit
218 19 sacha
219
# mais aussi par le reste d'Internet, mais en rate-limit
220
-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
221
-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 "
222
-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
223
-A dns_limit -j ACCEPT
224
225
# ICMP
226
-A INPUT -p icmp -j ACCEPT
227
-A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
228
229
# NRPE
230
-A INPUT -s 185.233.100.230 -p tcp --dport 5666 -j ACCEPT
231
232
# Keepalived
233
-A INPUT -s 45.67.81.0/24 -p vrrp -j ACCEPT
234
235
COMMIT
236 20 sacha
~~~
237 3 sacha
238
## Configurations spécifiques
239
240
### Génération du certificat SSL sur Hades
241
242
~~~
243
certbot --apache --agree-tos --email sysop@aquilenet.fr -d dns.aquilenet.fr
244
chgrp bind /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem
245
chmod 0640 /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem
246 16 sacha
openssl dhparam -out /etc/bind/dhparam.pem 4096
247
~~~
248
249
Copie du certificat sur gaia
250
251 21 sacha
* /etc/letsencrypt/renewal/dns.aquilenet.fr.conf
252 1 sacha
253 21 sacha
~~~
254
+ post_hook = /root/certificats.sh
255
~~~
256 20 sacha
257 22 sacha
* /root/certificats.sh
258
259
~~~
260
#!/bin/sh
261
cp -RL /etc/letsencrypt/live/dns.aquilenet.fr/ /etc/unbound/ssl/
262
systemctl restart unbound
263
scp -qrP 55555 /etc/unbound/ssl/dns.aquilenet.fr pan2.aquilenet.fr:/etc/unbound/ssl/
264
ssh -p 55555 pan2.aquilenet.fr systemctl restart unbound
265 16 sacha
~~~
266
267
### Clée sdns (auth par épinglage de la clé / key pining)
268
269
* A partir de la clé
270 23 sacha
271 16 sacha
~~~
272 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
273
writing RSA key
274
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
275
~~~
276 23 sacha
277 3 sacha
* ou à partir du certificat
278 23 sacha
279 3 sacha
~~~
280
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
281
writing RSA key
282
lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII=
283
~~~
284
285
### Keepalived
286
287 26 sacha
#### pan1 Master
288 3 sacha
289
* /etc/keepalived/keepalived.conf
290
291
~~~
292
global_defs {
293
  notification_email {
294
    sysop@aquilenet.fr
295
  }
296 24 sacha
  notification_email_from vrrp-dns@aquilenet.fr
297
  smtp_server localhost 
298 3 sacha
  smtp_connect_timeout 30
299
}
300
301
vrrp_instance DNS {
302
  state MASTER 
303 24 sacha
  interface enX0
304
  virtual_router_id 101
305
  priority 100 
306
  advert_int 5 
307 1 sacha
  smtp_alert
308 24 sacha
  unicast_src_ip 45.67.81.21 
309 1 sacha
  unicast_peer {
310 24 sacha
    45.67.81.22
311 1 sacha
  }
312 3 sacha
  virtual_ipaddress {
313 24 sacha
    45.67.81.23/32 dev enX0 scope global # VIP
314 3 sacha
  }
315 24 sacha
  virtual_ipaddress_excluded {
316
    2a0c:e300::1337/128 dev enX1
317
    }
318
319 3 sacha
}
320 24 sacha
321 3 sacha
~~~
322
323 25 sacha
#### pan2 Slave
324 3 sacha
325
* /etc/keepalived/keepalived.conf
326
327
~~~
328
global_defs {
329
  notification_email {
330
    sysop@aquilenet.fr
331
  }
332 25 sacha
  notification_email_from vrrp-dns@aquilenet.fr
333 3 sacha
  smtp_server localhost
334
  smtp_connect_timeout 30
335
}
336
337
vrrp_instance DNS {
338 25 sacha
  state SLAVE 
339
  interface enX0
340
  virtual_router_id 101 
341
  priority 50 
342
  advert_int 5 
343 1 sacha
  smtp_alert
344 25 sacha
  unicast_src_ip 45.67.81.22
345 1 sacha
  unicast_peer {
346 25 sacha
    45.67.81.21
347 4 sacha
  }
348
  virtual_ipaddress {
349 25 sacha
    45.67.81.23/32 dev enX0 scope global # VIP
350 4 sacha
  }
351 25 sacha
  virtual_ipaddress_excluded {
352
    2a0c:e300::1337/128 dev enX1
353
    }
354 13 sacha
}
355
356 8 sacha
~~~
357 4 sacha
358
## Validation
359
360 8 sacha
* test du service
361
~~~
362 1 sacha
dig +short dns.aquilenet.fr @45.67.81.23 
363 12 sacha
45.67.81.23
364 9 sacha
dig +https +short dns.aquilenet.fr @45.67.81.23      
365
45.67.81.23
366
dig +tls +short dns.aquilenet.fr @45.67.81.23      
367
45.67.81.23
368 10 sacha
~~~
369
370 9 sacha
* bascule keepalived
371 16 sacha
372 17 sacha
sur hades: `systemctl stop keepalived`
373 16 sacha
sur gaia: `ip a |grep /32`doit donner "inet 45.67.81.23/32 scope global eth1"
374
http://dns.aquilenet.fr/host permet de savoir quel est le serveur qui porte l'IP virtuelle
375
376
## Indexes de serveurs DNS ouverts:
377 1 sacha
378
https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers <= fait
379
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
380
https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait
381
https://dnsprivacy.org/public_resolvers/
382
383
## Ressources
384
385
https://www.bortzmeyer.org/doh-bortzmeyer-fr-policy.html
386
https://www.bortzmeyer.org/7858.html
387
https://kb.isc.org/docs/aa-01386