This commit is contained in:
ElevenNotes
2024-12-03 14:35:57 +01:00
parent 35b83c26d5
commit 25985de890
21 changed files with 373 additions and 109 deletions

View File

@@ -14,13 +14,19 @@ jobs:
release:
name: release
runs-on: ubuntu-latest
defaults:
run:
shell: bash
working-directory: ./
steps:
- name: create release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
run: |
set -ex; \
wget -O ./RELEASE.md https://raw.githubusercontent.com/${GITHUB_REPOSITORY}/refs/heads/master/RELEASE.md; \
gh release create "$tag" \
--repo="$GITHUB_REPOSITORY" \
--title="${tag#v}" \
--generate-notes
-F ./RELEASE.md

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
maintain/
project*
project*
build

View File

@@ -1,12 +1,27 @@
![Banner](https://github.com/11notes/defaults/blob/main/static/img/banner.png?raw=true)
# 🏔️ Alpine - BIND
![size](https://img.shields.io/docker/image-size/11notes/bind/9.18.30?color=0eb305) ![version](https://img.shields.io/docker/v/11notes/bind/9.18.30?color=eb7a09) ![pulls](https://img.shields.io/docker/pulls/11notes/bind?color=2b75d6)
[<img src="https://img.shields.io/badge/github-source-blue?logo=github">](https://github.com/11notes/docker-bind/tree/9.18.31) ![size](https://img.shields.io/docker/image-size/11notes/bind/9.18.31?color=0eb305) ![version](https://img.shields.io/docker/v/11notes/bind/9.18.31?color=eb7a09) ![pulls](https://img.shields.io/docker/pulls/11notes/bind?color=2b75d6)
**BIND DNS server**
**High performance bind with default operating modes**
# SYNOPSIS
What can I do with this? This image will run BIND9 DNS server precompiled for large installations and maximum performance.
**What can I do with this?** This image will run BIND9 DNS server precompiled for large installations and maximum performance. It also offers three operating modes: Master, Slave and Resolver set via **command: ["mode"]**.
# Master
If run as master, set the IPs of the slaves via *BIND_SLAVES*. Bind will operate with catalog zones for all slaves. You can add new zones via the *addzone* script that requires the zone name and the IP of at least one NS (slave). You can then use nsupdate to update the master with new records and all changes are populates to all slaves automatically. Add a new zone like this:
```shell
docker exec master addzone contoso.com 10.255.53.52
```
It will automatically create a default zone and populate it as well as add a random key for managing the zone via nsupdate or via the dynamically created root key at startup (check /bind/etc/keys.conf for generated keys). Checkout **compose.authoritative.yaml** for an example.
# Slave
If run as slave, make sure you set the *BIND_MASTERS* IPs so they will pickup all changes automatically. The slave enables recursion, so make sure you have a resolver present to resolve queries not handles by the slave. The slave will respond to all IPs on RFC1918 by default. You can setup your own config as well. You can run as many slaves as you like.
# Resolver
If run as a resolver, it will cache all results and use the root zone NS to create its own cache database for all records requested. Make sure the resolver has internet access. The resolver will accept all connections from any RFC1918 address. Checkout **compose.resolver.yaml** for an example.
# VOLUMES
* **/bind/etc** - Directory of named.conf
@@ -16,7 +31,7 @@ What can I do with this? This image will run BIND9 DNS server precompiled for la
```yaml
services:
bind:
image: "11notes/bind:9.18.30"
image: "11notes/bind:9.18.31"
container_name: "bind"
environment:
TZ: "Europe/Zurich"
@@ -35,28 +50,6 @@ volumes:
var:
```
# EXAMPLES
## config /bind/etc/named.conf
```
options {
listen-on { any; };
directory "/bind/etc";
recursion no;
allow-notify { none; };
forwarders { 9.9.9.9; 9.9.9.10; };
version "0.0";
auth-nxdomain no;
max-cache-size 0;
dnssec-validation auto;
};
statistics-channels {
inet 0.0.0.0 port 8053;
};
server ::/0 { bogus yes; };
```
# DEFAULT SETTINGS
| Parameter | Value | Description |
| --- | --- | --- |
@@ -70,9 +63,11 @@ server ::/0 { bogus yes; };
| --- | --- | --- |
| `TZ` | [Time Zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | |
| `DEBUG` | Show debug information | |
| `BIND_SLAVES` | IPs of bind slaves if using authoritative master (add ;) | |
| `BIND_MASTERS` | IPs of bind master if using authoritative slave (add ;) | |
# SOURCE
* [11notes/bind](https://github.com/11notes/docker-bind)
* [11notes/bind:9.18.31](https://github.com/11notes/docker-bind/tree/9.18.31)
# PARENT IMAGE
* [11notes/alpine:stable](https://hub.docker.com/r/11notes/alpine)
@@ -86,5 +81,4 @@ server ::/0 { bogus yes; };
* Use Lets Encrypt certificates to protect your SSL endpoints
# ElevenNotes<sup>™️</sup>
This image is provided to you at your own risk. Always make backups before updating an image to a new version. Check the changelog for breaking changes. You can find all my repositories on [github](https://github.com/11notes).
This image is provided to you at your own risk. Always make backups before updating an image to a different version. Check the [RELEASE.md](https://github.com/11notes/docker-bind/blob/9.18.31/RELEASE.md) for breaking changes. You can find all my repositories on [github](https://github.com/11notes).

2
RELEASE.md Normal file
View File

@@ -0,0 +1,2 @@
### New Features
* Operating modus: Master, Slave and Resolver

View File

@@ -8,7 +8,7 @@
# :: Build
FROM 11notes/alpine:stable as build
ARG BUILD_VERSION=9.18.30
ARG BUILD_VERSION=9.18.31
ARG BUILD_DIR=/bind9
USER root
@@ -79,14 +79,14 @@
RUN set -ex; \
cd ${BUILD_DIR}; \
make install-strip;
make install;
# :: Header
FROM 11notes/alpine:stable
COPY --from=util /util/linux/shell/elevenLogJSON /usr/local/bin
COPY --from=util /util/docker /usr/local/bin
COPY --from=build /opt/bind /opt/bind
ENV APP_NAME="bind"
ENV APP_VERSION=9.18.30
ENV APP_VERSION=9.18.31
ENV APP_ROOT=/bind
# :: Run
@@ -111,10 +111,6 @@
jemalloc \
krb5;
# :: upgrade
RUN set -ex; \
apk --no-cache --update upgrade;
# :: copy root filesystem
COPY ./rootfs /
RUN set -ex; \
@@ -131,7 +127,7 @@
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
# :: Monitor
HEALTHCHECK CMD /usr/local/bin/healthcheck.sh || exit 1
HEALTHCHECK --interval=5s --timeout=3s CMD /usr/local/bin/healthcheck.sh || exit 1
# :: Start
USER docker

View File

@@ -12,7 +12,7 @@
# :: Build
FROM --platform=linux/arm64 11notes/alpine:stable as build
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
ARG BUILD_VERSION=9.18.30
ARG BUILD_VERSION=9.18.31
ARG BUILD_DIR=/bind9
USER root
@@ -83,15 +83,15 @@
RUN set -ex; \
cd ${BUILD_DIR}; \
make install-strip;
make install;
# :: Header
FROM --platform=linux/arm64 11notes/alpine:stable
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
COPY --from=util /util/linux/shell/elevenLogJSON /usr/local/bin
COPY --from=util /util/docker /usr/local/bin
COPY --from=build /opt/bind /opt/bind
ENV APP_NAME="bind"
ENV APP_VERSION=9.18.30
ENV APP_VERSION=9.18.31
ENV APP_ROOT=/bind
# :: Run
@@ -116,10 +116,6 @@
jemalloc \
krb5;
# :: upgrade
RUN set -ex; \
apk --no-cache --update upgrade;
# :: copy root filesystem
COPY ./rootfs /
RUN set -ex; \
@@ -136,7 +132,7 @@
VOLUME ["${APP_ROOT}/etc", "${APP_ROOT}/var"]
# :: Monitor
HEALTHCHECK CMD /usr/local/bin/healthcheck.sh || exit 1
HEALTHCHECK --interval=5s --timeout=3s CMD /usr/local/bin/healthcheck.sh || exit 1
# :: Start
USER docker

View File

@@ -0,0 +1,55 @@
name: "authoritative"
services:
master:
image: "11notes/bind:9.18.31"
container_name: "master"
command: ["master"]
environment:
TZ: "Europe/Zurich"
BIND_SLAVES: "10.255.53.2;10.255.53.3;"
networks:
macvlan:
ipv4_address: 10.255.53.1
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
slave1:
image: "11notes/bind:9.18.31"
container_name: "slave1"
command: ["slave"]
environment:
TZ: "Europe/Zurich"
BIND_MASTERS: "10.255.53.1;"
networks:
macvlan:
ipv4_address: 10.255.53.2
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
slave2:
image: "11notes/bind:9.18.31"
container_name: "slave2"
command: ["slave"]
environment:
TZ: "Europe/Zurich"
BIND_MASTERS: "10.255.53.1;"
networks:
macvlan:
ipv4_address: 10.255.53.3
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always
volumes:
etc:
var:
networks:
macvlan:
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: "10.255.53.0/24"
gateway: "10.255.53.254"

15
compose.resolver.yaml Normal file
View File

@@ -0,0 +1,15 @@
name: "resolver"
services:
resolver:
image: "11notes/bind:9.18.31"
container_name: "resolver"
command: ["resolver"]
environment:
TZ: "Europe/Zurich"
ports:
- "53:53/udp"
- "53:53/tcp"
- "8053:8053/tcp"
sysctls:
- "net.ipv4.ip_unprivileged_port_start=53"
restart: always

View File

@@ -1,6 +1,6 @@
services:
bind:
image: "11notes/bind:9.18.30"
image: "11notes/bind:9.18.31"
container_name: "bind"
environment:
TZ: "Europe/Zurich"

View File

@@ -1,4 +0,0 @@
#!/bin/bash
curl -Lo manifest-tool https://github.com/estesp/manifest-tool/releases/download/v0.9.0/manifest-tool-linux-amd64
chmod +x manifest-tool
./manifest-tool push from-spec multi-arch-manifest-version.yaml

View File

@@ -1,10 +1,10 @@
image: 11notes/bind:9.18.30
image: 11notes/bind:9.18.31
manifests:
- image: 11notes/bind:9.18.30
- image: 11notes/bind:9.18.31
platform:
architecture: amd64
os: linux
- image: 11notes/bind:9.18.30
- image: 11notes/bind:9.18.31
platform:
architecture: arm64
os: linux

View File

@@ -0,0 +1,49 @@
options {
listen-on { any; };
directory "/bind/etc";
recursion no;
version "0.0";
auth-nxdomain no;
max-cache-size 0;
dnssec-validation no;
notify explicit;
allow-transfer { %SLAVES% };
also-notify { %SLAVES% };
allow-new-zones yes;
};
server ::/0 { bogus yes; };
key "rndc" {
algorithm hmac-sha256;
secret "%KEY%";
};
key "catalog.home.arpa" {
algorithm hmac-sha256;
secret "%KEY_CATALOG%";
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc"; };
};
statistics-channels {
inet 0.0.0.0 port 8053;
};
acl acl-rfc1918 {
127.0.0.1;
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
};
view "authoritative" {
include "/bind/etc/keys.conf";
match-clients { acl-rfc1918; };
allow-query { acl-rfc1918; };
zone "catalog.home.arpa" { type master; file "/bind/var/catalog.home.arpa.db"; allow-update { key catalog.home.arpa.; 127.0.0.1; }; };
};

View File

@@ -0,0 +1,42 @@
options {
listen-on { any; };
directory "/bind/etc";
recursion no;
version "0.0";
auth-nxdomain no;
max-cache-size 0;
dnssec-validation no;
notify explicit;
allow-new-zones yes;
catalog-zones { zone "catalog.home.arpa" default-masters { %MASTERS% }; };
};
server ::/0 { bogus yes; };
key "rndc" {
algorithm hmac-sha256;
secret "%KEY%";
};
controls {
inet 127.0.0.1 port 953
allow { 127.0.0.1; } keys { "rndc"; };
};
acl acl-rfc1918 {
127.0.0.1;
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
};
view "authoritative" {
recursion yes;
match-clients { acl-rfc1918; };
allow-query { acl-rfc1918; };
allow-recursion { acl-rfc1918; };
allow-query-cache { acl-rfc1918; };
zone "catalog.home.arpa" { type slave; file "/bind/var/catalog.home.arpa.db"; masters { %MASTERS% }; };
};

View File

@@ -0,0 +1,38 @@
options {
listen-on { any; };
directory "/bind/etc";
recursion no;
version "0.0";
auth-nxdomain no;
max-cache-size 0;
dnssec-validation auto;
notify no;
allow-transfer { none; };
also-notify { none; };
prefetch 2 9;
recursive-clients 4096;
};
statistics-channels {
inet 0.0.0.0 port 8053;
};
server ::/0 { bogus yes; };
acl acl-rfc1918 {
127.0.0.1;
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
};
view "resolver" {
recursion yes;
match-clients { acl-rfc1918; };
allow-query { acl-rfc1918; };
allow-recursion { acl-rfc1918; };
allow-query-cache { acl-rfc1918; };
zone "." { type hint; file "/bind/var/root.db"; };
};

View File

@@ -0,0 +1,10 @@
key "rndc" {
algorithm hmac-sha256;
secret "%KEY%";
};
options {
default-key "rndc";
default-server 127.0.0.1;
default-port 953;
};

View File

@@ -1,17 +0,0 @@
options {
listen-on { any; };
directory "/bind/etc";
recursion no;
allow-notify { none; };
forwarders { 9.9.9.9; 9.9.9.10; };
version "0.0";
auth-nxdomain no;
max-cache-size 0;
dnssec-validation auto;
};
statistics-channels {
inet 0.0.0.0 port 8053;
};
server ::/0 { bogus yes; };

View File

@@ -1,26 +0,0 @@
. 518400 IN NS a.root-servers.net.
. 518400 IN NS b.root-servers.net.
. 518400 IN NS c.root-servers.net.
. 518400 IN NS d.root-servers.net.
. 518400 IN NS e.root-servers.net.
. 518400 IN NS f.root-servers.net.
. 518400 IN NS g.root-servers.net.
. 518400 IN NS h.root-servers.net.
. 518400 IN NS i.root-servers.net.
. 518400 IN NS j.root-servers.net.
. 518400 IN NS k.root-servers.net.
. 518400 IN NS l.root-servers.net.
. 518400 IN NS m.root-servers.net.
a.root-servers.net. 518400 IN A 198.41.0.4
b.root-servers.net. 518400 IN A 170.247.170.2
c.root-servers.net. 518400 IN A 192.33.4.12
d.root-servers.net. 518400 IN A 199.7.91.13
e.root-servers.net. 518400 IN A 192.203.230.10
f.root-servers.net. 518400 IN A 192.5.5.241
g.root-servers.net. 518400 IN A 192.112.36.4
h.root-servers.net. 518400 IN A 198.97.190.53
i.root-servers.net. 518400 IN A 192.36.148.17
j.root-servers.net. 518400 IN A 192.58.128.30
k.root-servers.net. 518400 IN A 193.0.14.129
l.root-servers.net. 518400 IN A 199.7.83.42
m.root-servers.net. 518400 IN A 202.12.27.33

View File

@@ -0,0 +1,32 @@
#!/bin/ash
# create dummy zone
DB=${APP_ROOT}/var/${1}.db
cat <<EOT > ${APP_ROOT}/var/${1}.db
${1}. IN SOA . . 1 28800 7200 604800 86400
${1}. IN NS ns1.${1}.
ns1.${1}. IN A ${2}
EOT
# change workdir
cd ${APP_ROOT}/etc
# create TSIG for new zone
KEY=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
echo "key \"${1}\" { algorithm hmac-sha256; secret \"${KEY}\"; };" >> /bind/etc/keys.conf
# add new zone to master
/opt/bind/sbin/rndc addzone ${1} IN authoritative '{type primary; file "'${DB}'"; allow-update { key '${1}'.; key root.; 127.0.0.1; }; };'
# update catalog with new zone
UID=$(echo "${1}" | sha1sum | tr -d "[:space:]-")
cat <<EOT | /opt/bind/bin/nsupdate
server 127.0.0.1 53
update add ${UID}.zones.catalog.home.arpa 3600 IN PTR ${1}
send
EOT
elevenLogJSON info "added new zone ${1} to catalog as ${UID}.zones.catalog.home.arpa"
# reload config due to new keys
/opt/bind/sbin/rndc reload &> /dev/null

View File

@@ -1,15 +1,90 @@
#!/bin/ash
if [ -z "${1}" ]; then
if [ ! -f "/bind/var/root.db" ]; then
elevenLogJSON info "creating root db"
rootdb
fi
NAMED_CONF=${APP_ROOT}/etc/named.conf
RNDC_CONF=${APP_ROOT}/etc/rndc.conf
elevenLogJSON info "starting ${APP_NAME} (${APP_VERSION})"
if [ -z "${1}" ]; then
echo "custom" > ${APP_ROOT}/etc/mode
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION}"
set -- "/opt/bind/sbin/named" \
-fg \
-c "/bind/etc/named.conf" \
-c "${NAMED_CONF}" \
-u docker
else
if echo "$@" | grep -q "resolver"; then
# run bind as a resolver
echo "slave" > ${APP_ROOT}/etc/mode
if [ ! -f "${APP_ROOT}/var/root.db" ]; then
elevenLogJSON info "creating root db for resolver"
rootdb
fi
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating resolver configuration"
cp ${APP_ROOT}/.default/resolver.conf ${NAMED_CONF}
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as resolver"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
fi
if echo "$@" | grep -q "master"; then
# run bind as an authoritative master
echo "master" > ${APP_ROOT}/etc/mode
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating authoritative master configuration"
cp ${APP_ROOT}/.default/authoritative-master.conf ${NAMED_CONF}
cp ${APP_ROOT}/.default/rndc.conf ${RNDC_CONF}
KEY=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
KEY_CATALOG=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
sed -i 's/%SLAVES%/'${BIND_SLAVES}'/' ${NAMED_CONF}
sed -i 's/%KEY%/'${KEY}'/' ${NAMED_CONF}
sed -i 's/%KEY%/'${KEY}'/' ${RNDC_CONF}
sed -i 's/%KEY_CATALOG%/'${KEY_CATALOG}'/' ${NAMED_CONF}
fi
if [ ! -f "${APP_ROOT}/var/catalog.home.arpa.db" ]; then
echo "\$TTL 1h" > ${APP_ROOT}/var/catalog.home.arpa.db
echo "catalog.home.arpa. IN SOA . . 1 28800 7200 604800 86400" >> ${APP_ROOT}/var/catalog.home.arpa.db
echo "catalog.home.arpa. IN NS invalid." >> ${APP_ROOT}/var/catalog.home.arpa.db
echo "version IN TXT \"1\"" >> ${APP_ROOT}/var/catalog.home.arpa.db
fi
if [ ! -f "${APP_ROOT}/etc/keys.conf" ]; then
KEY=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
echo "key \"root\" { algorithm hmac-sha256; secret \"${KEY}\"; };" > ${APP_ROOT}/etc/keys.conf
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as authoritative master"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
fi
if echo "$@" | grep -q "slave"; then
# run bind as an authoritative slave
echo "slave" > ${APP_ROOT}/etc/mode
if [ ! -f "${NAMED_CONF}" ]; then
elevenLogJSON info "creating authoritative slave configuration"
cp ${APP_ROOT}/.default/authoritative-slave.conf ${NAMED_CONF}
KEY=$(head -200 /dev/urandom | cksum | cut -f1 -d " " | sha256sum | tr -d "[:space:]-")
sed -i 's/%MASTERS%/'${BIND_MASTERS}'/' ${NAMED_CONF}
sed -i 's/%KEY%/'${KEY}'/' ${NAMED_CONF}
fi
elevenLogJSON info "starting ${APP_NAME} v${APP_VERSION} as authoritative slave"
set -- "/opt/bind/sbin/named" \
-fg \
-c "${NAMED_CONF}" \
-u docker
fi
fi
exec "$@"

View File

@@ -1,2 +1,2 @@
#!/bin/ash
dig . NS @localhost || exit 1
/opt/bind/bin/dig +time=2 +tries=1 . NS @localhost || exit 1

View File

@@ -6,4 +6,4 @@
ROOT_DB_NS=a.root-servers.net
fi
dig +bufsize=1200 +norec NS . @${ROOT_DB_NS} | egrep -v ';|^$' | egrep -v '\S.+AAAA.+|^$' | sort > /bind/var/root.db
/opt/bind/bin/dig +bufsize=1200 +norec NS . @${ROOT_DB_NS} | egrep -v ';|^$' | egrep -v '\S.+AAAA.+|^$' | sort > /bind/var/root.db