~evilham/cdist-evilham

6ad346915695460e8eef299dc1cb8c5787e94d94 — Evilham 2 months ago 2ca5cdc
[__knot*] Refactored adding a zone and added __knotc

Now it's significantly simpler to setup a primary/secondary setting and to
manage zones and PTRs.

The __knotc type is atm very basic and basically just runs a knotc script on the
remote host.
M type/__evilham_knot_dns/manifest => type/__evilham_knot_dns/manifest +8 -1
@@ 161,13 161,20 @@ if ! grep -q default "${__object}/explorer/available-templates"; then
    KNOT_TEMPLATE_SECTION="$(cat <<EOF
${KNOT_TEMPLATE_SECTION:-template:}
  - id: default
    storage: "/var/db/knot/master"
    storage: "/var/db/knot/primary"
    semantic-checks: on
    disable-any: on
    serial-policy: dateserial
    file: "%s.zone"
    global-module: mod-cookies
    global-module: mod-rrl/default
    global-module: mod-stats
  - id: secondary
    storage: "/var/db/knot/secondary"
    semantic-checks: on
    disable-any: on
    serial-policy: dateserial
    file: "%s.zone"
EOF
)"
fi

A type/__evilham_knot_dns_add_zone/explorer/available-zone-files => type/__evilham_knot_dns_add_zone/explorer/available-zone-files +11 -0
@@ 0,0 1,11 @@
#!/bin/sh -e

KNOT_DB_DIR="/var/db/knot"
KNOT_PRIMARY_DIR="${KNOT_DB_DIR}/primary"
KNOT_SECONDARY_DIR="${KNOT_DB_DIR}/secondary"

for dir in "${KNOT_PRIMARY_DIR}" "${KNOT_SECONDARY_DIR}"; do
    if [ -d "${dir}" ]; then
        find "${dir}" -type f -name '*.zone' || true
    fi
done

A type/__evilham_knot_dns_add_zone/gencode-remote => type/__evilham_knot_dns_add_zone/gencode-remote +70 -0
@@ 0,0 1,70 @@
#!/bin/sh -e


ZONE="${__object_id}"

KNOT_PRIMARY_DIR="/var/db/knot/primary"
ZONE_FILE="${KNOT_PRIMARY_DIR}/${ZONE}.zone"

CREATE_ZONE_FILE="YES"
if [ -f "${__object}/parameter/dont-create-zone-file" ]; then
    CREATE_ZONE_FILE=""
fi
if [ -f "${__object}/parameter/transfer-remote" ]; then
    TRANSFER_REMOTE="$(cat "${__object}/parameter/transfer-remote")"
fi

# Don't bother with zone file if we were either told not to or are secondary.
if [ -z "${CREATE_ZONE_FILE}" -o -n "${TRANSFER_REMOTE}" ]; then
    exit 0
fi
# This zone has a zone file already, exit
if grep -q "${ZONE}.zone"  "${__object}/explorer/available-zone-files"; then
    exit 0
fi

# First, convert email to a format for the DNS
FULL_EMAIL="$(cat "${__object}/parameter/admin-email")"
# Everything before '@' must have dots escaped with '\.'
EMAIL_USER="$(echo "${FULL_EMAIL}" | cut -d '@' -f 1 | sed -e 's/[.]/\\./g')"
# Everything after '@' remains the same
EMAIL_DOMAIN="$(echo "${FULL_EMAIL}" | cut -d '@' -f 2)"
# '@' gets replaced with a dot.
ADMIN_EMAIL="${EMAIL_USER}.${EMAIL_DOMAIN}"

if [ -f "${__object}/parameter/zone-file-contents" ]; then
    ZONE_FILE_CONTENTS="$(cat "${__object}/parameter/zone-file-contents")"
else
    if [ -f "${__object}/parameter/name-server" ]; then
        PRIMARY_NAME_SERVER="$(head -n 1 "${__object}/parameter/name-server")"
        SECONDARY_NAME_SERVERS="$(tail -n +2 "${__object}/parameter/name-server")"
    fi
    if [ -z "${PRIMARY_NAME_SERVER}" ]; then
        PRIMARY_NAME_SERVER="${__target_host}"
    fi
    # We follow RIPE's recommendations for SOA records by default:
    # https://www.ripe.net/publications/docs/ripe-203
    # We hard-code: TTLs 1h (3600), Serial %Y%m%d00, Refresh 24h (86400),
    #               Retry 2h (7200), Expire 1000h (3600)
    #               and minimum 2d (172800)
    # This will be replaced by knot when the zone gets modified with e.g. nsupdate
    SERIAL="$(date +"%Y%m%d00")"
    ZONE_FILE_CONTENTS="$(cat <<EOF
;; Generated automatically by cdist.
${ZONE}. 3600 SOA ${PRIMARY_NAME_SERVER}. ${ADMIN_EMAIL}. ${SERIAL} 86400 7200 3600 172800
${ZONE}. 3600 NS  ${PRIMARY_NAME_SERVER}.
EOF
)"
    for ns in ${SECONDARY_NAME_SERVERS}; do
        ZONE_FILE_CONTENTS="$(cat <<EOF
${ZONE_FILE_CONTENTS}
${ZONE}. 3600 NS  ${ns}.
EOF
)"
    done
fi
cat <<EOF
cat > "${ZONE_FILE}" <<END
${ZONE_FILE_CONTENTS}
END
EOF

A type/__evilham_knot_dns_add_zone/manifest => type/__evilham_knot_dns_add_zone/manifest +109 -0
@@ 0,0 1,109 @@
#!/bin/sh -e
#
# Get OS-dependent settings
#
os="$(cat "${__global}/explorer/os")"

KNOT_ETC_DIR="/etc/knot"
case "${os}" in
    *bsd)
        KNOT_ETC_DIR="/usr/local/etc/knot"
    ;;
    *)
        echo "This type hasn't been tested in ${os}, please try it and let us know how it (doesn't) works" > /dev/stderr
        exit 1
    ;;
esac

ZONE="${__object_id}"

INDENT="    "
# Deal with parameters
if [ -f "${__object}/parameter/admin-email" ]; then
    ADMIN_EMAIL="$(cat "${__object}/parameter/admin-email")"
fi
if [ -f "${__object}/parameter/acl" ]; then
    ACL="$(cat "${__object}/parameter/acl")"
    if [ -n "${ACL}" ]; then
        ACL="${INDENT}acl: ${ACL}"
    fi
fi
if [ -f "${__object}/parameter/module" ]; then
    MODULE="$(cat "${__object}/parameter/module")"
    if [ -n "${MODULE}" ]; then
        MODULE="${INDENT}module: ${MODULE}"
    fi
fi
if [ -f "${__object}/parameter/notify-remote" ]; then
    NOTIFY_REMOTE="$(cat "${__object}/parameter/notify-remote")"
    if [ -n "${NOTIFY_REMOTE}" ]; then
        NOTIFY_REMOTE="${INDENT}notify: ${NOTIFY_REMOTE}"
    fi
fi
TEMPLATE="$(cat "${__object}/parameter/template")"
if [ "${TEMPLATE}" = "default" ]; then
    TEMPLATE=""
fi
if [ -f "${__object}/parameter/transfer-remote" ]; then
    TRANSFER_REMOTE="$(cat "${__object}/parameter/transfer-remote")"
    if [ -n "${TRANSFER_REMOTE}" ]; then
        TRANSFER_REMOTE="${INDENT}master: ${TRANSFER_REMOTE}"
    fi
fi
source="$(cat "${__object}/parameter/source")"
if [ "${source}" = "-" ]; then
    source="${__object}/stdin"
fi

# Fail early if missing data
if [ -z "${source}" -a -z "${ADMIN_EMAIL}" ]; then
    echo "--admin-email is only optional if you are passing --source." > /dev/stderr
    exit 1
fi

# Ensure knot's directories for zone files exists
# This comes from FreeBSD's port system
# TODO: treat other OSs nicely
KNOT_UID="553"
KNOT_GID="553"
KNOT_DB_DIR="/var/db/knot"
KNOT_PRIMARY_DIR="${KNOT_DB_DIR}/primary"
KNOT_SECONDARY_DIR="${KNOT_DB_DIR}/secondary"
# Proceed sequentially
export CDIST_ORDER_DEPENDENCY=1
__directory --owner "${KNOT_UID}" --group "${KNOT_GID}" "${KNOT_DB_DIR}"
#
# Having transfer-remote being defined implies that we are secondary to some other server
if [ -z "${TRANSFER_REMOTE}" ]; then
    __directory --owner "${KNOT_UID}" --group "${KNOT_GID}" "${KNOT_PRIMARY_DIR}"
else
    __directory --owner "${KNOT_UID}" --group "${KNOT_GID}" "${KNOT_SECONDARY_DIR}"
    if [ -z "${TEMPLATE}" ]; then
        # Use secondary template if we aren't a primary server
        TEMPLATE="secondary"
    fi
fi
# Go back to being parallel
unset CDIST_ORDER_DEPENDENCY

if [ -n "${TEMPLATE}" ]; then
    TEMPLATE="${INDENT}template: ${TEMPLATE}"
fi

#
# Actually deal with registering the zone remotely
# Either use the passed source data or generate automatically from data
#
if [ -n "${source}" ]; then
    __evilham_knot_dns_section_item --source "${source}" "zone/${ZONE}"
else
    __evilham_knot_dns_section_item --source "-" "zone/${ZONE}" <<EOF
zone:
  - domain: ${ZONE}
${TEMPLATE}
${ACL}
${NOTIFY_REMOTE}
${TRANSFER_REMOTE}
${MODULE}
EOF
fi

A type/__evilham_knot_dns_add_zone/parameter/boolean => type/__evilham_knot_dns_add_zone/parameter/boolean +1 -0
@@ 0,0 1,1 @@
dont-create-zone-file

A type/__evilham_knot_dns_add_zone/parameter/default/source => type/__evilham_knot_dns_add_zone/parameter/default/source +0 -0

A type/__evilham_knot_dns_add_zone/parameter/default/template => type/__evilham_knot_dns_add_zone/parameter/default/template +1 -0
@@ 0,0 1,1 @@
default
\ No newline at end of file

A type/__evilham_knot_dns_add_zone/parameter/optional => type/__evilham_knot_dns_add_zone/parameter/optional +8 -0
@@ 0,0 1,8 @@
acl
admin-email
module
notify-remote
template
transfer-remote
source
zone-file-contents

A type/__evilham_knot_dns_add_zone/parameter/optional_multiple => type/__evilham_knot_dns_add_zone/parameter/optional_multiple +1 -0
@@ 0,0 1,1 @@
name-server

M type/__evilham_knot_dns_ptr/manifest => type/__evilham_knot_dns_ptr/manifest +3 -7
@@ 59,11 59,7 @@ fi
# and rounded as RIPE recommends.
#
for forward_zone in ${FORWARD_ZONES}; do
    __evilham_knot_dns_section_item ${ZONE_PARAMETERS} \
                                    --source "-" \
                                    "zone/${forward_zone}" <<EOF
zone:
  - domain: ${forward_zone}
    module: mod-synthrecord/r_${KNOT_ID_SUFFIX}
EOF
    __evilham_knot_dns_add_zone ${ZONE_PARAMETERS} \
                                --module "mod-synthrecord/r_${KNOT_ID_SUFFIX}" \
                                "${forward_zone}"
done

D type/__evilham_knot_dns_section_item/explorer/available-zone-files => type/__evilham_knot_dns_section_item/explorer/available-zone-files +0 -11
@@ 1,11 0,0 @@
#!/bin/sh -e

# This comes from FreeBSD's port system
KNOT_UID="553"
KNOT_GID="553"
KNOT_DB_DIR="/var/db/knot"
KNOT_MASTER_DIR="/var/db/knot/master"

if [ -d "${KNOT_MASTER_DIR}" ]; then
    find "${KNOT_MASTER_DIR}" -type f -name '*.zone' || true
fi

M type/__evilham_knot_dns_section_item/gencode-remote => type/__evilham_knot_dns_section_item/gencode-remote +7 -49
@@ 1,4 1,11 @@
#!/bin/sh
SECTION="$(echo "${__object_id}" | cut -d '/' -f 1)"

if [ "${SECTION}" != "key" ]; then
    # Nothing to do for non-keys atm
    exit 0
fi

#
# Get OS-dependent settings
#


@@ 13,11 20,6 @@ case "${os}" in
    ;;
esac

KNOT_MASTER_DIR="/var/db/knot/master"



SECTION="$(echo "${__object_id}" | cut -d '/' -f 1)"
NAME="$(echo "${__object_id}" | cut -d '/' -f 2)"

SECTION_DIR="${KNOT_ETC_DIR}/conf.d/${SECTION}"


@@ 27,53 29,9 @@ if [ -f "${__object}/parameter/regen-key" ]; then
    REGEN_KEY="YES"
fi

if [ "${SECTION}" == "key" ]; then
    cat <<EOF
# Regenerate if needed or requested
if [ -n "${REGEN_KEY}" -o ! -f "${ITEM_FILE}" ]
    keymgr -t "${NAME}" > "${ITEM_FILE}"
fi
EOF
elif [ "${SECTION}" == "zone" ]; then
    if ! grep -q "${NAME}.zone"  "${__object}/explorer/available-zone-files"; then
        # This zone doesn't have a zone file yet, let's create one
        EMAIL="$(cat "${__object}/parameter/zone-admin-email")"
        EMAIL_USER="$(echo "${EMAIL}" | cut -d '@' -f 1 | sed -e 's/[.]/\\./g')"
        EMAIL_DOMAIN="$(echo "${EMAIL}" | cut -d '@' -f 2)"
        ADMIN_EMAIL="${EMAIL_USER}.${EMAIL_DOMAIN}"
        if [ -f "${__object}/parameter/zone-file-contents" ]; then
            ZONE_FILE_CONTENTS="$(cat "${__object}/parameter/zone-file-contents")"
        else
            if [ -f "${__object}/parameter/zone-primary-name-server" ]; then
                ZONE_NAME_SERVER="$(cat "${__object}/parameter/zone-primary-name-server")"
            else
                ZONE_NAME_SERVER="${__target_host}"
            fi
            # We hard-code: TTLs 15m (900), Serial 1, Refresh 30m (1800),
            #               Retry 15m (900) and Expire 1000h (3600000)
            # This will be replaced by knot when the zone gets modified with e.g. nsupdate
            SERIAL="$(date +"%Y%m%d00")"
            ZONE_FILE_CONTENTS="$(cat <<EOF
;; Generated automatically by cdist.
${NAME}. 900 SOA ${ZONE_NAME_SERVER}. ${ADMIN_EMAIL}. ${SERIAL} 1800 900 3600000 900
${NAME}. 900 NS  ${ZONE_NAME_SERVER}.
EOF
)"
            if [ -f "${__object}/parameter/extra-name-server" ]; then
                EXTRA_NAME_SERVERS="$(cat "${__object}/parameter/extra-name-server")"
            fi
            for ns in ${EXTRA_NAME_SERVERS}; do
                ZONE_FILE_CONTENTS="$(cat <<EOF
${ZONE_FILE_CONTENTS}
${NAME}. 900 NS  ${ns}.
EOF
)"
            done
        fi
        cat <<EOF
cat > "${KNOT_MASTER_DIR}/${NAME}.zone" <<END
${ZONE_FILE_CONTENTS}
END
EOF
     fi
fi

M type/__evilham_knot_dns_section_item/manifest => type/__evilham_knot_dns_section_item/manifest +0 -17
@@ 46,10 46,6 @@ case "${SECTION}" in
            echo "Parameter --source is required for section ${SECTION}." > /dev/stderr
            exit 1
        fi
        if [ "${SECTION}" == "zone" -a ! -f "${__object}/parameter/zone-admin-email" ]; then
            echo "Parameter --zone-admin-email is required for section ${SECTION}." > /dev/stderr
            exit 1
        fi
        if [ "${SECTION}" != "module" -a -n "${SUBSECTION}" ]; then
            echo "Subsections are currently only allowed for the module section (got ${SECTION})." > /dev/stderr
            exit 1


@@ 74,19 70,6 @@ if [ "${SECTION}" == "key" ]; then
    # and generate keys as needed in `gencode-remote`.
    exit 0
fi
if [ "${SECTION}" == "zone" ]; then
    # Ensure knot's directory for zone files exists
    # This comes from FreeBSD's port system
    # TODO: treat other OSs nicely
    KNOT_UID="553"
    KNOT_GID="553"
    KNOT_DB_DIR="/var/db/knot"
    KNOT_MASTER_DIR="${KNOT_DB_DIR}/master"
    # Proceed sequentially
    export CDIST_ORDER_DEPENDENCY=1
    __directory --owner "${KNOT_UID}" --group "${KNOT_GID}" "${KNOT_DB_DIR}"
    __directory --owner "${KNOT_UID}" --group "${KNOT_GID}" "${KNOT_MASTER_DIR}"
fi

source="$(cat "${__object}/parameter/source")"
if [ "${source}" = "-" ]; then

M type/__evilham_knot_dns_section_item/parameter/optional => type/__evilham_knot_dns_section_item/parameter/optional +0 -3
@@ 1,4 1,1 @@
source
zone-admin-email
zone-file-contents
zone-primary-name-server

D type/__evilham_knot_dns_section_item/parameter/optional_multiple => type/__evilham_knot_dns_section_item/parameter/optional_multiple +0 -1
@@ 1,1 0,0 @@
extra-name-server
\ No newline at end of file

A type/__evilham_knotc/gencode-remote => type/__evilham_knotc/gencode-remote +22 -0
@@ 0,0 1,22 @@
#!/bin/sh

source="$(cat "${__object}/parameter/source")"
if [ "${source}" = "-" ]; then
    source="${__object}/stdin"
fi

if [ -n "${source}" ]; then
    SCRIPT="$(cat "${source}")"
else
    if [ ! -f "${__object}/parameter/pseudo-script" ]; then
        exit 0
    fi
    echo "This is still not supported" > /dev/stderr
    exit 1
fi

cat <<EOF
knotc <<eof
${SCRIPT}
eof
EOF

A type/__evilham_knotc/parameter/optional => type/__evilham_knotc/parameter/optional +2 -0
@@ 0,0 1,2 @@
source
pseudo-script