💾 Archived View for going-flying.com › ~mernisse › 22.gmi captured on 2022-04-29 at 11:16:25. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2022-04-28)
-=-=-=-=-=-=-
Views are one of the more powerful features of BIND. In the previous two issues we talked about providing a recursive resolver and an authoritative resolver, but we provided them to anyone who asked us, equally. What if we only wanted to provide recursion to our local network but provide authoritative resolution to everyone? Well we can do that with BIND ACLs. Now lets say we want to provide our LAN with *different* answers than to the Internet at large, we can use BIND ACLs and Views to do that. This opens up a huge amount of power in providing DNS to our clients.
So first we have to classify clients. As you might expect we do this with ACLs (access control lists). We saw one last time in our primary resolver configuration but for this time lets expand on our hypothetical example domain with some IP address space. We will use 192.168.242.0/23 and fd00:0242::/48 as our LAN. To start with we want to create an ACL that identifies our IP space.
acl internal-networks { 127.0.0.1/32; ::1/128; 192.168.242.0/23; fd00:0242::/48; };
Now that we have an ACL lets look at locking down our server. It is generally good practice with DNS to not provide rescursive services on your authoritative servers. This prevents people from causing your server to query others. There are many vulnerable DNS servers out there (mostly the embedded ones running on consumer Internet gateways) can be used for traffic amplification DDoS attacks and by denying recursion you prevent your server from being used in this manner. In the main named.conf on Debian you should have an options section, in there you can use the following directives with our ACL.
allow-query is what it says on the tin. You can use this to restrict answers of any kind to listed clients. In our case we want to use the built-in ACL 'any' to allow all clients to at least ask us questions.
allow-query-cache restricts access to cached data. This means that if the answer is in the cache, the server will reply with it, it doesn't mean the server will to get the answer though. In my case I restrict this to the same group that can trigger a recursive lookup.
allow-recursion controls who can trigger a recursive lookup. Only members of this group can cause our server to ask other servers questions.
options { allow-query { any; }; allow-query-cache { internal-networks; }; allow-recursion { internal-networks; }; };
So now that we have locked down our server to split who can query our zones versus who can get us to go out and query other zones on their behalf let us look at a much more powerful feature in BIND called views. This lets you create a different picture of your DNS configuration based on the client. In our example lets say we split our IP space up into trusted clients and guests. We can say 192.168.242.0/24 and fd00:0242::/64 are 'trusted' and 192.168.243.0/24 and fd00:0242::1::/64 are our 'guest' networks. First we need to setup our ACLs.
acl trusted-networks { 192.168.242.0/24; fd00:0242::/64; }; acl guest-networks { 192.168.243.0/24; fd00:0242::1::/64; };
Lets look at our primary server from last time and setup our server to serve our zone to both groups.
view "guests" { match-clients { guest-networks; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; }; view "trusted" { match-clients { trusted-networks; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; }; view "public" { match-clients { any; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; };
This configuration will serve our zone to anyone who asks. It is functionally the same as doing nothing different from last time. Lets add some filtering to our guest network by using the quad9.net DNS service. They provide a filtered view of the Internet, blocking malware domains at the lowest level. If we add the following into our 'guests' view it will force any queries for things our server doesn't know to the quad9.net service.
forwarders { 9.9.9.9; 2620:fe::9; }; forward only;
Next lets say we want our LAN clients to get an internally hosted version of our website instead of the public version. Recall from last time our example zone:
$TTL 21600 @ IN SOA ns01.ub3rgeek.net. hostmaster.ub3rgeek.net. ( 2021030200 ; serial 3600 ; refresh (1 hour) 1800 ; retry (30 mins) 1209600 ; expire (2 weeks) 21600 ; minimum (6 hrs) ) A 69.55.65.182 AAAA 2606:c380:c001:3::2 NS ns01.ub3rgeek.net. NS ns02.ub3rgeek.net.
We can create a copy of this for our internal clients and change our A and AAAA records to our internal webserver. We will save this in a separate file, for example 'trusted-going-flying.com'.
$TTL 21600 @ IN SOA ns01.ub3rgeek.net. hostmaster.ub3rgeek.net. ( 2021030200 ; serial 3600 ; refresh (1 hour) 1800 ; retry (30 mins) 1209600 ; expire (2 weeks) 21600 ; minimum (6 hrs) ) A 192.168.242.2 AAAA fd00:0242::1 NS ns01.ub3rgeek.net. NS ns02.ub3rgeek.net.
Now we change the zone stanza in our trusted view to reference our new zone.
zone "going-flying.com" IN { type master; notify yes; file "trusted-going-flying.com"; allow-update { none; }; allow-transfer { peers; }; };
Finally lets hook up our trusted clients to the DNS over TLS forwarder we built back in the first part of this series. If you have followed along I bet you'll be able to guess how we do it, since it is essentially the same as our quad9 filtering. In the 'trusted' view add the following.
forwarders { ::1 port 5300; }; forward only;
Hopefully you can start to see how powerful this is. I use this extensively along with other technologies like VLANs, VPNs, firewalls and proxies to provide segmentation and protection to clients and servers that are under my control. You can steer almost any client anywhere you want if you control DNS and with views you can do this with great granularity. Our hypothetical configuration looks like the below now, provides quad9.net protection for our guests, a custom version of 'going-flying.com' and DNS over TLS recursion for our trusted clients and the default version of our domain to everyone else.
options { allow-query { any; }; allow-query-cache { internal-networks; }; allow-recursion { internal-networks; }; }; acl internal-networks { 127.0.0.1/32; ::1/128; 192.168.242.0/23; fd00:0242::/48; }; acl trusted-networks { 192.168.242.0/24; fd00:0242::/64; }; acl guest-networks { 192.168.243.0/24; fd00:0242::1::/64; }; view "guests" { match-clients { guest-networks; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; }; view "trusted" { match-clients { trusted-networks; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; forwarders { ::1 port 5300; }; forward only; }; view "public" { match-clients { any; }; zone "going-flying.com" IN { type master; notify yes; file "going-flying.com"; allow-update { none; }; allow-transfer { peers; }; }; };
Now in the last part of the DNS series I'll mention some higher level things like DNSSEC and give some hints on how I automated all of this with Puppet.
🚀 © MMXX-MMXXII matt@going-flying.com