GoZones is an application that will take DNS Zones as defined in YAML and generate BIND-compatable DNS Zone files and the configuration required to load the zone file.
GoZones can operate in single-file input/output batches, or via an HTTP server, in a variety of different modes:
- Server Mode: GoZones will listen for DNS requests and respond with the generated zone file. Supported by the standalone binary and container images.
- File Mode: GoZones will read a zone file and generate the BIND configuration at a specified path. Supported by the standalone binary and container images.
- File Mode Fronting to BIND: GoZones will read a zone file and generate the BIND configuration at a specified path, which will then start a BIND server Supported in a container image.
# File Mode - input source, output target (default mode)
$ ./go-zones -source=./example.server.yml -dir=./generated
# Server Mode - listens on a port and responds with the generated assets
$ ./go-zones -mode server -config=./example.config.yml
Pre-built container images can be found at https://quay.io/repository/kenmoini/go-zones
GoZones comes with a set of Containerfile
s that can be built with Docker or Podman with the following commands:
# Build the container
podman build -f Containerfile -t go-zones .
# Create a config directory locally with a server configuration YAML file
mkdir -p config && cp example.config.yml config/config.yml
# Mount that directory and run a container
podman run -p 8080:8080 -v "$(pwd)"/config:/etc/go-zones/ go-zones
There is an extra Containerfile.file-to-bind
container definition file that will set up a container image that starts GoZones to generate zone files and BIND configuration, then starts a BIND DNS Server.
# Build the container
podman build -f Containerfile.file-to-BIND -t go-zones:file-to-bind .
# Create a config directory locally with a Zones configuration YAML file for file mode operation
mkdir -p config && cp example.server.yml config/server.yml
# Mount that directory and run a container
podman run --name go-zones-ftb -d -p 8053:8053 -v "$(pwd)"/config:/etc/go-zones/ go-zones:file-to-bind
If you're interested in running a GoZones File-to-BIND container as a service with a static IP, you can do so with the following (tested on RHEL 8.3 with Podman 2.2.1):
First you must create a Bridge Network Device on your system - this creates a virtual device, the bridge, that allows containers and VMs on your system to connect through to the network that system is connected to.
Creating a Bridge device is outside of the scope of this document, find the different ways to create one here: https://www.tecmint.com/create-network-bridge-in-rhel-centos-8/
By default, containers will have access to a bridge device that connects the Pods to a NAT'd network. This is not ideal for running static services for your network - instead, use Podman to create a new network that uses a macvlan-style container network to connect to a bridge device. Run the following commands:
sudo podman create network lanBridge
sudo nano /etc/cni/net.d/lanBridge.conflist
Make the file look something like this, substituting for bridge (your bridge device), and your bridged network subnet and range Podman can utilize (it can overlap with your full subnet, DHCP would be passed off to the gateway through the bridge):
{
"cniVersion": "0.4.0",
"name": "lanBridge",
"plugins": [
{
"type": "bridge",
"bridge": "LANbr0",
"ipam": {
"type": "host-local",
"ranges": [
[
{
"subnet": "192.168.42.0/24",
"rangeStart": "192.168.42.2",
"rangeEnd": "192.168.42.254",
"gateway": "192.168.42.1"
}
]
],
"routes": [
{"dst": "0.0.0.0/0"}
]
}
},
{
"type": "portmap",
"capabilities": {
"portMappings": true
}
},
{
"type": "firewall",
"backend": ""
},
{
"type": "tuning",
"capabilities": {
"mac": true
}
}
]
}
Before firing up a service wraped deployment, test the plumbing so far:
# Create needed directories
mkdir -p /opt/service-containers/dns-core-1/volumes/etc-conf
# Download an example zones file
curl https://raw.githubusercontent.com/kenmoini/go-zones/main/zones.yml.example -o /opt/service-containers/dns-core-1/volumes/etc-conf/zones.yml
# Test the container, assign it an IP in your bridged subnet range
podman run -d --name dns-core-1 --network lanBridge --ip 192.168.42.10 -p 53 -v /opt/service-containers/dns-core-1/volumes/etc-conf:/etc/go-zones/ quay.io/kenmoini/go-zones:file-to-bind
Note that the -d
option will launch the container into the background - test the BIND DNS Server running in the container, the query for example.net should look like the following from an internal network:
dig @192.168.42.10 example.net
; <<>> DiG 9.11.20-RedHat-9.11.20-5.el8_3.1 <<>> @192.168.42.10 example.net
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7346
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 710f246c6fde139b45d1957e60453e6b526aded7b99e739f (good)
;; QUESTION SECTION:
;example.net. IN A
;; ANSWER SECTION:
example.net. 3600 IN A 192.168.42.100
;; AUTHORITY SECTION:
example.net. 86400 IN NS dns-core-1.example.labs.
example.net. 86400 IN NS dns-core-2.example.labs.
;; ADDITIONAL SECTION:
dns-core-1.example.labs. 86400 IN A 192.168.42.2
dns-core-2.example.labs. 86400 IN A 192.168.42.3
;; Query time: 0 msec
;; SERVER: 192.168.42.10#53(192.168.42.10)
;; WHEN: Sun Mar 07 15:58:19 EST 2021
;; MSG SIZE rcvd: 178
Note that you may need to handle some SELinux contexts (like disabling it lol jk kinda not jk) - also don't forget to clean up the running container with podman ps
and podman kill dns-core-1 && podman rm dns-core-1
Now that the service is tested to work properly you can create a service file and launch the container at system boot.
Reference the file go-zones-file-to-bind-podman.service
in this repository for defining your service. The file is ready to work with these example steps as a service called dns-core-1
and the following steps will produce that resulting service:
# Download the service file
curl https://raw.githubusercontent.com/kenmoini/go-zones/main/go-zones-file-to-bind-podman.service -o /etc/systemd/system/dns-core-1.service
# Reload systemd services
systemctl daemon-reload
# Start service
systemctl enable --now dns-core-1
# Check service status and running container
systemctl status dns-core-1
podman ps
If you need additional assets along side the Golang binary in the built container you can simply place them in the container_root
directory - directories/files in this container_root
directory will be copied to the root of the container file system. You can find an example of using a touchfile to create the /etc/go-zones/
directory in the built container.
Since this is just a Golang application, as long as you have Golang v1.15+ then the following commands will do the job:
go build
# or mega test
rm -rf generated/ && go build && ./go-zones -source=./example.server.yml -dir=./generated
./go-zones