Wiki » Historique » Révision 19
Révision 18 (sacha, 26/02/2023 21:03) → Révision 19/35 (sacha, 10/12/2023 05:10)
{{>toc}} # DNS récursif Ouvert DoH DoT & haute disponibilité **45.67.81.23 - dns.aquilenet.fr** On propos un Aquilenet propose deux serveurs DNS récursif ouvert ouverts cf https://www.aquilenet.fr/services/dns/ https://dns.aquilenet.fr/ 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. 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. Pan[1|2] portent Une configuration spécifique pour l'ip 45.67.81.23 gracieusement offerte par les copains de https://yaal.coop/fr un ce vlan est dédié a été fait sur les switches et les hyperviseurs, ce réseau de l'hyperviseur. qui permet au final à pan1 et pan2 d'avoir une seconde interface qui porte l'IP virtuelle, elle n'est pas abordée dans ce document. ## Configurations communes à pan1 et pan2 ### Nginx * /etc/nginx/sites-enabled/default /etc/nginx/site-avaible ~~~ server { listen 45.67.81.23:80 ; 443 ssl http2 default_server; listen [::]:80 ; location ~ /.well-known/acme-challenge { allow all; root /var/www/letsencrypt; } location / { return 301 https://dns.aquilenet.fr; } [::]:443 ssl http2 default_server; server_name dns.aquilenet.fr; root /var/www/dns.aquilenet.fr; include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot location ~ /.well-known/acme-challenge { allow all; root /var/www/letsencrypt; } ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot server_tokens off; ssl_session_cache shared:SSL:10m; } server { # resolver 127.0.0.1 valid=300s; # Replace with your local resolver resolver_timeout 5s; # HTTP Security Headers add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=63072000"; listen 45.67.81.23:443 ssl http2; listen [::]:443 ssl http2; root /var/www/dns.aquilenet.fr; index index.htm; ssl_certificate /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem; ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem; location /dns-query { grpc_pass grpc://127.0.0.1:443; } } root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm root@pan1:/etc/unbound/ssl# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host noprefixroute valid_lft forever preferred_lft forever 2: enX0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether 00:16:3e:01:01:21 brd ff:ff:ff:ff:ff:ff inet 45.67.81.21/24 brd 45.67.81.255 scope global enX0 valid_lft forever preferred_lft forever inet 45.67.81.23/32 scope global enX0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe01:121/64 scope link valid_lft forever preferred_lft forever root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm root@pan1:/etc/unbound/ssl# vi /var/www/dns.aquilenet.fr/index.htm root@pan1:/etc/unbound/ssl# cat /etc/nginx/sites-enabled/default server { listen 45.67.81.23:80 ; listen [::]:80 ; location ~ /.well-known/acme-challenge { allow all; root /var/www/letsencrypt; } location / { return 301 https://dns.aquilenet.fr; } server_name dns.aquilenet.fr; /etc/letsencrypt/live/dns.aquilenet.fr/fullchain.pem; # managed by Certbot location ~ /.well-known/acme-challenge { allow all; root /var/www/letsencrypt; } } server { listen 45.67.81.23:443 ssl http2; listen [::]:443 ssl http2; root /var/www/dns.aquilenet.fr; index index.htm; ssl_certificate /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem; ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem; location /dns-query { grpc_pass grpc://127.0.0.1:443; } } ~~~ ### Unbound ~~~ server { listen 45.67.81.23:80 ; listen [::]:80 ; location ~ /.well-known/acme-challenge { allow all; root /var/www/letsencrypt; } location / { return 301 https://dns.aquilenet.fr; } server_name dns.aquilenet.fr; /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem; # managed by Certbot location ~ /.well-known/acme-challenge / { allow all; root /var/www/letsencrypt; } try_files $uri /index.htm; } server location /dns-query { listen proxy_pass 45.67.81.23:443 ssl http2; http://localhost:1443/dns-query; listen [::]:443 ssl http2; proxy_set_header Host $host; root /var/www/dns.aquilenet.fr; index index.htm; ssl_certificate /etc/unbound/ssl/dns.aquilenet.fr/fullchain.pem; ssl_certificate_key /etc/unbound/ssl/dns.aquilenet.fr/privkey.pem; location /dns-query { grpc_pass grpc://127.0.0.1:443; proxy_set_header X-Real-IP $remote_addr; } } root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound cat: /etc/unbound/unbound: Aucun fichier ou dossier de ce type root@pan1:/etc/unbound/ssl# cat /etc/unbound/unbound.conf include-toplevel: "/etc/unbound/unbound.conf.d/*.conf" ~~~ server: verbosity: 1 access-control: 0.0.0.0/0 allow interface: 45.67.81.23 # interface: 45.67.81.23@443 interface: 45.67.81.23@853 ### Unbound http-notls-downstream: yes interface: 127.0.0.1@443 port: 53 tls-port: 853 https-port: 443 root-hints: "/usr/share/dns/root.hints" harden-glue: yes harden-large-queries: yes harden-dnssec-stripped: yes harden-below-nxdomain: yes harden-referral-path: yes harden-algo-downgrade: no # false positives with improperly configured zones use-caps-for-id: no # makes lots of queries fail edns-buffer-size: 1232 rrset-roundrobin: yes cache-min-ttl: 300 cache-max-ttl: 86400 serve-expired: yes harden-algo-downgrade: yes harden-short-bufsize: yes hide-identity: yes identity: "dns.aquilenet.fr" hide-version: yes do-daemonize: no neg-cache-size: 4m qname-minimisation: yes deny-any: yes minimal-responses: yes prefetch: yes prefetch-key: yes num-threads: 2 msg-cache-size: 50m rrset-cache-size: 100m so-reuseport: yes so-rcvbuf: 4m so-sndbuf: 4m unwanted-reply-threshold: 100000 log-queries: no log-replies: no log-servfail: no log-local-actions: no logfile: /dev/null # imposer la QNAME minimisation (RFC 7816) qname-minimisation: yes # même si le serveur faisant autorité ne le veut pas # après discussion, il est possible que cette option ne soit # pas recommandée dans le cadre d'un résolveur ouvert qname-minimisation-strict: yes # DoH tls-service-key: "/etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem" tls-service-pem: "/etc/letsencrypt/live/dns.aquilenet.fr/cert.pem" ~~~ ~~~ ### AppArmor * /etc/apparmor.d/usr.sbin.unbound décomenter: include <local/usr.sbin.unbound> * /etc/apparmor.d/local/usr.sbin.unbound ~~~ /etc/letsencrypt/archive/** r, /etc/letsencrypt/live/** r, ~~~ appliquer avec: `apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound` ### Iptables ~~~ *filter :INPUT DROP :FORWARD DROP :OUTPUT ACCEPT -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP -A INPUT -s 0.0.0.0 -i eth0 -j DROP -A INPUT -d 0.0.0.0 -i eth0 -j DROP -A INPUT -s 255.255.255.255 -i eth0 -j DROP -A INPUT -d 255.255.255.255 -i eth0 -j DROP -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p tcp -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -p udp ! --dport 53 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A OUTPUT -o lo -j ACCEPT # SSH no more 10 attempts in 3 min -A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --update --hitcount 10 --seconds 180 -j DROP -A INPUT -i eth0 -p tcp --dport 55555 -m recent --name SSH --set -j ACCEPT # Web -A INPUT -p tcp --dport 80 -j ACCEPT # smtp -A INPUT -i eth0 -p tcp --dport 25 443 -j ACCEPT # smtps ~~~ -A INPUT -i eth0 -p tcp --dport 465 -j ACCEPT ~~~ # submission -A INPUT -i eth0 -p tcp --dport 587 -j ACCEPT # DNS # récursif, lisible par nos abonnés seulement -N dns_limit -A dns_limit -s 185.233.100.0/22 -j ACCEPT -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 53 -j dns_limit -A INPUT -d 45.67.81.23 -p udp -m udp --dport 53 -j dns_limit -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 443 -j dns_limit -A INPUT -d 45.67.81.23 -p tcp -m tcp --dport 853 -j dns_limit # mais aussi par le reste d'Internet, mais en rate-limit -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 -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 " -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 -A dns_limit -j ACCEPT ~~~ # ICMP -A INPUT -p icmp -j ACCEPT -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT # NRPE -A INPUT -s 185.233.100.230 -p tcp --dport 5666 -j ACCEPT # Keepalived -A INPUT -s 45.67.81.0/24 -p vrrp -j ACCEPT COMMIT ## Configurations spécifiques ### Génération du certificat SSL sur Hades ~~~ certbot --apache --agree-tos --email sysop@aquilenet.fr -d dns.aquilenet.fr chgrp bind /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem chmod 0640 /etc/letsencrypt/live/dns.aquilenet.fr/privkey.pem openssl dhparam -out /etc/bind/dhparam.pem 4096 ~~~ Copie du certificat sur gaia * /etc/letsencrypt/renewal-hooks/post/sync-cert.sh ~~~ #!/bin/bash rsync -aPHSA /etc/letsencrypt/archive/dns.aquilenet.fr gaia:/etc/letsencrypt/archive/ ~~~ ### Clée sdns (auth par épinglage de la clé / key pining) * A partir de la clé ~~~ 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 writing RSA key lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII= ~~~ * ou à partir du certificat ~~~ 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 writing RSA key lBk09CRIPJ+J4O9rmbvJkEiGYoH5r9rxOIQdxkYxyII= ~~~ ### Keepalived #### Hades Master * /etc/keepalived/keepalived.conf ~~~ global_defs { notification_email { sysop@aquilenet.fr } notification_email_from vrrp-dns@aquilenet.fr.fr smtp_server localhost smtp_connect_timeout 30 } vrrp_instance DNS { state MASTER interface eth0 virtual_router_id 101 priority 100 advert_int 2 smtp_alert unicast_src_ip 185.233.100.16 unicast_peer { 185.233.100.2 } virtual_ipaddress { 45.67.81.23/32 dev eth1 scope global # VIP } } ~~~ #### Gaia Slave * /etc/keepalived/keepalived.conf ~~~ global_defs { notification_email { sysop@aquilenet.fr } notification_email_from vrrp-dns@aquilenet.fr.fr smtp_server localhost smtp_connect_timeout 30 } vrrp_instance DNS { state BACKUP interface eth0 virtual_router_id 101 priority 50 advert_int 2 smtp_alert unicast_src_ip 185.233.100.2 unicast_peer { 185.233.100.16 } virtual_ipaddress { 45.67.81.23/32 dev eth1 scope global # VIP } } ~~~ ## Validation * test du service ~~~ dig +short dns.aquilenet.fr @45.67.81.23 45.67.81.23 dig +https +short dns.aquilenet.fr @45.67.81.23 45.67.81.23 dig +tls +short dns.aquilenet.fr @45.67.81.23 45.67.81.23 ~~~ * bascule keepalived sur hades: `systemctl stop keepalived` sur gaia: `ip a |grep /32`doit donner "inet 45.67.81.23/32 scope global eth1" http://dns.aquilenet.fr/host permet de savoir quel est le serveur qui porte l'IP virtuelle ## Indexes de serveurs DNS ouverts: https://github.com/curl/curl/wiki/DNS-over-HTTPS#publicly-available-servers <= fait https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait https://diyisp.org/dokuwiki/doku.php?id=technical:dnsresolver <= fait https://dnsprivacy.org/public_resolvers/ ## Ressources https://www.bortzmeyer.org/doh-bortzmeyer-fr-policy.html https://www.bortzmeyer.org/7858.html https://kb.isc.org/docs/aa-01386