Skip to content

Latest commit

 

History

History
211 lines (154 loc) · 8.46 KB

README.md

File metadata and controls

211 lines (154 loc) · 8.46 KB

GoZones

Docker Repository on Quay Tests release

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.

Example Commands & Parameters

# 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

Deployment - As a Container

Pre-built container images can be found at https://quay.io/repository/kenmoini/go-zones

GoZones comes with a set of Containerfiles that can be built with Docker or Podman with the following commands:

Server Mode Container

# 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

File Mode Fronting to BIND

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

Container-as-a-Service

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):

1. Create Bridge Device

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/

2. Create a new Podman Bridge Network

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
         }
      }
   ]
}
3. Test the Container and Network

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

4. Creating a Service

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

Adding extra files to the container image

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.

Deployment - Building From Source

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