This commit is contained in:
		
					parent
					
						
							
								9c43b0693c
							
						
					
				
			
			
				commit
				
					
						78e9fc2150
					
				
			
		
					 1 changed files with 80 additions and 0 deletions
				
			
		|  | @ -0,0 +1,80 @@ | |||
| --- | ||||
| categories: | ||||
| - General | ||||
| - Linux | ||||
| comments: true | ||||
| date: 2021-01-30 01:05:17+01:00 | ||||
| disable_share: true | ||||
| draft: true | ||||
| featured_image: /images/banner.jpg | ||||
| omit_header_text: true | ||||
| tags: | ||||
| - general | ||||
| - openwrt | ||||
| - turris-omnia | ||||
| title: 'Quick tips: Server Name Indication for internal domains with Turris Omnia' | ||||
| --- | ||||
| 
 | ||||
| ## Omnia? | ||||
| 
 | ||||
| The [Turris Omnia](https://www.turris.com/en/omnia/overview/) is quite a nice (although a little pricey) OpenWRT-based router from [CZ.NIC](https://www.nic.cz/). It provides a fairly powerful CPU, relatively unconstrained [eMMC](https://en.wikipedia.org/wiki/MultiMediaCard#eMMC) space, and quite a lot of hackability (some revisions even have GPIO ports to play with). It runs a modified version of OpenWRT, named [TurrisOS](https://docs.turris.cz/basics/tos-versions/). | ||||
| 
 | ||||
| ## The problem | ||||
| 
 | ||||
| A few years ago, I built a custom NAS for my storage needs, using a cheap Intel SoC (J1900 chipset) and a (much pricier) [mini-ITX small form factor server tower](https://www.ipc.in-win.com/soho-smb-iw-ms04). While I want it to be primarily a NAS, I wanted to run a few services on it, for example [Nextcloud](https://nextcloud.org) or [Pymedusa](https://github.com/pymedusa/Medusa). Of course, in these days it's better to use HTTPS, and the process is both cheap and fast using [Let's Encrypt](https://letsencrypt.org). I also wanted to use [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) with multiple subdomains (`files.example.com`, `medusa.example.com`, etc.) pointing to the same internal LAN IP (because some of the software I used is much harder to set up with subpaths of a single domain). | ||||
| 
 | ||||
| Actually setting up the certificates (with the dns-01 challenge) was rather easy to do (I might do a separate blog post on the topic), but then I got hit by a problem: the default domain used by DHCP in Omnia is `lan`, which of course is not the same as the one used with the Let's Encrypt certificates. Also, subdomains meant that I had to insert static host mapping for each one of them, which made testing of new software (on a new subdomain) and maintenance tedious. | ||||
| 
 | ||||
| Hence, the question: | ||||
| 
 | ||||
| **How could I have an arbitrary number of subdomains (`foo.bar`, `baz.foo.bar`) all resolve to the same IP without manual mapping? | ||||
| 
 | ||||
| ## The solution | ||||
| 
 | ||||
| Unlike upstream OpenWRT, TurrisOS does not use [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html) for name resolution (it is only used as DHCP server), opting instead for [Knot Resolver](https://www.knot-resolver.cz/), also developed by CZ.NIC. kresd (the Knot Resolver daemon) is sufficiently nimble and can be scripted and configured with a bit of Lua. Unlike others that absolutely require features that are dnsmasq specific, I had absolutely no problems with it. | ||||
| 
 | ||||
| Thanks to the [extensive documentation](https://knot-resolver.readthedocs.io/en/stable/) and [some helpful developers](https://forum.turris.cz/u/vcunat) I was able to configure it to do exactly like I wanted. | ||||
| 
 | ||||
| One first needs to check, on the Omnia, the configuration file which is located at `/etc/config/resolver`, and navigate to the options related to kresd: | ||||
| 
 | ||||
| ``` | ||||
| config resolver 'kresd' | ||||
| option rundir '/tmp/kresd' | ||||
| option log_stderr '0' | ||||
| option log_stdout '0' | ||||
| option forks '1' | ||||
| option include_config '/etc/kresd/custom.conf' | ||||
| option keep_cache '0' | ||||
| list hostname_config '/etc/hosts' | ||||
| ``` | ||||
| 
 | ||||
| This is my configuration, which might be different from yours. What's important is `option include_config`, which you can point to a custom file where you can set additional kresd configuration. | ||||
| 
 | ||||
| What I did was to create this file and add: | ||||
| 
 | ||||
| ```lua | ||||
| 
 | ||||
| local genRR = policy.ANSWER({ | ||||
| [kres.type.A] = { rdata=kres.str2ip('192.168.30.55'), ttl=900 }, | ||||
| }, true) | ||||
| 
 | ||||
| policy.add(policy.suffix(genRR, { todname('internal.example.com.') })) | ||||
| ``` | ||||
| 
 | ||||
| What does it do? It sets a [query policy](https://knot-resolver.readthedocs.io/en/stable/modules-policy.html#mod-policy), which tells kresd what to do exactly with some requests. | ||||
| 
 | ||||
| Notice that these statements will *only* work with kresd >= 5.1, but even the legacy TurrisOS 3.x has the latest version, if you are up-to-date with updates. | ||||
| 
 | ||||
| In particular, when the request is `kres.type.A`, so an A record, it gives back `192.168.30.55` with a [time-to-live](https://en.wikipedia.org/wiki/Time_to_live) of 900 seconds. This means that every request that follows this policy will answer the same IP address. The secont line adds [a new policy rule](https://knot-resolver.readthedocs.io/en/stable/modules-policy.html#policy.add) to the resolver, which means that every subdomain of `internal.example.com` will resolve to 192.168.30.55. | ||||
| 
 | ||||
| Since kresd assumes data in the DNS wire format, as defined in [RFC 1035](https://tools.ietf.org/html/rfc1035), we use a couple of convenience functions (`kres.str2ip` and `todname`) so we can just type our IP addresses or domain names without any trouble. We can also, potentially, specify multiple subdomains to check with the `policy.todnames` function: | ||||
| 
 | ||||
| ```lua | ||||
| policy.add(policy.suffix(genRR, policy.todnames({'internal.example.com', 'external.example.com'}))) | ||||
| ``` | ||||
| 
 | ||||
| Once that is a done deal, you can just restart kresd on the Omnia (`/etc/init.d/resolver restart`) to have kresd pick up your configuration. If it doesn't start... well, you have a problem. In this case you can set `log_stderr` and `log_stdout` to 1 in the configuration and then check `/var/log/messages` for potential configuration errors. | ||||
| 
 | ||||
| ## Conclusion | ||||
| 
 | ||||
| Like this, I was able to set Let's Encrypt for all the subdomains I needed and I could also use HTTPS internally, without resorting to ideas like adding my own CA (which would have complicated things quite a bit. It took a while to figure out, including [troubles due to API changes](https://forum.turris.cz/t/kresd-crashes-with-policy-configuration-and-fqdn-as-router-name/14722), but now it performs exactly as I want to. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue